diff options
author | AlexSm <alex@ydb.tech> | 2023-12-22 17:10:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-22 17:10:22 +0100 |
commit | 148f920350c60c0ca2d89b637a5aea9093eee450 (patch) | |
tree | 6314b1433dac833398c333731e83f0ad77e81a0b /contrib/python | |
parent | 7116d46ae7c0259b5f9d489de263f8701e432b1c (diff) | |
download | ydb-148f920350c60c0ca2d89b637a5aea9093eee450.tar.gz |
Library import 2 (#639)
Diffstat (limited to 'contrib/python')
18 files changed, 305 insertions, 208 deletions
diff --git a/contrib/python/importlib-metadata/py3/.dist-info/METADATA b/contrib/python/importlib-metadata/py3/.dist-info/METADATA index 395be499f1..9e58c1d38e 100644 --- a/contrib/python/importlib-metadata/py3/.dist-info/METADATA +++ b/contrib/python/importlib-metadata/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: importlib-metadata -Version: 6.8.0 +Version: 6.9.0 Summary: Read metadata from Python packages Home-page: https://github.com/python/importlib_metadata Author: Jason R. Coombs @@ -12,29 +12,30 @@ Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only Requires-Python: >=3.8 License-File: LICENSE -Requires-Dist: typing-extensions (>=3.6.4) ; python_version < "3.8" +Requires-Dist: typing-extensions >=3.6.4 ; python_version < "3.8" Provides-Extra: docs -Requires-Dist: sphinx (>=3.5) ; extra == 'docs' -Requires-Dist: jaraco.packaging (>=9) ; extra == 'docs' -Requires-Dist: rst.linker (>=1.9) ; extra == 'docs' +Requires-Dist: sphinx >=3.5 ; extra == 'docs' +Requires-Dist: sphinx <7.2.5 ; extra == 'docs' +Requires-Dist: jaraco.packaging >=9.3 ; extra == 'docs' +Requires-Dist: rst.linker >=1.9 ; extra == 'docs' Requires-Dist: furo ; extra == 'docs' Requires-Dist: sphinx-lint ; extra == 'docs' -Requires-Dist: jaraco.tidelift (>=1.4) ; extra == 'docs' +Requires-Dist: jaraco.tidelift >=1.4 ; extra == 'docs' Provides-Extra: perf Requires-Dist: ipython ; extra == 'perf' Provides-Extra: testing -Requires-Dist: pytest (>=6) ; extra == 'testing' -Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing' +Requires-Dist: pytest >=6 ; extra == 'testing' +Requires-Dist: pytest-checkdocs >=2.4 ; extra == 'testing' Requires-Dist: pytest-cov ; extra == 'testing' -Requires-Dist: pytest-enabler (>=2.2) ; extra == 'testing' +Requires-Dist: pytest-enabler >=2.2 ; extra == 'testing' Requires-Dist: pytest-ruff ; extra == 'testing' Requires-Dist: packaging ; extra == 'testing' Requires-Dist: pyfakefs ; extra == 'testing' Requires-Dist: flufl.flake8 ; extra == 'testing' -Requires-Dist: pytest-perf (>=0.9.2) ; extra == 'testing' -Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing' -Requires-Dist: pytest-mypy (>=0.9.1) ; (platform_python_implementation != "PyPy") and extra == 'testing' -Requires-Dist: importlib-resources (>=1.3) ; (python_version < "3.9") and extra == 'testing' +Requires-Dist: pytest-perf >=0.9.2 ; extra == 'testing' +Requires-Dist: pytest-black >=0.3.7 ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: pytest-mypy >=0.9.1 ; (platform_python_implementation != "PyPy") and extra == 'testing' +Requires-Dist: importlib-resources >=1.3 ; (python_version < "3.9") and extra == 'testing' .. image:: https://img.shields.io/pypi/v/importlib_metadata.svg :target: https://pypi.org/project/importlib_metadata @@ -128,10 +129,3 @@ Available as part of the Tidelift Subscription. This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. `Learn more <https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=referral&utm_campaign=github>`_. - -Security Contact -================ - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure. diff --git a/contrib/python/importlib-metadata/py3/README.rst b/contrib/python/importlib-metadata/py3/README.rst index f42e88db71..73ddc5fab4 100644 --- a/contrib/python/importlib-metadata/py3/README.rst +++ b/contrib/python/importlib-metadata/py3/README.rst @@ -90,10 +90,3 @@ Available as part of the Tidelift Subscription. This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. `Learn more <https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=referral&utm_campaign=github>`_. - -Security Contact -================ - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure. diff --git a/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py b/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py index 36fed6ecee..8416afdbd6 100644 --- a/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py +++ b/contrib/python/importlib-metadata/py3/importlib_metadata/__init__.py @@ -298,6 +298,13 @@ class EntryPoints(tuple): except StopIteration: raise KeyError(name) + def __repr__(self): + """ + Repr with classname and tuple constructor to + signal that we deviate from regular tuple behavior. + """ + return '%s(%r)' % (self.__class__.__name__, tuple(self)) + def select(self, **params): """ Select entry points from self that match the diff --git a/contrib/python/importlib-metadata/py3/importlib_metadata/_adapters.py b/contrib/python/importlib-metadata/py3/importlib_metadata/_adapters.py index e33cba5e44..120e43a048 100644 --- a/contrib/python/importlib-metadata/py3/importlib_metadata/_adapters.py +++ b/contrib/python/importlib-metadata/py3/importlib_metadata/_adapters.py @@ -54,7 +54,7 @@ class Message(email.message.Message): def __getitem__(self, item): """ Warn users that a ``KeyError`` can be expected when a - mising key is supplied. Ref python/importlib_metadata#371. + missing key is supplied. Ref python/importlib_metadata#371. """ res = super().__getitem__(item) if res is None: diff --git a/contrib/python/importlib-metadata/py3/ya.make b/contrib/python/importlib-metadata/py3/ya.make index baed051fc4..cb87df460a 100644 --- a/contrib/python/importlib-metadata/py3/ya.make +++ b/contrib/python/importlib-metadata/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(6.8.0) +VERSION(6.9.0) LICENSE(Apache-2.0) 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) |