Skip to content

Commit 5f6437c

Browse files
committed
patch: domain & url modules
- `domain` allows trailing underscore under the pretense of rfc 2782 - adds separator based query parsing - changelog includes what parameters were removed causing incompatibly
1 parent 854375f commit 5f6437c

File tree

5 files changed

+27
-6
lines changed

5 files changed

+27
-6
lines changed

CHANGES.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,19 +147,21 @@ _**Breaking**_ ⚠️
147147
- `extremes.py` renamed to `_extremes.py` and is no longer exposed.
148148
- `truthy` was discarded in favour of simple `bool()` function.
149149
- `ipv4_cidr()` and `ipv6_cidr()` has been dropped in favour of `cidr: bool = True` and `cidr: bool = True` keyword-only parameters.
150-
- `email` API now accepts the following keyword-only arguments:
150+
- `email()` API now accepts the following keyword-only arguments:
151151
- `simple_host: bool = False`,
152152
- `ipv6_address: bool = False`,
153153
- `ipv4_address: bool = False`,
154154
- `rfc_1034: bool = False` and
155155
- `rfc_2782: bool = False`.
156-
- `url` has been refactored, it accepts the following keyword-only arguments:
156+
- `whitelist=None` has been removed from `email()`.
157+
- `url()` has been refactored, it accepts the following keyword-only arguments:
157158
- `skip_ipv6_addr: bool = False`,
158159
- `skip_ipv4_addr: bool = False`,
159160
- `may_have_port: bool = True`,
160161
- `simple_host: bool = False`,
161162
- `rfc_1034: bool = False` and
162163
- `rfc_2782: bool = False`.
164+
- `public=False` keyword argument has been removed from `url()`.
163165
- Exposes `i18n` functions directly via `__init__.py`.
164166
- `@validator` decorator catches `Exception`.
165167

src/validators/domain.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def domain(value: str, /, *, rfc_1034: bool = False, rfc_2782: bool = False):
4242
# First character of the domain
4343
rf"^(?:[a-zA-Z0-9{'_'if rfc_2782 else ''}]"
4444
# Sub domain + hostname
45-
+ r"(?:[a-zA-Z0-9-_]{0,61}[A-Za-z0-9])?\.)"
45+
+ rf"(?:[a-zA-Z0-9-_]{{0,61}}[A-Za-z0-9{'_'if rfc_2782 else ''}])?\.)"
4646
# First 61 characters of the gTLD
4747
+ r"+[A-Za-z0-9][A-Za-z0-9-_]{0,61}"
4848
# Last character of the gTLD

src/validators/url.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ def _validate_scheme(value: str):
3838
"""Validate scheme."""
3939
# More schemes will be considered later.
4040
return (
41-
value in {"ftp", "ftps", "git", "http", "https", "rtsp", "sftp", "ssh", "telnet"}
41+
value
42+
# fmt: off
43+
in {
44+
"ftp", "ftps", "git", "http", "https",
45+
"rtmp", "rtmps", "rtsp", "sftp",
46+
"ssh", "telnet",
47+
}
48+
# fmt: on
4249
if value
4350
else False
4451
)
@@ -112,8 +119,18 @@ def _validate_optionals(path: str, query: str, fragment: str, strict_query: bool
112119
optional_segments = True
113120
if path:
114121
optional_segments &= bool(_path_regex().match(path))
115-
if query and parse_qs(query, strict_parsing=strict_query):
116-
optional_segments &= True
122+
try:
123+
if (
124+
query
125+
# ref: https://github.com/python/cpython/issues/117109
126+
and parse_qs(query, strict_parsing=strict_query, separator="&")
127+
and parse_qs(query, strict_parsing=strict_query, separator=";")
128+
):
129+
optional_segments &= True
130+
except TypeError:
131+
# for Python < v3.9.2 (official v3.10)
132+
if query and parse_qs(query, strict_parsing=strict_query):
133+
optional_segments &= True
117134
if fragment:
118135
# See RFC3986 Section 3.5 Fragment for allowed characters
119136
optional_segments &= bool(re.fullmatch(r"[0-9a-zA-Z?/:@\-._~%!$&'()*+,;=]*", fragment))

tests/test_domain.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
("11.com", False, False),
1919
("3.cn.", True, False),
2020
("_example.com", False, True),
21+
("example_.com", False, True),
2122
("a.cn", False, False),
2223
("sub1.sub2.sample.co.uk", False, False),
2324
("somerandomexample.xn--fiqs8s", False, False),

tests/test_url.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ def test_returns_true_on_valid_url(value: str):
152152
"http://[2010:836B:4179::836B:4179",
153153
"http://2010:836B:4179::836B:4179",
154154
"http://2010:836B:4179::836B:4179:80/index.html",
155+
"https://example.org?q=search');alert(document.domain);",
155156
"https://www.example.com/foo/?bar=baz&inga=42&quux",
156157
"https://foo.com/img/bar/baz.jpg?-62169987208",
157158
"https://foo.bar.net/baz.php?-/inga/test-lenient-query/",

0 commit comments

Comments
 (0)