aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/yarl
diff options
context:
space:
mode:
authorAlexSm <alex@ydb.tech>2023-12-22 17:10:22 +0100
committerGitHub <noreply@github.com>2023-12-22 17:10:22 +0100
commit148f920350c60c0ca2d89b637a5aea9093eee450 (patch)
tree6314b1433dac833398c333731e83f0ad77e81a0b /contrib/python/yarl
parent7116d46ae7c0259b5f9d489de263f8701e432b1c (diff)
downloadydb-148f920350c60c0ca2d89b637a5aea9093eee450.tar.gz
Library import 2 (#639)
Diffstat (limited to 'contrib/python/yarl')
-rw-r--r--contrib/python/yarl/.dist-info/METADATA104
-rw-r--r--contrib/python/yarl/README.rst14
-rw-r--r--contrib/python/yarl/tests/test_cached_property.py33
-rw-r--r--contrib/python/yarl/tests/test_quoting.py21
-rw-r--r--contrib/python/yarl/tests/test_update_query.py2
-rw-r--r--contrib/python/yarl/tests/test_url.py159
-rw-r--r--contrib/python/yarl/tests/test_url_build.py74
-rw-r--r--contrib/python/yarl/tests/test_url_parsing.py18
-rw-r--r--contrib/python/yarl/tests/test_url_update_netloc.py20
-rw-r--r--contrib/python/yarl/ya.make2
-rw-r--r--contrib/python/yarl/yarl/__init__.py2
-rw-r--r--contrib/python/yarl/yarl/_quoting_c.pyx8
-rw-r--r--contrib/python/yarl/yarl/_url.py4
13 files changed, 282 insertions, 179 deletions
diff --git a/contrib/python/yarl/.dist-info/METADATA b/contrib/python/yarl/.dist-info/METADATA
index 8585ab738d..548567bd12 100644
--- a/contrib/python/yarl/.dist-info/METADATA
+++ b/contrib/python/yarl/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: yarl
-Version: 1.9.3
+Version: 1.9.4
Summary: Yet another URL library
Home-page: https://github.com/aio-libs/yarl
Author: Andrew Svetlov
@@ -116,9 +116,9 @@ automatically encoded giving canonical representation as result:
.. code-block:: pycon
- >>> url = URL('https://www.python.org/путь')
+ >>> url = URL('https://www.python.org/шлях')
>>> url
- URL('https://www.python.org/%D0%BF%D1%83%D1%82%D1%8C')
+ URL('https://www.python.org/%D1%88%D0%BB%D1%8F%D1%85')
Regular properties are *percent-decoded*, use ``raw_`` versions for
getting *encoded* strings:
@@ -126,17 +126,17 @@ getting *encoded* strings:
.. code-block:: pycon
>>> url.path
- '/путь'
+ '/шлях'
>>> url.raw_path
- '/%D0%BF%D1%83%D1%82%D1%8C'
+ '/%D1%88%D0%BB%D1%8F%D1%85'
Human readable representation of URL is available as ``.human_repr()``:
.. code-block:: pycon
>>> url.human_repr()
- 'https://www.python.org/путь'
+ 'https://www.python.org/шлях'
For full documentation please read https://yarl.aio-libs.org.
@@ -157,12 +157,12 @@ used with our wheels) the the tarball will be used to compile the library from
the source code. It requires a C compiler and and Python headers installed.
To skip the compilation you must explicitly opt-in by using a PEP 517
-configuration setting ``--pure-python``, or setting the ``YARL_NO_EXTENSIONS``
+configuration setting ``pure-python``, or setting the ``YARL_NO_EXTENSIONS``
environment variable to a non-empty value, e.g.:
.. code-block:: console
- $ pip install yarl --config-settings=--pure-python=
+ $ pip install yarl --config-settings=pure-python=false
Please note that the pure-Python (uncompiled) version is much slower. However,
PyPy always uses a pure-Python implementation, and, as such, it is unaffected
@@ -262,13 +262,83 @@ It's *Apache 2* licensed and freely available.
.. towncrier release notes start
+1.9.4 (2023-12-06)
+==================
+
+Bug fixes
+---------
+
+- Started raising ``TypeError`` when a string value is passed into
+ ``yarl.URL.build()`` as the ``port`` argument -- by `@commonism <https://github.com/sponsors/commonism>`__.
+
+ Previously the empty string as port would create malformed URLs when rendered as string representations. (`#883 <https://github.com/aio-libs/yarl/issues/883>`__)
+
+
+Packaging updates and notes for downstreams
+-------------------------------------------
+
+- The leading ``--`` has been dropped from the `PEP 517 <https://peps.python.org/pep-517>`__ in-tree build
+ backend config setting names. ``--pure-python`` is now just ``pure-python``
+ -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__.
+
+ The usage now looks as follows:
+
+ .. code-block:: console
+
+ $ python -m build \
+ --config-setting=pure-python=true \
+ --config-setting=with-cython-tracing=true
+
+ (`#963 <https://github.com/aio-libs/yarl/issues/963>`__)
+
+
+Contributor-facing changes
+--------------------------
+
+- A step-by-step ``Release Guide`` guide has
+ been added, describing how to release *yarl* -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__.
+
+ This is primarily targeting maintainers. (`#960 <https://github.com/aio-libs/yarl/issues/960>`__)
+- Coverage collection has been implemented for the Cython modules
+ -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__.
+
+ It will also be reported to Codecov from any non-release CI jobs.
+
+ To measure coverage in a development environment, *yarl* can be
+ installed in editable mode, which requires an environment variable
+ ``YARL_CYTHON_TRACING=1`` to be set:
+
+ .. code-block:: console
+
+ $ YARL_CYTHON_TRACING=1 python -Im pip install -e .
+
+ Editable install produces C-files required for the Cython coverage
+ plugin to map the measurements back to the PYX-files. (`#961 <https://github.com/aio-libs/yarl/issues/961>`__)
+- It is now possible to request line tracing in Cython builds using the
+ ``with-cython-tracing`` `PEP 517 <https://peps.python.org/pep-517>`__ config setting
+ -- `@webknjaz <https://github.com/sponsors/webknjaz>`__.
+
+ This can be used in CI and development environment to measure coverage
+ on Cython modules, but is not normally useful to the end-users or
+ downstream packagers.
+
+ Here's a usage example:
+
+ .. code-block:: console
+
+ $ python -Im pip install . --config-settings=with-cython-tracing=true
+
+ For editable installs, this setting is on by default. Otherwise, it's
+ off unless requested explicitly. (`#962 <https://github.com/aio-libs/yarl/issues/962>`__)
+
+
1.9.3 (2023-11-20)
==================
Bug fixes
---------
-- Stopped dropping trailing slashes in ``yarl.URL.joinpath()`` -- by `@mjpieters <https://github.com/sponsors/mjpieters>`__. (`#862 <https://github.com/aio-libs/yarl/issues/862>`__, `#866 <https://github.com/aio-libs/yarl/issues/866>`__)
+- Stopped dropping trailing slashes in ``yarl.URL.joinpath()`` -- by `@gmacon <https://github.com/sponsors/gmacon>`__. (`#862 <https://github.com/aio-libs/yarl/issues/862>`__, `#866 <https://github.com/aio-libs/yarl/issues/866>`__)
- Started accepting string subclasses in ``__truediv__()`` operations (``URL / segment``) -- by `@mjpieters <https://github.com/sponsors/mjpieters>`__. (`#871 <https://github.com/aio-libs/yarl/issues/871>`__, `#884 <https://github.com/aio-libs/yarl/issues/884>`__)
- Fixed the human representation of URLs with square brackets in usernames and passwords -- by `@mjpieters <https://github.com/sponsors/mjpieters>`__. (`#876 <https://github.com/aio-libs/yarl/issues/876>`__, `#882 <https://github.com/aio-libs/yarl/issues/882>`__)
- Updated type hints to include ``URL.missing_port()``, ``URL.__bytes__()``
@@ -280,12 +350,12 @@ Packaging updates and notes for downstreams
-------------------------------------------
- Integrated Cython 3 to enable building *yarl* under Python 3.12 -- by `@mjpieters <https://github.com/sponsors/mjpieters>`__. (`#829 <https://github.com/aio-libs/yarl/issues/829>`__, `#881 <https://github.com/aio-libs/yarl/issues/881>`__)
-- Declared modern ``setuptools.build_meta`` as the ``517`` build
+- Declared modern ``setuptools.build_meta`` as the `PEP 517 <https://peps.python.org/pep-517>`__ build
backend in ``pyproject.toml`` explicitly -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__. (`#886 <https://github.com/aio-libs/yarl/issues/886>`__)
- Converted most of the packaging setup into a declarative ``setup.cfg``
config -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__. (`#890 <https://github.com/aio-libs/yarl/issues/890>`__)
-- Replaced the packaging is replaced from an old-fashioned ``setup.py`` to an
- in-tree ``517`` build backend -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__.
+- The packaging is replaced from an old-fashioned ``setup.py`` to an
+ in-tree `PEP 517 <https://peps.python.org/pep-517>`__ build backend -- by `@webknjaz <https://github.com/sponsors/webknjaz>`__.
Whenever the end-users or downstream packagers need to build ``yarl`` from
source (a Git checkout or an sdist), they may pass a ``config_settings``
@@ -296,7 +366,7 @@ Packaging updates and notes for downstreams
.. code-block:: console
- $ python -m pip install . --config-settings=--pure-python=
+ $ python -m pip install . --config-settings=--pure-python=false
This will also work with ``-e | --editable``.
@@ -304,10 +374,16 @@ Packaging updates and notes for downstreams
.. code-block:: console
- $ python -m build --config-setting=--pure-python=
+ $ python -m build --config-setting=--pure-python=false
Adding ``-w | --wheel`` can force ``pypa/build`` produce a wheel from source
directly, as opposed to building an ``sdist`` and then building from it. (`#893 <https://github.com/aio-libs/yarl/issues/893>`__)
+
+ .. attention::
+
+ v1.9.3 was the only version using the ``--pure-python`` setting name.
+ Later versions dropped the ``--`` prefix, making it just ``pure-python``.
+
- Declared Python 3.12 supported officially in the distribution package metadata
-- by `@edgarrmondragon <https://github.com/sponsors/edgarrmondragon>`__. (`#942 <https://github.com/aio-libs/yarl/issues/942>`__)
diff --git a/contrib/python/yarl/README.rst b/contrib/python/yarl/README.rst
index a1032b206a..844ffff692 100644
--- a/contrib/python/yarl/README.rst
+++ b/contrib/python/yarl/README.rst
@@ -74,9 +74,9 @@ automatically encoded giving canonical representation as result:
.. code-block:: pycon
- >>> url = URL('https://www.python.org/путь')
+ >>> url = URL('https://www.python.org/шлях')
>>> url
- URL('https://www.python.org/%D0%BF%D1%83%D1%82%D1%8C')
+ URL('https://www.python.org/%D1%88%D0%BB%D1%8F%D1%85')
Regular properties are *percent-decoded*, use ``raw_`` versions for
getting *encoded* strings:
@@ -84,17 +84,17 @@ getting *encoded* strings:
.. code-block:: pycon
>>> url.path
- '/путь'
+ '/шлях'
>>> url.raw_path
- '/%D0%BF%D1%83%D1%82%D1%8C'
+ '/%D1%88%D0%BB%D1%8F%D1%85'
Human readable representation of URL is available as ``.human_repr()``:
.. code-block:: pycon
>>> url.human_repr()
- 'https://www.python.org/путь'
+ 'https://www.python.org/шлях'
For full documentation please read https://yarl.aio-libs.org.
@@ -115,12 +115,12 @@ used with our wheels) the the tarball will be used to compile the library from
the source code. It requires a C compiler and and Python headers installed.
To skip the compilation you must explicitly opt-in by using a PEP 517
-configuration setting ``--pure-python``, or setting the ``YARL_NO_EXTENSIONS``
+configuration setting ``pure-python``, or setting the ``YARL_NO_EXTENSIONS``
environment variable to a non-empty value, e.g.:
.. code-block:: console
- $ pip install yarl --config-settings=--pure-python=
+ $ pip install yarl --config-settings=pure-python=false
Please note that the pure-Python (uncompiled) version is much slower. However,
PyPy always uses a pure-Python implementation, and, as such, it is unaffected
diff --git a/contrib/python/yarl/tests/test_cached_property.py b/contrib/python/yarl/tests/test_cached_property.py
index 5dcb5ece23..834f6db437 100644
--- a/contrib/python/yarl/tests/test_cached_property.py
+++ b/contrib/python/yarl/tests/test_cached_property.py
@@ -3,42 +3,27 @@ import pytest
from yarl._url import cached_property
-def test_reify():
- class A:
- def __init__(self):
- self._cache = {}
+class A:
+ def __init__(self):
+ self._cache = {}
+
+ @cached_property
+ def prop(self):
+ """Docstring."""
+ return 1
- @cached_property
- def prop(self):
- return 1
+def test_reify():
a = A()
assert 1 == a.prop
def test_reify_class():
- class A:
- def __init__(self):
- self._cache = {}
-
- @cached_property
- def prop(self):
- """Docstring."""
- return 1
-
assert isinstance(A.prop, cached_property)
assert "Docstring." == A.prop.__doc__
def test_reify_assignment():
- class A:
- def __init__(self):
- self._cache = {}
-
- @cached_property
- def prop(self):
- return 1
-
a = A()
with pytest.raises(AttributeError):
diff --git a/contrib/python/yarl/tests/test_quoting.py b/contrib/python/yarl/tests/test_quoting.py
index 7ebc0f9b04..d9b6ae8e4b 100644
--- a/contrib/python/yarl/tests/test_quoting.py
+++ b/contrib/python/yarl/tests/test_quoting.py
@@ -226,14 +226,21 @@ def test_unquoting_bad_percent_escapes(unquoter, input, expected):
assert unquoter()(input) == expected
-@pytest.mark.xfail
-# FIXME: After conversion to bytes, should not cause UTF-8 decode fail.
-# See https://url.spec.whatwg.org/#percent-encoded-bytes
-def test_unquoting_invalid_utf8_sequence(unquoter):
- with pytest.raises(ValueError):
- unquoter()("%AB")
+@pytest.mark.xfail(
+ reason="""
+ FIXME: After conversion to bytes, should not cause UTF-8 decode fail.
+ See https://url.spec.whatwg.org/#percent-encoded-bytes
+
+ Refs:
+ * https://github.com/aio-libs/yarl/pull/216
+ * https://github.com/aio-libs/yarl/pull/214
+ * https://github.com/aio-libs/yarl/pull/7
+ """,
+)
+@pytest.mark.parametrize("urlencoded_string", ("%AB", "%AB%AB"))
+def test_unquoting_invalid_utf8_sequence(unquoter, urlencoded_string):
with pytest.raises(ValueError):
- unquoter()("%AB%AB")
+ unquoter()(urlencoded_string)
def test_unquoting_mixed_case_percent_escapes(unquoter):
diff --git a/contrib/python/yarl/tests/test_update_query.py b/contrib/python/yarl/tests/test_update_query.py
index e47c468341..176259d750 100644
--- a/contrib/python/yarl/tests/test_update_query.py
+++ b/contrib/python/yarl/tests/test_update_query.py
@@ -171,7 +171,7 @@ class _CStr(str):
class _EmptyStrEr:
def __str__(self):
- return ""
+ return "" # pragma: no cover # <-- this should never happen
class _CInt(int, _EmptyStrEr):
diff --git a/contrib/python/yarl/tests/test_url.py b/contrib/python/yarl/tests/test_url.py
index af13d0b5d5..59d543754d 100644
--- a/contrib/python/yarl/tests/test_url.py
+++ b/contrib/python/yarl/tests/test_url.py
@@ -64,8 +64,8 @@ def test_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"
+ url = URL("http://user:password@оун-упа.укр:8888/path/to?a=1&b=2")
+ assert str(url.origin()) == "http://xn----8sb1bdhvc.xn--j1amh:8888"
def test_origin_ipv6():
@@ -117,8 +117,8 @@ def test_raw_user():
def test_raw_user_non_ascii():
- url = URL("http://вася@example.com")
- assert "%D0%B2%D0%B0%D1%81%D1%8F" == url.raw_user
+ url = URL("http://бажан@example.com")
+ assert "%D0%B1%D0%B0%D0%B6%D0%B0%D0%BD" == url.raw_user
def test_no_user():
@@ -127,8 +127,8 @@ def test_no_user():
def test_user_non_ascii():
- url = URL("http://вася@example.com")
- assert "вася" == url.user
+ url = URL("http://бажан@example.com")
+ assert "бажан" == url.user
def test_raw_password():
@@ -164,13 +164,13 @@ def test_raw_host():
def test_raw_host_non_ascii():
- url = URL("http://историк.рф")
- assert "xn--h1aagokeh.xn--p1ai" == url.raw_host
+ url = URL("http://оун-упа.укр")
+ assert "xn----8sb1bdhvc.xn--j1amh" == url.raw_host
def test_host_non_ascii():
- url = URL("http://историк.рф")
- assert "историк.рф" == url.host
+ url = URL("http://оун-упа.укр")
+ assert "оун-упа.укр" == url.host
def test_localhost():
@@ -210,12 +210,13 @@ def test_authority_short() -> None:
def test_authority_full_nonasci() -> None:
- url = URL("http://ваня:пароль@айдеко.рф:8080/path")
+ url = URL("http://степан:пароль@слава.укр:8080/path")
assert url.raw_authority == (
- "%D0%B2%D0%B0%D0%BD%D1%8F:%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C@"
- "xn--80aidohy.xn--p1ai:8080"
+ "%D1%81%D1%82%D0%B5%D0%BF%D0%B0%D0%BD:"
+ "%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C@"
+ "xn--80aaf8a3a.xn--j1amh:8080"
)
- assert url.authority == "ваня:пароль@айдеко.рф:8080"
+ assert url.authority == "степан:пароль@слава.укр:8080"
def test_lowercase():
@@ -225,9 +226,9 @@ def test_lowercase():
def test_lowercase_nonascii():
- url = URL("http://Айдеко.Рф")
- assert url.raw_host == "xn--80aidohy.xn--p1ai"
- assert url.host == "айдеко.рф"
+ url = URL("http://Слава.Укр")
+ assert url.raw_host == "xn--80aaf8a3a.xn--j1amh"
+ assert url.host == "слава.укр"
def test_compressed_ipv6():
@@ -294,13 +295,13 @@ def test_raw_path():
def test_raw_path_non_ascii():
- url = URL("http://example.com/путь/сюда")
- assert "/%D0%BF%D1%83%D1%82%D1%8C/%D1%81%D1%8E%D0%B4%D0%B0" == url.raw_path
+ url = URL("http://example.com/шлях/сюди")
+ assert "/%D1%88%D0%BB%D1%8F%D1%85/%D1%81%D1%8E%D0%B4%D0%B8" == url.raw_path
def test_path_non_ascii():
- url = URL("http://example.com/путь/сюда")
- assert "/путь/сюда" == url.path
+ url = URL("http://example.com/шлях/сюди")
+ assert "/шлях/сюди" == url.path
def test_path_with_spaces():
@@ -352,8 +353,8 @@ def test_raw_path_qs():
assert url.raw_path_qs == "/?%D0%B1=%D0%B2&%D1%8E=%D0%BA"
url = URL("http://example.com/path?б=в&ю=к")
assert url.raw_path_qs == "/path?%D0%B1=%D0%B2&%D1%8E=%D0%BA"
- url = URL("http://example.com/путь?a=1&b=2")
- assert url.raw_path_qs == "/%D0%BF%D1%83%D1%82%D1%8C?a=1&b=2"
+ url = URL("http://example.com/шлях?a=1&b=2")
+ assert url.raw_path_qs == "/%D1%88%D0%BB%D1%8F%D1%85?a=1&b=2"
def test_query_string_spaces():
@@ -375,8 +376,8 @@ def test_raw_fragment():
def test_raw_fragment_non_ascii():
- url = URL("http://example.com/path#якорь")
- assert "%D1%8F%D0%BA%D0%BE%D1%80%D1%8C" == url.raw_fragment
+ url = URL("http://example.com/path#якір")
+ assert "%D1%8F%D0%BA%D1%96%D1%80" == url.raw_fragment
def test_raw_fragment_safe():
@@ -385,8 +386,8 @@ def test_raw_fragment_safe():
def test_fragment_non_ascii():
- url = URL("http://example.com/path#якорь")
- assert "якорь" == url.fragment
+ url = URL("http://example.com/path#якір")
+ assert "якір" == url.fragment
def test_raw_parts_empty():
@@ -435,17 +436,17 @@ def test_parts_for_empty_url():
def test_raw_parts_non_ascii():
- url = URL("http://example.com/путь/сюда")
+ url = URL("http://example.com/шлях/сюди")
assert (
"/",
- "%D0%BF%D1%83%D1%82%D1%8C",
- "%D1%81%D1%8E%D0%B4%D0%B0",
+ "%D1%88%D0%BB%D1%8F%D1%85",
+ "%D1%81%D1%8E%D0%B4%D0%B8",
) == url.raw_parts
def test_parts_non_ascii():
- url = URL("http://example.com/путь/сюда")
- assert ("/", "путь", "сюда") == url.parts
+ url = URL("http://example.com/шлях/сюди")
+ assert ("/", "шлях", "сюди") == url.parts
def test_name_for_empty_url():
@@ -489,8 +490,8 @@ def test_relative_raw_name_slash():
def test_name_non_ascii():
- url = URL("http://example.com/путь")
- assert url.name == "путь"
+ url = URL("http://example.com/шлях")
+ assert url.name == "шлях"
def test_suffix_for_empty_url():
@@ -534,8 +535,8 @@ def test_relative_raw_suffix_dot():
def test_suffix_non_ascii():
- url = URL("http://example.com/путь.суффикс")
- assert url.suffix == ".суффикс"
+ url = URL("http://example.com/шлях.суфікс")
+ assert url.suffix == ".суфікс"
def test_suffix_with_empty_name():
@@ -594,8 +595,8 @@ def test_relative_raw_suffixes_dot():
def test_suffixes_non_ascii():
- url = URL("http://example.com/путь.суффикс")
- assert url.suffixes == (".суффикс",)
+ url = URL("http://example.com/шлях.суфікс")
+ assert url.suffixes == (".суфікс",)
def test_suffixes_with_empty_name():
@@ -753,15 +754,15 @@ def test_div_for_relative_url_started_with_slash():
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 == ("/", "сюда", "туда")
+ url = URL("http://example.com/сюди")
+ url2 = url / "туди"
+ assert url2.path == "/сюди/туди"
+ assert url2.raw_path == "/%D1%81%D1%8E%D0%B4%D0%B8/%D1%82%D1%83%D0%B4%D0%B8"
+ assert url2.parts == ("/", "сюди", "туди")
assert url2.raw_parts == (
"/",
- "%D1%81%D1%8E%D0%B4%D0%B0",
- "%D1%82%D1%83%D0%B4%D0%B0",
+ "%D1%81%D1%8E%D0%B4%D0%B8",
+ "%D1%82%D1%83%D0%B4%D0%B8",
)
@@ -846,13 +847,13 @@ def test_joinpath_relative(url, to_join, expected):
"url,to_join,encoded,e_path,e_raw_path,e_parts,e_raw_parts",
[
pytest.param(
- "http://example.com/сюда",
- ("туда",),
+ "http://example.com/сюди",
+ ("туди",),
False,
- "/сюда/туда",
- "/%D1%81%D1%8E%D0%B4%D0%B0/%D1%82%D1%83%D0%B4%D0%B0",
- ("/", "сюда", "туда"),
- ("/", "%D1%81%D1%8E%D0%B4%D0%B0", "%D1%82%D1%83%D0%B4%D0%B0"),
+ "/сюди/туди",
+ "/%D1%81%D1%8E%D0%B4%D0%B8/%D1%82%D1%83%D0%B4%D0%B8",
+ ("/", "сюди", "туди"),
+ ("/", "%D1%81%D1%8E%D0%B4%D0%B8", "%D1%82%D1%83%D0%B4%D0%B8"),
id="non-ascii",
),
pytest.param(
@@ -1093,11 +1094,11 @@ def test_with_name_empty():
def test_with_name_non_ascii():
- url = URL("http://example.com/path").with_name("путь")
- assert url.path == "/путь"
- assert url.raw_path == "/%D0%BF%D1%83%D1%82%D1%8C"
- assert url.parts == ("/", "путь")
- assert url.raw_parts == ("/", "%D0%BF%D1%83%D1%82%D1%8C")
+ url = URL("http://example.com/path").with_name("шлях")
+ assert url.path == "/шлях"
+ assert url.raw_path == "/%D1%88%D0%BB%D1%8F%D1%85"
+ assert url.parts == ("/", "шлях")
+ assert url.raw_parts == ("/", "%D1%88%D0%BB%D1%8F%D1%85")
def test_with_name_percent_encoded():
@@ -1185,11 +1186,11 @@ def test_with_suffix_empty():
def test_with_suffix_non_ascii():
- url = URL("http://example.com/path").with_suffix(".путь")
- assert url.path == "/path.путь"
- assert url.raw_path == "/path.%D0%BF%D1%83%D1%82%D1%8C"
- assert url.parts == ("/", "path.путь")
- assert url.raw_parts == ("/", "path.%D0%BF%D1%83%D1%82%D1%8C")
+ url = URL("http://example.com/path").with_suffix(".шлях")
+ assert url.path == "/path.шлях"
+ assert url.raw_path == "/path.%D1%88%D0%BB%D1%8F%D1%85"
+ assert url.parts == ("/", "path.шлях")
+ assert url.raw_parts == ("/", "path.%D1%88%D0%BB%D1%8F%D1%85")
def test_with_suffix_percent_encoded():
@@ -1340,8 +1341,8 @@ def test_from_ascii_login():
def test_from_non_ascii_login():
- url = URL("http://вася@host:1234/")
- assert ("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/") == str(url)
+ url = URL("http://бажан@host:1234/")
+ assert ("http://%D0%B1%D0%B0%D0%B6%D0%B0%D0%BD@host:1234/") == str(url)
def test_from_ascii_login_and_password():
@@ -1360,10 +1361,10 @@ def test_from_ascii_login_and_password():
def test_from_non_ascii_login_and_password():
- url = URL("http://вася:пароль@host:1234/")
+ url = URL("http://бажан:пароль@host:1234/")
assert (
"http://"
- "%D0%B2%D0%B0%D1%81%D1%8F"
+ "%D0%B1%D0%B0%D0%B6%D0%B0%D0%BD"
":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C"
"@host:1234/"
) == str(url)
@@ -1384,16 +1385,16 @@ def test_from_ascii_path_lower_case():
def test_from_non_ascii_path():
- url = URL("http://example.com/путь/туда")
+ url = URL("http://example.com/шлях/туди")
assert (
- "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0"
+ "http://example.com/%D1%88%D0%BB%D1%8F%D1%85/%D1%82%D1%83%D0%B4%D0%B8"
) == str(url)
def test_bytes():
- url = URL("http://example.com/путь/туда")
+ url = URL("http://example.com/шлях/туди")
assert (
- b"http://example.com/%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0"
+ b"http://example.com/%D1%88%D0%BB%D1%8F%D1%85/%D1%82%D1%83%D0%B4%D0%B8"
== bytes(url)
)
@@ -1610,23 +1611,23 @@ def test_split_result_non_decoded():
def test_human_repr():
- url = URL("http://вася:пароль@хост.домен:8080/путь/сюда?арг=вал#фраг")
+ url = URL("http://бажан:пароль@хост.домен:8080/шлях/сюди?арг=вал#фраг")
s = url.human_repr()
assert URL(s) == url
- assert s == "http://вася:пароль@хост.домен:8080/путь/сюда?арг=вал#фраг"
+ assert s == "http://бажан:пароль@хост.домен:8080/шлях/сюди?арг=вал#фраг"
def test_human_repr_defaults():
- url = URL("путь")
+ url = URL("шлях")
s = url.human_repr()
- assert s == "путь"
+ assert s == "шлях"
def test_human_repr_default_port():
- url = URL("http://вася:пароль@хост.домен/путь/сюда?арг=вал#фраг")
+ url = URL("http://бажан:пароль@хост.домен/шлях/сюди?арг=вал#фраг")
s = url.human_repr()
assert URL(s) == url
- assert s == "http://вася:пароль@хост.домен/путь/сюда?арг=вал#фраг"
+ assert s == "http://бажан:пароль@хост.домен/шлях/сюди?арг=вал#фраг"
def test_human_repr_ipv6():
@@ -1667,20 +1668,20 @@ def test_human_repr_delimiters():
def test_human_repr_non_printable():
url = URL.build(
scheme="http",
- user="вася\n\xad\u200b",
+ user="бажан\n\xad\u200b",
password="пароль\n\xad\u200b",
host="хост.домен",
port=8080,
- path="/путь\n\xad\u200b",
+ path="/шлях\n\xad\u200b",
query={"арг\n\xad\u200b": "вал\n\xad\u200b"},
fragment="фраг\n\xad\u200b",
)
s = url.human_repr()
assert URL(s) == url
assert (
- s == "http://вася%0A%C2%AD%E2%80%8B:пароль%0A%C2%AD%E2%80%8B"
+ s == "http://бажан%0A%C2%AD%E2%80%8B:пароль%0A%C2%AD%E2%80%8B"
"@хост.домен:8080"
- "/путь%0A%C2%AD%E2%80%8B"
+ "/шлях%0A%C2%AD%E2%80%8B"
"?арг%0A%C2%AD%E2%80%8B=вал%0A%C2%AD%E2%80%8B"
"#фраг%0A%C2%AD%E2%80%8B"
)
diff --git a/contrib/python/yarl/tests/test_url_build.py b/contrib/python/yarl/tests/test_url_build.py
index 51969fa849..5aecbc5854 100644
--- a/contrib/python/yarl/tests/test_url_build.py
+++ b/contrib/python/yarl/tests/test_url_build.py
@@ -32,12 +32,28 @@ def test_build_with_scheme_and_host():
assert u == URL("http://127.0.0.1")
-def test_build_with_port():
- with pytest.raises(ValueError):
- URL.build(port=8000)
-
- u = URL.build(scheme="http", host="127.0.0.1", port=8000)
- assert str(u) == "http://127.0.0.1:8000"
+@pytest.mark.parametrize(
+ ("port", "exc", "match"),
+ [
+ pytest.param(
+ 8000,
+ ValueError,
+ r"""(?x)
+ ^
+ Can't\ build\ URL\ with\ "port"\ but\ without\ "host"\.
+ $
+ """,
+ id="port-only",
+ ),
+ pytest.param(
+ "", TypeError, r"^The port is required to be int\.$", id="port-str"
+ ),
+ ],
+)
+def test_build_with_port(port, exc, match):
+ print(match)
+ with pytest.raises(exc, match=match):
+ URL.build(port=port)
def test_build_with_user():
@@ -85,8 +101,10 @@ def test_build_with_authority_and_host():
def test_build_with_authority():
- url = URL.build(scheme="http", authority="ваня:bar@host.com:8000", path="path")
- assert str(url) == "http://%D0%B2%D0%B0%D0%BD%D1%8F:bar@host.com:8000/path"
+ url = URL.build(scheme="http", authority="степан:bar@host.com:8000", path="path")
+ assert (
+ str(url) == "http://%D1%81%D1%82%D0%B5%D0%BF%D0%B0%D0%BD:bar@host.com:8000/path"
+ )
def test_build_with_authority_without_encoding():
@@ -109,23 +127,33 @@ def test_query_dict():
def test_build_path_quoting():
u = URL.build(
- scheme="http", host="127.0.0.1", path="/файл.jpg", query=dict(arg="Привет")
+ scheme="http",
+ host="127.0.0.1",
+ path="/фотографія.jpg",
+ query=dict(arg="Привіт"),
)
- assert u == URL("http://127.0.0.1/файл.jpg?arg=Привет")
+ assert u == URL("http://127.0.0.1/фотографія.jpg?arg=Привіт")
assert str(u) == (
- "http://127.0.0.1/%D1%84%D0%B0%D0%B9%D0%BB.jpg?"
- "arg=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82"
+ "http://127.0.0.1/"
+ "%D1%84%D0%BE%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D1%96%D1%8F.jpg?"
+ "arg=%D0%9F%D1%80%D0%B8%D0%B2%D1%96%D1%82"
)
def test_build_query_quoting():
- u = URL.build(scheme="http", host="127.0.0.1", path="/файл.jpg", query="arg=Привет")
+ u = URL.build(
+ scheme="http",
+ host="127.0.0.1",
+ path="/фотографія.jpg",
+ query="arg=Привіт",
+ )
- assert u == URL("http://127.0.0.1/файл.jpg?arg=Привет")
+ assert u == URL("http://127.0.0.1/фотографія.jpg?arg=Привіт")
assert str(u) == (
- "http://127.0.0.1/%D1%84%D0%B0%D0%B9%D0%BB.jpg?"
- "arg=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82"
+ "http://127.0.0.1/"
+ "%D1%84%D0%BE%D1%82%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D1%96%D1%8F.jpg?"
+ "arg=%D0%9F%D1%80%D0%B8%D0%B2%D1%96%D1%82"
)
@@ -143,14 +171,14 @@ def test_build_drop_dots():
def test_build_encode():
u = URL.build(
scheme="http",
- host="историк.рф",
- path="/путь/файл",
+ host="оун-упа.укр",
+ path="/шлях/криївка",
query_string="ключ=знач",
fragment="фраг",
)
expected = (
- "http://xn--h1aagokeh.xn--p1ai"
- "/%D0%BF%D1%83%D1%82%D1%8C/%D1%84%D0%B0%D0%B9%D0%BB"
+ "http://xn----8sb1bdhvc.xn--j1amh"
+ "/%D1%88%D0%BB%D1%8F%D1%85/%D0%BA%D1%80%D0%B8%D1%97%D0%B2%D0%BA%D0%B0"
"?%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87"
"#%D1%84%D1%80%D0%B0%D0%B3"
)
@@ -161,13 +189,13 @@ def test_build_already_encoded():
# resulting URL is invalid but not encoded
u = URL.build(
scheme="http",
- host="историк.рф",
- path="/путь/файл",
+ host="оун-упа.укр",
+ path="/шлях/криївка",
query_string="ключ=знач",
fragment="фраг",
encoded=True,
)
- assert str(u) == "http://историк.рф/путь/файл?ключ=знач#фраг"
+ assert str(u) == "http://оун-упа.укр/шлях/криївка?ключ=знач#фраг"
def test_build_percent_encoded():
diff --git a/contrib/python/yarl/tests/test_url_parsing.py b/contrib/python/yarl/tests/test_url_parsing.py
index cc753fcd0c..11aa8e92a4 100644
--- a/contrib/python/yarl/tests/test_url_parsing.py
+++ b/contrib/python/yarl/tests/test_url_parsing.py
@@ -214,15 +214,19 @@ class TestPort:
assert u.query_string == ""
assert u.fragment == ""
- @pytest.mark.xfail(reason="https://github.com/aio-libs/yarl/issues/821")
+ @pytest.mark.xfail(
+ # FIXME: remove "no cover" pragmas upon xfail marker deletion
+ reason="https://github.com/aio-libs/yarl/issues/821",
+ raises=ValueError,
+ )
def test_no_host(self):
u = URL("//:80")
- assert u.scheme == ""
- assert u.host == ""
- assert u.port == 80
- assert u.path == "/"
- assert u.query_string == ""
- assert u.fragment == ""
+ assert u.scheme == "" # pragma: no cover
+ assert u.host == "" # pragma: no cover
+ assert u.port == 80 # pragma: no cover
+ assert u.path == "/" # pragma: no cover
+ assert u.query_string == "" # pragma: no cover
+ assert u.fragment == "" # pragma: no cover
def test_double_port(self):
with pytest.raises(ValueError):
diff --git a/contrib/python/yarl/tests/test_url_update_netloc.py b/contrib/python/yarl/tests/test_url_update_netloc.py
index cf0cc1c44c..47d13bcd60 100644
--- a/contrib/python/yarl/tests/test_url_update_netloc.py
+++ b/contrib/python/yarl/tests/test_url_update_netloc.py
@@ -33,11 +33,11 @@ def test_with_user():
def test_with_user_non_ascii():
url = URL("http://example.com")
- 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%D1%8F@example.com"
- assert url2.authority == "вася@example.com:80"
+ url2 = url.with_user("бажан")
+ assert url2.raw_user == "%D0%B1%D0%B0%D0%B6%D0%B0%D0%BD"
+ assert url2.user == "бажан"
+ assert url2.raw_authority == "%D0%B1%D0%B0%D0%B6%D0%B0%D0%BD@example.com"
+ assert url2.authority == "бажан@example.com:80"
def test_with_user_percent_encoded():
@@ -159,11 +159,11 @@ def test_with_host_empty():
def test_with_host_non_ascii():
url = URL("http://example.com:123")
- 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"
+ url2 = url.with_host("оун-упа.укр")
+ assert url2.raw_host == "xn----8sb1bdhvc.xn--j1amh"
+ assert url2.host == "оун-упа.укр"
+ assert url2.raw_authority == "xn----8sb1bdhvc.xn--j1amh:123"
+ assert url2.authority == "оун-упа.укр:123"
def test_with_host_percent_encoded():
diff --git a/contrib/python/yarl/ya.make b/contrib/python/yarl/ya.make
index 0c3d0ce434..e1a242b811 100644
--- a/contrib/python/yarl/ya.make
+++ b/contrib/python/yarl/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(1.9.3)
+VERSION(1.9.4)
LICENSE(Apache-2.0)
diff --git a/contrib/python/yarl/yarl/__init__.py b/contrib/python/yarl/yarl/__init__.py
index f43aecbc92..127721ad09 100644
--- a/contrib/python/yarl/yarl/__init__.py
+++ b/contrib/python/yarl/yarl/__init__.py
@@ -1,5 +1,5 @@
from ._url import URL, cache_clear, cache_configure, cache_info
-__version__ = "1.9.3"
+__version__ = "1.9.4"
__all__ = ("URL", "cache_clear", "cache_configure", "cache_info")
diff --git a/contrib/python/yarl/yarl/_quoting_c.pyx b/contrib/python/yarl/yarl/_quoting_c.pyx
index 5335d17365..96f69c14e2 100644
--- a/contrib/python/yarl/yarl/_quoting_c.pyx
+++ b/contrib/python/yarl/yarl/_quoting_c.pyx
@@ -145,7 +145,7 @@ cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol):
if _write_pct(writer, <uint8_t>(0xe0 | (utf >> 12)), True) < 0:
return -1
if _write_pct(writer, <uint8_t>(0x80 | ((utf >> 6) & 0x3f)),
- True) < 0:
+ True) < 0:
return -1
return _write_pct(writer, <uint8_t>(0x80 | (utf & 0x3f)), True)
elif utf > 0x10FFFF:
@@ -155,10 +155,10 @@ cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol):
if _write_pct(writer, <uint8_t>(0xf0 | (utf >> 18)), True) < 0:
return -1
if _write_pct(writer, <uint8_t>(0x80 | ((utf >> 12) & 0x3f)),
- True) < 0:
- return -1
+ True) < 0:
+ return -1
if _write_pct(writer, <uint8_t>(0x80 | ((utf >> 6) & 0x3f)),
- True) < 0:
+ True) < 0:
return -1
return _write_pct(writer, <uint8_t>(0x80 | (utf & 0x3f)), True)
diff --git a/contrib/python/yarl/yarl/_url.py b/contrib/python/yarl/yarl/_url.py
index c8f2acb39b..9cca27ef86 100644
--- a/contrib/python/yarl/yarl/_url.py
+++ b/contrib/python/yarl/yarl/_url.py
@@ -233,6 +233,8 @@ class URL:
raise ValueError(
'Can\'t mix "authority" with "user", "password", "host" or "port".'
)
+ if not isinstance(port, (int, type(None))):
+ raise TypeError("The port is required to be int.")
if port and not host:
raise ValueError('Can\'t build URL with "port" but without "host".')
if query and query_string:
@@ -507,7 +509,7 @@ class URL:
return None
if "%" in raw:
# Hack for scoped IPv6 addresses like
- # fe80::2%Проверка
+ # fe80::2%Перевірка
# presence of '%' sign means only IPv6 address, so idna is useless.
return raw
return _idna_decode(raw)