mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
Revert percent encoding in URLs. (#4470)
* Revert "Fix `AnyUrl.build` doesn't do percent encoding (#3061) (#4224)"
This reverts commit e34ff9255f.
* change and warning
This commit is contained in:
@@ -0,0 +1 @@
|
||||
**Revert Change:** Revert percent encoding of URL parts which was originally added in #4224.
|
||||
@@ -1,10 +0,0 @@
|
||||
from pydantic import AnyUrl, stricturl
|
||||
|
||||
url = AnyUrl.build(scheme='https', host='example.com', query='query=my query')
|
||||
print(url)
|
||||
|
||||
my_url_builder = stricturl(quote_plus=True)
|
||||
url = my_url_builder.build(
|
||||
scheme='http', host='example.com', query='query=my query'
|
||||
)
|
||||
print(url)
|
||||
+5
-15
@@ -616,7 +616,11 @@ For URI/URL validation the following types are available:
|
||||
- `tld_required: bool = True`
|
||||
- `host_required: bool = True`
|
||||
- `allowed_schemes: Optional[Set[str]] = None`
|
||||
- `quote_plus: bool = False`
|
||||
|
||||
!!! warning
|
||||
In V1.10.0 and v1.10.1 `stricturl` also took an optional `quote_plus` argument and URL components were percent
|
||||
encoded in some cases. This feature was removed in v1.10.2, see
|
||||
[#4470](https://github.com/pydantic/pydantic/pull/4470) for explanation and more details.
|
||||
|
||||
The above types (which all inherit from `AnyUrl`) will attempt to give descriptive errors when invalid URLs are
|
||||
provided:
|
||||
@@ -679,20 +683,6 @@ If further validation is required, these properties can be used by validators to
|
||||
Also, Chrome, Firefox, and Safari all currently accept `http://exam_ple.com` as a URL, so we're in good
|
||||
(or at least big) company.
|
||||
|
||||
#### Building URLs
|
||||
|
||||
You can build URLs from separate [URL Properties](#url-properties) using the `build` method in
|
||||
[Pydantic URL types](#urls) or any type that inherits from them.
|
||||
|
||||
By default, *pydantic* percent encodes the following URL properties: `user`, `password`, `path`, `query`
|
||||
as per [RFC 3986](https://www.ietf.org/rfc/rfc3986.txt) without replacing spaces with `+` but this can
|
||||
be changed using the `stricturl` method:
|
||||
|
||||
!!! note
|
||||
Percent encoding was added in V1.10
|
||||
|
||||
{!.tmp_examples/types_url_building.md!}
|
||||
|
||||
### Color Type
|
||||
|
||||
You can use the `Color` data type for storing colors as per
|
||||
|
||||
+4
-13
@@ -26,7 +26,6 @@ from typing import (
|
||||
cast,
|
||||
no_type_check,
|
||||
)
|
||||
from urllib.parse import quote, quote_plus
|
||||
|
||||
from . import errors
|
||||
from .utils import Representation, update_not_none
|
||||
@@ -178,7 +177,6 @@ class AnyUrl(str):
|
||||
user_required: bool = False
|
||||
host_required: bool = True
|
||||
hidden_parts: Set[str] = set()
|
||||
quote_plus: bool = False
|
||||
|
||||
__slots__ = ('scheme', 'user', 'password', 'host', 'tld', 'host_type', 'port', 'path', 'query', 'fragment')
|
||||
|
||||
@@ -241,19 +239,18 @@ class AnyUrl(str):
|
||||
|
||||
url = scheme + '://'
|
||||
if user:
|
||||
url += cls.quote(user)
|
||||
url += user
|
||||
if password:
|
||||
url += ':' + cls.quote(password)
|
||||
url += ':' + password
|
||||
if user or password:
|
||||
url += '@'
|
||||
url += host
|
||||
if port and ('port' not in cls.hidden_parts or cls.get_default_parts(parts).get('port') != port):
|
||||
url += ':' + port
|
||||
if path:
|
||||
url += '/'.join(map(cls.quote, path.split('/')))
|
||||
url += path
|
||||
if query:
|
||||
queries = query.split('&')
|
||||
url += '?' + '&'.join(map(lambda s: '='.join(map(cls.quote, s.split('='))), queries))
|
||||
url += '?' + query
|
||||
if fragment:
|
||||
url += '#' + fragment
|
||||
return url
|
||||
@@ -394,10 +391,6 @@ class AnyUrl(str):
|
||||
parts[key] = value # type: ignore[literal-required]
|
||||
return parts
|
||||
|
||||
@classmethod
|
||||
def quote(cls, string: str, safe: str = '') -> str:
|
||||
return quote_plus(string, safe) if cls.quote_plus else quote(string, safe)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
extra = ', '.join(f'{n}={getattr(self, n)!r}' for n in self.__slots__ if getattr(self, n) is not None)
|
||||
return f'{self.__class__.__name__}({super().__repr__()}, {extra})'
|
||||
@@ -565,7 +558,6 @@ def stricturl(
|
||||
tld_required: bool = True,
|
||||
host_required: bool = True,
|
||||
allowed_schemes: Optional[Collection[str]] = None,
|
||||
quote_plus: bool = False,
|
||||
) -> Type[AnyUrl]:
|
||||
# use kwargs then define conf in a dict to aid with IDE type hinting
|
||||
namespace = dict(
|
||||
@@ -575,7 +567,6 @@ def stricturl(
|
||||
tld_required=tld_required,
|
||||
host_required=host_required,
|
||||
allowed_schemes=allowed_schemes,
|
||||
quote_plus=quote_plus,
|
||||
)
|
||||
return type('UrlValue', (AnyUrl,), namespace)
|
||||
|
||||
|
||||
@@ -679,31 +679,12 @@ def test_custom_schemes():
|
||||
(dict(scheme='ws', user='foo', password='x', host='example.net'), 'ws://foo:x@example.net'),
|
||||
(dict(scheme='ws', host='example.net', query='a=b', fragment='c=d'), 'ws://example.net?a=b#c=d'),
|
||||
(dict(scheme='http', host='example.net', port='1234'), 'http://example.net:1234'),
|
||||
(dict(scheme='http', user='foo@bar', host='example.net'), 'http://foo%40bar@example.net'),
|
||||
(dict(scheme='http', user='foo', password='a b', host='example.net'), 'http://foo:a%20b@example.net'),
|
||||
(dict(scheme='http', host='example.net', query='q=foo bar'), 'http://example.net?q=foo%20bar'),
|
||||
(dict(scheme='http', host='example.net', path="/m&m's"), 'http://example.net/m%26m%27s'),
|
||||
],
|
||||
)
|
||||
def test_build_url(kwargs, expected):
|
||||
assert AnyUrl(None, **kwargs) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'kwargs,expected',
|
||||
[
|
||||
(dict(scheme='https', host='example.com', query='query=my query'), 'https://example.com?query=my+query'),
|
||||
(
|
||||
dict(scheme='https', host='example.com', user='my name', password='a password'),
|
||||
'https://my+name:a+password@example.com',
|
||||
),
|
||||
(dict(scheme='https', host='example.com', path='/this is a path'), 'https://example.com/this+is+a+path'),
|
||||
],
|
||||
)
|
||||
def test_build_url_quote_plus(kwargs, expected):
|
||||
assert stricturl(quote_plus=True).build(**kwargs) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'kwargs,expected',
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user