Hello community, here is the log from the commit of package python-yarl for openSUSE:Factory checked in at 2020-10-29 09:46:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-yarl (Old) and /work/SRC/openSUSE:Factory/.python-yarl.new.3463 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-yarl" Thu Oct 29 09:46:15 2020 rev:14 rq:838272 version:1.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-yarl/python-yarl.changes 2020-07-31 16:08:01.988846749 +0200 +++ /work/SRC/openSUSE:Factory/.python-yarl.new.3463/python-yarl.changes 2020-10-29 09:46:17.624054560 +0100 @@ -1,0 +2,11 @@ +Mon Sep 28 12:05:26 UTC 2020 - Dirk Mueller <[email protected]> + +- update to 1.6.0: + - Allow for int and float subclasses in query, while still denying bool. + `#492 <https://github.com/aio-libs/yarl/issues/492>`_ + - Do not requote arguments in ``URL.build()``, ``with_xxx()`` and in ``/`` operator. + `#502 <https://github.com/aio-libs/yarl/issues/502>`_ + - Keep IPv6 brackets in ``origin()``. + `#504 <https://github.com/aio-libs/yarl/issues/504>`_ + +------------------------------------------------------------------- Old: ---- yarl-1.5.0.tar.gz New: ---- yarl-1.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-yarl.spec ++++++ --- /var/tmp/diff_new_pack.5x8pVD/_old 2020-10-29 09:46:18.604055486 +0100 +++ /var/tmp/diff_new_pack.5x8pVD/_new 2020-10-29 09:46:18.604055486 +0100 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-yarl -Version: 1.5.0 +Version: 1.6.0 Release: 0 Summary: Yet another URL library License: Apache-2.0 ++++++ yarl-1.5.0.tar.gz -> yarl-1.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/CHANGES.rst new/yarl-1.6.0/CHANGES.rst --- old/yarl-1.5.0/CHANGES.rst 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/CHANGES.rst 2020-09-23 18:36:11.000000000 +0200 @@ -14,6 +14,47 @@ .. towncrier release notes start +1.6.0 (2020-09-23) +================== + +Features +-------- + +- Allow for int and float subclasses in query, while still denying bool. + `#492 <https://github.com/aio-libs/yarl/issues/492>`_ + + +Bugfixes +-------- + +- Do not requote arguments in ``URL.build()``, ``with_xxx()`` and in ``/`` operator. + `#502 <https://github.com/aio-libs/yarl/issues/502>`_ +- Keep IPv6 brackets in ``origin()``. + `#504 <https://github.com/aio-libs/yarl/issues/504>`_ + + +---- + + +1.5.1 (2020-08-01) +================== + +Bugfixes +-------- + +- Fix including relocated internal ``yarl._quoting_c`` C-extension into published PyPI dists. + `#485 <https://github.com/aio-libs/yarl/issues/485>`_ + + +Misc +---- + +- `#484 <https://github.com/aio-libs/yarl/issues/484>`_ + + +---- + + 1.5.0 (2020-07-26) ================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/MANIFEST.in new/yarl-1.6.0/MANIFEST.in --- old/yarl-1.5.0/MANIFEST.in 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/MANIFEST.in 2020-09-23 18:36:11.000000000 +0200 @@ -6,9 +6,8 @@ graft tests global-exclude *.pyc global-exclude *.cache -include yarl/*.c -exclude yarl/_quoting.html -exclude yarl/_quoting.*.so -exclude yarl/_quoting.pyd -exclude yarl/_quoting.*.pyd +include yarl/_quoting_c.c +exclude yarl/*.html +exclude yarl/*.so +exclude yarl/*.pyd prune docs/_build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/PKG-INFO new/yarl-1.6.0/PKG-INFO --- old/yarl-1.5.0/PKG-INFO 2020-07-26 10:34:54.000000000 +0200 +++ new/yarl-1.6.0/PKG-INFO 2020-09-23 18:36:19.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: yarl -Version: 1.5.0 +Version: 1.6.0 Summary: Yet another URL library Home-page: https://github.com/aio-libs/yarl/ Author: Andrew Svetlov @@ -226,6 +226,47 @@ .. towncrier release notes start + 1.6.0 (2020-09-23) + ================== + + Features + -------- + + - Allow for int and float subclasses in query, while still denying bool. + `#492 <https://github.com/aio-libs/yarl/issues/492>`_ + + + Bugfixes + -------- + + - Do not requote arguments in ``URL.build()``, ``with_xxx()`` and in ``/`` operator. + `#502 <https://github.com/aio-libs/yarl/issues/502>`_ + - Keep IPv6 brackets in ``origin()``. + `#504 <https://github.com/aio-libs/yarl/issues/504>`_ + + + ---- + + + 1.5.1 (2020-08-01) + ================== + + Bugfixes + -------- + + - Fix including relocated internal ``yarl._quoting_c`` C-extension into published PyPI dists. + `#485 <https://github.com/aio-libs/yarl/issues/485>`_ + + + Misc + ---- + + - `#484 <https://github.com/aio-libs/yarl/issues/484>`_ + + + ---- + + 1.5.0 (2020-07-26) ================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/docs/api.rst new/yarl-1.6.0/docs/api.rst --- old/yarl-1.5.0/docs/api.rst 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/docs/api.rst 2020-09-23 18:36:11.000000000 +0200 @@ -572,7 +572,8 @@ .. note:: - The library accepts :class:`str` and :class:`int` as query argument values. + The library accepts :class:`str`, :class:`float`, :class:`int` and their + subclasses except :class:`bool` as query argument values. If a mapping such as :class:`dict` is used, the values may also be :class:`list` or :class:`tuple` to represent a key has many values. @@ -597,6 +598,15 @@ >>> URL('http://example.com/path?a=b&b=1').with_query([('b', '2')]) URL('http://example.com/path?b=2') + .. versionchanged:: 1.5 + + Support :class:`list` and :class:`tuple` as a query parameter value. + + .. versionchanged:: 1.6 + + Support subclasses of :class:`int` (except :class:`bool`) and :class:`float` + as a query parameter value. + .. method:: URL.update_query(query) URL.update_query(**kwargs) @@ -624,7 +634,8 @@ .. note:: - The library accepts :class:`str` and :class:`int` as query argument values. + The library accepts :class:`str`, :class:`float`, :class:`int` and their + subclasses except :class:`bool` as query argument values. If a mapping such as :class:`dict` is used, the values may also be :class:`list` or :class:`tuple` to represent a key has many values. @@ -661,6 +672,15 @@ Support for mod operator (``%``) to update the URL's query part. + .. versionchanged:: 1.5 + + Support :class:`list` and :class:`tuple` as a query parameter value. + + .. versionchanged:: 1.6 + + Support subclasses of :class:`int` (except :class:`bool`) and :class:`float` + as a query parameter value. + .. method:: URL.with_fragment(fragment) Return a new URL with *fragment* replaced, auto-encode *fragment* if needed. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/docs/spelling_wordlist.txt new/yarl-1.6.0/docs/spelling_wordlist.txt --- old/yarl-1.5.0/docs/spelling_wordlist.txt 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/docs/spelling_wordlist.txt 2020-09-23 18:36:11.000000000 +0200 @@ -11,3 +11,5 @@ uncompiled glibc manylinux +subclass +subclasses diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/setup.py new/yarl-1.6.0/setup.py --- old/yarl-1.5.0/setup.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/setup.py 2020-09-23 18:36:11.000000000 +0200 @@ -30,7 +30,11 @@ except IndexError: raise RuntimeError("Unable to determine version.") -install_requires = ["multidict>=4.0", "idna>=2.0", "typing_extensions>=3.7.4"] +install_requires = [ + "multidict>=4.0", + "idna>=2.0", + 'typing_extensions>=3.7.4;python_version<"3.8"', +] def read(name): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/tests/test_update_query.py new/yarl-1.6.0/tests/test_update_query.py --- old/yarl-1.5.0/tests/test_update_query.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/tests/test_update_query.py 2020-09-23 18:36:11.000000000 +0200 @@ -1,3 +1,5 @@ +import enum + import pytest from multidict import MultiDict @@ -155,34 +157,97 @@ url.with_query(query) -def test_with_query_non_str(): - url = URL("http://example.com") - with pytest.raises(TypeError): - url.with_query({"a": 1.1}) +class _CStr(str): + pass + + +class _EmptyStrEr: + def __str__(self): + return "" + + +class _CInt(int, _EmptyStrEr): + pass + + +class _CFloat(float, _EmptyStrEr): + pass -def test_with_query_bool(): [email protected]( + ("value", "expected"), + [ + pytest.param("1", "1", id="str"), + pytest.param(_CStr("1"), "1", id="custom str"), + pytest.param(1, "1", id="int"), + pytest.param(_CInt(1), "1", id="custom int"), + pytest.param(1.1, "1.1", id="float"), + pytest.param(_CFloat(1.1), "1.1", id="custom float"), + ], +) +def test_with_query_valid_type(value, expected): url = URL("http://example.com") - with pytest.raises(TypeError): - url.with_query({"a": True}) + expected = "http://example.com/?a={expected}".format_map(locals()) + assert str(url.with_query({"a": value})) == expected -def test_with_query_none(): [email protected]( + ("value", "exc_type"), + [ + pytest.param(True, TypeError, id="bool"), + pytest.param(None, TypeError, id="none"), + pytest.param(float("inf"), ValueError, id="non-finite float"), + pytest.param(float("nan"), ValueError, id="NaN float"), + ], +) +def test_with_query_invalid_type(value, exc_type): url = URL("http://example.com") - with pytest.raises(TypeError): - url.with_query({"a": None}) + with pytest.raises(exc_type): + url.with_query({"a": value}) -def test_with_query_list_non_str(): [email protected]( + ("value", "expected"), + [ + pytest.param("1", "1", id="str"), + pytest.param(_CStr("1"), "1", id="custom str"), + pytest.param(1, "1", id="int"), + pytest.param(_CInt(1), "1", id="custom int"), + pytest.param(1.1, "1.1", id="float"), + pytest.param(_CFloat(1.1), "1.1", id="custom float"), + ], +) +def test_with_query_list_valid_type(value, expected): url = URL("http://example.com") - with pytest.raises(TypeError): - url.with_query([("a", 1.0)]) + expected = "http://example.com/?a={expected}".format_map(locals()) + assert str(url.with_query([("a", value)])) == expected -def test_with_query_list_bool(): [email protected]( + ("value"), [pytest.param(True, id="bool"), pytest.param(None, id="none")] +) +def test_with_query_list_invalid_type(value): url = URL("http://example.com") with pytest.raises(TypeError): - url.with_query([("a", False)]) + url.with_query([("a", value)]) + + +def test_with_int_enum(): + class IntEnum(int, enum.Enum): + A = 1 + + url = URL("http://example.com/path") + url2 = url.with_query(a=IntEnum.A) + assert str(url2) == "http://example.com/path?a=1" + + +def test_with_float_enum(): + class FloatEnum(float, enum.Enum): + A = 1.1 + + url = URL("http://example.com/path") + url2 = url.with_query(a=FloatEnum.A) + assert str(url2) == "http://example.com/path?a=1.1" def test_with_query_multidict(): @@ -243,7 +308,11 @@ pytest.param({"key": "1&a=2"}, "?key=1%26a%3D2", id="mapping ampersand"), pytest.param([("&", "=")], "?%26=%3D", id="tuple list quote key"), pytest.param({"&": "="}, "?%26=%3D", id="mapping quote key"), - pytest.param([("a[]", "3")], "?a%5B%5D=3", id="quote one key braces",), + pytest.param( + [("a[]", "3")], + "?a%5B%5D=3", + id="quote one key braces", + ), pytest.param( [("a[]", "3"), ("a[]", "4")], "?a%5B%5D=3&a%5B%5D=4", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/tests/test_url.py new/yarl-1.6.0/tests/test_url.py --- old/yarl-1.5.0/tests/test_url.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/tests/test_url.py 2020-09-23 18:36:11.000000000 +0200 @@ -65,6 +65,16 @@ assert URL("http://example.com:8888") == url.origin() +def test_origin_nonascii(): + url = URL("http://user:password@историк.рф:8888/path/to?a=1&b=2") + assert str(url.origin()) == "http://xn--h1aagokeh.xn--p1ai:8888" + + +def test_origin_ipv6(): + url = URL("http://user:password@[::1]:8888/path/to?a=1&b=2") + assert str(url.origin()) == "http://[::1]:8888" + + def test_origin_not_absolute_url(): url = URL("/path/to?a=1&b=2") with pytest.raises(ValueError): @@ -502,6 +512,15 @@ assert "http://example.com/?f%C3%B8%C3%B8=f%C3%B8%C3%B8" == str(url2) +def test_percent_encoded_in_qs(): + url = URL("http://example.com") + url2 = url.with_query({"k%cf%80": "v%cf%80"}) + assert str(url2) == "http://example.com/?k%25cf%2580=v%25cf%2580" + assert url2.raw_query_string == "k%25cf%2580=v%25cf%2580" + assert url2.query_string == "k%cf%80=v%cf%80" + assert url2.query == {"k%cf%80": "v%cf%80"} + + # modifiers @@ -600,12 +619,25 @@ def test_div_non_ascii(): + url = URL("http://example.com/сюда") + url2 = url / "туда" + assert url2.path == "/сюда/туда" + assert url2.raw_path == "/%D1%81%D1%8E%D0%B4%D0%B0/%D1%82%D1%83%D0%B4%D0%B0" + assert url2.parts == ("/", "сюда", "туда") + assert url2.raw_parts == ( + "/", + "%D1%81%D1%8E%D0%B4%D0%B0", + "%D1%82%D1%83%D0%B4%D0%B0", + ) + + +def test_div_percent_encoded(): url = URL("http://example.com/path") - url2 = url / "сюда" - assert url2.path == "/path/сюда" - assert url2.raw_path == "/path/%D1%81%D1%8E%D0%B4%D0%B0" - assert url2.parts == ("/", "path", "сюда") - assert url2.raw_parts == ("/", "path", "%D1%81%D1%8E%D0%B4%D0%B0") + url2 = url / "%cf%80" + assert url2.path == "/path/%cf%80" + assert url2.raw_path == "/path/%25cf%2580" + assert url2.parts == ("/", "path", "%cf%80") + assert url2.raw_parts == ("/", "path", "%25cf%2580") def test_div_with_colon_and_at(): @@ -623,12 +655,50 @@ def test_with_path(): url = URL("http://example.com") - assert str(url.with_path("/test")) == "http://example.com/test" + url2 = url.with_path("/test") + assert str(url2) == "http://example.com/test" + assert url2.raw_path == "/test" + assert url2.path == "/test" + + +def test_with_path_nonascii(): + url = URL("http://example.com") + url2 = url.with_path("/π") + assert str(url2) == "http://example.com/%CF%80" + assert url2.raw_path == "/%CF%80" + assert url2.path == "/π" + + +def test_with_path_percent_encoded(): + url = URL("http://example.com") + url2 = url.with_path("/%cf%80") + assert str(url2) == "http://example.com/%25cf%2580" + assert url2.raw_path == "/%25cf%2580" + assert url2.path == "/%cf%80" def test_with_path_encoded(): url = URL("http://example.com") - assert str(url.with_path("/test", encoded=True)) == "http://example.com/test" + url2 = url.with_path("/test", encoded=True) + assert str(url2) == "http://example.com/test" + assert url2.raw_path == "/test" + assert url2.path == "/test" + + +def test_with_path_encoded_nonascii(): + url = URL("http://example.com") + url2 = url.with_path("/π", encoded=True) + assert str(url2) == "http://example.com/π" + assert url2.raw_path == "/π" + assert url2.path == "/π" + + +def test_with_path_encoded_percent_encoded(): + url = URL("http://example.com") + url2 = url.with_path("/%cf%80", encoded=True) + assert str(url2) == "http://example.com/%cf%80" + assert url2.raw_path == "/%cf%80" + assert url2.path == "/π" def test_with_path_dots(): @@ -666,7 +736,10 @@ def test_with_fragment(): url = URL("http://example.com") - assert str(url.with_fragment("frag")) == "http://example.com/#frag" + url2 = url.with_fragment("frag") + assert str(url2) == "http://example.com/#frag" + assert url2.raw_fragment == "frag" + assert url2.fragment == "frag" def test_with_fragment_safe(): @@ -682,6 +755,14 @@ assert url2.fragment == "фрагм" +def test_with_fragment_percent_encoded(): + url = URL("http://example.com") + url2 = url.with_fragment("%cf%80") + assert str(url2) == "http://example.com/#%25cf%2580" + assert url2.raw_fragment == "%25cf%2580" + assert url2.fragment == "%cf%80" + + def test_with_fragment_None(): url = URL("http://example.com/path#frag") url2 = url.with_fragment(None) @@ -714,6 +795,9 @@ assert url.raw_parts == ("/", "a", "b") url2 = url.with_name("c") assert url2.raw_parts == ("/", "a", "c") + assert url2.parts == ("/", "a", "c") + assert url2.raw_path == "/a/c" + assert url2.path == "/a/c" def test_with_name_for_naked_path(): @@ -759,6 +843,15 @@ assert url.raw_parts == ("/", "%D0%BF%D1%83%D1%82%D1%8C") +def test_with_name_percent_encoded(): + url = URL("http://example.com/path") + url2 = url.with_name("%cf%80") + assert url2.raw_parts == ("/", "%25cf%2580") + assert url2.parts == ("/", "%cf%80") + assert url2.raw_path == "/%25cf%2580" + assert url2.path == "/%cf%80" + + def test_with_name_with_slash(): with pytest.raises(ValueError): URL("http://example.com").with_name("a/b") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/tests/test_url_build.py new/yarl-1.6.0/tests/test_url_build.py --- old/yarl-1.5.0/tests/test_url_build.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/tests/test_url_build.py 2020-09-23 18:36:11.000000000 +0200 @@ -171,6 +171,60 @@ assert str(u) == "http://историк.рф/путь/файл?ключ=знач#фраг" +def test_build_percent_encoded(): + u = URL.build( + scheme="http", + host="%2d.org", + user="u%2d", + password="p%2d", + path="/%2d", + query_string="k%2d=v%2d", + fragment="f%2d", + ) + assert str(u) == "http://u%252d:p%252d@%2d.org/%252d?k%252d=v%252d#f%252d" + assert u.raw_host == "%2d.org" + assert u.host == "%2d.org" + assert u.raw_user == "u%252d" + assert u.user == "u%2d" + assert u.raw_password == "p%252d" + assert u.password == "p%2d" + assert u.raw_authority == "u%252d:p%252d@%2d.org" + assert u.authority == "u%2d:p%2d@%2d.org:80" + assert u.raw_path == "/%252d" + assert u.path == "/%2d" + assert u.query == {"k%2d": "v%2d"} + assert u.raw_query_string == "k%252d=v%252d" + assert u.query_string == "k%2d=v%2d" + assert u.raw_fragment == "f%252d" + assert u.fragment == "f%2d" + + +def test_build_with_authority_percent_encoded(): + u = URL.build(scheme="http", authority="u%2d:p%2d@%2d.org") + assert str(u) == "http://u%252d:p%252d@%2d.org" + assert u.raw_host == "%2d.org" + assert u.host == "%2d.org" + assert u.raw_user == "u%252d" + assert u.user == "u%2d" + assert u.raw_password == "p%252d" + assert u.password == "p%2d" + assert u.raw_authority == "u%252d:p%252d@%2d.org" + assert u.authority == "u%2d:p%2d@%2d.org:80" + + +def test_build_with_authority_percent_encoded_already_encoded(): + u = URL.build(scheme="http", authority="u%2d:p%2d@%2d.org", encoded=True) + assert str(u) == "http://u%2d:p%2d@%2d.org" + assert u.raw_host == "%2d.org" + assert u.host == "%2d.org" + assert u.user == "u-" + assert u.raw_user == "u%2d" + assert u.password == "p-" + assert u.raw_password == "p%2d" + assert u.authority == "u-:p-@%2d.org:80" + assert u.raw_authority == "u%2d:p%2d@%2d.org" + + def test_build_with_authority_with_path_with_leading_slash(): u = URL.build(scheme="http", host="example.com", path="/path_with_leading_slash") assert str(u) == "http://example.com/path_with_leading_slash" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/tests/test_url_update_netloc.py new/yarl-1.6.0/tests/test_url_update_netloc.py --- old/yarl-1.5.0/tests/test_url_update_netloc.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/tests/test_url_update_netloc.py 2020-09-23 18:36:11.000000000 +0200 @@ -37,6 +37,17 @@ url2 = url.with_user("вася") assert url2.raw_user == "%D0%B2%D0%B0%D1%81%D1%8F" assert url2.user == "вася" + assert url2.raw_authority == "%d0%b2%d0%b0%d1%81%[email protected]" + assert url2.authority == "вася@example.com:80" + + +def test_with_user_percent_encoded(): + url = URL("http://example.com") + url2 = url.with_user("%cf%80") + assert url2.raw_user == "%25cf%2580" + assert url2.user == "%cf%80" + assert url2.raw_authority == "%25cf%[email protected]" + assert url2.authority == "%[email protected]:80" def test_with_user_for_relative_url(): @@ -80,6 +91,17 @@ url2 = url.with_password("пароль") assert url2.raw_password == "%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" assert url2.password == "пароль" + assert url2.raw_authority == "john:%d0%bf%d0%b0%d1%80%d0%be%d0%bb%[email protected]" + assert url2.authority == "john:пароль@example.com:80" + + +def test_with_password_percent_encoded(): + url = URL("http://[email protected]") + url2 = url.with_password("%cf%80") + assert url2.raw_password == "%25cf%2580" + assert url2.password == "%cf%80" + assert url2.raw_authority == "john:%25cf%[email protected]" + assert url2.authority == "john:%[email protected]:80" def test_with_password_non_ascii_with_colon(): @@ -141,6 +163,17 @@ url2 = url.with_host("историк.рф") assert url2.raw_host == "xn--h1aagokeh.xn--p1ai" assert url2.host == "историк.рф" + assert url2.raw_authority == "xn--h1aagokeh.xn--p1ai:123" + assert url2.authority == "историк.рф:123" + + +def test_with_host_percent_encoded(): + url = URL("http://%25cf%2580%cf%80:%25cf%2580%[email protected]:123") + url2 = url.with_host("%cf%80.org") + assert url2.raw_host == "%cf%80.org" + assert url2.host == "%cf%80.org" + assert url2.raw_authority == "%25cf%2580%CF%80:%25cf%2580%CF%80@%cf%80.org:123" + assert url2.authority == "%cf%80π:%cf%80π@%cf%80.org:123" def test_with_host_for_relative_url(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/yarl/__init__.py new/yarl-1.6.0/yarl/__init__.py --- old/yarl-1.5.0/yarl/__init__.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/yarl/__init__.py 2020-09-23 18:36:11.000000000 +0200 @@ -1,5 +1,5 @@ from ._url import URL, cache_clear, cache_configure, cache_info -__version__ = "1.5.0" +__version__ = "1.6.0" __all__ = ("URL", "cache_clear", "cache_configure", "cache_info") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/yarl/__init__.pyi new/yarl-1.6.0/yarl/__init__.pyi --- old/yarl-1.5.0/yarl/__init__.pyi 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/yarl/__init__.pyi 2020-09-23 18:36:11.000000000 +0200 @@ -1,9 +1,14 @@ from typing import overload, Any, Tuple, Optional, Mapping, Union, Sequence, Type -from typing_extensions import TypedDict, Final, final import multidict from functools import _CacheInfo +import sys -_QueryVariable = Union[str, int] +if sys.version_info >= (3, 8): + from typing import TypedDict, Final, final +else: + from typing_extensions import TypedDict, Final, final + +_QueryVariable = Union[str, int, float] _Query = Union[ None, str, Mapping[str, _QueryVariable], Sequence[Tuple[str, _QueryVariable]] ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/yarl/_url.py new/yarl-1.6.0/yarl/_url.py --- old/yarl-1.5.0/yarl/_url.py 2020-07-26 10:34:42.000000000 +0200 +++ new/yarl-1.6.0/yarl/_url.py 2020-09-23 18:36:11.000000000 +0200 @@ -8,6 +8,8 @@ from multidict import MultiDict, MultiDictProxy import idna +import math + from ._quoting import _Quoter, _Unquoter @@ -126,11 +128,15 @@ # absolute-URI = scheme ":" hier-part [ "?" query ] __slots__ = ("_cache", "_val") - _QUOTER = _Quoter() - _PATH_QUOTER = _Quoter(safe="@:", protected="/+") - _QUERY_QUOTER = _Quoter(safe="?/:@", protected="=+&;", qs=True) + _QUOTER = _Quoter(requote=False) + _REQUOTER = _Quoter() + _PATH_QUOTER = _Quoter(safe="@:", protected="/+", requote=False) + _PATH_REQUOTER = _Quoter(safe="@:", protected="/+") + _QUERY_QUOTER = _Quoter(safe="?/:@", protected="=+&;", qs=True, requote=False) + _QUERY_REQUOTER = _Quoter(safe="?/:@", protected="=+&;", qs=True) _QUERY_PART_QUOTER = _Quoter(safe="?/:@", qs=True, requote=False) - _FRAGMENT_QUOTER = _Quoter(safe="?/:@") + _FRAGMENT_QUOTER = _Quoter(safe="?/:@", requote=False) + _FRAGMENT_REQUOTER = _Quoter(safe="?/:@") _UNQUOTER = _Unquoter() _PATH_UNQUOTER = _Unquoter(unsafe="+") @@ -168,15 +174,15 @@ ) from e netloc = cls._make_netloc( - val.username, val.password, host, port, encode=True + val.username, val.password, host, port, encode=True, requote=True ) - path = cls._PATH_QUOTER(val[2]) + path = cls._PATH_REQUOTER(val[2]) if netloc: path = cls._normalize_path(path) cls._validate_authority_uri_abs_path(host=host, path=path) - query = cls._QUERY_QUOTER(val[3]) - fragment = cls._FRAGMENT_QUOTER(val[4]) + query = cls._QUERY_REQUOTER(val[3]) + fragment = cls._FRAGMENT_REQUOTER(val[4]) val = SplitResult(val[0], netloc, path, query, fragment) self = object.__new__(cls) @@ -233,7 +239,9 @@ elif not user and not password and not host and not port: netloc = "" else: - netloc = cls._make_netloc(user, password, host, port, encode=not encoded) + netloc = cls._make_netloc( + user, password, host, port, encode=not encoded, encode_host=not encoded + ) if not encoded: path = cls._PATH_QUOTER(path) if netloc: @@ -383,7 +391,7 @@ if not self._val.scheme: raise ValueError("URL should have scheme") v = self._val - netloc = self._make_netloc(None, None, v.hostname, v.port, encode=False) + netloc = self._make_netloc(None, None, v.hostname, v.port) val = v._replace(netloc=netloc, path="", query="", fragment="") return URL(val, encoded=True) @@ -424,7 +432,7 @@ """ return self._make_netloc( - self.user, self.password, self.host, self.port, encode=False + self.user, self.password, self.host, self.port, encode_host=False ) @property @@ -747,8 +755,11 @@ return host @classmethod - def _make_netloc(cls, user, password, host, port, encode): - if encode: + def _make_netloc( + cls, user, password, host, port, encode=False, encode_host=True, requote=False + ): + quoter = cls._REQUOTER if requote else cls._QUOTER + if encode_host: ret = cls._encode_host(host) else: ret = host @@ -759,12 +770,12 @@ user = "" else: if encode: - user = cls._QUOTER(user) + user = quoter(user) if encode: - password = cls._QUOTER(password) + password = quoter(password) user = user + ":" + password elif user and encode: - user = cls._QUOTER(user) + user = quoter(user) if user: ret = user + "@" + ret return ret @@ -799,9 +810,7 @@ raise ValueError("user replacement is not allowed for relative URLs") return URL( self._val._replace( - netloc=self._make_netloc( - user, password, val.hostname, val.port, encode=True - ) + netloc=self._make_netloc(user, password, val.hostname, val.port) ), encoded=True, ) @@ -826,9 +835,7 @@ val = self._val return URL( self._val._replace( - netloc=self._make_netloc( - val.username, password, val.hostname, val.port, encode=True - ) + netloc=self._make_netloc(val.username, password, val.hostname, val.port) ), encoded=True, ) @@ -849,13 +856,10 @@ raise ValueError("host replacement is not allowed for relative URLs") if not host: raise ValueError("host removing is not allowed") - host = self._encode_host(host) val = self._val return URL( self._val._replace( - netloc=self._make_netloc( - val.username, val.password, host, val.port, encode=False - ) + netloc=self._make_netloc(val.username, val.password, host, val.port) ), encoded=True, ) @@ -902,14 +906,21 @@ @staticmethod def _query_var(v): - if isinstance(v, str): + cls = type(v) + if issubclass(cls, str): return v - if type(v) is int: # no subclasses like bool - return str(v) + if issubclass(cls, float): + if math.isinf(v): + raise ValueError("float('inf') is not supported") + if math.isnan(v): + raise ValueError("float('nan') is not supported") + return str(float(v)) + if issubclass(cls, int) and cls is not bool: + return str(int(v)) raise TypeError( "Invalid variable type: value " - "should be str or int, got {!r} " - "of type {}".format(v, type(v)) + "should be str, int or float, got {!r} " + "of type {}".format(v, cls) ) def _get_str_query(self, *args, **kwargs): @@ -1056,7 +1067,11 @@ SplitResult( self.scheme, self._make_netloc( - self.user, self.password, self.host, self._val.port, encode=False + self.user, + self.password, + self.host, + self._val.port, + encode_host=False, ), self.path, self.query_string, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/yarl.egg-info/PKG-INFO new/yarl-1.6.0/yarl.egg-info/PKG-INFO --- old/yarl-1.5.0/yarl.egg-info/PKG-INFO 2020-07-26 10:34:53.000000000 +0200 +++ new/yarl-1.6.0/yarl.egg-info/PKG-INFO 2020-09-23 18:36:19.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: yarl -Version: 1.5.0 +Version: 1.6.0 Summary: Yet another URL library Home-page: https://github.com/aio-libs/yarl/ Author: Andrew Svetlov @@ -226,6 +226,47 @@ .. towncrier release notes start + 1.6.0 (2020-09-23) + ================== + + Features + -------- + + - Allow for int and float subclasses in query, while still denying bool. + `#492 <https://github.com/aio-libs/yarl/issues/492>`_ + + + Bugfixes + -------- + + - Do not requote arguments in ``URL.build()``, ``with_xxx()`` and in ``/`` operator. + `#502 <https://github.com/aio-libs/yarl/issues/502>`_ + - Keep IPv6 brackets in ``origin()``. + `#504 <https://github.com/aio-libs/yarl/issues/504>`_ + + + ---- + + + 1.5.1 (2020-08-01) + ================== + + Bugfixes + -------- + + - Fix including relocated internal ``yarl._quoting_c`` C-extension into published PyPI dists. + `#485 <https://github.com/aio-libs/yarl/issues/485>`_ + + + Misc + ---- + + - `#484 <https://github.com/aio-libs/yarl/issues/484>`_ + + + ---- + + 1.5.0 (2020-07-26) ================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/yarl-1.5.0/yarl.egg-info/requires.txt new/yarl-1.6.0/yarl.egg-info/requires.txt --- old/yarl-1.5.0/yarl.egg-info/requires.txt 2020-07-26 10:34:53.000000000 +0200 +++ new/yarl-1.6.0/yarl.egg-info/requires.txt 2020-09-23 18:36:19.000000000 +0200 @@ -1,3 +1,5 @@ multidict>=4.0 idna>=2.0 + +[:python_version < "3.8"] typing_extensions>=3.7.4
