Coverage for documents/validators.py: 54%
18 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 09:07 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 09:07 +0000
1from urllib.parse import urlparse
3from django.core.exceptions import ValidationError
4from django.utils.translation import gettext_lazy as _
7def uri_validator(value: str, allowed_schemes: set[str] | None = None) -> None:
8 """
9 Validates that the given value parses as a URI with required components
10 and optionally restricts to specific schemes.
12 Args:
13 value: The URI string to validate
14 allowed_schemes: Optional set/list of allowed schemes (e.g. {'http', 'https'}).
15 If None, all schemes are allowed.
17 Raises:
18 ValidationError: If the URI is invalid or uses a disallowed scheme
19 """
20 try:
21 parts = urlparse(value)
22 if not parts.scheme: 22 ↛ 27line 22 didn't jump to line 27 because the condition on line 22 was always true
23 raise ValidationError(
24 _(f"Unable to parse URI {value}, missing scheme"),
25 params={"value": value},
26 )
27 elif not parts.netloc and not parts.path:
28 raise ValidationError(
29 _(f"Unable to parse URI {value}, missing net location or path"),
30 params={"value": value},
31 )
33 if allowed_schemes and parts.scheme not in allowed_schemes:
34 raise ValidationError(
35 _(
36 f"URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '.join(allowed_schemes)}",
37 ),
38 params={"value": value, "scheme": parts.scheme},
39 )
41 except ValidationError:
42 raise
43 except Exception as e:
44 raise ValidationError(
45 _(f"Unable to parse URI {value}"),
46 params={"value": value},
47 ) from e
50def url_validator(value) -> None:
51 """
52 Validates that the given value is a valid HTTP or HTTPS URL.
54 Args:
55 value: The URL string to validate
57 Raises:
58 ValidationError: If the URL is invalid or not using http/https scheme
59 """
60 uri_validator(value, allowed_schemes={"http", "https"})