Skip to content

Commit 67142cf

Browse files
committed
✨ Improve error messages for URL validation
Resolves #2243 Signed-off-by: ff137 <ff137@proton.me>
1 parent 90637c2 commit 67142cf

1 file changed

Lines changed: 23 additions & 1 deletion

File tree

src/marshmallow/validate.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from abc import ABC, abstractmethod
88
from itertools import zip_longest
99
from operator import attrgetter
10+
from urllib.parse import urlparse
1011

1112
from marshmallow import types
1213
from marshmallow.exceptions import ValidationError
@@ -210,11 +211,32 @@ def __call__(self, value: str) -> str:
210211
if "://" in value:
211212
scheme = value.split("://")[0].lower()
212213
if scheme not in self.schemes:
213-
raise ValidationError(message)
214+
raise ValidationError(
215+
f"Invalid URL scheme '{scheme}'. "
216+
f"Allowed schemes are: {', '.join(self.schemes)}."
217+
)
214218

215219
regex = self._regex(self.relative, self.absolute, self.require_tld)
216220

217221
if not regex.search(value):
222+
if self.require_tld:
223+
try:
224+
# Extract the netloc (hostname and port)
225+
parsed_url = urlparse(value)
226+
hostname = parsed_url.hostname
227+
except (ValueError, TypeError, AttributeError):
228+
hostname = None
229+
230+
if hostname:
231+
# Check if hostname is an IP address
232+
is_ip = re.match(r"\d+\.\d+\.\d+\.\d+", hostname)
233+
# Check if hostname contains a dot (.)
234+
has_tld = "." in hostname
235+
if not is_ip and not has_tld:
236+
raise ValidationError(
237+
"URL must include a top-level domain (e.g., '.com', '.org')."
238+
)
239+
# Default error message for other failures
218240
raise ValidationError(message)
219241

220242
return value

0 commit comments

Comments
 (0)