From e612584928a5c64f458ea1752a092e53c8f5093c Mon Sep 17 00:00:00 2001 From: "deepin-community-bot[bot]" <156989552+deepin-community-bot[bot]@users.noreply.github.com> Date: Thu, 26 Dec 2024 12:42:17 +0000 Subject: [PATCH] feat: update yarl to 1.13.1-1 --- .coveragerc | 33 + CHANGES.rst | 857 +- CHANGES/.TEMPLATE.rst | 90 + CHANGES/.gitignore | 28 + CHANGES/README.rst | 109 + LICENSE | 191 +- MANIFEST.in | 10 +- NOTICE | 13 + PKG-INFO | 929 +- README.rst | 38 +- debian/changelog | 27 +- debian/control | 8 +- ...ot-add-changelog-to-long-description.patch | 29 - .../0002-docs-disable-intersphinx.patch | 8 +- ...docs-disable-sidebar_collapse-option.patch | 4 +- ...rivacy-breach-links-in-documentation.patch | 4 +- ...wncrier-changelog-generation-for-now.patch | 22 + debian/patches/0005-python3.11-test-fix.patch | 24 - ...h.expandvars-instead-of-external-one.patch | 35 + debian/patches/series | 4 +- debian/patches/square_bracket_handling.patch | 110 +- docs/api.rst | 259 +- docs/changes.rst | 18 + docs/conf.py | 61 +- docs/contributing/guidelines.rst | 28 + docs/contributing/release_guide.rst | 105 + docs/index.rst | 36 +- docs/spelling_wordlist.txt | 34 + packaging/README.md | 11 + packaging/pep517_backend/__init__.py | 1 + packaging/pep517_backend/__main__.py | 6 + packaging/pep517_backend/_backend.py | 395 + packaging/pep517_backend/_compat.py | 33 + .../pep517_backend/_cython_configuration.py | 107 + packaging/pep517_backend/_transformers.py | 107 + packaging/pep517_backend/cli.py | 53 + packaging/pep517_backend/hooks.py | 21 + pyproject.toml | 95 +- pytest.ini | 88 + requirements/cython.txt | 1 + requirements/dev.txt | 2 + requirements/doc-spelling.txt | 2 + requirements/doc.txt | 4 + requirements/lint.txt | 1 + requirements/test.txt | 7 + requirements/towncrier.txt | 1 + setup.cfg | 87 +- setup.py | 91 - tests/test_cache.py | 16 +- tests/test_cached_property.py | 33 +- tests/test_helpers.py | 91 + tests/test_normalize_path.py | 6 + tests/test_quoting.py | 21 +- tests/test_update_query.py | 116 +- tests/test_url.py | 663 +- tests/test_url_build.py | 143 +- tests/test_url_parsing.py | 105 +- tests/test_url_query.py | 240 +- tests/test_url_update_netloc.py | 86 +- towncrier.toml | 68 + yarl.egg-info/PKG-INFO | 929 +- yarl.egg-info/SOURCES.txt | 35 +- yarl.egg-info/not-zip-safe | 1 + yarl.egg-info/requires.txt | 5 +- yarl/__init__.py | 22 +- yarl/__init__.pyi | 118 - yarl/_helpers.py | 31 + yarl/_helpers_c.pyi | 6 + yarl/_helpers_c.pyx | 36 + yarl/_helpers_py.py | 41 + yarl/_quoting.py | 6 +- yarl/_quoting_c.c | 11939 ---------------- yarl/_quoting_c.pyi | 8 +- yarl/_quoting_c.pyx | 14 +- yarl/_quoting_py.py | 13 +- yarl/_url.py | 1141 +- 76 files changed, 7008 insertions(+), 13152 deletions(-) create mode 100644 .coveragerc create mode 100644 CHANGES/.TEMPLATE.rst create mode 100644 CHANGES/.gitignore create mode 100644 CHANGES/README.rst create mode 100644 NOTICE delete mode 100644 debian/patches/0001-do-not-add-changelog-to-long-description.patch create mode 100644 debian/patches/0005-drop-towncrier-changelog-generation-for-now.patch delete mode 100644 debian/patches/0005-python3.11-test-fix.patch create mode 100644 debian/patches/0006-use-os.path.expandvars-instead-of-external-one.patch create mode 100644 docs/changes.rst create mode 100644 docs/contributing/guidelines.rst create mode 100644 docs/contributing/release_guide.rst create mode 100644 packaging/README.md create mode 100644 packaging/pep517_backend/__init__.py create mode 100644 packaging/pep517_backend/__main__.py create mode 100644 packaging/pep517_backend/_backend.py create mode 100644 packaging/pep517_backend/_compat.py create mode 100644 packaging/pep517_backend/_cython_configuration.py create mode 100644 packaging/pep517_backend/_transformers.py create mode 100644 packaging/pep517_backend/cli.py create mode 100644 packaging/pep517_backend/hooks.py create mode 100644 pytest.ini create mode 100644 requirements/cython.txt create mode 100644 requirements/dev.txt create mode 100644 requirements/doc-spelling.txt create mode 100644 requirements/doc.txt create mode 100644 requirements/lint.txt create mode 100644 requirements/test.txt create mode 100644 requirements/towncrier.txt delete mode 100644 setup.py create mode 100644 tests/test_helpers.py create mode 100644 towncrier.toml create mode 100644 yarl.egg-info/not-zip-safe delete mode 100644 yarl/__init__.pyi create mode 100644 yarl/_helpers.py create mode 100644 yarl/_helpers_c.pyi create mode 100644 yarl/_helpers_c.pyx create mode 100644 yarl/_helpers_py.py delete mode 100644 yarl/_quoting_c.c diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..b48bd29 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,33 @@ +[html] +show_contexts = true +skip_covered = false + +[paths] +source = + yarl + */lib/pypy*/site-packages/yarl + */lib/python*/site-packages/yarl + */Lib/site-packages/yarl + +[report] +fail_under = 98.95 +skip_covered = true +skip_empty = true +show_missing = true +exclude_also = + ^\s*@pytest\.mark\.xfail + +[run] +branch = true +cover_pylib = false +# https://coverage.rtfd.io/en/latest/contexts.html#dynamic-contexts +# dynamic_context = test_function # conflicts with `pytest-cov` if set here +parallel = true +plugins = + covdefaults + Cython.Coverage +relative_files = true +source = + . +source_pkgs = + yarl diff --git a/CHANGES.rst b/CHANGES.rst index f693780..de9d1ab 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -14,6 +14,821 @@ Changelog .. towncrier release notes start +1.13.1 +====== + +*(2024-09-27)* + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of calling :py:meth:`~yarl.URL.build` with ``authority`` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1163`. + + +---- + + +1.13.0 +====== + +*(2024-09-26)* + + +Bug fixes +--------- + +- Started rejecting ASCII hostnames with invalid characters. For host strings that + look like authority strings, the exception message includes advice on what to do + instead -- by :user:`mjpieters`. + + *Related issues and pull requests on GitHub:* + :issue:`880`, :issue:`954`. + +- Fixed IPv6 addresses missing brackets when the :class:`~yarl.URL` was converted to a string -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1157`, :issue:`1158`. + + +Features +-------- + +- Added :attr:`~yarl.URL.host_subcomponent` which returns the :rfc:`3986#section-3.2.2` host subcomponent -- by :user:`bdraco`. + + The only current practical difference between :attr:`~yarl.URL.raw_host` and :attr:`~yarl.URL.host_subcomponent` is that IPv6 addresses are returned bracketed. + + *Related issues and pull requests on GitHub:* + :issue:`1159`. + + +---- + + +1.12.1 +====== + +*(2024-09-23)* + + +No significant changes. + + +---- + + +1.12.0 +====== + +*(2024-09-23)* + + +Features +-------- + +- Added :attr:`~yarl.URL.path_safe` to be able to fetch the path without ``%2F`` and ``%25`` decoded -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1150`. + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Restore decoding ``%2F`` (``/``) in ``URL.path`` -- by :user:`bdraco`. + + This change restored the behavior before :issue:`1057`. + + *Related issues and pull requests on GitHub:* + :issue:`1151`. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of processing paths -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1143`. + + +---- + + +1.11.1 +====== + +*(2024-09-09)* + + +Bug fixes +--------- + +- Allowed scheme replacement for relative URLs if the scheme does not require a host -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`280`, :issue:`1138`. + +- Allowed empty host for URL schemes other than the special schemes listed in the WHATWG URL spec -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1136`. + + +Features +-------- + +- Loosened restriction on integers as query string values to allow classes that implement ``__int__`` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1139`. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of normalizing paths -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1137`. + + +---- + + +1.11.0 +====== + +*(2024-09-08)* + + +Features +-------- + +- Added :meth:`URL.extend_query() ` method, which can be used to extend parameters without replacing same named keys -- by :user:`bdraco`. + + This method was primarily added to replace the inefficient hand rolled method currently used in ``aiohttp``. + + *Related issues and pull requests on GitHub:* + :issue:`1128`. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of the Cython ``cached_property`` implementation -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1122`. + +- Simplified computing ports by removing unnecessary code -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1123`. + +- Improved performance of encoding non IPv6 hosts -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1125`. + +- Improved performance of :meth:`URL.build() ` when the path, query string, or fragment is an empty string -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1126`. + +- Improved performance of the :meth:`URL.update_query() ` method -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1130`. + +- Improved performance of processing query string changes when arguments are :class:`str` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1131`. + + +---- + + +1.10.0 +====== + +*(2024-09-06)* + + +Bug fixes +--------- + +- Fixed joining a path when the existing path was empty -- by :user:`bdraco`. + + A regression in :meth:`URL.join() ` was introduced in :issue:`1082`. + + *Related issues and pull requests on GitHub:* + :issue:`1118`. + + +Features +-------- + +- Added :meth:`URL.without_query_params() ` method, to drop some parameters from query string -- by :user:`hongquan`. + + *Related issues and pull requests on GitHub:* + :issue:`774`, :issue:`898`, :issue:`1010`. + +- The previously protected types ``_SimpleQuery``, ``_QueryVariable``, and ``_Query`` are now available for use externally as ``SimpleQuery``, ``QueryVariable``, and ``Query`` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1050`, :issue:`1113`. + + +Contributor-facing changes +-------------------------- + +- Replaced all :class:`~typing.Optional` with :class:`~typing.Union` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1095`. + + +Miscellaneous internal changes +------------------------------ + +- Significantly improved performance of parsing the network location -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1112`. + +- Added internal types to the cache to prevent future refactoring errors -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1117`. + + +---- + + +1.9.11 +====== + +*(2024-09-04)* + + +Bug fixes +--------- + +- Fixed a :exc:`TypeError` with ``MultiDictProxy`` and Python 3.8 -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1084`, :issue:`1105`, :issue:`1107`. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of encoding hosts -- by :user:`bdraco`. + + Previously, the library would unconditionally try to parse a host as an IP Address. The library now avoids trying to parse a host as an IP Address if the string is not in one of the formats described in :rfc:`3986#section-3.2.2`. + + *Related issues and pull requests on GitHub:* + :issue:`1104`. + + +---- + + +1.9.10 +====== + +*(2024-09-04)* + + +Bug fixes +--------- + +- :meth:`URL.join() ` has been changed to match + :rfc:`3986` and align with + :meth:`/ operation ` and :meth:`URL.joinpath() ` + when joining URLs with empty segments. + Previously :py:func:`urllib.parse.urljoin` was used, + which has known issues with empty segments + (`python/cpython#84774 `_). + + Due to the semantics of :meth:`URL.join() `, joining an + URL with scheme requires making it relative, prefixing with ``./``. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/").join(URL("./https://github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + Empty segments are honored in the base as well as the joined part. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/https://").join(URL("github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + + -- by :user:`commonism` + + This change initially appeared in 1.9.5 but was reverted in 1.9.6 to resolve a problem with query string handling. + + *Related issues and pull requests on GitHub:* + :issue:`1039`, :issue:`1082`. + + +Features +-------- + +- Added :attr:`~yarl.URL.absolute` which is now preferred over ``URL.is_absolute()`` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1100`. + + +---- + + +1.9.9 +===== + +*(2024-09-04)* + + +Bug fixes +--------- + +- Added missing type on :attr:`~yarl.URL.port` -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1097`. + + +---- + + +1.9.8 +===== + +*(2024-09-03)* + + +Features +-------- + +- Covered the :class:`~yarl.URL` object with types -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1084`. + +- Cache parsing of IP Addresses when encoding hosts -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1086`. + + +Contributor-facing changes +-------------------------- + +- Covered the :class:`~yarl.URL` object with types -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1084`. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of handling ports -- by :user:`bdraco`. + + *Related issues and pull requests on GitHub:* + :issue:`1081`. + + +---- + + +1.9.7 +===== + +*(2024-09-01)* + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Removed support :rfc:`3986#section-3.2.3` port normalization when the scheme is not one of ``http``, ``https``, ``wss``, or ``ws`` -- by :user:`bdraco`. + + Support for port normalization was recently added in :issue:`1033` and contained code that would do blocking I/O if the scheme was not one of the four listed above. The code has been removed because this library is intended to be safe for usage with :mod:`asyncio`. + + *Related issues and pull requests on GitHub:* + :issue:`1076`. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of property caching -- by :user:`bdraco`. + + The ``reify`` implementation from ``aiohttp`` was adapted to replace the internal ``cached_property`` implementation. + + *Related issues and pull requests on GitHub:* + :issue:`1070`. + + +---- + + +1.9.6 +===== + +*(2024-08-30)* + + +Bug fixes +--------- + +- Reverted :rfc:`3986` compatible :meth:`URL.join() ` honoring empty segments which was introduced in :issue:`1039`. + + This change introduced a regression handling query string parameters with joined URLs. The change was reverted to maintain compatibility with the previous behavior. + + *Related issues and pull requests on GitHub:* + :issue:`1067`. + + +---- + + +1.9.5 +===== + +*(2024-08-30)* + + +Bug fixes +--------- + +- Joining URLs with empty segments has been changed + to match :rfc:`3986`. + + Previously empty segments would be removed from path, + breaking use-cases such as + + .. code-block:: python + + URL("https://web.archive.org/web/") / "https://github.com/" + + Now :meth:`/ operation ` and :meth:`URL.joinpath() ` + keep empty segments, but do not introduce new empty segments. + e.g. + + .. code-block:: python + + URL("https://example.org/") / "" + + does not introduce an empty segment. + + -- by :user:`commonism` and :user:`youtux` + + *Related issues and pull requests on GitHub:* + :issue:`1026`. + +- The default protocol ports of well-known URI schemes are now taken into account + during the normalization of the URL string representation in accordance with + :rfc:`3986#section-3.2.3`. + + Specified ports are removed from the :class:`str` representation of a :class:`~yarl.URL` + if the port matches the scheme's default port -- by :user:`commonism`. + + *Related issues and pull requests on GitHub:* + :issue:`1033`. + +- :meth:`URL.join() ` has been changed to match + :rfc:`3986` and align with + :meth:`/ operation ` and :meth:`URL.joinpath() ` + when joining URLs with empty segments. + Previously :py:func:`urllib.parse.urljoin` was used, + which has known issues with empty segments + (`python/cpython#84774 `_). + + Due to the semantics of :meth:`URL.join() `, joining an + URL with scheme requires making it relative, prefixing with ``./``. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/").join(URL("./https://github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + Empty segments are honored in the base as well as the joined part. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/https://").join(URL("github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + + -- by :user:`commonism` + + *Related issues and pull requests on GitHub:* + :issue:`1039`. + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Stopped decoding ``%2F`` (``/``) in ``URL.path``, as this could lead to code incorrectly treating it as a path separator + -- by :user:`Dreamsorcerer`. + + *Related issues and pull requests on GitHub:* + :issue:`1057`. + +- Dropped support for Python 3.7 -- by :user:`Dreamsorcerer`. + + *Related issues and pull requests on GitHub:* + :issue:`1016`. + + +Improved documentation +---------------------- + +- On the :doc:`Contributing docs ` page, + a link to the ``Towncrier philosophy`` has been fixed. + + *Related issues and pull requests on GitHub:* + :issue:`981`. + +- The pre-existing :meth:`/ magic method ` + has been documented in the API reference -- by :user:`commonism`. + + *Related issues and pull requests on GitHub:* + :issue:`1026`. + + +Packaging updates and notes for downstreams +------------------------------------------- + +- A flaw in the logic for copying the project directory into a + temporary folder that led to infinite recursion when :envvar:`TMPDIR` + was set to a project subdirectory path. This was happening in Fedora + and its downstream due to the use of `pyproject-rpm-macros + `__. It was + only reproducible with ``pip wheel`` and was not affecting the + ``pyproject-build`` users. + + -- by :user:`hroncok` and :user:`webknjaz` + + *Related issues and pull requests on GitHub:* + :issue:`992`, :issue:`1014`. + +- Support Python 3.13 and publish non-free-threaded wheels + + *Related issues and pull requests on GitHub:* + :issue:`1054`. + + +Contributor-facing changes +-------------------------- + +- The CI/CD setup has been updated to test ``arm64`` wheels + under macOS 14, except for Python 3.7 that is unsupported + in that environment -- by :user:`webknjaz`. + + *Related issues and pull requests on GitHub:* + :issue:`1015`. + +- Removed unused type ignores and casts -- by :user:`hauntsaninja`. + + *Related issues and pull requests on GitHub:* + :issue:`1031`. + + +Miscellaneous internal changes +------------------------------ + +- ``port``, ``scheme``, and ``raw_host`` are now ``cached_property`` -- by :user:`bdraco`. + + ``aiohttp`` accesses these properties quite often, which cause :mod:`urllib` to build the ``_hostinfo`` property every time. ``port``, ``scheme``, and ``raw_host`` are now cached properties, which will improve performance. + + *Related issues and pull requests on GitHub:* + :issue:`1044`, :issue:`1058`. + + +---- + + +1.9.4 (2023-12-06) +================== + +Bug fixes +--------- + +- Started raising :py:exc:`TypeError` when a string value is passed into + :py:meth:`~yarl.URL.build` as the ``port`` argument -- by :user:`commonism`. + + Previously the empty string as port would create malformed URLs when rendered as string representations. (:issue:`883`) + + +Packaging updates and notes for downstreams +------------------------------------------- + +- The leading ``--`` has been dropped from the :pep:`517` in-tree build + backend config setting names. ``--pure-python`` is now just ``pure-python`` + -- by :user:`webknjaz`. + + The usage now looks as follows: + + .. code-block:: console + + $ python -m build \ + --config-setting=pure-python=true \ + --config-setting=with-cython-tracing=true + + (:issue:`963`) + + +Contributor-facing changes +-------------------------- + +- A step-by-step :doc:`Release Guide ` guide has + been added, describing how to release *yarl* -- by :user:`webknjaz`. + + This is primarily targeting maintainers. (:issue:`960`) +- Coverage collection has been implemented for the Cython modules + -- by :user:`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: + + .. code-block:: console + + $ 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. + + :issue:`961` + +- It is now possible to request line tracing in Cython builds using the + ``with-cython-tracing`` :pep:`517` config setting + -- :user:`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. + + The following produces C-files required for the Cython coverage + plugin to map the measurements back to the PYX-files: + + .. code-block:: console + + $ python -Im pip install -e . + + Alternatively, the ``YARL_CYTHON_TRACING=1`` environment variable + can be set to do the same as the :pep:`517` config setting. + + :issue:`962` + + +1.9.3 (2023-11-20) +================== + +Bug fixes +--------- + +- Stopped dropping trailing slashes in :py:meth:`~yarl.URL.joinpath` -- by :user:`gmacon`. (:issue:`862`, :issue:`866`) +- Started accepting string subclasses in :meth:`~yarl.URL.__truediv__` operations (``URL / segment``) -- by :user:`mjpieters`. (:issue:`871`, :issue:`884`) +- Fixed the human representation of URLs with square brackets in usernames and passwords -- by :user:`mjpieters`. (:issue:`876`, :issue:`882`) +- Updated type hints to include ``URL.missing_port()``, ``URL.__bytes__()`` + and the ``encoding`` argument to :py:meth:`~yarl.URL.joinpath` + -- by :user:`mjpieters`. (:issue:`891`) + + +Packaging updates and notes for downstreams +------------------------------------------- + +- Integrated Cython 3 to enable building *yarl* under Python 3.12 -- by :user:`mjpieters`. (:issue:`829`, :issue:`881`) +- Declared modern ``setuptools.build_meta`` as the :pep:`517` build + backend in :file:`pyproject.toml` explicitly -- by :user:`webknjaz`. (:issue:`886`) +- Converted most of the packaging setup into a declarative :file:`setup.cfg` + config -- by :user:`webknjaz`. (:issue:`890`) +- The packaging is replaced from an old-fashioned :file:`setup.py` to an + in-tree :pep:`517` build backend -- by :user:`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`` + flag ``--pure-python``. If this flag is not set, a C-extension will be built + and included into the distribution. + + Here is how this can be done with ``pip``: + + .. code-block:: console + + $ python -m pip install . --config-settings=--pure-python=false + + This will also work with ``-e | --editable``. + + The same can be achieved via ``pypa/build``: + + .. code-block:: console + + $ 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. (:issue:`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 :user:`edgarrmondragon`. (:issue:`942`) + + +Contributor-facing changes +-------------------------- + +- A regression test for no-host URLs was added per :issue:`821` + and :rfc:`3986` -- by :user:`kenballus`. (:issue:`821`, :issue:`822`) +- Started testing *yarl* against Python 3.12 in CI -- by :user:`mjpieters`. (:issue:`881`) +- All Python 3.12 jobs are now marked as required to pass in CI + -- by :user:`edgarrmondragon`. (:issue:`942`) +- MyST is now integrated in Sphinx -- by :user:`webknjaz`. + + This allows the contributors to author new documents in Markdown + when they have difficulties with going straight RST. (:issue:`953`) + + +1.9.2 (2023-04-25) +================== + +Bugfixes +-------- + +- Fix regression with :meth:`~yarl.URL.__truediv__` and absolute URLs with empty paths causing the raw path to lack the leading ``/``. + (`#854 `_) + + +1.9.1 (2023-04-21) +================== + +Bugfixes +-------- + +- Marked tests that fail on older Python patch releases (< 3.7.10, < 3.8.8 and < 3.9.2) as expected to fail due to missing a security fix for CVE-2021-23336. (`#850 `_) + + +1.9.0 (2023-04-19) +================== + +This release was never published to PyPI, due to issues with the build process. + +Features +-------- + +- Added ``URL.joinpath(*elements)``, to create a new URL appending multiple path elements. (`#704 `_) +- Made :meth:`URL.__truediv__() ` return ``NotImplemented`` if called with an + unsupported type — by :user:`michaeljpeters`. + (`#832 `_) + + +Bugfixes +-------- + +- Path normalization for absolute URLs no longer raises a ValueError exception + when ``..`` segments would otherwise go beyond the URL path root. + (`#536 `_) +- Fixed an issue with update_query() not getting rid of the query when argument is None. (`#792 `_) +- Added some input restrictions on with_port() function to prevent invalid boolean inputs or out of valid port inputs; handled incorrect 0 port representation. (`#793 `_) +- Made :py:meth:`~yarl.URL.build` raise a :py:exc:`TypeError` if the ``host`` argument is :py:data:`None` — by :user:`paulpapacz`. (`#808 `_) +- Fixed an issue with ``update_query()`` getting rid of the query when the argument + is empty but not ``None``. (`#845 `_) + + +Misc +---- + +- `#220 `_ + + 1.8.2 (2022-12-03) ================== @@ -41,7 +856,8 @@ Features Improved Documentation ---------------------- -- Fixed broken internal references to :meth:`~URL.human_repr`. (`#665 `_) +- Fixed broken internal references to :meth:`~yarl.URL.human_repr`. + (`#665 `_) - Fixed broken external references to :doc:`multidict:index` docs. (`#665 `_) @@ -80,7 +896,8 @@ Bugfixes Features -------- -- Add `__bytes__()` magic method so that `bytes(url)` will work and use optimal ASCII encoding. (`#582 `_) +- Add ``__bytes__()`` magic method so that ``bytes(url)`` will work and use optimal ASCII encoding. + (`#582 `_) - Started shipping platform-specific arm64 wheels for Apple Silicon. (`#622 `_) - Started shipping platform-specific wheels with the ``musl`` tag targeting typical Alpine Linux runtimes. (`#622 `_) - Added support for Python 3.10. (`#622 `_) @@ -195,7 +1012,7 @@ Features - Convert host to lowercase on URL building. `#386 `_ -- Allow using ``mod`` operator (`%`) for updating query string (an alias for ``update_query()`` method). +- Allow using ``mod`` operator (``%``) for updating query string (an alias for ``update_query()`` method). `#435 `_ - Allow use of sequences such as ``list`` and ``tuple`` in the values of a mapping such as ``dict`` to represent that a key has many values:: @@ -204,7 +1021,7 @@ Features assert url.with_query({"a": [1, 2]}) == URL("http://example.com/?a=1&a=2") `#443 `_ -- Support URL.build() with scheme and path (creates a relative URL). +- Support ``URL.build()`` with scheme and path (creates a relative URL). `#464 `_ - Cache slow IDNA encode/decode calls. `#476 `_ @@ -223,9 +1040,9 @@ Bugfixes `#409 `_ - Fix a bug where query component, passed in a form of mapping or sequence, is unquoted in unexpected way. `#426 `_ -- Hide `Query` and `QueryVariable` type aliases in `__init__.pyi`, now they are prefixed with underscore. +- Hide ``Query`` and ``QueryVariable`` type aliases in ``__init__.pyi``, now they are prefixed with underscore. `#431 `_ -- Keep ipv6 brackets after updating port/user/password. +- Keep IPv6 brackets after updating port/user/password. `#451 `_ @@ -238,7 +1055,7 @@ Bugfixes Features -------- -- Workaround for missing `str.isascii()` in Python 3.6 +- Workaround for missing ``str.isascii()`` in Python 3.6 `#389 `_ @@ -269,7 +1086,7 @@ Features * Don't create a new URL if fragment is unchanged (#292) -* Included in error msg the path that produces starting slash forbidden error (#376) +* Included in error message the path that produces starting slash forbidden error (#376) * Skip slow IDNA encoding for ASCII-only strings (#387) @@ -328,7 +1145,7 @@ Features 1.1.1 (2018-02-17) ================== -* Fix performance regression: don't encode empty netloc (#170) +* Fix performance regression: don't encode empty ``netloc`` (#170) 1.1.0 (2018-01-21) ================== @@ -390,16 +1207,16 @@ Features * Drop strict mode (#123) -* Fix ``"ValueError: Unallowed PCT %"`` when there's a ``"%"`` in the url (#124) +* Fix ``"ValueError: Unallowed PCT %"`` when there's a ``"%"`` in the URL (#124) 0.13.0 (2017-10-01) =================== * Document ``encoded`` parameter (#102) -* Support relative urls like ``'?key=value'`` (#100) +* Support relative URLs like ``'?key=value'`` (#100) -* Unsafe encoding for QS fixed. Encode ``;`` char in value param (#104) +* Unsafe encoding for QS fixed. Encode ``;`` character in value parameter (#104) * Process passwords without user names (#95) @@ -420,18 +1237,18 @@ Features 0.10.3 (2017-06-13) =================== -* Prevent double URL args unquoting (#83) +* Prevent double URL arguments unquoting (#83) 0.10.2 (2017-05-05) =================== -* Unexpected hash behaviour (#75) +* Unexpected hash behavior (#75) 0.10.1 (2017-05-03) =================== -* Unexpected compare behaviour (#73) +* Unexpected compare behavior (#73) * Do not quote or unquote + if not a query string. (#74) @@ -503,7 +1320,7 @@ Features * Fix core dumps (#41) -* tmpbuf - compiling error (#43) +* ``tmpbuf`` - compiling error (#43) * Added ``URL.update_path()`` method @@ -539,13 +1356,13 @@ Features 0.6.0 (2016-11-07) ================== -* Explicitly use UTF8 encoding in setup.py (#20) +* Explicitly use UTF8 encoding in :file:`setup.py` (#20) * Properly unquote non-UTF8 strings (#19) 0.5.3 (2016-11-02) ================== -* Don't use namedtuple fields but indexes on URL construction +* Don't use :py:class:`typing.NamedTuple` fields but indexes on URL construction 0.5.2 (2016-11-02) ================== @@ -560,7 +1377,7 @@ Features 0.5.0 (2016-11-02) ================== -* Add cython optimization for quoting/unquoting +* Add Cython optimization for quoting/unquoting * Provide binary wheels 0.4.3 (2016-09-29) @@ -613,7 +1430,7 @@ Features 0.1.4 (2016-09-09) ================== -* Add kwargs support for ``with_query()`` (#10) +* Add ``kwargs`` support for ``with_query()`` (#10) 0.1.3 (2016-09-07) ================== diff --git a/CHANGES/.TEMPLATE.rst b/CHANGES/.TEMPLATE.rst new file mode 100644 index 0000000..2879ab2 --- /dev/null +++ b/CHANGES/.TEMPLATE.rst @@ -0,0 +1,90 @@ +{# TOWNCRIER TEMPLATE #} + +*({{ versiondata.date }})* + +{% for section, _ in sections.items() %} +{% set underline = underlines[0] %}{% if section %}{{section}} +{{ underline * section|length }}{% set underline = underlines[1] %} + +{% endif %} + +{% if sections[section] %} +{% for category, val in definitions.items() if category in sections[section]%} +{{ definitions[category]['name'] }} +{{ underline * definitions[category]['name']|length }} + +{% if definitions[category]['showcontent'] %} +{% for text, change_note_refs in sections[section][category].items() %} +- {{ text }} + + {{- '\n' * 2 -}} + + {#- + NOTE: Replacing 'e' with 'f' is a hack that prevents Jinja's `int` + NOTE: filter internal implementation from treating the input as an + NOTE: infinite float when it looks like a scientific notation (with a + NOTE: single 'e' char in between digits), raising an `OverflowError`, + NOTE: subsequently. 'f' is still a hex letter so it won't affect the + NOTE: check for whether it's a (short or long) commit hash or not. + Ref: https://github.com/pallets/jinja/issues/1921 + -#} + {%- + set pr_issue_numbers = change_note_refs + | map('lower') + | map('replace', 'e', 'f') + | map('int', default=None) + | select('integer') + | map('string') + | list + -%} + {%- set arbitrary_refs = [] -%} + {%- set commit_refs = [] -%} + {%- with -%} + {%- set commit_ref_candidates = change_note_refs | reject('in', pr_issue_numbers) -%} + {%- for cf in commit_ref_candidates -%} + {%- if cf | length in (7, 8, 40) and cf | int(default=None, base=16) is not none -%} + {%- set _ = commit_refs.append(cf) -%} + {%- else -%} + {%- set _ = arbitrary_refs.append(cf) -%} + {%- endif -%} + {%- endfor -%} + {%- endwith -%} + + {% if pr_issue_numbers %} + *Related issues and pull requests on GitHub:* + :issue:`{{ pr_issue_numbers | join('`, :issue:`') }}`. + {{- '\n' * 2 -}} + {%- endif -%} + + {% if commit_refs %} + *Related commits on GitHub:* + :commit:`{{ commit_refs | join('`, :commit:`') }}`. + {{- '\n' * 2 -}} + {%- endif -%} + + {% if arbitrary_refs %} + *Unlinked references:* + {{ arbitrary_refs | join(', ') }}. + {{- '\n' * 2 -}} + {%- endif -%} + +{% endfor %} +{% else %} +- {{ sections[section][category]['']|join(', ') }} + +{% endif %} +{% if sections[section][category]|length == 0 %} +No significant changes. + +{% else %} +{% endif %} + +{% endfor %} +{% else %} +No significant changes. + + +{% endif %} +{% endfor %} +---- +{{ '\n' * 2 }} diff --git a/CHANGES/.gitignore b/CHANGES/.gitignore new file mode 100644 index 0000000..d6409a0 --- /dev/null +++ b/CHANGES/.gitignore @@ -0,0 +1,28 @@ +* +!.TEMPLATE.rst +!.gitignore +!README.rst +!*.bugfix +!*.bugfix.rst +!*.bugfix.*.rst +!*.breaking +!*.breaking.rst +!*.breaking.*.rst +!*.contrib +!*.contrib.rst +!*.contrib.*.rst +!*.deprecation +!*.deprecation.rst +!*.deprecation.*.rst +!*.doc +!*.doc.rst +!*.doc.*.rst +!*.feature +!*.feature.rst +!*.feature.*.rst +!*.misc +!*.misc.rst +!*.misc.*.rst +!*.packaging +!*.packaging.rst +!*.packaging.*.rst diff --git a/CHANGES/README.rst b/CHANGES/README.rst new file mode 100644 index 0000000..9c0e790 --- /dev/null +++ b/CHANGES/README.rst @@ -0,0 +1,109 @@ +.. _Adding change notes with your PRs: + +Adding change notes with your PRs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is very important to maintain a log for news of how +updating to the new version of the software will affect +end-users. This is why we enforce collection of the change +fragment files in pull requests as per `Towncrier philosophy`_. + +The idea is that when somebody makes a change, they must record +the bits that would affect end-users only including information +that would be useful to them. Then, when the maintainers publish +a new release, they'll automatically use these records to compose +a change log for the respective version. It is important to +understand that including unnecessary low-level implementation +related details generates noise that is not particularly useful +to the end-users most of the time. And so such details should be +recorded in the Git history rather than a changelog. + +Alright! So how to add a news fragment? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``yarl`` uses `towncrier `_ +for changelog management. +To submit a change note about your PR, add a text file into the +``CHANGES/`` folder. It should contain an +explanation of what applying this PR will change in the way +end-users interact with the project. One sentence is usually +enough but feel free to add as many details as you feel necessary +for the users to understand what it means. + +**Use the past tense** for the text in your fragment because, +combined with others, it will be a part of the "news digest" +telling the readers **what changed** in a specific version of +the library *since the previous version*. You should also use +reStructuredText syntax for highlighting code (inline or block), +linking parts of the docs or external sites. +If you wish to sign your change, feel free to add ``-- by +:user:`github-username``` at the end (replace ``github-username`` +with your own!). + +Finally, name your file following the convention that Towncrier +understands: it should start with the number of an issue or a +PR followed by a dot, then add a patch type, like ``feature``, +``doc``, ``contrib`` etc., and add ``.rst`` as a suffix. If you +need to add more than one fragment, you may add an optional +sequence number (delimited with another period) between the type +and the suffix. + +In general the name will follow ``..rst`` pattern, +where the categories are: + +- ``bugfix``: A bug fix for something we deemed an improper undesired + behavior that got corrected in the release to match pre-agreed + expectations. +- ``feature``: A new behavior, public APIs. That sort of stuff. +- ``deprecation``: A declaration of future API removals and breaking + changes in behavior. +- ``breaking``: When something public gets removed in a breaking way. + Could be deprecated in an earlier release. +- ``doc``: Notable updates to the documentation structure or build + process. +- ``packaging``: Notes for downstreams about unobvious side effects + and tooling. Changes in the test invocation considerations and + runtime assumptions. +- ``contrib``: Stuff that affects the contributor experience. e.g. + Running tests, building the docs, setting up the development + environment. +- ``misc``: Changes that are hard to assign to any of the above + categories. + +A pull request may have more than one of these components, for example +a code change may introduce a new feature that deprecates an old +feature, in which case two fragments should be added. It is not +necessary to make a separate documentation fragment for documentation +changes accompanying the relevant code changes. + +Examples for adding changelog entries to your Pull Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +File :file:`CHANGES/603.removal.1.rst`: + +.. code-block:: rst + + Dropped Python 3.5 support; Python 3.6 is the minimal supported Python + version -- by :user:`webknjaz`. + +File :file:`CHANGES/550.bugfix.rst`: + +.. code-block:: rst + + Started shipping Windows wheels for the x86 architecture + -- by :user:`Dreamsorcerer`. + +File :file:`CHANGES/553.feature.rst`: + +.. code-block:: rst + + Added support for ``GenericAliases`` (``MultiDict[str]``) under Python 3.9 + and higher -- by :user:`mjpieters`. + +.. tip:: + + See :file:`towncrier.toml` for all available categories + (``tool.towncrier.type``). + +.. _Towncrier philosophy: + https://towncrier.readthedocs.io/en/stable/#philosophy diff --git a/LICENSE b/LICENSE index fa53b2b..d645695 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,193 @@ - Copyright 2016-2021, Andrew Svetlov and aio-libs team + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MANIFEST.in b/MANIFEST.in index dab6cb9..904cf68 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,12 +1,20 @@ +include .coveragerc +include pyproject.toml +include pytest.ini +include towncrier.toml include LICENSE +include NOTICE include CHANGES.rst include README.rst graft yarl +graft packaging graft docs +graft CHANGES +graft requirements graft tests -include yarl/*.c global-exclude *.pyc global-exclude *.cache +exclude yarl/*.c exclude yarl/*.html exclude yarl/*.so exclude yarl/*.pyd diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..fa53b2b --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ + Copyright 2016-2021, Andrew Svetlov and aio-libs team + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/PKG-INFO b/PKG-INFO index e51f20e..23a3ff7 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,28 +1,49 @@ Metadata-Version: 2.1 Name: yarl -Version: 1.8.2 +Version: 1.13.1 Summary: Yet another URL library -Home-page: https://github.com/aio-libs/yarl/ +Home-page: https://github.com/aio-libs/yarl Author: Andrew Svetlov Author-email: andrew.svetlov@gmail.com -License: Apache 2 -Classifier: License :: OSI Approved :: Apache Software License +Maintainer: aiohttp team +Maintainer-email: team@aiohttp.org +License: Apache-2.0 +Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org +Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org +Project-URL: CI: GitHub Workflows, https://github.com/aio-libs/yarl/actions?query=branch:master +Project-URL: Code of Conduct, https://github.com/aio-libs/.github/blob/master/CODE_OF_CONDUCT.md +Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/yarl +Project-URL: Docs: Changelog, https://yarl.aio-libs.org/en/latest/changes/ +Project-URL: Docs: RTD, https://yarl.aio-libs.org +Project-URL: GitHub: issues, https://github.com/aio-libs/yarl/issues +Project-URL: GitHub: repo, https://github.com/aio-libs/yarl +Keywords: cython,cext,yarl +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Cython Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.7 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.8 Description-Content-Type: text/x-rst License-File: LICENSE +License-File: NOTICE +Requires-Dist: idna>=2.0 +Requires-Dist: multidict>=4.0 yarl ==== +The module provides handy URL class for URL parsing and changing. + .. image:: https://github.com/aio-libs/yarl/workflows/CI/badge.svg :target: https://github.com/aio-libs/yarl/actions?query=workflow%3ACI :align: right @@ -35,15 +56,19 @@ yarl .. image:: https://readthedocs.org/projects/yarl/badge/?version=latest - :target: https://yarl.readthedocs.io + :target: https://yarl.aio-libs.org .. image:: https://img.shields.io/pypi/pyversions/yarl.svg :target: https://pypi.python.org/pypi/yarl -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter +.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs:matrix.org + :alt: Matrix Room — #aio-libs:matrix.org + +.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs-space:matrix.org + :alt: Matrix Space — #aio-libs-space:matrix.org Introduction ------------ @@ -90,9 +115,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: @@ -100,19 +125,19 @@ 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.readthedocs.org. +For full documentation please read https://yarl.aio-libs.org. Installation @@ -130,12 +155,13 @@ manylinux-compliant because of the missing glibc and therefore, cannot be 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 setting the `YARL_NO_EXTENSIONS` +To skip the compilation you must explicitly opt-in by using a PEP 517 +configuration setting ``pure-python``, or setting the ``YARL_NO_EXTENSIONS`` environment variable to a non-empty value, e.g.: -.. code-block:: bash +.. code-block:: console - $ YARL_NO_EXTENSIONS=1 pip install yarl + $ 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 @@ -150,7 +176,7 @@ YARL requires multidict_ library. API documentation ------------------ -The documentation is located at https://yarl.readthedocs.org +The documentation is located at https://yarl.aio-libs.org. Why isn't boolean supported by the URL query API? @@ -200,9 +226,6 @@ Please file an issue on the `bug tracker `_ if you have found a bug or have some suggestion in order to improve the library. -The library uses `Azure Pipelines `_ for -Continuous Integration. - Discussion list --------------- @@ -223,7 +246,6 @@ It's *Apache 2* licensed and freely available. .. _multidict: https://github.com/aio-libs/multidict - ========= Changelog ========= @@ -240,6 +262,821 @@ Changelog .. towncrier release notes start +1.13.1 +====== + +*(2024-09-27)* + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of calling ``yarl.URL.build()`` with ``authority`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1163 `__. + + +---- + + +1.13.0 +====== + +*(2024-09-26)* + + +Bug fixes +--------- + +- Started rejecting ASCII hostnames with invalid characters. For host strings that + look like authority strings, the exception message includes advice on what to do + instead -- by `@mjpieters `__. + + *Related issues and pull requests on GitHub:* + `#880 `__, `#954 `__. + +- Fixed IPv6 addresses missing brackets when the ``~yarl.URL`` was converted to a string -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1157 `__, `#1158 `__. + + +Features +-------- + +- Added ``~yarl.URL.host_subcomponent`` which returns the ``3986#section-3.2.2`` host subcomponent -- by `@bdraco `__. + + The only current practical difference between ``~yarl.URL.raw_host`` and ``~yarl.URL.host_subcomponent`` is that IPv6 addresses are returned bracketed. + + *Related issues and pull requests on GitHub:* + `#1159 `__. + + +---- + + +1.12.1 +====== + +*(2024-09-23)* + + +No significant changes. + + +---- + + +1.12.0 +====== + +*(2024-09-23)* + + +Features +-------- + +- Added ``~yarl.URL.path_safe`` to be able to fetch the path without ``%2F`` and ``%25`` decoded -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1150 `__. + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Restore decoding ``%2F`` (``/``) in ``URL.path`` -- by `@bdraco `__. + + This change restored the behavior before `#1057 `__. + + *Related issues and pull requests on GitHub:* + `#1151 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of processing paths -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1143 `__. + + +---- + + +1.11.1 +====== + +*(2024-09-09)* + + +Bug fixes +--------- + +- Allowed scheme replacement for relative URLs if the scheme does not require a host -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#280 `__, `#1138 `__. + +- Allowed empty host for URL schemes other than the special schemes listed in the WHATWG URL spec -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1136 `__. + + +Features +-------- + +- Loosened restriction on integers as query string values to allow classes that implement ``__int__`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1139 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of normalizing paths -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1137 `__. + + +---- + + +1.11.0 +====== + +*(2024-09-08)* + + +Features +-------- + +- Added ``URL.extend_query()()`` method, which can be used to extend parameters without replacing same named keys -- by `@bdraco `__. + + This method was primarily added to replace the inefficient hand rolled method currently used in ``aiohttp``. + + *Related issues and pull requests on GitHub:* + `#1128 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of the Cython ``cached_property`` implementation -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1122 `__. + +- Simplified computing ports by removing unnecessary code -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1123 `__. + +- Improved performance of encoding non IPv6 hosts -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1125 `__. + +- Improved performance of ``URL.build()()`` when the path, query string, or fragment is an empty string -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1126 `__. + +- Improved performance of the ``URL.update_query()()`` method -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1130 `__. + +- Improved performance of processing query string changes when arguments are ``str`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1131 `__. + + +---- + + +1.10.0 +====== + +*(2024-09-06)* + + +Bug fixes +--------- + +- Fixed joining a path when the existing path was empty -- by `@bdraco `__. + + A regression in ``URL.join()()`` was introduced in `#1082 `__. + + *Related issues and pull requests on GitHub:* + `#1118 `__. + + +Features +-------- + +- Added ``URL.without_query_params()()`` method, to drop some parameters from query string -- by `@hongquan `__. + + *Related issues and pull requests on GitHub:* + `#774 `__, `#898 `__, `#1010 `__. + +- The previously protected types ``_SimpleQuery``, ``_QueryVariable``, and ``_Query`` are now available for use externally as ``SimpleQuery``, ``QueryVariable``, and ``Query`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1050 `__, `#1113 `__. + + +Contributor-facing changes +-------------------------- + +- Replaced all ``~typing.Optional`` with ``~typing.Union`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1095 `__. + + +Miscellaneous internal changes +------------------------------ + +- Significantly improved performance of parsing the network location -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1112 `__. + +- Added internal types to the cache to prevent future refactoring errors -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1117 `__. + + +---- + + +1.9.11 +====== + +*(2024-09-04)* + + +Bug fixes +--------- + +- Fixed a ``TypeError`` with ``MultiDictProxy`` and Python 3.8 -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1084 `__, `#1105 `__, `#1107 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of encoding hosts -- by `@bdraco `__. + + Previously, the library would unconditionally try to parse a host as an IP Address. The library now avoids trying to parse a host as an IP Address if the string is not in one of the formats described in ``3986#section-3.2.2``. + + *Related issues and pull requests on GitHub:* + `#1104 `__. + + +---- + + +1.9.10 +====== + +*(2024-09-04)* + + +Bug fixes +--------- + +- ``URL.join()()`` has been changed to match + ``3986`` and align with + ``/ operation()`` and ``URL.joinpath()()`` + when joining URLs with empty segments. + Previously ``urllib.parse.urljoin`` was used, + which has known issues with empty segments + (`python/cpython#84774 `_). + + Due to the semantics of ``URL.join()()``, joining an + URL with scheme requires making it relative, prefixing with ``./``. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/").join(URL("./https://github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + Empty segments are honored in the base as well as the joined part. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/https://").join(URL("github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + + -- by `@commonism `__ + + This change initially appeared in 1.9.5 but was reverted in 1.9.6 to resolve a problem with query string handling. + + *Related issues and pull requests on GitHub:* + `#1039 `__, `#1082 `__. + + +Features +-------- + +- Added ``~yarl.URL.absolute`` which is now preferred over ``URL.is_absolute()`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1100 `__. + + +---- + + +1.9.9 +===== + +*(2024-09-04)* + + +Bug fixes +--------- + +- Added missing type on ``~yarl.URL.port`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1097 `__. + + +---- + + +1.9.8 +===== + +*(2024-09-03)* + + +Features +-------- + +- Covered the ``~yarl.URL`` object with types -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1084 `__. + +- Cache parsing of IP Addresses when encoding hosts -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1086 `__. + + +Contributor-facing changes +-------------------------- + +- Covered the ``~yarl.URL`` object with types -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1084 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of handling ports -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1081 `__. + + +---- + + +1.9.7 +===== + +*(2024-09-01)* + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Removed support ``3986#section-3.2.3`` port normalization when the scheme is not one of ``http``, ``https``, ``wss``, or ``ws`` -- by `@bdraco `__. + + Support for port normalization was recently added in `#1033 `__ and contained code that would do blocking I/O if the scheme was not one of the four listed above. The code has been removed because this library is intended to be safe for usage with ``asyncio``. + + *Related issues and pull requests on GitHub:* + `#1076 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of property caching -- by `@bdraco `__. + + The ``reify`` implementation from ``aiohttp`` was adapted to replace the internal ``cached_property`` implementation. + + *Related issues and pull requests on GitHub:* + `#1070 `__. + + +---- + + +1.9.6 +===== + +*(2024-08-30)* + + +Bug fixes +--------- + +- Reverted ``3986`` compatible ``URL.join()()`` honoring empty segments which was introduced in `#1039 `__. + + This change introduced a regression handling query string parameters with joined URLs. The change was reverted to maintain compatibility with the previous behavior. + + *Related issues and pull requests on GitHub:* + `#1067 `__. + + +---- + + +1.9.5 +===== + +*(2024-08-30)* + + +Bug fixes +--------- + +- Joining URLs with empty segments has been changed + to match ``3986``. + + Previously empty segments would be removed from path, + breaking use-cases such as + + .. code-block:: python + + URL("https://web.archive.org/web/") / "https://github.com/" + + Now ``/ operation()`` and ``URL.joinpath()()`` + keep empty segments, but do not introduce new empty segments. + e.g. + + .. code-block:: python + + URL("https://example.org/") / "" + + does not introduce an empty segment. + + -- by `@commonism `__ and `@youtux `__ + + *Related issues and pull requests on GitHub:* + `#1026 `__. + +- The default protocol ports of well-known URI schemes are now taken into account + during the normalization of the URL string representation in accordance with + ``3986#section-3.2.3``. + + Specified ports are removed from the ``str`` representation of a ``~yarl.URL`` + if the port matches the scheme's default port -- by `@commonism `__. + + *Related issues and pull requests on GitHub:* + `#1033 `__. + +- ``URL.join()()`` has been changed to match + ``3986`` and align with + ``/ operation()`` and ``URL.joinpath()()`` + when joining URLs with empty segments. + Previously ``urllib.parse.urljoin`` was used, + which has known issues with empty segments + (`python/cpython#84774 `_). + + Due to the semantics of ``URL.join()()``, joining an + URL with scheme requires making it relative, prefixing with ``./``. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/").join(URL("./https://github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + Empty segments are honored in the base as well as the joined part. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/https://").join(URL("github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + + -- by `@commonism `__ + + *Related issues and pull requests on GitHub:* + `#1039 `__. + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Stopped decoding ``%2F`` (``/``) in ``URL.path``, as this could lead to code incorrectly treating it as a path separator + -- by `@Dreamsorcerer `__. + + *Related issues and pull requests on GitHub:* + `#1057 `__. + +- Dropped support for Python 3.7 -- by `@Dreamsorcerer `__. + + *Related issues and pull requests on GitHub:* + `#1016 `__. + + +Improved documentation +---------------------- + +- On the ``Contributing docs`` page, + a link to the ``Towncrier philosophy`` has been fixed. + + *Related issues and pull requests on GitHub:* + `#981 `__. + +- The pre-existing ``/ magic method()`` + has been documented in the API reference -- by `@commonism `__. + + *Related issues and pull requests on GitHub:* + `#1026 `__. + + +Packaging updates and notes for downstreams +------------------------------------------- + +- A flaw in the logic for copying the project directory into a + temporary folder that led to infinite recursion when ``TMPDIR`` + was set to a project subdirectory path. This was happening in Fedora + and its downstream due to the use of `pyproject-rpm-macros + `__. It was + only reproducible with ``pip wheel`` and was not affecting the + ``pyproject-build`` users. + + -- by `@hroncok `__ and `@webknjaz `__ + + *Related issues and pull requests on GitHub:* + `#992 `__, `#1014 `__. + +- Support Python 3.13 and publish non-free-threaded wheels + + *Related issues and pull requests on GitHub:* + `#1054 `__. + + +Contributor-facing changes +-------------------------- + +- The CI/CD setup has been updated to test ``arm64`` wheels + under macOS 14, except for Python 3.7 that is unsupported + in that environment -- by `@webknjaz `__. + + *Related issues and pull requests on GitHub:* + `#1015 `__. + +- Removed unused type ignores and casts -- by `@hauntsaninja `__. + + *Related issues and pull requests on GitHub:* + `#1031 `__. + + +Miscellaneous internal changes +------------------------------ + +- ``port``, ``scheme``, and ``raw_host`` are now ``cached_property`` -- by `@bdraco `__. + + ``aiohttp`` accesses these properties quite often, which cause ``urllib`` to build the ``_hostinfo`` property every time. ``port``, ``scheme``, and ``raw_host`` are now cached properties, which will improve performance. + + *Related issues and pull requests on GitHub:* + `#1044 `__, `#1058 `__. + + +---- + + +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 `__. + + Previously the empty string as port would create malformed URLs when rendered as string representations. (`#883 `__) + + +Packaging updates and notes for downstreams +------------------------------------------- + +- The leading ``--`` has been dropped from the `PEP 517 `__ in-tree build + backend config setting names. ``--pure-python`` is now just ``pure-python`` + -- by `@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 `__) + + +Contributor-facing changes +-------------------------- + +- A step-by-step ``Release Guide`` guide has + been added, describing how to release *yarl* -- by `@webknjaz `__. + + This is primarily targeting maintainers. (`#960 `__) +- Coverage collection has been implemented for the Cython modules + -- by `@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: + + .. code-block:: console + + $ 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 `__ + +- It is now possible to request line tracing in Cython builds using the + ``with-cython-tracing`` `PEP 517 `__ config setting + -- `@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. + + The following produces C-files required for the Cython coverage + plugin to map the measurements back to the PYX-files: + + .. code-block:: console + + $ python -Im pip install -e . + + Alternatively, the ``YARL_CYTHON_TRACING=1`` environment variable + can be set to do the same as the `PEP 517 `__ config setting. + + `#962 `__ + + +1.9.3 (2023-11-20) +================== + +Bug fixes +--------- + +- Stopped dropping trailing slashes in ``yarl.URL.joinpath()`` -- by `@gmacon `__. (`#862 `__, `#866 `__) +- Started accepting string subclasses in ``yarl.URL.__truediv__()`` operations (``URL / segment``) -- by `@mjpieters `__. (`#871 `__, `#884 `__) +- Fixed the human representation of URLs with square brackets in usernames and passwords -- by `@mjpieters `__. (`#876 `__, `#882 `__) +- Updated type hints to include ``URL.missing_port()``, ``URL.__bytes__()`` + and the ``encoding`` argument to ``yarl.URL.joinpath()`` + -- by `@mjpieters `__. (`#891 `__) + + +Packaging updates and notes for downstreams +------------------------------------------- + +- Integrated Cython 3 to enable building *yarl* under Python 3.12 -- by `@mjpieters `__. (`#829 `__, `#881 `__) +- Declared modern ``setuptools.build_meta`` as the `PEP 517 `__ build + backend in ``pyproject.toml`` explicitly -- by `@webknjaz `__. (`#886 `__) +- Converted most of the packaging setup into a declarative ``setup.cfg`` + config -- by `@webknjaz `__. (`#890 `__) +- The packaging is replaced from an old-fashioned ``setup.py`` to an + in-tree `PEP 517 `__ build backend -- by `@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`` + flag ``--pure-python``. If this flag is not set, a C-extension will be built + and included into the distribution. + + Here is how this can be done with ``pip``: + + .. code-block:: console + + $ python -m pip install . --config-settings=--pure-python=false + + This will also work with ``-e | --editable``. + + The same can be achieved via ``pypa/build``: + + .. code-block:: console + + $ 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 `__) + + .. 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 `__. (`#942 `__) + + +Contributor-facing changes +-------------------------- + +- A regression test for no-host URLs was added per `#821 `__ + and ``3986`` -- by `@kenballus `__. (`#821 `__, `#822 `__) +- Started testing *yarl* against Python 3.12 in CI -- by `@mjpieters `__. (`#881 `__) +- All Python 3.12 jobs are now marked as required to pass in CI + -- by `@edgarrmondragon `__. (`#942 `__) +- MyST is now integrated in Sphinx -- by `@webknjaz `__. + + This allows the contributors to author new documents in Markdown + when they have difficulties with going straight RST. (`#953 `__) + + +1.9.2 (2023-04-25) +================== + +Bugfixes +-------- + +- Fix regression with ``yarl.URL.__truediv__()`` and absolute URLs with empty paths causing the raw path to lack the leading ``/``. + (`#854 `_) + + +1.9.1 (2023-04-21) +================== + +Bugfixes +-------- + +- Marked tests that fail on older Python patch releases (< 3.7.10, < 3.8.8 and < 3.9.2) as expected to fail due to missing a security fix for CVE-2021-23336. (`#850 `_) + + +1.9.0 (2023-04-19) +================== + +This release was never published to PyPI, due to issues with the build process. + +Features +-------- + +- Added ``URL.joinpath(*elements)``, to create a new URL appending multiple path elements. (`#704 `_) +- Made ``URL.__truediv__()()`` return ``NotImplemented`` if called with an + unsupported type — by `@michaeljpeters `__. + (`#832 `_) + + +Bugfixes +-------- + +- Path normalization for absolute URLs no longer raises a ValueError exception + when ``..`` segments would otherwise go beyond the URL path root. + (`#536 `_) +- Fixed an issue with update_query() not getting rid of the query when argument is None. (`#792 `_) +- Added some input restrictions on with_port() function to prevent invalid boolean inputs or out of valid port inputs; handled incorrect 0 port representation. (`#793 `_) +- Made ``yarl.URL.build()`` raise a ``TypeError`` if the ``host`` argument is ``None`` — by `@paulpapacz `__. (`#808 `_) +- Fixed an issue with ``update_query()`` getting rid of the query when the argument + is empty but not ``None``. (`#845 `_) + + +Misc +---- + +- `#220 `_ + + 1.8.2 (2022-12-03) ================== @@ -267,8 +1104,9 @@ Features Improved Documentation ---------------------- -- Fixed broken internal references to ``(?P=rendered_text)``. (`#665 `_) -- Fixed broken external references to ``(?P=rendered_text)`` docs. (`#665 `_) +- Fixed broken internal references to ``yarl.URL.human_repr()``. + (`#665 `_) +- Fixed broken external references to ``multidict:index`` docs. (`#665 `_) Deprecations and Removals @@ -306,7 +1144,8 @@ Bugfixes Features -------- -- Add `__bytes__()` magic method so that `bytes(url)` will work and use optimal ASCII encoding. (`#582 `_) +- Add ``__bytes__()`` magic method so that ``bytes(url)`` will work and use optimal ASCII encoding. + (`#582 `_) - Started shipping platform-specific arm64 wheels for Apple Silicon. (`#622 `_) - Started shipping platform-specific wheels with the ``musl`` tag targeting typical Alpine Linux runtimes. (`#622 `_) - Added support for Python 3.10. (`#622 `_) @@ -421,7 +1260,7 @@ Features - Convert host to lowercase on URL building. `#386 `_ -- Allow using ``mod`` operator (`%`) for updating query string (an alias for ``update_query()`` method). +- Allow using ``mod`` operator (``%``) for updating query string (an alias for ``update_query()`` method). `#435 `_ - Allow use of sequences such as ``list`` and ``tuple`` in the values of a mapping such as ``dict`` to represent that a key has many values:: @@ -430,7 +1269,7 @@ Features assert url.with_query({"a": [1, 2]}) == URL("http://example.com/?a=1&a=2") `#443 `_ -- Support URL.build() with scheme and path (creates a relative URL). +- Support ``URL.build()`` with scheme and path (creates a relative URL). `#464 `_ - Cache slow IDNA encode/decode calls. `#476 `_ @@ -449,9 +1288,9 @@ Bugfixes `#409 `_ - Fix a bug where query component, passed in a form of mapping or sequence, is unquoted in unexpected way. `#426 `_ -- Hide `Query` and `QueryVariable` type aliases in `__init__.pyi`, now they are prefixed with underscore. +- Hide ``Query`` and ``QueryVariable`` type aliases in ``__init__.pyi``, now they are prefixed with underscore. `#431 `_ -- Keep ipv6 brackets after updating port/user/password. +- Keep IPv6 brackets after updating port/user/password. `#451 `_ @@ -464,7 +1303,7 @@ Bugfixes Features -------- -- Workaround for missing `str.isascii()` in Python 3.6 +- Workaround for missing ``str.isascii()`` in Python 3.6 `#389 `_ @@ -495,7 +1334,7 @@ Features * Don't create a new URL if fragment is unchanged (#292) -* Included in error msg the path that produces starting slash forbidden error (#376) +* Included in error message the path that produces starting slash forbidden error (#376) * Skip slow IDNA encoding for ASCII-only strings (#387) @@ -554,7 +1393,7 @@ Features 1.1.1 (2018-02-17) ================== -* Fix performance regression: don't encode empty netloc (#170) +* Fix performance regression: don't encode empty ``netloc`` (#170) 1.1.0 (2018-01-21) ================== @@ -616,16 +1455,16 @@ Features * Drop strict mode (#123) -* Fix ``"ValueError: Unallowed PCT %"`` when there's a ``"%"`` in the url (#124) +* Fix ``"ValueError: Unallowed PCT %"`` when there's a ``"%"`` in the URL (#124) 0.13.0 (2017-10-01) =================== * Document ``encoded`` parameter (#102) -* Support relative urls like ``'?key=value'`` (#100) +* Support relative URLs like ``'?key=value'`` (#100) -* Unsafe encoding for QS fixed. Encode ``;`` char in value param (#104) +* Unsafe encoding for QS fixed. Encode ``;`` character in value parameter (#104) * Process passwords without user names (#95) @@ -646,18 +1485,18 @@ Features 0.10.3 (2017-06-13) =================== -* Prevent double URL args unquoting (#83) +* Prevent double URL arguments unquoting (#83) 0.10.2 (2017-05-05) =================== -* Unexpected hash behaviour (#75) +* Unexpected hash behavior (#75) 0.10.1 (2017-05-03) =================== -* Unexpected compare behaviour (#73) +* Unexpected compare behavior (#73) * Do not quote or unquote + if not a query string. (#74) @@ -729,7 +1568,7 @@ Features * Fix core dumps (#41) -* tmpbuf - compiling error (#43) +* ``tmpbuf`` - compiling error (#43) * Added ``URL.update_path()`` method @@ -765,13 +1604,13 @@ Features 0.6.0 (2016-11-07) ================== -* Explicitly use UTF8 encoding in setup.py (#20) +* Explicitly use UTF8 encoding in ``setup.py`` (#20) * Properly unquote non-UTF8 strings (#19) 0.5.3 (2016-11-02) ================== -* Don't use namedtuple fields but indexes on URL construction +* Don't use ``typing.NamedTuple`` fields but indexes on URL construction 0.5.2 (2016-11-02) ================== @@ -786,7 +1625,7 @@ Features 0.5.0 (2016-11-02) ================== -* Add cython optimization for quoting/unquoting +* Add Cython optimization for quoting/unquoting * Provide binary wheels 0.4.3 (2016-09-29) @@ -839,7 +1678,7 @@ Features 0.1.4 (2016-09-09) ================== -* Add kwargs support for ``with_query()`` (#10) +* Add ``kwargs`` support for ``with_query()`` (#10) 0.1.3 (2016-09-07) ================== diff --git a/README.rst b/README.rst index 6347ece..fe9c856 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,8 @@ yarl ==== +The module provides handy URL class for URL parsing and changing. + .. image:: https://github.com/aio-libs/yarl/workflows/CI/badge.svg :target: https://github.com/aio-libs/yarl/actions?query=workflow%3ACI :align: right @@ -13,15 +15,19 @@ yarl .. image:: https://readthedocs.org/projects/yarl/badge/?version=latest - :target: https://yarl.readthedocs.io + :target: https://yarl.aio-libs.org .. image:: https://img.shields.io/pypi/pyversions/yarl.svg :target: https://pypi.python.org/pypi/yarl -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter +.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs:matrix.org + :alt: Matrix Room — #aio-libs:matrix.org + +.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs-space:matrix.org + :alt: Matrix Space — #aio-libs-space:matrix.org Introduction ------------ @@ -68,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: @@ -78,19 +84,19 @@ 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.readthedocs.org. +For full documentation please read https://yarl.aio-libs.org. Installation @@ -108,12 +114,13 @@ manylinux-compliant because of the missing glibc and therefore, cannot be 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 setting the `YARL_NO_EXTENSIONS` +To skip the compilation you must explicitly opt-in by using a PEP 517 +configuration setting ``pure-python``, or setting the ``YARL_NO_EXTENSIONS`` environment variable to a non-empty value, e.g.: -.. code-block:: bash +.. code-block:: console - $ YARL_NO_EXTENSIONS=1 pip install yarl + $ 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 @@ -128,7 +135,7 @@ YARL requires multidict_ library. API documentation ------------------ -The documentation is located at https://yarl.readthedocs.org +The documentation is located at https://yarl.aio-libs.org. Why isn't boolean supported by the URL query API? @@ -178,9 +185,6 @@ Please file an issue on the `bug tracker `_ if you have found a bug or have some suggestion in order to improve the library. -The library uses `Azure Pipelines `_ for -Continuous Integration. - Discussion list --------------- diff --git a/debian/changelog b/debian/changelog index 6495641..bf0253c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,29 @@ -yarl (1.8.2-3deepin1) unstable; urgency=medium +yarl (1.13.1-1) unstable; urgency=medium - * No source change upload against python 3.12. + * New upstream release + + -- Piotr Ożarowski Tue, 01 Oct 2024 16:10:29 +0200 + +yarl (1.13.0-1) unstable; urgency=medium + + * New upstream release + + -- Piotr Ożarowski Fri, 27 Sep 2024 15:40:07 +0200 - -- Tianyu Chen Mon, 08 Jul 2024 09:58:39 +0200 +yarl (1.9.4-1) unstable; urgency=medium + + * New upstream release + * Drop no longer needed patches + * Add pybuild-plugin-pyproject to Build-Depends (setup.py replaced with + pyproject.toml) + * Add python3-pytest-xdist to Build-Depends (used during tests) + * Drop towncrier changelog generation as sphinxcontrib.towncrier.ext is not + packaged yet + * Add python3-myst-parser and python3-alabaster to Build-Depends + (used while building docs) + * Add 0006-use-os.path.expandvars-instead-of-external-one patch + + -- Piotr Ożarowski Thu, 18 Apr 2024 10:56:28 +0200 yarl (1.8.2-3) unstable; urgency=medium diff --git a/debian/control b/debian/control index fe40359..62488cf 100644 --- a/debian/control +++ b/debian/control @@ -4,15 +4,21 @@ Priority: optional Maintainer: Piotr Ożarowski Uploaders: Debian Python Team Build-Depends: debhelper-compat (= 13), dh-python, + pybuild-plugin-pyproject, cython3, python3-all-dev, python3-setuptools, - python3-sphinx, python3-idna, python3-multidict, +# used to build documentation + python3-sphinx, + python3-myst-parser, + python3-alabaster, +# used during tests: python3-pytest , python3-pytest-runner , python3-pytest-cov , + python3-pytest-xdist , Standards-Version: 4.6.1 Homepage: https://github.com/aio-libs/yarl/ Vcs-Git: https://salsa.debian.org/python-team/packages/yarl.git diff --git a/debian/patches/0001-do-not-add-changelog-to-long-description.patch b/debian/patches/0001-do-not-add-changelog-to-long-description.patch deleted file mode 100644 index e295ea5..0000000 --- a/debian/patches/0001-do-not-add-changelog-to-long-description.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: =?utf-8?q?Piotr_O=C5=BCarowski?= -Date: Sun, 6 Nov 2016 22:11:09 +0100 -Subject: do not add changelog to long description - -it contains non-ascii characters (and thus FTBFS) and we install it via -separate file anyway ---- - setup.py | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/setup.py b/setup.py -index 5434635..d361108 100644 ---- a/setup.py -+++ b/setup.py -@@ -51,10 +51,10 @@ args = dict( - name="yarl", - version=version, - description=("Yet another URL library"), -- long_description="\n\n".join( -- [read("README.rst"), sanitize_rst_roles(read("CHANGES.rst"))] -- ), -- long_description_content_type="text/x-rst", -+ # long_description="\n\n".join( -+ # [read("README.rst"), sanitize_rst_roles(read("CHANGES.rst"))] -+ # ), -+ # long_description_content_type="text/x-rst", - classifiers=[ - "License :: OSI Approved :: Apache Software License", - "Intended Audience :: Developers", diff --git a/debian/patches/0002-docs-disable-intersphinx.patch b/debian/patches/0002-docs-disable-intersphinx.patch index f386b54..0121c9c 100644 --- a/debian/patches/0002-docs-disable-intersphinx.patch +++ b/debian/patches/0002-docs-disable-intersphinx.patch @@ -7,13 +7,13 @@ Subject: docs: disable intersphinx 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py -index 64d98e2..d7154ce 100644 +index 2b223d4..5016552 100644 --- a/docs/conf.py +++ b/docs/conf.py -@@ -51,7 +51,7 @@ with _version_path.open() as fp: - # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom - # ones. +@@ -63,7 +63,7 @@ with _version_path.open() as fp: extensions = [ + # stdlib-party extensions: + "sphinx.ext.extlinks", - "sphinx.ext.intersphinx", + # "sphinx.ext.intersphinx", "sphinx.ext.coverage", diff --git a/debian/patches/0003-docs-disable-sidebar_collapse-option.patch b/debian/patches/0003-docs-disable-sidebar_collapse-option.patch index 67135bf..ddc26e3 100644 --- a/debian/patches/0003-docs-disable-sidebar_collapse-option.patch +++ b/debian/patches/0003-docs-disable-sidebar_collapse-option.patch @@ -8,10 +8,10 @@ theme packaged in Debian doesn't have this option 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py -index d7154ce..86a3961 100644 +index 5016552..e969da2 100644 --- a/docs/conf.py +++ b/docs/conf.py -@@ -177,7 +177,7 @@ html_theme_options = { +@@ -214,7 +214,7 @@ html_theme_options = { "body_text": "#482C0A", "sidebar_text": "#49443E", "sidebar_header": "#4B4032", diff --git a/debian/patches/0004-disable-privacy-breach-links-in-documentation.patch b/debian/patches/0004-disable-privacy-breach-links-in-documentation.patch index 2ea279a..ac9606b 100644 --- a/debian/patches/0004-disable-privacy-breach-links-in-documentation.patch +++ b/debian/patches/0004-disable-privacy-breach-links-in-documentation.patch @@ -7,10 +7,10 @@ Subject: disable privacy breach links in documentation 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py -index 86a3961..dc23b53 100644 +index e969da2..0b00fc1 100644 --- a/docs/conf.py +++ b/docs/conf.py -@@ -165,12 +165,12 @@ html_theme = "alabaster" +@@ -202,12 +202,12 @@ html_theme = "alabaster" html_theme_options = { "logo": "yarl-icon-128x128.png", "description": "Yet another URL library", diff --git a/debian/patches/0005-drop-towncrier-changelog-generation-for-now.patch b/debian/patches/0005-drop-towncrier-changelog-generation-for-now.patch new file mode 100644 index 0000000..3bd1f13 --- /dev/null +++ b/debian/patches/0005-drop-towncrier-changelog-generation-for-now.patch @@ -0,0 +1,22 @@ +From: =?utf-8?q?Piotr_O=C5=BCarowski?= +Date: Thu, 18 Apr 2024 11:46:04 +0200 +Subject: drop towncrier changelog generation for now + +sphinxcontrib.towncrier.ext is not yet packaged in Debian +--- + docs/conf.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/conf.py b/docs/conf.py +index 0b00fc1..af7fad7 100644 +--- a/docs/conf.py ++++ b/docs/conf.py +@@ -69,7 +69,7 @@ extensions = [ + "sphinx.ext.viewcode", + # Third-party extensions: + "alabaster", +- "sphinxcontrib.towncrier.ext", # provides `towncrier-draft-entries` directive ++ #"sphinxcontrib.towncrier.ext", # provides `towncrier-draft-entries` directive + "myst_parser", # extended markdown; https://pypi.org/project/myst-parser/ + ] + diff --git a/debian/patches/0005-python3.11-test-fix.patch b/debian/patches/0005-python3.11-test-fix.patch deleted file mode 100644 index b9046a4..0000000 --- a/debian/patches/0005-python3.11-test-fix.patch +++ /dev/null @@ -1,24 +0,0 @@ -From ca968581e8dcc074b56c50693f0890082d230d4c Mon Sep 17 00:00:00 2001 -From: Sam Bull -Date: Mon, 9 Jan 2023 23:10:14 +0000 -Subject: [PATCH] Fix 3.11 tests (#810) - ---- - tests/test_url_parsing.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/tests/test_url_parsing.py b/tests/test_url_parsing.py -index 0a7f5f1d..0f0dd7ee 100644 ---- a/tests/test_url_parsing.py -+++ b/tests/test_url_parsing.py -@@ -73,8 +73,8 @@ def test_not_a_scheme1(self): - assert u.fragment == "" - - def test_not_a_scheme2(self): -- u = URL("37signals:book") -- assert u.scheme == "37signals" -+ u = URL("signals37:book") -+ assert u.scheme == "signals37" - assert u.host is None - assert u.path == "book" - assert u.query_string == "" diff --git a/debian/patches/0006-use-os.path.expandvars-instead-of-external-one.patch b/debian/patches/0006-use-os.path.expandvars-instead-of-external-one.patch new file mode 100644 index 0000000..511b426 --- /dev/null +++ b/debian/patches/0006-use-os.path.expandvars-instead-of-external-one.patch @@ -0,0 +1,35 @@ +From: =?utf-8?q?Piotr_O=C5=BCarowski?= +Date: Thu, 18 Apr 2024 12:04:06 +0200 +Subject: use os.path.expandvars instead of external one + +--- + packaging/pep517_backend/_cython_configuration.py | 2 +- + pyproject.toml | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/packaging/pep517_backend/_cython_configuration.py b/packaging/pep517_backend/_cython_configuration.py +index 316b85f..704ff1e 100644 +--- a/packaging/pep517_backend/_cython_configuration.py ++++ b/packaging/pep517_backend/_cython_configuration.py +@@ -7,7 +7,7 @@ from contextlib import contextmanager + from pathlib import Path + from sys import version_info as _python_version_tuple + +-from expandvars import expandvars ++from os.path import expandvars + + from ._compat import load_toml_from_string # noqa: WPS436 + from ._transformers import ( # noqa: WPS436 +diff --git a/pyproject.toml b/pyproject.toml +index 9d5f3d9..4dbf861 100644 +--- a/pyproject.toml ++++ b/pyproject.toml +@@ -3,7 +3,7 @@ requires = [ + # NOTE: The following build dependencies are necessary for initial + # NOTE: provisioning of the in-tree build backend located under + # NOTE: `packaging/pep517_backend/`. +- "expandvars", ++ #"expandvars", + "setuptools >= 47", # Minimum required for `version = attr:` + "tomli; python_version < '3.11'", + ] diff --git a/debian/patches/series b/debian/patches/series index 01cc0f4..842803b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,6 +1,6 @@ square_bracket_handling.patch -0001-do-not-add-changelog-to-long-description.patch 0002-docs-disable-intersphinx.patch 0003-docs-disable-sidebar_collapse-option.patch 0004-disable-privacy-breach-links-in-documentation.patch -0005-python3.11-test-fix.patch +0005-drop-towncrier-changelog-generation-for-now.patch +0006-use-os.path.expandvars-instead-of-external-one.patch diff --git a/debian/patches/square_bracket_handling.patch b/debian/patches/square_bracket_handling.patch index b6bb563..e1d19b5 100644 --- a/debian/patches/square_bracket_handling.patch +++ b/debian/patches/square_bracket_handling.patch @@ -1,4 +1,3 @@ -From 5c977b52a33bf58f016e5968934c3fcb8b49b239 Mon Sep 17 00:00:00 2001 From: Martijn Pieters Date: Tue, 6 Jun 2023 17:38:47 +0100 Subject: [PATCH] Correct square bracket handling in URL netloc @@ -15,111 +14,14 @@ Subject: [PATCH] Correct square bracket handling in URL netloc as long as urllib.parse.urlsplit() accepts them but this is not something that yarl.URL() needs to support explicitly. --- - CHANGES/876.bugfix.rst | 1 + - tests/test_url.py | 10 ++-------- - tests/test_url_parsing.py | 28 ++-------------------------- - yarl/_url.py | 4 ++-- - 4 files changed, 7 insertions(+), 36 deletions(-) + CHANGES/876.bugfix.rst | 1 + + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/876.bugfix.rst +diff --git a/CHANGES/876.bugfix.rst b/CHANGES/876.bugfix.rst +new file mode 100644 +index 0000000..ef62c7e --- /dev/null -+++ yarl/CHANGES/876.bugfix.rst ++++ b/CHANGES/876.bugfix.rst @@ -0,0 +1 @@ +Fixed the human representation of URLs with square brackets in usernames and passwords. ---- yarl.orig/tests/test_url.py -+++ yarl/tests/test_url.py -@@ -235,12 +235,6 @@ - assert url.host == url.raw_host - - --def test_ipv6_zone(): -- url = URL("http://[fe80::822a:a8ff:fe49:470c%тест%42]:123") -- assert url.raw_host == "fe80::822a:a8ff:fe49:470c%тест%42" -- assert url.host == url.raw_host -- -- - def test_ipv4_zone(): - # I'm unsure if it is correct. - url = URL("http://1.2.3.4%тест%42:123") -@@ -1514,8 +1508,8 @@ - s = url.human_repr() - assert URL(s) == url - assert ( -- s == "http:// !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~" -- ": !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~" -+ s == "http:// !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40%5B\\%5D^_`{|}~" -+ ": !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40%5B\\%5D^_`{|}~" - "@хост.домен:8080" - "/ !\"%23$%25&'()*+,-./:;<=>%3F@[\\]^_`{|}~" - "? !\"%23$%25%26'()*%2B,-./:%3B<%3D>?@[\\]^_`{|}~" ---- yarl.orig/tests/test_url_parsing.py -+++ yarl/tests/test_url_parsing.py -@@ -178,14 +178,6 @@ - assert u.query_string == "" - assert u.fragment == "" - -- def test_masked_ipv4(self): -- u = URL("//[127.0.0.1]/") -- assert u.scheme == "" -- assert u.host == "127.0.0.1" -- assert u.path == "/" -- assert u.query_string == "" -- assert u.fragment == "" -- - def test_ipv6(self): - u = URL("//[::1]/") - assert u.scheme == "" -@@ -194,15 +186,7 @@ - assert u.query_string == "" - assert u.fragment == "" - -- def test_strange_ip(self): -- u = URL("//[-1]/") -- assert u.scheme == "" -- assert u.host == "-1" -- assert u.path == "/" -- assert u.query_string == "" -- assert u.fragment == "" -- -- def test_strange_ip_2(self): -+ def test_ipvfuture_address(self): - u = URL("//[v1.-1]/") - assert u.scheme == "" - assert u.host == "v1.-1" -@@ -210,14 +194,6 @@ - assert u.query_string == "" - assert u.fragment == "" - -- def test_strange_ip_3(self): -- u = URL("//v1.[::1]/") -- assert u.scheme == "" -- assert u.host == "::1" -- assert u.path == "/" -- assert u.query_string == "" -- assert u.fragment == "" -- - - class TestPort: - def test_canonical(self): -@@ -320,7 +296,7 @@ - assert u.fragment == "" - - def test_weird_user3(self): -- u = URL("//[some]@host") -+ u = URL("//%5Bsome%5D@host") - assert u.scheme == "" - assert u.user == "[some]" - assert u.password is None ---- yarl.orig/yarl/_url.py -+++ yarl/yarl/_url.py -@@ -1079,8 +1079,8 @@ - - def human_repr(self): - """Return decoded human readable string for URL representation.""" -- user = _human_quote(self.user, "#/:?@") -- password = _human_quote(self.password, "#/:?@") -+ user = _human_quote(self.user, "#/:?@[]") -+ password = _human_quote(self.password, "#/:?@[]") - host = self.host - if host: - host = self._encode_host(self.host, human=True) diff --git a/docs/api.rst b/docs/api.rst index b850e0c..b7b80cf 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -54,8 +54,8 @@ But for *non-ascii* case *encoding* is applied. .. doctest:: - >>> str(URL('http://εμπορικόσήμα.eu/путь/這裡')) - 'http://xn--jxagkqfkduily1i.eu/%D0%BF%D1%83%D1%82%D1%8C/%E9%80%99%E8%A3%A1' + >>> str(URL('http://εμπορικόσήμα.eu/шлях/這裡')) + 'http://xn--jxagkqfkduily1i.eu/%D1%88%D0%BB%D1%8F%D1%85/%E9%80%99%E8%A3%A1' The same is true for *user*, *password*, *query* and *fragment* parts of URL. @@ -70,11 +70,11 @@ Use :meth:`~URL.human_repr` for getting human readable representation: .. doctest:: - >>> url = URL('http://εμπορικόσήμα.eu/путь/這裡') + >>> url = URL('http://εμπορικόσήμα.eu/шлях/這裡') >>> str(url) - 'http://xn--jxagkqfkduily1i.eu/%D0%BF%D1%83%D1%82%D1%8C/%E9%80%99%E8%A3%A1' + 'http://xn--jxagkqfkduily1i.eu/%D1%88%D0%BB%D1%8F%D1%85/%E9%80%99%E8%A3%A1' >>> url.human_repr() - 'http://εμπορικόσήμα.eu/путь/這裡' + 'http://εμπορικόσήμα.eu/шлях/這裡' .. note:: @@ -120,8 +120,8 @@ There are two kinds of properties: *decoded* and *encoded* (with >>> URL('http://john@example.com').user 'john' - >>> URL('http://андрей@example.com').user - 'андрей' + >>> URL('http://бажан@example.com').user + 'бажан' >>> URL('http://example.com').user is None True @@ -133,8 +133,8 @@ There are two kinds of properties: *decoded* and *encoded* (with .. doctest:: - >>> URL('http://андрей@example.com').raw_user - '%D0%B0%D0%BD%D0%B4%D1%80%D0%B5%D0%B9' + >>> URL('http://довбуш@example.com').raw_user + '%D0%B4%D0%BE%D0%B2%D0%B1%D1%83%D1%88' >>> URL('http://example.com').raw_user is None True @@ -147,7 +147,7 @@ There are two kinds of properties: *decoded* and *encoded* (with >>> URL('http://john:pass@example.com').password 'pass' - >>> URL('http://андрей:пароль@example.com').password + >>> URL('http://степан:пароль@example.com').password 'пароль' >>> URL('http://example.com').password is None True @@ -191,7 +191,22 @@ There are two kinds of properties: *decoded* and *encoded* (with >>> URL('http://хост.домен').raw_host 'xn--n1agdj.xn--d1acufc' + >>> URL('http://[::1]').raw_host + '::1' + +.. attribute:: URL.host_subcomponent + + :rfc:`3986#section-3.2.2` host subcomponent part of URL, ``None`` for relative URLs + (:ref:`yarl-api-relative-urls`). + + .. doctest:: + + >>> URL('http://хост.домен').host_subcomponent + 'xn--n1agdj.xn--d1acufc' + >>> URL('http://[::1]').host_subcomponent + '[::1]' + .. versionadded:: 1.13 .. attribute:: URL.port @@ -265,11 +280,30 @@ There are two kinds of properties: *decoded* and *encoded* (with >>> URL('http://example.com/path/to').path '/path/to' - >>> URL('http://example.com/путь/сюда').path - '/путь/сюда' + >>> URL('http://example.com/шлях/сюди').path + '/шлях/сюди' >>> URL('http://example.com').path '/' + .. warning:: + + In many situations it is important to distinguish between path separators + (a literal ``/``) and other forward slashes (a literal ``%2F``). Use + :attr:`URL.path_safe` for these cases. + +.. attribute:: URL.path_safe + + Similar to :attr:`URL.path` except it doesn't decode ``%2F`` or ``%25``. + This allows to distinguish between path separators (``/``) and encoded + slashes (``%2F``). + + Note that ``%25`` is also not decoded to avoid issues with double unquoting + of values. e.g. You can unquote the value with + ``URL.path_safe.replace("%2F", "/").replace("%25", %")`` to get the same + result as :meth:`URL.path`. If the ``%25`` was unquoted, it would be + impossible to tell the difference between ``%2F`` and ``%252F``. + + .. versionadded:: 1.12 .. attribute:: URL.path_qs @@ -287,8 +321,8 @@ There are two kinds of properties: *decoded* and *encoded* (with .. doctest:: - >>> URL('http://example.com/путь/сюда?ключ=знач').raw_path_qs - '/%D0%BF%D1%83%D1%82%D1%8C/%D1%81%D1%8E%D0%B4%D0%B0?%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87' + >>> URL('http://example.com/шлях/сюди?ключ=знач').raw_path_qs + '/%D1%88%D0%BB%D1%8F%D1%85/%D1%81%D1%8E%D0%B4%D0%B8?%D0%BA%D0%BB%D1%8E%D1%87=%D0%B7%D0%BD%D0%B0%D1%87' .. versionadded:: 0.15 @@ -298,8 +332,8 @@ There are two kinds of properties: *decoded* and *encoded* (with .. doctest:: - >>> URL('http://example.com/путь/сюда').raw_path - '/%D0%BF%D1%83%D1%82%D1%8C/%D1%81%D1%8E%D0%B4%D0%B0' + >>> URL('http://example.com/шлях/сюди').raw_path + '/%D1%88%D0%BB%D1%8F%D1%85/%D1%81%D1%8E%D0%B4%D0%B8' .. attribute:: URL.query_string @@ -333,8 +367,8 @@ There are two kinds of properties: *decoded* and *encoded* (with >>> URL('http://example.com/path#fragment').fragment 'fragment' - >>> URL('http://example.com/path#якорь').fragment - 'якорь' + >>> URL('http://example.com/path#якір').fragment + 'якір' >>> URL('http://example.com/path').fragment '' @@ -344,8 +378,8 @@ There are two kinds of properties: *decoded* and *encoded* (with .. doctest:: - >>> URL('http://example.com/path#якорь').raw_fragment - '%D1%8F%D0%BA%D0%BE%D1%80%D1%8C' + >>> URL('http://example.com/path#якір').raw_fragment + '%D1%8F%D0%BA%D1%96%D1%80' @@ -361,8 +395,8 @@ For *path* and *query* *yarl* supports additional helpers: >>> URL('http://example.com/path/to').parts ('/', 'path', 'to') - >>> URL('http://example.com/путь/сюда').parts - ('/', 'путь', 'сюда') + >>> URL('http://example.com/шлях/сюди').parts + ('/', 'шлях', 'сюди') >>> URL('http://example.com').parts ('/',) @@ -373,8 +407,8 @@ For *path* and *query* *yarl* supports additional helpers: .. doctest:: - >>> URL('http://example.com/путь/сюда').raw_parts - ('/', '%D0%BF%D1%83%D1%82%D1%8C', '%D1%81%D1%8E%D0%B4%D0%B0') + >>> URL('http://example.com/шлях/сюди').raw_parts + ('/', '%D1%88%D0%BB%D1%8F%D1%85', '%D1%81%D1%8E%D0%B4%D0%B8') .. attribute:: URL.name @@ -384,8 +418,8 @@ For *path* and *query* *yarl* supports additional helpers: >>> URL('http://example.com/path/to').name 'to' - >>> URL('http://example.com/путь/сюда').name - 'сюда' + >>> URL('http://example.com/шлях/сюди').name + 'сюди' >>> URL('http://example.com/path/').name '' @@ -395,8 +429,8 @@ For *path* and *query* *yarl* supports additional helpers: .. doctest:: - >>> URL('http://example.com/путь/сюда').raw_name - '%D1%81%D1%8E%D0%B4%D0%B0' + >>> URL('http://example.com/шлях/сюди').raw_name + '%D1%81%D1%8E%D0%B4%D0%B8' .. attribute:: URL.suffix @@ -406,8 +440,8 @@ For *path* and *query* *yarl* supports additional helpers: >>> URL('http://example.com/path/to.txt').suffix '.txt' - >>> URL('http://example.com/путь.сюда').suffix - '.сюда' + >>> URL('http://example.com/шлях.сюди').suffix + '.сюди' >>> URL('http://example.com/path').suffix '' @@ -417,8 +451,8 @@ For *path* and *query* *yarl* supports additional helpers: .. doctest:: - >>> URL('http://example.com/путь.сюда').raw_suffix - '.%D1%81%D1%8E%D0%B4%D0%B0' + >>> URL('http://example.com/шлях.сюди').raw_suffix + '.%D1%81%D1%8E%D0%B4%D0%B8' .. attribute:: URL.suffixes @@ -428,8 +462,8 @@ For *path* and *query* *yarl* supports additional helpers: >>> URL('http://example.com/path/to.tar.gz').suffixes ('.tar', '.gz') - >>> URL('http://example.com/путь.тут.да').suffixes - ('.тут', '.да') + >>> URL('http://example.com/шлях.тут.ось').suffixes + ('.тут', '.ось') >>> URL('http://example.com/path').suffixes () @@ -439,8 +473,8 @@ For *path* and *query* *yarl* supports additional helpers: .. doctest:: - >>> URL('http://example.com/путь.тут.да').raw_suffixes - ('.%D1%82%D1%83%D1%82', '.%D0%B4%D0%B0') + >>> URL('http://example.com/шлях.тут.ось').raw_suffixes + ('.%D1%82%D1%83%D1%82', '.%D0%BE%D1%81%D1%8C') .. attribute:: URL.query @@ -470,7 +504,7 @@ The module supports both absolute and relative URLs. Absolute URL should start from either *scheme* or ``'//'``. -.. method:: URL.is_absolute() +.. attribute:: URL.absolute A check for absolute URLs. @@ -479,15 +513,19 @@ Absolute URL should start from either *scheme* or ``'//'``. .. doctest:: - >>> URL('http://example.com').is_absolute() + >>> URL('http://example.com').absolute True - >>> URL('//example.com').is_absolute() + >>> URL('//example.com').absolute True - >>> URL('/path/to').is_absolute() + >>> URL('/path/to').absolute False - >>> URL('path').is_absolute() + >>> URL('path').absolute False + .. versionchanged:: 1.9.10 + + The :attr:`~yarl.URL.absolute` property is preferred over the ``is_absolute()`` method. + New URL generation ------------------ @@ -533,6 +571,9 @@ section generates a new :class:`URL` instance. >>> URL('http://example.com').with_scheme('https') URL('https://example.com') + Returned URL may have a *different* ``port`` + (:ref:`default port substitution `). + .. method:: URL.with_user(user) Return a new URL with *user* replaced, auto-encode *user* if needed. @@ -543,8 +584,8 @@ section generates a new :class:`URL` instance. >>> URL('http://user:pass@example.com').with_user('new_user') URL('http://new_user:pass@example.com') - >>> URL('http://user:pass@example.com').with_user('вася') - URL('http://%D0%B2%D0%B0%D1%81%D1%8F:pass@example.com') + >>> URL('http://user:pass@example.com').with_user('олекса') + URL('http://%D0%BE%D0%BB%D0%B5%D0%BA%D1%81%D0%B0:pass@example.com') >>> URL('http://user:pass@example.com').with_user(None) URL('http://example.com') @@ -652,6 +693,48 @@ section generates a new :class:`URL` instance. Support subclasses of :class:`int` (except :class:`bool`) and :class:`float` as a query parameter value. +.. method:: URL.extend_query(query) + URL.extend_query(**kwargs) + + Returns a new URL with *query* part extended. + + Unlike :meth:`update_query`, this method keeps duplicate keys. + + Returned :class:`URL` object will contain query string which extends + parts from passed query parts (or parts of parsed query string). + + Accepts any :class:`~collections.abc.Mapping` (e.g. :class:`dict`, + :class:`~multidict.MultiDict` instances) or :class:`str`, + auto-encode the argument if needed. + + A sequence of ``(key, value)`` pairs is supported as well. + + Also it can take an arbitrary number of keyword arguments. + + Returns the same :class:`URL` if *query* of ``None`` is passed. + + .. note:: + + 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. + + Please see :ref:`yarl-bools-support` for the reason why :class:`bool` is not + supported out-of-the-box. + + .. doctest:: + + >>> URL('http://example.com/path?a=b&b=1').extend_query(b='2') + URL('http://example.com/path?a=b&b=1&b=2') + >>> URL('http://example.com/path?a=b&b=1').extend_query([('b', '2')]) + URL('http://example.com/path?a=b&b=1&b=2') + >>> URL('http://example.com/path?a=b&c=e&c=f').extend_query(c='d') + URL('http://example.com/path?a=b&c=e&c=f&c=d') + + .. versionadded:: 1.11.0 + .. method:: URL.update_query(query) URL.update_query(**kwargs) @@ -726,6 +809,16 @@ section generates a new :class:`URL` instance. Support subclasses of :class:`int` (except :class:`bool`) and :class:`float` as a query parameter value. +.. method:: URL.without_query_params(*query_params) + + Return a new URL whose *query* part does not contain specified ``query_params``. + + Accepts :class:`str` for ``query_params``. + + It does nothing if none of specified ``query_params`` are present in the query. + + .. versionadded:: 1.10.0 + .. method:: URL.with_fragment(fragment) Return a new URL with *fragment* replaced, auto-encode *fragment* if needed. @@ -736,8 +829,8 @@ section generates a new :class:`URL` instance. >>> URL('http://example.com/path#frag').with_fragment('anchor') URL('http://example.com/path#anchor') - >>> URL('http://example.com/path#frag').with_fragment('якорь') - URL('http://example.com/path#%D1%8F%D0%BA%D0%BE%D1%80%D1%8C') + >>> URL('http://example.com/path#frag').with_fragment('якір') + URL('http://example.com/path#%D1%8F%D0%BA%D1%96%D1%80') >>> URL('http://example.com/path#frag').with_fragment(None) URL('http://example.com/path') @@ -752,8 +845,8 @@ section generates a new :class:`URL` instance. >>> URL('http://example.com/path/to?arg#frag').with_name('new') URL('http://example.com/path/new') - >>> URL('http://example.com/path/to').with_name('имя') - URL('http://example.com/path/%D0%B8%D0%BC%D1%8F') + >>> URL('http://example.com/path/to').with_name("ім'я") + URL('http://example.com/path/%D1%96%D0%BC%27%D1%8F') .. method:: URL.with_suffix(suffix) @@ -766,8 +859,8 @@ section generates a new :class:`URL` instance. >>> URL('http://example.com/path/to?arg#frag').with_suffix('.doc') URL('http://example.com/path/to.doc') - >>> URL('http://example.com/path/to').with_suffix('.cуффикс') - URL('http://example.com/path/to.c%D1%83%D1%84%D1%84%D0%B8%D0%BA%D1%81') + >>> URL('http://example.com/path/to').with_suffix('.cуфікс') + URL('http://example.com/path/to.c%D1%83%D1%84%D1%96%D0%BA%D1%81') .. attribute:: URL.parent @@ -813,9 +906,47 @@ The path is encoded if needed. URL('http://example.com/path/to/subpath') >>> url.parts ('/', 'path', 'to', 'subpath') - >>> url = URL('http://example.com/path?arg#frag') / 'сюда' + >>> url = URL('http://example.com/path?arg#frag') / 'сюди' >>> url - URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B0') + URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B8') + +.. method:: URL.joinpath(*other, encoded=False) + + Construct a new URL by with all ``other`` elements appended to + *path*, and cleaned up *query* and *fragment* parts. + + Passing ``encoded=True`` parameter prevents path element auto-encoding, the caller is + responsible for taking care of URL correctness. + + .. doctest:: + + >>> url = URL('http://example.com/path?arg#frag').joinpath('to', 'subpath') + >>> url + URL('http://example.com/path/to/subpath') + >>> url.parts + ('/', 'path', 'to', 'subpath') + >>> url = URL('http://example.com/path?arg#frag').joinpath('сюди') + >>> url + URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B8') + >>> url = URL('http://example.com/path').joinpath('%D1%81%D1%8E%D0%B4%D0%B8', encoded=True) + >>> url + URL('http://example.com/path/%D1%81%D1%8E%D0%B4%D0%B8') + + .. versionadded:: 1.9 + +.. method:: URL.__truediv__(url) + + Shortcut for :meth:`URL.joinpath` with a single element and ``encoded=False``. + + .. doctest:: + + >>> url = URL('http://example.com/path?arg#frag') / 'to' + >>> url + URL('http://example.com/path/to') + >>> url.parts + ('/', 'path', 'to') + + .. versionadded:: 0.9 .. method:: URL.join(url) @@ -906,18 +1037,20 @@ Default port substitution Cache control ------------- -IDNA conversion used for host encoding is quite expensive operation, that's why the -``yarl`` library caches IDNA encoding/decoding calls by storing last ``256`` encodes -and last ``256`` decodes in the global LRU cache. +IDNA conversion, host validation, and IP Address parsing used for host +encoding are quite expensive operations, that's why the ``yarl`` +library caches these calls by storing last ``256`` results in the +global LRU cache. .. function:: cache_clear() - Clear IDNA caches. + Clear IDNA, host validation, and IP Address caches. .. function:: cache_info() - Return a dictionary with ``"idna_encode"`` and ``"idna_decode"`` keys, each value + Return a dictionary with ``"idna_encode"``, ``"idna_decode"``, ``"ip_address"``, + and ``"host_validate"`` keys, each value points to corresponding ``CacheInfo`` structure (see :func:`functools.lru_cache` for details): @@ -926,15 +1059,19 @@ and last ``256`` decodes in the global LRU cache. >>> yarl.cache_info() {'idna_encode': CacheInfo(hits=5, misses=5, maxsize=256, currsize=5), - 'idna_decode': CacheInfo(hits=24, misses=15, maxsize=256, currsize=15)} + 'idna_decode': CacheInfo(hits=24, misses=15, maxsize=256, currsize=15), + 'ip_address': CacheInfo(hits=46933, misses=84, maxsize=256, currsize=101), + 'host_validate': CacheInfo(hits=0, misses=0, maxsize=256, currsize=0)} + -.. function:: cache_configure(*, idna_encode_size=256, idna_decode_size=256) +.. function:: cache_configure(*, idna_encode_size=256, idna_decode_size=256, ip_address_size=256, host_validate_size=256) - Set IDNA encode and decode cache sizes (``256`` for each by default). + Set the IP Address, host validation, and IDNA encode and + decode cache sizes (``256`` for each by default). - Pass ``None`` to make the corresponding cache unbounded (may speed up the IDNA - encoding/decoding operation a little but the memory footprint can be very high, + Pass ``None`` to make the corresponding cache unbounded (may speed up host encoding + operation a little but the memory footprint can be very high, please use with caution). References diff --git a/docs/changes.rst b/docs/changes.rst new file mode 100644 index 0000000..08dd848 --- /dev/null +++ b/docs/changes.rst @@ -0,0 +1,18 @@ +.. _yarl_changes: + +========= +Changelog +========= + +.. only:: not is_release + + To be included in v\ |release| (if present) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + .. towncrier-draft-entries:: |release| [UNRELEASED DRAFT] + + Released versions + ^^^^^^^^^^^^^^^^^ + +.. include:: ../CHANGES.rst + :start-after: .. towncrier release notes start diff --git a/docs/conf.py b/docs/conf.py index 64d98e2..2b223d4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,10 +26,20 @@ # # needs_sphinx = '1.0' -import pathlib +import os import re +from pathlib import Path -_docs_path = pathlib.Path(__file__).parent +PROJECT_ROOT_DIR = Path(__file__).parents[1].resolve() +IS_RELEASE_ON_RTD = ( + os.getenv("READTHEDOCS", "False") == "True" + and os.environ["READTHEDOCS_VERSION_TYPE"] == "tag" +) +if IS_RELEASE_ON_RTD: + tags.add("is_release") + + +_docs_path = Path(__file__).parent _version_path = _docs_path / "../yarl/__init__.py" @@ -51,11 +61,16 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + # stdlib-party extensions: + "sphinx.ext.extlinks", "sphinx.ext.intersphinx", "sphinx.ext.coverage", "sphinx.ext.doctest", "sphinx.ext.viewcode", + # Third-party extensions: "alabaster", + "sphinxcontrib.towncrier.ext", # provides `towncrier-draft-entries` directive + "myst_parser", # extended markdown; https://pypi.org/project/myst-parser/ ] @@ -68,7 +83,7 @@ intersphinx_mapping = { "python": ("https://docs.python.org/3", None), - "multidict": ("https://multidict.readthedocs.io/en/stable", None), + "multidict": ("https://multidict.aio-libs.org/en/stable", None), } @@ -79,7 +94,6 @@ # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = ".rst" # The encoding of source files. # @@ -88,9 +102,17 @@ # The master toctree document. master_doc = "index" -# General information about the project. -project = "yarl" -copyright = "2016-2018, Andrew Svetlov and aio-libs team" +# -- Project information ----------------------------------------------------- + +github_url = "https://github.com" +github_repo_org = "aio-libs" +github_repo_name = "yarl" +github_repo_slug = f"{github_repo_org}/{github_repo_name}" +github_repo_url = f"{github_url}/{github_repo_slug}" +github_sponsors_url = f"{github_url}/sponsors" + +project = github_repo_name +copyright = f"2016, Andrew Svetlov, {project} contributors and aio-libs team" author = "Andrew Svetlov and aio-libs team" # The version info for the project you're documenting, acts as replacement for @@ -102,6 +124,10 @@ # The full version, including alpha/beta/rc tags. release = "{major}.{minor}.{patch}-{tag}".format(**_version_info) +rst_epilog = f""" +.. |project| replace:: {project} +""" # pylint: disable=invalid-name + # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # @@ -154,6 +180,17 @@ # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False +# -- Extension configuration ------------------------------------------------- + +# -- Options for extlinks extension --------------------------------------- +extlinks = { + "issue": (f"{github_repo_url}/issues/%s", "#%s"), + "pr": (f"{github_repo_url}/pull/%s", "PR #%s"), + "commit": (f"{github_repo_url}/commit/%s", "%s"), + "gh": (f"{github_url}/%s", "GitHub: %s"), + "user": (f"{github_sponsors_url}/%s", "@%s"), +} + # -- Options for HTML output ---------------------------------------------- @@ -405,3 +442,13 @@ default_role = "any" nitpicky = True +nitpick_ignore = [ + ("envvar", "TMPDIR"), +] + +# -- Options for towncrier_draft extension ----------------------------------- + +towncrier_draft_autoversion_mode = "draft" # or: 'sphinx-version', 'sphinx-release' +towncrier_draft_include_empty = True +towncrier_draft_working_directory = PROJECT_ROOT_DIR +# Not yet supported: towncrier_draft_config_path = 'pyproject.toml' # relative to cwd diff --git a/docs/contributing/guidelines.rst b/docs/contributing/guidelines.rst new file mode 100644 index 0000000..f0413b8 --- /dev/null +++ b/docs/contributing/guidelines.rst @@ -0,0 +1,28 @@ +----------------- +Contributing docs +----------------- + +We use Sphinx_ to generate our docs website. You can trigger +the process locally by executing: + + .. code-block:: shell-session + + $ make doc + +It is also integrated with `Read The Docs`_ that builds and +publishes each commit to the main branch and generates live +docs previews for each pull request. + +The sources of the Sphinx_ documents use reStructuredText as a +de-facto standard. But in order to make contributing docs more +beginner-friendly, we've integrated `MyST parser`_ allowing us +to also accept new documents written in an extended version of +Markdown that supports using Sphinx directives and roles. `Read +the docs `_ to learn more on how to use it. + +.. _MyST docs: https://myst-parser.readthedocs.io/en/latest/using/intro.html#writing-myst-in-sphinx +.. _MyST parser: https://pypi.org/project/myst-parser/ +.. _Read The Docs: https://readthedocs.org +.. _Sphinx: https://www.sphinx-doc.org + +.. include:: ../../CHANGES/README.rst diff --git a/docs/contributing/release_guide.rst b/docs/contributing/release_guide.rst new file mode 100644 index 0000000..b32d8fe --- /dev/null +++ b/docs/contributing/release_guide.rst @@ -0,0 +1,105 @@ +************* +Release Guide +************* + +Welcome to the |project| Release Guide! + +This page contains information on how to release a new version +of |project| using the automated Continuous Delivery pipeline. + +.. tip:: + + The intended audience for this document is maintainers + and core contributors. + + +Pre-release activities +====================== + +1. Check if there are any open Pull Requests that could be + desired in the upcoming release. If there are any — merge + them. If some are incomplete, try to get them ready. + Don't forget to review the enclosed change notes per our + guidelines. +2. Visually inspect the draft section of the :ref:`Changelog` + page. Make sure the content looks consistent, uses the same + writing style, targets the end-users and adheres to our + documented guidelines. + Most of the changelog sections will typically use the past + tense or another way to relay the effect of the changes for + the users, since the previous release. + It should not target core contributors as the information + they are normally interested in is already present in the + Git history. + Update the changelog fragments if you see any problems with + this changelog section. +3. Optionally, test the previously published nightlies, that are + available through GitHub Actions CI/CD artifacts, locally. +4. If you are satisfied with the above, inspect the changelog + section categories in the draft. Presence of the breaking + changes or features will hint you what version number + segment to bump for the release. +5. Update the hardcoded version string in :file:`yarl/__init__.py`. + Generate a new changelog from the fragments, and commit it + along with the fragments removal and the Python module changes. + Use the following commands, don't prepend a leading-``v`` before + the version number. Just use the raw version number as per + :pep:`440`. + + .. code-block:: shell-session + + [dir:yarl] $ yarl/__init__.py + [dir:yarl] $ python -m towncrier build \ + -- --version 'VERSION_WITHOUT_LEADING_V' + [dir:yarl] $ git commit -v CHANGES{.rst,/} yarl/__init__.py + +.. seealso:: + + :ref:`Adding change notes with your PRs` + Writing beautiful changelogs for humans + + +The release stage +================= + +1. Tag the commit with version and changelog changes, created + during the preparation stage. If possible, make it GPG-signed. + Prepend a leading ``v`` before the version number for the tag + name. Add an extra sentence describing the release contents, + in a few words. + + .. code-block:: shell-session + + [dir:yarl] $ git tag \ + -s 'VERSION_WITH_LEADING_V' \ + -m 'VERSION_WITH_LEADING_V' \ + -m 'This release does X and Y.' + + +2. Push that tag to the upstream repository, which ``origin`` is + considered to be in the example below. + + .. code-block:: shell-session + + [dir:yarl] $ git push origin 'VERSION_WITH_LEADING_V' + +3. You can open the `GitHub Actions CI/CD workflow page `_ in your web browser to monitor the + progress. But generally, you don't need to babysit the CI. +4. Check that web page or your email inbox for the notification + with an approval request. GitHub will send it when it reaches + the final "publishing" job. +5. Approve the deployment and wait for the CD workflow to complete. +6. Verify that the following things got created: + - a PyPI release + - a Git tag + - a GitHub Releases page +7. Tell everyone you released a new version of |project| :) + Depending on your mental capacity and the burnout stage, you + are encouraged to post the updates in issues asking for the + next release, contributed PRs, Bluesky, Twitter etc. You can + also call out prominent contributors and thank them! + + +.. _GitHub Actions CI/CD workflow: + https://github.com/aio-libs/yarl/actions/workflows/ci-cd.yml diff --git a/docs/index.rst b/docs/index.rst index 637acfa..f3f4387 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -61,9 +61,9 @@ automatically encoded giving canonical representation as result: .. doctest:: - >>> 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: @@ -71,17 +71,17 @@ getting *encoded* strings: .. doctest:: >>> 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 :meth:`~yarl.URL.human_repr`: .. doctest:: >>> url.human_repr() - 'https://www.python.org/путь' + 'https://www.python.org/шлях' For full documentation please read :ref:`yarl-api` section. @@ -101,12 +101,13 @@ manylinux-compliant because of the missing glibc and therefore, cannot be 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 setting the ``YARL_NO_EXTENSIONS`` +To skip the compilation you must explicitly opt-in by using a PEP 517 +configuration setting ``pure-python``, or setting the ``YARL_NO_EXTENSIONS`` environment variable to a non-empty value, e.g.: -:: +.. code-block:: console - $ YARL_NO_EXTENSIONS=1 pip install yarl + $ 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 @@ -174,9 +175,6 @@ Please file an issue on the `bug tracker `_ if you have found a bug or have some suggestion in order to improve the library. -The library uses `Azure Pipelines `_ for -Continuous Integration. - Discussion list --------------- @@ -201,6 +199,22 @@ Contents: api +.. toctree:: + :caption: What's new + + changes + +.. toctree:: + :caption: Contributing + + contributing/guidelines + +.. toctree:: + :caption: Maintenance + + contributing/release_guide + + Indices and tables ================== diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index aa468b4..8e66ca9 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -1,16 +1,50 @@ +Bluesky +Bugfixes +Changelog +Codecov +Cython +GPG IPv +PRs +PYX +Towncrier +Twitter +UTF +aiohttp +backend boolean booleans bools +changelog +changelogs +config de +decodable +dev +dists +downstreams facto glibc google +hardcoded +hostnames +macOS mailto manylinux multi +nightlies +pre +rc +reStructuredText +reencoding +requote +requoting +runtimes +sdist subclass subclasses +subcomponent svetlov uncompiled +v1 yarl diff --git a/packaging/README.md b/packaging/README.md new file mode 100644 index 0000000..9940dc5 --- /dev/null +++ b/packaging/README.md @@ -0,0 +1,11 @@ +# `pep517_backend` in-tree build backend + +The `pep517_backend.hooks` importable exposes callables declared by PEP 517 +and PEP 660 and is integrated into `pyproject.toml`'s +`[build-system].build-backend` through `[build-system].backend-path`. + +# Design considerations + +`__init__.py` is to remain empty, leaving `hooks.py` the only entrypoint +exposing the callables. The logic is contained in private modules. This is +to prevent import-time side effects. diff --git a/packaging/pep517_backend/__init__.py b/packaging/pep517_backend/__init__.py new file mode 100644 index 0000000..74ae436 --- /dev/null +++ b/packaging/pep517_backend/__init__.py @@ -0,0 +1 @@ +"""PEP 517 build backend for optionally pre-building Cython.""" diff --git a/packaging/pep517_backend/__main__.py b/packaging/pep517_backend/__main__.py new file mode 100644 index 0000000..7ad33e7 --- /dev/null +++ b/packaging/pep517_backend/__main__.py @@ -0,0 +1,6 @@ +import sys + +from . import cli + +if __name__ == "__main__": + sys.exit(cli.run_main_program(argv=sys.argv)) diff --git a/packaging/pep517_backend/_backend.py b/packaging/pep517_backend/_backend.py new file mode 100644 index 0000000..bb318f5 --- /dev/null +++ b/packaging/pep517_backend/_backend.py @@ -0,0 +1,395 @@ +# fmt: off +"""PEP 517 build backend wrapper for pre-building Cython for wheel.""" + +from __future__ import annotations + +import os +import typing as t +from contextlib import contextmanager, nullcontext, suppress +from functools import partial +from pathlib import Path +from shutil import copytree +from sys import implementation as _system_implementation +from sys import stderr as _standard_error_stream +from sys import version_info as _python_version_tuple +from tempfile import TemporaryDirectory +from warnings import warn as _warn_that + +from setuptools.build_meta import build_sdist as _setuptools_build_sdist +from setuptools.build_meta import build_wheel as _setuptools_build_wheel +from setuptools.build_meta import ( + get_requires_for_build_wheel as _setuptools_get_requires_for_build_wheel, +) +from setuptools.build_meta import ( + prepare_metadata_for_build_wheel as _setuptools_prepare_metadata_for_build_wheel, +) + +try: + from setuptools.build_meta import build_editable as _setuptools_build_editable +except ImportError: + _setuptools_build_editable = None # type: ignore[assignment] + + +# isort: split +from distutils.command.install import install as _distutils_install_cmd +from distutils.core import Distribution as _DistutilsDistribution +from distutils.dist import DistributionMetadata as _DistutilsDistributionMetadata + +with suppress(ImportError): + # NOTE: Only available for wheel builds that bundle C-extensions. Declared + # NOTE: by `get_requires_for_build_wheel()` and + # NOTE: `get_requires_for_build_editable()`, when `pure-python` + # NOTE: is not passed. + from Cython.Build.Cythonize import main as _cythonize_cli_cmd + +from ._compat import chdir_cm +from ._cython_configuration import ( # noqa: WPS436 + get_local_cython_config as _get_local_cython_config, +) +from ._cython_configuration import ( + make_cythonize_cli_args_from_config as _make_cythonize_cli_args_from_config, +) +from ._cython_configuration import patched_env as _patched_cython_env +from ._transformers import sanitize_rst_roles # noqa: WPS436 + +__all__ = ( # noqa: WPS410 + 'build_sdist', + 'build_wheel', + 'get_requires_for_build_wheel', + 'prepare_metadata_for_build_wheel', + *( + () if _setuptools_build_editable is None + else ( + 'build_editable', + 'get_requires_for_build_editable', + 'prepare_metadata_for_build_editable', + ) + ), +) + +_ConfigDict = t.Dict[str, t.Union[str, t.List[str], None]] + + +CYTHON_TRACING_CONFIG_SETTING = 'with-cython-tracing' +"""Config setting name toggle to include line tracing to C-exts.""" + +CYTHON_TRACING_ENV_VAR = 'YARL_CYTHON_TRACING' +"""Environment variable name toggle used to opt out of making C-exts.""" + +PURE_PYTHON_CONFIG_SETTING = 'pure-python' +"""Config setting name toggle that is used to opt out of making C-exts.""" + +PURE_PYTHON_ENV_VAR = 'YARL_NO_EXTENSIONS' +"""Environment variable name toggle used to opt out of making C-exts.""" + +IS_PY3_12_PLUS = _python_version_tuple[:2] >= (3, 12) +"""A flag meaning that the current runtime is Python 3.12 or higher.""" + +IS_CPYTHON = _system_implementation.name == "cpython" +"""A flag meaning that the current interpreter implementation is CPython.""" + +PURE_PYTHON_MODE_CLI_FALLBACK = not IS_CPYTHON +"""A fallback for ``pure-python`` is not set.""" + + +def _is_truthy_setting_value(setting_value) -> bool: + truthy_values = {'', None, 'true', '1', 'on'} + return setting_value.lower() in truthy_values + + +def _get_setting_value( + config_settings: _ConfigDict | None = None, + config_setting_name: str | None = None, + env_var_name: str | None = None, + *, + default: bool = False, +) -> bool: + user_provided_setting_sources = ( + (config_settings, config_setting_name, (KeyError, TypeError)), + (os.environ, env_var_name, KeyError), + ) + for src_mapping, src_key, lookup_errors in user_provided_setting_sources: + if src_key is None: + continue + + with suppress(lookup_errors): # type: ignore[arg-type] + return _is_truthy_setting_value(src_mapping[src_key]) # type: ignore[index] + + return default + + +def _make_pure_python(config_settings: _ConfigDict | None = None) -> bool: + return _get_setting_value( + config_settings, + PURE_PYTHON_CONFIG_SETTING, + PURE_PYTHON_ENV_VAR, + default=PURE_PYTHON_MODE_CLI_FALLBACK, + ) + + +def _include_cython_line_tracing( + config_settings: _ConfigDict | None = None, + *, + default=False, +) -> bool: + return _get_setting_value( + config_settings, + CYTHON_TRACING_CONFIG_SETTING, + CYTHON_TRACING_ENV_VAR, + default=default, + ) + + +@contextmanager +def patched_distutils_cmd_install(): + """Make `install_lib` of `install` cmd always use `platlib`. + + :yields: None + """ + # Without this, build_lib puts stuff under `*.data/purelib/` folder + orig_finalize = _distutils_install_cmd.finalize_options + + def new_finalize_options(self): # noqa: WPS430 + self.install_lib = self.install_platlib + orig_finalize(self) + + _distutils_install_cmd.finalize_options = new_finalize_options + try: + yield + finally: + _distutils_install_cmd.finalize_options = orig_finalize + + +@contextmanager +def patched_dist_has_ext_modules(): + """Make `has_ext_modules` of `Distribution` always return `True`. + + :yields: None + """ + # Without this, build_lib puts stuff under `*.data/platlib/` folder + orig_func = _DistutilsDistribution.has_ext_modules + + _DistutilsDistribution.has_ext_modules = lambda *args, **kwargs: True + try: + yield + finally: + _DistutilsDistribution.has_ext_modules = orig_func + + +@contextmanager +def patched_dist_get_long_description(): + """Make `has_ext_modules` of `Distribution` always return `True`. + + :yields: None + """ + # Without this, build_lib puts stuff under `*.data/platlib/` folder + _orig_func = _DistutilsDistributionMetadata.get_long_description + + def _get_sanitized_long_description(self): + return sanitize_rst_roles(self.long_description) + + _DistutilsDistributionMetadata.get_long_description = ( + _get_sanitized_long_description + ) + try: + yield + finally: + _DistutilsDistributionMetadata.get_long_description = _orig_func + + +def _exclude_dir_path( + excluded_dir_path: Path, + visited_directory: str, + _visited_dir_contents: list[str], +) -> list[str]: + """Prevent recursive directory traversal.""" + # This stops the temporary directory from being copied + # into self recursively forever. + # Ref: https://github.com/aio-libs/yarl/issues/992 + visited_directory_subdirs_to_ignore = [ + subdir + for subdir in _visited_dir_contents + if excluded_dir_path == Path(visited_directory) / subdir + ] + if visited_directory_subdirs_to_ignore: + print( + f'Preventing `{excluded_dir_path !s}` from being ' + 'copied into itself recursively...', + file=_standard_error_stream, + ) + return visited_directory_subdirs_to_ignore + + +@contextmanager +def _in_temporary_directory(src_dir: Path) -> t.Iterator[None]: + with TemporaryDirectory(prefix='.tmp-yarl-pep517-') as tmp_dir: + tmp_dir_path = Path(tmp_dir) + root_tmp_dir_path = tmp_dir_path.parent + _exclude_tmpdir_parent = partial(_exclude_dir_path, root_tmp_dir_path) + + with chdir_cm(tmp_dir): + tmp_src_dir = tmp_dir_path / 'src' + copytree( + src_dir, + tmp_src_dir, + ignore=_exclude_tmpdir_parent, + symlinks=True, + ) + os.chdir(tmp_src_dir) + yield + + +@contextmanager +def maybe_prebuild_c_extensions( + line_trace_cython_when_unset: bool = False, + build_inplace: bool = False, + config_settings: _ConfigDict | None = None, +) -> t.Generator[None, t.Any, t.Any]: + """Pre-build C-extensions in a temporary directory, when needed. + + This context manager also patches metadata, setuptools and distutils. + + :param build_inplace: Whether to copy and chdir to a temporary location. + :param config_settings: :pep:`517` config settings mapping. + + """ + cython_line_tracing_requested = _include_cython_line_tracing( + config_settings, + default=line_trace_cython_when_unset, + ) + is_pure_python_build = _make_pure_python(config_settings) + + if is_pure_python_build: + print("*********************", file=_standard_error_stream) + print("* Pure Python build *", file=_standard_error_stream) + print("*********************", file=_standard_error_stream) + + if cython_line_tracing_requested: + _warn_that( + f'The `{CYTHON_TRACING_CONFIG_SETTING !s}` setting requesting ' + 'Cython line tracing is set, but building C-extensions is not. ' + 'This option will not have any effect for in the pure-python ' + 'build mode.', + RuntimeWarning, + stacklevel=999, + ) + + yield + return + + print("**********************", file=_standard_error_stream) + print("* Accelerated build *", file=_standard_error_stream) + print("**********************", file=_standard_error_stream) + if not IS_CPYTHON: + _warn_that( + 'Building C-extensions under the runtimes other than CPython is ' + 'unsupported and will likely fail. Consider passing the ' + f'`{PURE_PYTHON_CONFIG_SETTING !s}` PEP 517 config setting.', + RuntimeWarning, + stacklevel=999, + ) + + build_dir_ctx = ( + nullcontext() if build_inplace + else _in_temporary_directory(src_dir=Path.cwd().resolve()) + ) + with build_dir_ctx: + config = _get_local_cython_config() + + cythonize_args = _make_cythonize_cli_args_from_config(config) + with _patched_cython_env(config['env'], cython_line_tracing_requested): + _cythonize_cli_cmd(cythonize_args) + with patched_distutils_cmd_install(): + with patched_dist_has_ext_modules(): + yield + + +@patched_dist_get_long_description() +def build_wheel( + wheel_directory: str, + config_settings: _ConfigDict | None = None, + metadata_directory: str | None = None, +) -> str: + """Produce a built wheel. + + This wraps the corresponding ``setuptools``' build backend hook. + + :param wheel_directory: Directory to put the resulting wheel in. + :param config_settings: :pep:`517` config settings mapping. + :param metadata_directory: :file:`.dist-info` directory path. + + """ + with maybe_prebuild_c_extensions( + line_trace_cython_when_unset=False, + build_inplace=False, + config_settings=config_settings, + ): + return _setuptools_build_wheel( + wheel_directory=wheel_directory, + config_settings=config_settings, + metadata_directory=metadata_directory, + ) + + +@patched_dist_get_long_description() +def build_editable( + wheel_directory: str, + config_settings: _ConfigDict | None = None, + metadata_directory: str | None = None, +) -> str: + """Produce a built wheel for editable installs. + + This wraps the corresponding ``setuptools``' build backend hook. + + :param wheel_directory: Directory to put the resulting wheel in. + :param config_settings: :pep:`517` config settings mapping. + :param metadata_directory: :file:`.dist-info` directory path. + + """ + with maybe_prebuild_c_extensions( + line_trace_cython_when_unset=True, + build_inplace=True, + config_settings=config_settings, + ): + return _setuptools_build_editable( + wheel_directory=wheel_directory, + config_settings=config_settings, + metadata_directory=metadata_directory, + ) + + +def get_requires_for_build_wheel( + config_settings: _ConfigDict | None = None, +) -> list[str]: + """Determine additional requirements for building wheels. + + :param config_settings: :pep:`517` config settings mapping. + + """ + is_pure_python_build = _make_pure_python(config_settings) + + if not is_pure_python_build and not IS_CPYTHON: + _warn_that( + 'Building C-extensions under the runtimes other than CPython is ' + 'unsupported and will likely fail. Consider passing the ' + f'`{PURE_PYTHON_CONFIG_SETTING !s}` PEP 517 config setting.', + RuntimeWarning, + stacklevel=999, + ) + + c_ext_build_deps = [] if is_pure_python_build else [ + 'Cython >= 3.0.0b3' if IS_PY3_12_PLUS # Only Cython 3+ is compatible + else 'Cython', + ] + + return _setuptools_get_requires_for_build_wheel( + config_settings=config_settings, + ) + c_ext_build_deps + + +build_sdist = patched_dist_get_long_description()(_setuptools_build_sdist) +get_requires_for_build_editable = get_requires_for_build_wheel +prepare_metadata_for_build_wheel = patched_dist_get_long_description()( + _setuptools_prepare_metadata_for_build_wheel, +) +prepare_metadata_for_build_editable = prepare_metadata_for_build_wheel diff --git a/packaging/pep517_backend/_compat.py b/packaging/pep517_backend/_compat.py new file mode 100644 index 0000000..dccada6 --- /dev/null +++ b/packaging/pep517_backend/_compat.py @@ -0,0 +1,33 @@ +"""Cross-python stdlib shims.""" + +import os +import typing as t +from contextlib import contextmanager +from pathlib import Path + +# isort: off +try: + from contextlib import chdir as chdir_cm # type: ignore[attr-defined, unused-ignore] # noqa: E501 +except ImportError: + + @contextmanager # type: ignore[no-redef, unused-ignore] + def chdir_cm(path: os.PathLike) -> t.Iterator[None]: + """Temporarily change the current directory, recovering on exit.""" + original_wd = Path.cwd() + os.chdir(path) + try: + yield + finally: + os.chdir(original_wd) + + +# isort: on + + +try: + from tomllib import loads as load_toml_from_string +except ImportError: + from tomli import loads as load_toml_from_string + + +__all__ = ("chdir_cm", "load_toml_from_string") # noqa: WPS410 diff --git a/packaging/pep517_backend/_cython_configuration.py b/packaging/pep517_backend/_cython_configuration.py new file mode 100644 index 0000000..316b85f --- /dev/null +++ b/packaging/pep517_backend/_cython_configuration.py @@ -0,0 +1,107 @@ +# fmt: off + +from __future__ import annotations + +import os +from contextlib import contextmanager +from pathlib import Path +from sys import version_info as _python_version_tuple + +from expandvars import expandvars + +from ._compat import load_toml_from_string # noqa: WPS436 +from ._transformers import ( # noqa: WPS436 + get_cli_kwargs_from_config, + get_enabled_cli_flags_from_config, +) + + +def get_local_cython_config() -> dict: + """Grab optional build dependencies from pyproject.toml config. + + :returns: config section from ``pyproject.toml`` + :rtype: dict + + This basically reads entries from:: + + [tool.local.cythonize] + # Env vars provisioned during cythonize call + src = ["src/**/*.pyx"] + + [tool.local.cythonize.env] + # Env vars provisioned during cythonize call + LDFLAGS = "-lssh" + + [tool.local.cythonize.flags] + # This section can contain the following booleans: + # * annotate — generate annotated HTML page for source files + # * build — build extension modules using distutils + # * inplace — build extension modules in place using distutils (implies -b) + # * force — force recompilation + # * quiet — be less verbose during compilation + # * lenient — increase Python compat by ignoring some compile time errors + # * keep-going — compile as much as possible, ignore compilation failures + annotate = false + build = false + inplace = true + force = true + quiet = false + lenient = false + keep-going = false + + [tool.local.cythonize.kwargs] + # This section can contain args that have values: + # * exclude=PATTERN exclude certain file patterns from the compilation + # * parallel=N run builds in N parallel jobs (default: calculated per system) + exclude = "**.py" + parallel = 12 + + [tool.local.cythonize.kwargs.directives] + # This section can contain compiler directives + # NAME = "VALUE" + + [tool.local.cythonize.kwargs.compile-time-env] + # This section can contain compile time env vars + # NAME = "VALUE" + + [tool.local.cythonize.kwargs.options] + # This section can contain cythonize options + # NAME = "VALUE" + """ + config_toml_txt = (Path.cwd().resolve() / 'pyproject.toml').read_text() + config_mapping = load_toml_from_string(config_toml_txt) + return config_mapping['tool']['local']['cythonize'] + + +def make_cythonize_cli_args_from_config(config) -> list[str]: + py_ver_arg = f'-{_python_version_tuple.major!s}' + + cli_flags = get_enabled_cli_flags_from_config(config['flags']) + cli_kwargs = get_cli_kwargs_from_config(config['kwargs']) + + return cli_flags + [py_ver_arg] + cli_kwargs + ['--'] + config['src'] + + +@contextmanager +def patched_env(env: dict[str, str], cython_line_tracing_requested: bool): + """Temporary set given env vars. + + :param env: tmp env vars to set + :type env: dict + + :yields: None + """ + orig_env = os.environ.copy() + expanded_env = {name: expandvars(var_val) for name, var_val in env.items()} + os.environ.update(expanded_env) + + if cython_line_tracing_requested: + os.environ['CFLAGS'] = ' '.join(( + os.getenv('CFLAGS', ''), + '-DCYTHON_TRACE_NOGIL=1', # Implies CYTHON_TRACE=1 + )).strip() + try: + yield + finally: + os.environ.clear() + os.environ.update(orig_env) diff --git a/packaging/pep517_backend/_transformers.py b/packaging/pep517_backend/_transformers.py new file mode 100644 index 0000000..6c544a5 --- /dev/null +++ b/packaging/pep517_backend/_transformers.py @@ -0,0 +1,107 @@ +"""Data conversion helpers for the in-tree PEP 517 build backend.""" + +from itertools import chain +from re import sub as _substitute_with_regexp + + +def _emit_opt_pairs(opt_pair): + flag, flag_value = opt_pair + flag_opt = f"--{flag!s}" + if isinstance(flag_value, dict): + sub_pairs = flag_value.items() + else: + sub_pairs = ((flag_value,),) + + yield from ("=".join(map(str, (flag_opt,) + pair)) for pair in sub_pairs) + + +def get_cli_kwargs_from_config(kwargs_map): + """Make a list of options with values from config.""" + return list(chain.from_iterable(map(_emit_opt_pairs, kwargs_map.items()))) + + +def get_enabled_cli_flags_from_config(flags_map): + """Make a list of enabled boolean flags from config.""" + return [f"--{flag}" for flag, is_enabled in flags_map.items() if is_enabled] + + +def sanitize_rst_roles(rst_source_text: str) -> str: + """Replace RST roles with inline highlighting.""" + pep_role_regex = r"""(?x) + :pep:`(?P\d+)` + """ + pep_substitution_pattern = ( + r"`PEP \g >`__" + ) + + user_role_regex = r"""(?x) + :user:`(?P[^`]+)(?:\s+(.*))?` + """ + user_substitution_pattern = ( + r"`@\g " + r">`__" + ) + + issue_role_regex = r"""(?x) + :issue:`(?P[^`]+)(?:\s+(.*))?` + """ + issue_substitution_pattern = ( + r"`#\g " + r">`__" + ) + + pr_role_regex = r"""(?x) + :pr:`(?P[^`]+)(?:\s+(.*))?` + """ + pr_substitution_pattern = ( + r"`PR #\g " + r">`__" + ) + + commit_role_regex = r"""(?x) + :commit:`(?P[^`]+)(?:\s+(.*))?` + """ + commit_substitution_pattern = ( + r"`\g " + r">`__" + ) + + gh_role_regex = r"""(?x) + :gh:`(?P[^`<]+)(?:\s+([^`]*))?` + """ + gh_substitution_pattern = r"GitHub: ``\g``" + + meth_role_regex = r"""(?x) + (?::py)?:meth:`~?(?P[^`<]+)(?:\s+([^`]*))?` + """ + meth_substitution_pattern = r"``\g()``" + + role_regex = r"""(?x) + (?::\w+)?:\w+:`(?P[^`<]+)(?:\s+([^`]*))?` + """ + substitution_pattern = r"``\g``" + + project_substitution_regex = r"\|project\|" + project_substitution_pattern = "yarl" + + substitutions = ( + (pep_role_regex, pep_substitution_pattern), + (user_role_regex, user_substitution_pattern), + (issue_role_regex, issue_substitution_pattern), + (pr_role_regex, pr_substitution_pattern), + (commit_role_regex, commit_substitution_pattern), + (gh_role_regex, gh_substitution_pattern), + (meth_role_regex, meth_substitution_pattern), + (role_regex, substitution_pattern), + (project_substitution_regex, project_substitution_pattern), + ) + + rst_source_normalized_text = rst_source_text + for regex, substitution in substitutions: + rst_source_normalized_text = _substitute_with_regexp( + regex, + substitution, + rst_source_normalized_text, + ) + + return rst_source_normalized_text diff --git a/packaging/pep517_backend/cli.py b/packaging/pep517_backend/cli.py new file mode 100644 index 0000000..f3a1c85 --- /dev/null +++ b/packaging/pep517_backend/cli.py @@ -0,0 +1,53 @@ +# fmt: off + +from __future__ import annotations + +import sys +from itertools import chain +from pathlib import Path + +from Cython.Compiler.Main import compile as _translate_cython_cli_cmd +from Cython.Compiler.Main import parse_command_line as _split_cython_cli_args + +from ._cython_configuration import get_local_cython_config as _get_local_cython_config +from ._cython_configuration import ( + make_cythonize_cli_args_from_config as _make_cythonize_cli_args_from_config, +) +from ._cython_configuration import patched_env as _patched_cython_env + +_PROJECT_PATH = Path(__file__).parents[2] + + +def run_main_program(argv) -> int | str: + """Invoke ``translate-cython`` or fail.""" + if len(argv) != 2: + return 'This program only accepts one argument -- "translate-cython"' + + if argv[1] != 'translate-cython': + return 'This program only implements the "translate-cython" subcommand' + + config = _get_local_cython_config() + config['flags'] = {'keep-going': config['flags']['keep-going']} + config['src'] = list( + map( + str, + chain.from_iterable( + map(_PROJECT_PATH.glob, config['src']), + ), + ), + ) + translate_cython_cli_args = _make_cythonize_cli_args_from_config(config) + + cython_options, cython_sources = _split_cython_cli_args( + translate_cython_cli_args, + ) + + with _patched_cython_env(config['env'], cython_line_tracing_requested=True): + return _translate_cython_cli_cmd( + cython_sources, + cython_options, + ).num_errors + + +if __name__ == '__main__': + sys.exit(run_main_program(argv=sys.argv)) diff --git a/packaging/pep517_backend/hooks.py b/packaging/pep517_backend/hooks.py new file mode 100644 index 0000000..5fa77fe --- /dev/null +++ b/packaging/pep517_backend/hooks.py @@ -0,0 +1,21 @@ +"""PEP 517 build backend for optionally pre-building Cython.""" + +from contextlib import suppress as _suppress + +from setuptools.build_meta import * # Re-exporting PEP 517 hooks # pylint: disable=unused-wildcard-import,wildcard-import # noqa: E501, F401, F403 + +# Re-exporting PEP 517 hooks +from ._backend import ( # type: ignore[assignment] # noqa: WPS436 + build_sdist, + build_wheel, + get_requires_for_build_wheel, + prepare_metadata_for_build_wheel, +) + +with _suppress(ImportError): # Only succeeds w/ setuptools implementing PEP 660 + # Re-exporting PEP 660 hooks + from ._backend import ( # type: ignore[assignment] # noqa: WPS436 + build_editable, + get_requires_for_build_editable, + prepare_metadata_for_build_editable, + ) diff --git a/pyproject.toml b/pyproject.toml index ff755a7..9d5f3d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,93 @@ [build-system] -requires = ["setuptools>=40", "wheel"] +requires = [ + # NOTE: The following build dependencies are necessary for initial + # NOTE: provisioning of the in-tree build backend located under + # NOTE: `packaging/pep517_backend/`. + "expandvars", + "setuptools >= 47", # Minimum required for `version = attr:` + "tomli; python_version < '3.11'", +] +backend-path = ["packaging"] # requires `pip >= 20` or `pep517 >= 0.6.0` +build-backend = "pep517_backend.hooks" # wraps `setuptools.build_meta` -[tool.towncrier] -package = "yarl" -filename = "CHANGES.rst" -directory = "CHANGES/" -title_format = "{version} ({project_date})" -issue_format = "`#{issue} `_" +[tool.local.cythonize] +# This attr can contain multiple globs +src = ["yarl/*.pyx"] +[tool.local.cythonize.env] +# Env vars provisioned during cythonize call +#CFLAGS = "-DCYTHON_TRACE=1 ${CFLAGS}" +#LDFLAGS = "${LDFLAGS}" + +[tool.local.cythonize.flags] +# This section can contain the following booleans: +# * annotate — generate annotated HTML page for source files +# * build — build extension modules using distutils +# * inplace — build extension modules in place using distutils (implies -b) +# * force — force recompilation +# * quiet — be less verbose during compilation +# * lenient — increase Python compat by ignoring some compile time errors +# * keep-going — compile as much as possible, ignore compilation failures +annotate = false +build = false +inplace = true +force = true +quiet = false +lenient = false +keep-going = false + +[tool.local.cythonize.kwargs] +# This section can contain args that have values: +# * exclude=PATTERN exclude certain file patterns from the compilation +# * parallel=N run builds in N parallel jobs (default: calculated per system) +# exclude = "**.py" +# parallel = 12 + +[tool.local.cythonize.kwargs.directive] +# This section can contain compiler directives. Ref: +# https://cython.rtfd.io/en/latest/src/userguide/source_files_and_compilation.html#compiler-directives +embedsignature = "True" +emit_code_comments = "True" +linetrace = "True" # Implies `profile=True` + +[tool.local.cythonize.kwargs.compile-time-env] +# This section can contain compile time env vars + +[tool.local.cythonize.kwargs.option] +# This section can contain cythonize options +# Ref: https://github.com/cython/cython/blob/d6e6de9/Cython/Compiler/Options.py#L694-L730 +#docstrings = "True" +#embed_pos_in_docstring = "True" +#warning_errors = "True" +#error_on_unknown_names = "True" +#error_on_uninitialized = "True" [tool.cibuildwheel] -test-requires = "-r requirements/ci.txt" -test-command = "pytest {project}/tests" +build-frontend = "build" +before-test = [ + # NOTE: Attempt to have pip pre-compile PyYAML wheel with our build + # NOTE: constraints unset. The hope is that pip will cache that wheel + # NOTE: and the test env provisioning stage will pick up PyYAML from + # NOTE: said cache rather than attempting to build it with a conflicting. + # NOTE: Version of Cython. + # Ref: https://github.com/pypa/cibuildwheel/issues/1666 + "PIP_CONSTRAINT= pip install PyYAML", +] +test-requires = "-r requirements/test.txt" +test-command = "pytest -v --no-cov {project}/tests" # don't build PyPy wheels, install from source instead skip = "pp*" + +[tool.cibuildwheel.environment] +COLOR = "yes" +FORCE_COLOR = "1" +MYPY_FORCE_COLOR = "1" +PIP_CONSTRAINT = "requirements/cython.txt" +PRE_COMMIT_COLOR = "always" +PY_COLORS = "1" + +[tool.cibuildwheel.config-settings] +pure-python = "false" + +[tool.cibuildwheel.windows] +before-test = [] # Windows cmd has different syntax and pip chooses wheels diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..a4b7d0c --- /dev/null +++ b/pytest.ini @@ -0,0 +1,88 @@ +[pytest] +addopts = + # `pytest-xdist`: + --numprocesses=auto + + # Show 10 slowest invocations: + --durations=10 + + # Report all the things == -rxXs: + -ra + + # Show values of the local vars in errors/tracebacks: + --showlocals + + # Autocollect and invoke the doctests from all modules: + # https://docs.pytest.org/en/stable/doctest.html + --doctest-modules + + # Dump the test results in junit format: + # --junitxml=.test-results/pytest/results.xml + + # Pre-load the `pytest-cov` plugin early: + -p pytest_cov + + # `pytest-cov`: + --cov + --cov-context=test + --cov-config=.coveragerc + + # Fail on config parsing warnings: + # --strict-config + + # Fail on non-existing markers: + # * Deprecated since v6.2.0 but may be reintroduced later covering a + # broader scope: + # --strict + # * Exists since v4.5.0 (advised to be used instead of `--strict`): + --strict-markers + +doctest_optionflags = ALLOW_UNICODE ELLIPSIS + +# Marks tests with an empty parameterset as xfail(run=False) +empty_parameter_set_mark = xfail + +faulthandler_timeout = 30 + +filterwarnings = + error + + # FIXME: drop this once `pytest-cov` is updated. + # Ref: https://github.com/pytest-dev/pytest-cov/issues/557 + ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning + + # https://github.com/pytest-dev/pytest/issues/10977 and https://github.com/pytest-dev/pytest/pull/10894 + ignore:ast\.(Num|NameConstant|Str) is deprecated and will be removed in Python 3\.14; use ast\.Constant instead:DeprecationWarning:_pytest + ignore:Attribute s is deprecated and will be removed in Python 3\.14; use value instead:DeprecationWarning:_pytest + +# https://docs.pytest.org/en/stable/usage.html#creating-junitxml-format-files +junit_duration_report = call +# xunit1 contains more metadata than xunit2 so it's better for CI UIs: +junit_family = xunit1 +junit_logging = all +junit_log_passing_tests = true +junit_suite_name = yarl_test_suite + +# A mapping of markers to their descriptions allowed in strict mode: +markers = + +minversion = 3.8.2 + +# Optimize pytest's lookup by restricting potentially deep dir tree scan: +norecursedirs = + build + dist + docs + venv + virtualenv + yarl.egg-info + .cache + .eggs + .git + .github + .tox + *.egg + +testpaths = tests/ + +xfail_strict = true diff --git a/requirements/cython.txt b/requirements/cython.txt new file mode 100644 index 0000000..3eaca16 --- /dev/null +++ b/requirements/cython.txt @@ -0,0 +1 @@ +cython==3.0.11 diff --git a/requirements/dev.txt b/requirements/dev.txt new file mode 100644 index 0000000..2a4069d --- /dev/null +++ b/requirements/dev.txt @@ -0,0 +1,2 @@ +-r test.txt +-r towncrier.txt diff --git a/requirements/doc-spelling.txt b/requirements/doc-spelling.txt new file mode 100644 index 0000000..c94dfb6 --- /dev/null +++ b/requirements/doc-spelling.txt @@ -0,0 +1,2 @@ +-r doc.txt +sphinxcontrib-spelling==8.0.0; platform_system!="Windows" # We only use it in Azure CI diff --git a/requirements/doc.txt b/requirements/doc.txt new file mode 100644 index 0000000..ab21660 --- /dev/null +++ b/requirements/doc.txt @@ -0,0 +1,4 @@ +-r towncrier.txt +myst-parser >= 0.10.0 +sphinx==8.0.2 +sphinxcontrib-towncrier diff --git a/requirements/lint.txt b/requirements/lint.txt new file mode 100644 index 0000000..1509fe7 --- /dev/null +++ b/requirements/lint.txt @@ -0,0 +1 @@ +pre-commit==3.8.0 diff --git a/requirements/test.txt b/requirements/test.txt new file mode 100644 index 0000000..f23edfc --- /dev/null +++ b/requirements/test.txt @@ -0,0 +1,7 @@ +-r cython.txt +covdefaults +idna==3.10 +multidict==6.1.0 +pytest==8.3.3 +pytest-cov>=2.3.1 +pytest-xdist diff --git a/requirements/towncrier.txt b/requirements/towncrier.txt new file mode 100644 index 0000000..409f3a3 --- /dev/null +++ b/requirements/towncrier.txt @@ -0,0 +1 @@ +towncrier==23.11.0 diff --git a/setup.cfg b/setup.cfg index f67e76c..f90634d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,13 +1,73 @@ +[bdist_wheel] +universal = 0 + [metadata] -license_file = LICENSE +name = yarl +version = attr: yarl.__version__ +url = https://github.com/aio-libs/yarl +project_urls = + Chat: Matrix = https://matrix.to/#/#aio-libs:matrix.org + Chat: Matrix Space = https://matrix.to/#/#aio-libs-space:matrix.org + CI: GitHub Workflows = https://github.com/aio-libs/yarl/actions?query=branch:master + Code of Conduct = https://github.com/aio-libs/.github/blob/master/CODE_OF_CONDUCT.md + Coverage: codecov = https://codecov.io/github/aio-libs/yarl + Docs: Changelog = https://yarl.aio-libs.org/en/latest/changes/ + Docs: RTD = https://yarl.aio-libs.org + GitHub: issues = https://github.com/aio-libs/yarl/issues + GitHub: repo = https://github.com/aio-libs/yarl +description = Yet another URL library +long_description = file: README.rst, CHANGES.rst +long_description_content_type = text/x-rst +author = Andrew Svetlov +author_email = andrew.svetlov@gmail.com +maintainer = aiohttp team +maintainer_email = team@aiohttp.org +license = Apache-2.0 +license_files = + LICENSE + NOTICE +classifiers = + Development Status :: 5 - Production/Stable + + Intended Audience :: Developers + + License :: OSI Approved :: Apache Software License + + Programming Language :: Cython + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 + Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 + + Topic :: Internet :: WWW/HTTP + Topic :: Software Development :: Libraries :: Python Modules +keywords = + cython + cext + yarl + +[options] +python_requires = >=3.8 +packages = + yarl +zip_safe = False +include_package_data = True +install_requires = + idna >= 2.0 + multidict >= 4.0 + +[options.package_data] +* = + *.so -[tool:pytest] -addopts = --cov=yarl -v -filterwarnings = error -norecursedirs = dist docs build .tox .eggs venv virtualenv .git -minversion = 3.8.2 -testpaths = tests/ -junit_suite_name = yarl_test_suite +[options.exclude_package_data] +* = + *.c + *.h [pep8] max-line-length = 79 @@ -15,18 +75,13 @@ max-line-length = 79 [flake8] ignore = E203,E301,E302,E704,W503,W504,F811 max-line-length = 88 +per-file-ignores = + + packaging/pep517_backend/hooks.py: F401 [isort] profile = black -[mypy] - -[mypy-idna] -ignore_missing_imports = true - -[mypy-pytest] -ignore_missing_imports = true - [egg_info] tag_build = tag_date = 0 diff --git a/setup.py b/setup.py deleted file mode 100644 index 5434635..0000000 --- a/setup.py +++ /dev/null @@ -1,91 +0,0 @@ -import os -import pathlib -import re -import sys - -from setuptools import Extension, setup - -NO_EXTENSIONS = bool(os.environ.get("YARL_NO_EXTENSIONS")) # type: bool - -if sys.implementation.name != "cpython": - NO_EXTENSIONS = True - - -extensions = [Extension("yarl._quoting_c", ["yarl/_quoting_c.c"])] -# extra_compile_args=["-g"], -# extra_link_args=["-g"], - - -here = pathlib.Path(__file__).parent -fname = here / "yarl" / "__init__.py" - -with fname.open(encoding="utf8") as fp: - try: - version = re.findall(r'^__version__ = "([^"]+)"$', fp.read(), re.M)[0] - except IndexError: - raise RuntimeError("Unable to determine version.") - -install_requires = [ - "multidict>=4.0", - "idna>=2.0", - 'typing-extensions>=3.7.4;python_version<"3.8"', -] - - -def read(name): - fname = here / name - with fname.open(encoding="utf8") as f: - return f.read() - - -# $ echo ':something:`test `' | sed 's/:\w\+:`\(\w\+\)\(\s\+\(.*\)\)\?`/``\1``/g' -# ``test`` -def sanitize_rst_roles(rst_source_text: str) -> str: - """Replace RST roles with inline highlighting.""" - role_regex = r":\w+:`(?P[^`]+)(\s+(.*))?`" - substitution_pattern = r"``(?P=rendered_text)``" - return re.sub(role_regex, substitution_pattern, rst_source_text) - - -args = dict( - name="yarl", - version=version, - description=("Yet another URL library"), - long_description="\n\n".join( - [read("README.rst"), sanitize_rst_roles(read("CHANGES.rst"))] - ), - long_description_content_type="text/x-rst", - classifiers=[ - "License :: OSI Approved :: Apache Software License", - "Intended Audience :: Developers", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Topic :: Internet :: WWW/HTTP", - ], - author="Andrew Svetlov", - author_email="andrew.svetlov@gmail.com", - url="https://github.com/aio-libs/yarl/", - license="Apache 2", - packages=["yarl"], - install_requires=install_requires, - python_requires=">=3.7", - include_package_data=True, - exclude_package_data={"": ["*.c"]}, -) - - -if not NO_EXTENSIONS: - print("**********************") - print("* Accelerated build *") - print("**********************") - setup(ext_modules=extensions, **args) -else: - print("*********************") - print("* Pure Python build *") - print("*********************") - setup(**args) diff --git a/tests/test_cache.py b/tests/test_cache.py index 22141dd..9b0e75a 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -13,7 +13,7 @@ def test_cache_clear() -> None: def test_cache_info() -> None: info = yarl.cache_info() - assert info.keys() == {"idna_encode", "idna_decode"} + assert info.keys() == {"idna_encode", "idna_decode", "ip_address", "host_validate"} def test_cache_configure_default() -> None: @@ -21,8 +21,18 @@ def test_cache_configure_default() -> None: def test_cache_configure_None() -> None: - yarl.cache_configure(idna_encode_size=None, idna_decode_size=None) + yarl.cache_configure( + idna_encode_size=None, + idna_decode_size=None, + ip_address_size=None, + host_validate_size=None, + ) def test_cache_configure_explicit() -> None: - yarl.cache_configure(idna_encode_size=128, idna_decode_size=128) + yarl.cache_configure( + idna_encode_size=128, + idna_decode_size=128, + ip_address_size=128, + host_validate_size=128, + ) diff --git a/tests/test_cached_property.py b/tests/test_cached_property.py index 5dcb5ec..834f6db 100644 --- a/tests/test_cached_property.py +++ b/tests/test_cached_property.py @@ -3,42 +3,27 @@ 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/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 0000000..cdfff12 --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,91 @@ +import platform + +import pytest + +from yarl import _helpers, _helpers_py + +IS_PYPY = platform.python_implementation() == "PyPy" + + +class CachedPropertyMixin: + cached_property = NotImplemented + + def test_cached_property(self) -> None: + class A: + def __init__(self): + self._cache = {} + + @self.cached_property # type: ignore[misc] + def prop(self): + return 1 + + a = A() + assert a.prop == 1 + + def test_cached_property_class(self) -> None: + class A: + def __init__(self): + """Init.""" + # self._cache not set because its never accessed in this test + + @self.cached_property # type: ignore[misc] + def prop(self): + """Docstring.""" + + assert isinstance(A.prop, self.cached_property) + assert A.prop.__doc__ == "Docstring." + + def test_cached_property_assignment(self) -> None: + class A: + def __init__(self): + self._cache = {} + + @self.cached_property # type: ignore[misc] + def prop(self): + """Mock property.""" + + a = A() + + with pytest.raises(AttributeError): + a.prop = 123 + + def test_cached_property_without_cache(self) -> None: + class A: + def __init__(self): + pass + + @self.cached_property # type: ignore[misc] + def prop(self): + """Mock property.""" + + a = A() + + with pytest.raises(AttributeError): + a.prop = 123 + + def test_cached_property_check_without_cache(self) -> None: + class A: + def __init__(self): + pass + + @self.cached_property # type: ignore[misc] + def prop(self): + """Mock property.""" + + a = A() + with pytest.raises(AttributeError): + assert a.prop == 1 + + +class TestPyCachedProperty(CachedPropertyMixin): + cached_property = _helpers_py.cached_property # type: ignore[assignment] + + +if ( + not _helpers.NO_EXTENSIONS + and not IS_PYPY + and hasattr(_helpers, "cached_property_c") +): + + class TestCCachedProperty(CachedPropertyMixin): + cached_property = _helpers.cached_property_c # type: ignore[assignment, attr-defined, unused-ignore] # noqa: E501 diff --git a/tests/test_normalize_path.py b/tests/test_normalize_path.py index 96660ea..20d8981 100644 --- a/tests/test_normalize_path.py +++ b/tests/test_normalize_path.py @@ -8,6 +8,7 @@ ("/", "/"), ("//", "//"), ("///", "///"), + ("path", "path"), # Single-dot ("path/to", "path/to"), ("././path/to", "path/to"), @@ -15,10 +16,15 @@ ("path/././to", "path/to"), ("path/to/.", "path/to/"), ("path/to/./.", "path/to/"), + ("/path/to/.", "/path/to/"), # Double-dots ("../path/to", "path/to"), ("path/../to", "to"), ("path/../../to", "to"), + # absolute path root / is maintained; tests based on two + # tests from web-platform-tests project's urltestdata.json + ("/foo/../../../ton", "/ton"), + ("/foo/../../../..bar", "/..bar"), # Non-ASCII characters ("μονοπάτι/../../να/ᴜɴɪ/ᴄᴏᴅᴇ", "να/ᴜɴɪ/ᴄᴏᴅᴇ"), ("μονοπάτι/../../να/𝕦𝕟𝕚/𝕔𝕠𝕕𝕖/.", "να/𝕦𝕟𝕚/𝕔𝕠𝕕𝕖/"), diff --git a/tests/test_quoting.py b/tests/test_quoting.py index 7ebc0f9..d9b6ae8 100644 --- a/tests/test_quoting.py +++ b/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/tests/test_update_query.py b/tests/test_update_query.py index 3c8de49..e652f45 100644 --- a/tests/test_update_query.py +++ b/tests/test_update_query.py @@ -40,6 +40,17 @@ def test_update_query_with_multiple_args(): url.update_query("a", "b") +def test_update_query_with_none_arg(): + url = URL("http://example.com/?foo=bar&baz=foo") + expected_url = URL("http://example.com/") + assert url.update_query(None) == expected_url + + +def test_update_query_with_empty_dict(): + url = URL("http://example.com/?foo=bar&baz=foo") + assert url.update_query({}) == url + + def test_with_query_list_of_pairs(): url = URL("http://example.com") assert str(url.with_query([("a", "1")])) == "http://example.com/?a=1" @@ -48,7 +59,7 @@ def test_with_query_list_of_pairs(): def test_with_query_list_non_pairs(): url = URL("http://example.com") with pytest.raises(ValueError): - url.with_query(["a=1", "b=2" "c=3"]) + url.with_query(["a=1", "b=2", "c=3"]) def test_with_query_kwargs(): @@ -160,7 +171,7 @@ class _CStr(str): class _EmptyStrEr: def __str__(self): - return "" + return "" # pragma: no cover # <-- this should never happen class _CInt(int, _EmptyStrEr): @@ -238,6 +249,19 @@ class IntEnum(int, enum.Enum): assert str(url2) == "http://example.com/path?a=1" +def test_with_class_that_implements__int__(): + """Allow classes that implement __int__ to be used in query strings.""" + + class myint: + + def __int__(self): + return 84 + + url = URL("http://example.com/path") + url2 = url.with_query(a=myint()) + assert str(url2) == "http://example.com/path?a=84" + + def test_with_float_enum(): class FloatEnum(float, enum.Enum): A = 1.1 @@ -342,6 +366,16 @@ def test_update_query_multiple_keys(): assert str(u2) == "http://example.com/path?a=3&a=4" +def test_update_query_with_non_ascii(): + url = URL("http://example.com/?foo=bar&baz=foo&%F0%9D%95%A6=%F0%9D%95%A6") + assert url.update_query({"𝕦": "𝕦"}) == url + + +def test_update_query_with_non_ascii_as_str(): + url = URL("http://example.com/?foo=bar&baz=foo&%F0%9D%95%A6=%F0%9D%95%A6") + assert url.update_query("𝕦=𝕦") == url + + # mod operator @@ -353,3 +387,81 @@ def test_update_query_with_mod_operator(): assert str(url % {"a": "1"} % {"b": "2"}) == "http://example.com/?a=1&b=2" assert str(url % {"a": "1"} % {"a": "3", "b": "2"}) == "http://example.com/?a=3&b=2" assert str(url / "foo" % {"a": "1"}) == "http://example.com/foo?a=1" + + +def test_extend_query(): + url = URL("http://example.com/") + assert str(url.extend_query({"a": "1"})) == "http://example.com/?a=1" + assert str(URL("test").extend_query(a=1)) == "test?a=1" + + url = URL("http://example.com/?foo=bar") + expected_url = URL("http://example.com/?foo=bar&baz=foo") + + assert url.extend_query({"baz": "foo"}) == expected_url + assert url.extend_query(baz="foo") == expected_url + assert url.extend_query("baz=foo") == expected_url + + +def test_extend_query_with_args_and_kwargs(): + url = URL("http://example.com/") + + with pytest.raises(ValueError): + url.extend_query("a", foo="bar") + + +def test_extend_query_with_multiple_args(): + url = URL("http://example.com/") + + with pytest.raises(ValueError): + url.extend_query("a", "b") + + +def test_extend_query_with_none_arg(): + url = URL("http://example.com/?foo=bar&baz=foo") + assert url.extend_query(None) == url + + +def test_extend_query_with_empty_dict(): + url = URL("http://example.com/?foo=bar&baz=foo") + assert url.extend_query({}) == url + + +def test_extend_query_existing_keys(): + url = URL("http://example.com/?a=2") + assert str(url.extend_query({"a": "1"})) == "http://example.com/?a=2&a=1" + assert str(URL("test").extend_query(a=1)) == "test?a=1" + + url = URL("http://example.com/?foo=bar&baz=original") + expected_url = URL("http://example.com/?foo=bar&baz=original&baz=foo") + + assert url.extend_query({"baz": "foo"}) == expected_url + assert url.extend_query(baz="foo") == expected_url + assert url.extend_query("baz=foo") == expected_url + + +def test_extend_query_with_args_and_kwargs_with_existing(): + url = URL("http://example.com/?a=original") + + with pytest.raises(ValueError): + url.extend_query("a", foo="bar") + + +def test_extend_query_with_non_ascii(): + url = URL("http://example.com/?foo=bar&baz=foo") + expected = URL("http://example.com/?foo=bar&baz=foo&%F0%9D%95%A6=%F0%9D%95%A6") + assert url.extend_query({"𝕦": "𝕦"}) == expected + + +def test_extend_query_with_non_ascii_as_str(): + url = URL("http://example.com/?foo=bar&baz=foo&") + expected = URL("http://example.com/?foo=bar&baz=foo&%F0%9D%95%A6=%F0%9D%95%A6") + assert url.extend_query("𝕦=𝕦") == expected + + +def test_extend_query_with_non_ascii_same_key(): + url = URL("http://example.com/?foo=bar&baz=foo&%F0%9D%95%A6=%F0%9D%95%A6") + expected = URL( + "http://example.com/?foo=bar&baz=foo" + "&%F0%9D%95%A6=%F0%9D%95%A6&%F0%9D%95%A6=%F0%9D%95%A6" + ) + assert url.extend_query({"𝕦": "𝕦"}) == expected diff --git a/tests/test_url.py b/tests/test_url.py index 2d4f1cb..49245b8 100644 --- a/tests/test_url.py +++ b/tests/test_url.py @@ -1,4 +1,5 @@ -from urllib.parse import SplitResult +from enum import Enum +from urllib.parse import SplitResult, quote, unquote import pytest @@ -8,7 +9,7 @@ def test_inheritance(): with pytest.raises(TypeError) as ctx: - class MyURL(URL): # type: ignore[misc] + class MyURL(URL): pass assert ( @@ -63,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(): @@ -113,11 +114,13 @@ def test_scheme(): def test_raw_user(): url = URL("http://user@example.com") assert "user" == url.raw_user + assert url.raw_user == url._val.username 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 + assert url.raw_user == url._val.username def test_no_user(): @@ -126,18 +129,20 @@ 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(): url = URL("http://user:password@example.com") assert "password" == url.raw_password + assert url.raw_password == url._val.password def test_raw_password_non_ascii(): url = URL("http://user:пароль@example.com") assert "%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" == url.raw_password + assert url.raw_password == url._val.password def test_password_non_ascii(): @@ -151,6 +156,14 @@ def test_password_without_user(): assert "password" == url.password +def test_empty_password_without_user(): + url = URL("http://:@example.com") + assert url.user is None + assert url.password == "" + assert url.raw_password == "" + assert url.raw_password == url._val.password + + def test_user_empty_password(): url = URL("http://user:@example.com") assert "user" == url.user @@ -160,16 +173,36 @@ def test_user_empty_password(): def test_raw_host(): url = URL("http://example.com") assert "example.com" == url.raw_host + assert url.raw_host == url._val.hostname + + +@pytest.mark.parametrize( + ("host"), + [ + ("example.com"), + ("[::1]"), + ("xn--gnter-4ya.com"), + ], +) +def test_host_subcomponent(host: str): + url = URL(f"http://{host}") + assert url.host_subcomponent == host + + +def test_host_subcomponent_return_idna_encoded_host(): + url = URL("http://оун-упа.укр") + assert url.host_subcomponent == "xn----8sb1bdhvc.xn--j1amh" 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 + assert url.raw_host == url._val.hostname def test_host_non_ascii(): - url = URL("http://историк.рф") - assert "историк.рф" == url.host + url = URL("http://оун-упа.укр") + assert "оун-упа.укр" == url.host def test_localhost(): @@ -185,16 +218,19 @@ def test_host_with_underscore(): def test_raw_host_when_port_is_specified(): url = URL("http://example.com:8888") assert "example.com" == url.raw_host + assert url.raw_host == url._val.hostname def test_raw_host_from_str_with_ipv4(): url = URL("http://127.0.0.1:80") assert url.raw_host == "127.0.0.1" + assert url.raw_host == url._val.hostname def test_raw_host_from_str_with_ipv6(): url = URL("http://[::1]:80") assert url.raw_host == "::1" + assert url.raw_host == url._val.hostname def test_authority_full() -> None: @@ -209,36 +245,40 @@ 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_authority_unknown_scheme() -> None: + v = "scheme://user:password@example.com:43/path/to?a=1&b=2" + url = URL(v) + assert str(url) == v def test_lowercase(): url = URL("http://gitHUB.com") assert url.raw_host == "github.com" assert url.host == url.raw_host + assert url.raw_host == url._val.hostname 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.raw_host == url._val.hostname + assert url.host == "слава.укр" def test_compressed_ipv6(): url = URL("http://[1DEC:0:0:0::1]") assert url.raw_host == "1dec::1" assert url.host == url.raw_host - - -def test_ipv6_zone(): - url = URL("http://[fe80::822a:a8ff:fe49:470c%тест%42]:123") - assert url.raw_host == "fe80::822a:a8ff:fe49:470c%тест%42" - assert url.host == url.raw_host + assert url.raw_host == url._val.hostname def test_ipv4_zone(): @@ -246,16 +286,19 @@ def test_ipv4_zone(): url = URL("http://1.2.3.4%тест%42:123") assert url.raw_host == "1.2.3.4%тест%42" assert url.host == url.raw_host + assert url.raw_host == url._val.hostname def test_port_for_explicit_port(): url = URL("http://example.com:8888") assert 8888 == url.port + assert url.explicit_port == url._val.port def test_port_for_implicit_port(): url = URL("http://example.com") assert 80 == url.port + assert url.explicit_port == url._val.port def test_port_for_relative_url(): @@ -271,21 +314,25 @@ def test_port_for_unknown_scheme(): def test_explicit_port_for_explicit_port(): url = URL("http://example.com:8888") assert 8888 == url.explicit_port + assert url.explicit_port == url._val.port def test_explicit_port_for_implicit_port(): url = URL("http://example.com") assert url.explicit_port is None + assert url.explicit_port == url._val.port def test_explicit_port_for_relative_url(): url = URL("/path/to") assert url.explicit_port is None + assert url.explicit_port == url._val.port def test_explicit_port_for_unknown_scheme(): url = URL("unknown://example.com") assert url.explicit_port is None + assert url.explicit_port == url._val.port def test_raw_path_string_empty(): @@ -299,13 +346,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(): @@ -316,6 +363,49 @@ def test_path_with_spaces(): assert "/a b" == url.path +def test_path_with_2F(): + """Path should decode %2F.""" + + url = URL("http://example.com/foo/bar%2fbaz") + assert url.path == "/foo/bar/baz" + + +def test_path_safe_with_2F(): + """Path safe should not decode %2F, otherwise it may look like a path separator.""" + + url = URL("http://example.com/foo/bar%2fbaz") + assert url.path_safe == "/foo/bar%2Fbaz" + + +def test_path_safe_with_25(): + """Path safe should not decode %25, otherwise it is prone to double unquoting.""" + + url = URL("http://example.com/foo/bar%252Fbaz") + assert url.path_safe == "/foo/bar%252Fbaz" + unquoted = url.path_safe.replace("%2F", "/").replace("%25", "%") + assert unquoted == "/foo/bar%2Fbaz" + + +@pytest.mark.parametrize( + "original_path", + [ + "m+@bar/baz", + "m%2B@bar/baz", + "m%252B@bar/baz", + "m%2F@bar/baz", + ], +) +def test_path_safe_only_round_trips(original_path: str) -> None: + """Path safe can round trip with documented decode method.""" + encoded_once = quote(original_path, safe="") + encoded_twice = quote(encoded_once, safe="") + + url = URL(f"http://example.com/{encoded_twice}") + unquoted = url.path_safe.replace("%2F", "/").replace("%25", "%") + assert unquoted == f"/{encoded_once}" + assert unquote(unquoted) == f"/{original_path}" + + def test_raw_path_for_empty_url(): url = URL() assert "" == url.raw_path @@ -357,8 +447,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(): @@ -380,8 +470,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(): @@ -390,8 +480,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(): @@ -431,7 +521,7 @@ def test_raw_parts_for_relative_path_starting_from_slash(): def test_raw_parts_for_relative_double_path(): url = URL("path/to") - assert url.raw_parts == url.raw_parts + assert ("path", "to") == url.raw_parts def test_parts_for_empty_url(): @@ -440,17 +530,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(): @@ -494,8 +584,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(): @@ -539,8 +629,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(): @@ -599,8 +689,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(): @@ -690,23 +780,27 @@ def test_clear_query_on_getting_parent_toplevel(): def test_div_root(): - url = URL("http://example.com") - assert str(url / "path" / "to") == "http://example.com/path/to" + url = URL("http://example.com") / "path" / "to" + assert str(url) == "http://example.com/path/to" + assert url.raw_path == "/path/to" def test_div_root_with_slash(): - url = URL("http://example.com/") - assert str(url / "path" / "to") == "http://example.com/path/to" + url = URL("http://example.com/") / "path" / "to" + assert str(url) == "http://example.com/path/to" + assert url.raw_path == "/path/to" def test_div(): - url = URL("http://example.com/path") - assert str(url / "to") == "http://example.com/path/to" + url = URL("http://example.com/path") / "to" + assert str(url) == "http://example.com/path/to" + assert url.raw_path == "/path/to" def test_div_with_slash(): - url = URL("http://example.com/path/") - assert str(url / "to") == "http://example.com/path/to" + url = URL("http://example.com/path/") / "to" + assert str(url) == "http://example.com/path/to" + assert url.raw_path == "/path/to" def test_div_path_starting_from_slash_is_forbidden(): @@ -715,6 +809,24 @@ def test_div_path_starting_from_slash_is_forbidden(): url / "/to/others" +class StrEnum(str, Enum): + spam = "ham" + + def __str__(self): + return self.value + + +def test_div_path_srting_subclass(): + url = URL("http://example.com/path/") / StrEnum.spam + assert str(url) == "http://example.com/path/ham" + + +def test_div_bad_type(): + url = URL("http://example.com/path/") + with pytest.raises(TypeError): + url / 3 + + def test_div_cleanup_query_and_fragment(): url = URL("http://example.com/path?a=1#frag") assert str(url / "to") == "http://example.com/path/to" @@ -736,15 +848,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", ) @@ -767,6 +879,203 @@ def test_div_with_dots(): assert url.raw_path == "/path/to" +# joinpath + + +@pytest.mark.parametrize( + "base,to_join,expected", + [ + pytest.param("", ("path", "to"), "http://example.com/path/to", id="root"), + pytest.param( + "/", ("path", "to"), "http://example.com/path/to", id="root-with-slash" + ), + pytest.param("/path", ("to",), "http://example.com/path/to", id="path"), + pytest.param( + "/path/", ("to",), "http://example.com/path/to", id="path-with-slash" + ), + pytest.param( + "/path", ("",), "http://example.com/path/", id="path-add-trailing-slash" + ), + pytest.param( + "/path?a=1#frag", + ("to",), + "http://example.com/path/to", + id="cleanup-query-and-fragment", + ), + pytest.param("", ("path/",), "http://example.com/path/", id="trailing-slash"), + pytest.param( + "", + ( + "path", + "", + ), + "http://example.com/path/", + id="trailing-slash-empty-string", + ), + pytest.param( + "", ("path/", "to/"), "http://example.com/path/to/", id="duplicate-slash" + ), + pytest.param("", (), "http://example.com", id="empty-segments"), + pytest.param( + "/", ("path/",), "http://example.com/path/", id="base-slash-trailing-slash" + ), + pytest.param( + "/", + ("path/", "to/"), + "http://example.com/path/to/", + id="base-slash-duplicate-slash", + ), + pytest.param("/", (), "http://example.com", id="base-slash-empty-segments"), + ], +) +def test_joinpath(base, to_join, expected): + url = URL(f"http://example.com{base}") + assert str(url.joinpath(*to_join)) == expected + + +@pytest.mark.parametrize( + "base,to_join,expected", + [ + pytest.param("path", "a", "path/a", id="default_default"), + pytest.param("path", "./a", "path/a", id="default_relative"), + pytest.param("path/", "a", "path/a", id="empty-segment_default"), + pytest.param("path/", "./a", "path/a", id="empty-segment_relative"), + pytest.param("path", ".//a", "path//a", id="default_empty-segment"), + pytest.param("path/", ".//a", "path//a", id="empty-segment_empty_segment"), + pytest.param("path//", "a", "path//a", id="empty-segments_default"), + pytest.param("path//", "./a", "path//a", id="empty-segments_relative"), + pytest.param("path//", ".//a", "path///a", id="empty-segments_empty-segment"), + pytest.param("path", "a/", "path/a/", id="default_trailing-empty-segment"), + pytest.param("path", "a//", "path/a//", id="default_trailing-empty-segments"), + pytest.param("path", "a//b", "path/a//b", id="default_embedded-empty-segment"), + ], +) +def test_joinpath_empty_segments(base, to_join, expected): + url = URL(f"http://example.com/{base}") + assert ( + f"http://example.com/{expected}" == str(url.joinpath(to_join)) + and str(url / to_join) == f"http://example.com/{expected}" + ) + + +def test_joinpath_single_empty_segments(): + """joining standalone empty segments does not create empty segments""" + a = URL("/1//2///3") + assert a.parts == ("/", "1", "", "2", "", "", "3") + b = URL("scheme://host").joinpath(*a.parts[1:]) + assert b.path == "/1/2/3" + + +@pytest.mark.parametrize( + "url,to_join,expected", + [ + pytest.param(URL(), ("a",), ("a",), id="empty-url"), + pytest.param(URL("a"), ("b",), ("a", "b"), id="relative-path"), + pytest.param(URL("a"), ("b", "", "c"), ("a", "b", "c"), id="empty-element"), + pytest.param(URL("/a"), ("b"), ("/", "a", "b"), id="absolute-path"), + pytest.param(URL(), ("a/",), ("a", ""), id="trailing-slash"), + pytest.param(URL(), ("a/", "b/"), ("a", "b", ""), id="duplicate-slash"), + pytest.param(URL(), (), ("",), id="empty-segments"), + ], +) +def test_joinpath_relative(url, to_join, expected): + assert url.joinpath(*to_join).raw_parts == expected + + +@pytest.mark.parametrize( + "url,to_join,encoded,e_path,e_raw_path,e_parts,e_raw_parts", + [ + pytest.param( + "http://example.com/сюди", + ("туди",), + False, + "/сюди/туди", + "/%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( + "http://example.com/path", + ("%cf%80",), + False, + "/path/%cf%80", + "/path/%25cf%2580", + ("/", "path", "%cf%80"), + ("/", "path", "%25cf%2580"), + id="percent-encoded", + ), + pytest.param( + "http://example.com/path", + ("%cf%80",), + True, + "/path/π", + "/path/%cf%80", + ("/", "path", "π"), + ("/", "path", "%cf%80"), + id="encoded-percent-encoded", + ), + ], +) +def test_joinpath_encoding( + url, to_join, encoded, e_path, e_raw_path, e_parts, e_raw_parts +): + joined = URL(url).joinpath(*to_join, encoded=encoded) + assert joined.path == e_path + assert joined.raw_path == e_raw_path + assert joined.parts == e_parts + assert joined.raw_parts == e_raw_parts + + +@pytest.mark.parametrize( + "to_join,expected", + [ + pytest.param(("path:abc@123",), "/base/path:abc@123", id="with-colon-and-at"), + pytest.param(("..", "path", ".", "to"), "/path/to", id="with-dots"), + ], +) +def test_joinpath_edgecases(to_join, expected): + url = URL("http://example.com/base").joinpath(*to_join) + assert url.raw_path == expected + + +def test_joinpath_path_starting_from_slash_is_forbidden(): + url = URL("http://example.com/path/") + with pytest.raises( + ValueError, match="Appending path .* starting from slash is forbidden" + ): + assert url.joinpath("/to/others") + + +PATHS = [ + # No dots + ("", ""), + ("path", "path"), + # Single-dot + ("path/to", "path/to"), + ("././path/to", "path/to"), + ("path/./to", "path/to"), + ("path/././to", "path/to"), + ("path/to/.", "path/to/"), + ("path/to/./.", "path/to/"), + # Double-dots + ("../path/to", "path/to"), + ("path/../to", "to"), + ("path/../../to", "to"), + # Non-ASCII characters + ("μονοπάτι/../../να/ᴜɴɪ/ᴄᴏᴅᴇ", "να/ᴜɴɪ/ᴄᴏᴅᴇ"), + ("μονοπάτι/../../να/𝕦𝕟𝕚/𝕔𝕠𝕕𝕖/.", "να/𝕦𝕟𝕚/𝕔𝕠𝕕𝕖/"), +] + + +@pytest.mark.parametrize("original,expected", PATHS) +def test_join_path_normalized(original: str, expected: str) -> None: + """Test that joinpath normalizes paths.""" + base_url = URL("http://example.com") + new_url = base_url.joinpath(original) + assert new_url.path == f"/{expected}" + + # with_path @@ -953,11 +1262,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(): @@ -1045,11 +1354,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(): @@ -1108,26 +1417,31 @@ def test_with_suffix_replace(): def test_is_absolute_for_relative_url(): url = URL("/path/to") assert not url.is_absolute() + assert not url.absolute def test_is_absolute_for_absolute_url(): url = URL("http://example.com") assert url.is_absolute() + assert url.absolute def test_is_non_absolute_for_empty_url(): url = URL() assert not url.is_absolute() + assert not url.absolute def test_is_non_absolute_for_empty_url2(): url = URL("") assert not url.is_absolute() + assert not url.absolute def test_is_absolute_path_starting_from_double_slash(): url = URL("//www.python.org") assert url.is_absolute() + assert url.absolute # is_default_port @@ -1146,6 +1460,7 @@ def test_is_default_port_for_absolute_url_without_port(): def test_is_default_port_for_absolute_url_with_default_port(): url = URL("http://example.com:80") assert url.is_default_port() + assert str(url) == "http://example.com" def test_is_default_port_for_absolute_url_with_nondefault_port(): @@ -1200,8 +1515,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(): @@ -1220,10 +1535,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) @@ -1244,16 +1559,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) ) @@ -1464,29 +1779,112 @@ def test_join_from_rfc_3986_abnormal(url, expected): assert base.join(url) == expected +EMPTY_SEGMENTS = [ + ( + "https://web.archive.org/web/", + "./https://github.com/aio-libs/yarl", + "https://web.archive.org/web/https://github.com/aio-libs/yarl", + ), + ( + "https://web.archive.org/web/https://github.com/", + "aio-libs/yarl", + "https://web.archive.org/web/https://github.com/aio-libs/yarl", + ), +] + + +@pytest.mark.parametrize("base,url,expected", EMPTY_SEGMENTS) +def test_join_empty_segments(base, url, expected): + base = URL(base) + url = URL(url) + expected = URL(expected) + joined = base.join(url) + assert joined == expected + + +SIMPLE_BASE = "http://a/b/c/d" +URLLIB_URLJOIN = [ + ("", "http://a/b/c/g?y/./x", "http://a/b/c/g?y/./x"), + ("", "http://a/./g", "http://a/./g"), + ("svn://pathtorepo/dir1", "dir2", "svn://pathtorepo/dir2"), + ("svn+ssh://pathtorepo/dir1", "dir2", "svn+ssh://pathtorepo/dir2"), + ("ws://a/b", "g", "ws://a/g"), + ("wss://a/b", "g", "wss://a/g"), + # test for issue22118 duplicate slashes + (SIMPLE_BASE + "/", "foo", SIMPLE_BASE + "/foo"), + # Non-RFC-defined tests, covering variations of base and trailing + # slashes + ("http://a/b/c/d/e/", "../../f/g/", "http://a/b/c/f/g/"), + ("http://a/b/c/d/e", "../../f/g/", "http://a/b/f/g/"), + ("http://a/b/c/d/e/", "/../../f/g/", "http://a/f/g/"), + ("http://a/b/c/d/e", "/../../f/g/", "http://a/f/g/"), + ("http://a/b/c/d/e/", "../../f/g", "http://a/b/c/f/g"), + ("http://a/b/", "../../f/g/", "http://a/f/g/"), + ("a", "b", "b"), + ("http:///", "..", "http:///"), + ("a/", "b", "a/b"), + ("a/b", "c", "a/c"), + ("a/b/", "c", "a/b/c"), + ( + "https://x.org/", + "/?text=Hello+G%C3%BCnter", + "https://x.org/?text=Hello+G%C3%BCnter", + ), + ( + "https://x.org/", + "?text=Hello+G%C3%BCnter", + "https://x.org/?text=Hello+G%C3%BCnter", + ), + ("http://example.com", "http://example.com", "http://example.com"), + ("http://x.org", "https://x.org#fragment", "https://x.org#fragment"), +] + + +@pytest.mark.parametrize("base,url,expected", URLLIB_URLJOIN) +def test_join_cpython_urljoin(base, url, expected): + # tests from cpython urljoin + base = URL(base) + url = URL(url) + expected = URL(expected) + joined = base.join(url) + assert joined == expected + + +def test_join_preserves_leading_slash(): + """Test that join preserves leading slash in path.""" + base = URL.build(scheme="https", host="localhost", port=443) + new = base.join(URL("") / "_msearch") + assert str(new) == "https://localhost/_msearch" + assert new.path == "/_msearch" + + +def test_empty_authority(): + assert URL("http:///").authority == "" + + def test_split_result_non_decoded(): with pytest.raises(ValueError): URL(SplitResult("http", "example.com", "path", "qs", "frag")) 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(): @@ -1514,8 +1912,8 @@ def test_human_repr_delimiters(): s = url.human_repr() assert URL(s) == url assert ( - s == "http:// !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~" - ": !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~" + s == "http:// !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40%5B\\%5D^_`{|}~" + ": !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40%5B\\%5D^_`{|}~" "@хост.домен:8080" "/ !\"%23$%25&'()*+,-./:;<=>%3F@[\\]^_`{|}~" "? !\"%23$%25%26'()*%2B,-./:%3B<%3D>?@[\\]^_`{|}~" @@ -1527,20 +1925,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" ) @@ -1559,6 +1957,7 @@ def test_relative_is_relative(): url = URL("http://user:pass@example.com:8080/path?a=b#frag") rel = url.relative() assert not rel.is_absolute() + assert not rel.absolute def test_relative_abs_parts_are_removed(): @@ -1590,3 +1989,83 @@ def test_requoting(): u = URL("http://127.0.0.1/?next=http%3A//example.com/") assert u.raw_query_string == "next=http://example.com/" assert str(u) == "http://127.0.0.1/?next=http://example.com/" + + +def test_join_query_string(): + """Test that query strings are correctly joined.""" + original = URL("http://127.0.0.1:62869") + path_url = URL( + "/api?start=2022-03-27T14:05:00%2B03:00&end=2022-03-27T16:05:00%2B03:00" + ) + assert path_url.query.get("start") == "2022-03-27T14:05:00+03:00" + assert path_url.query.get("end") == "2022-03-27T16:05:00+03:00" + new = original.join(path_url) + assert new.query.get("start") == "2022-03-27T14:05:00+03:00" + assert new.query.get("end") == "2022-03-27T16:05:00+03:00" + + +def test_join_query_string_with_special_chars(): + """Test url joining when the query string has non-ascii params.""" + original = URL("http://127.0.0.1") + path_url = URL("/api?text=%D1%82%D0%B5%D0%BA%D1%81%D1%82") + assert path_url.query.get("text") == "текст" + new = original.join(path_url) + assert new.query.get("text") == "текст" + + +def test_join_encoded_url(): + """Test that url encoded urls are correctly joined.""" + original = URL("http://127.0.0.1:62869") + path_url = URL("/api/%34") + assert original.path == "/" + assert path_url.path == "/api/4" + new = original.join(path_url) + assert new.path == "/api/4" + + +# cache + + +def test_parsing_populates_cache(): + """Test that parsing a URL populates the cache.""" + url = URL("http://user:password@example.com:80/path?a=b#frag") + assert url._cache["raw_user"] == "user" + assert url._cache["raw_password"] == "password" + assert url._cache["raw_host"] == "example.com" + assert url._cache["explicit_port"] == 80 + assert url._cache["raw_query_string"] == "a=b" + assert url._cache["raw_fragment"] == "frag" + assert url._cache["scheme"] == "http" + assert url.raw_user == "user" + assert url.raw_password == "password" + assert url.raw_host == "example.com" + assert url.explicit_port == 80 + assert url.raw_query_string == "a=b" + assert url.raw_fragment == "frag" + assert url.scheme == "http" + url._cache.clear() + assert url.raw_user == "user" + assert url.raw_password == "password" + assert url.raw_host == "example.com" + assert url.explicit_port == 80 + assert url.raw_query_string == "a=b" + assert url.raw_fragment == "frag" + assert url.scheme == "http" + assert url._cache["raw_user"] == "user" + assert url._cache["raw_password"] == "password" + assert url._cache["raw_host"] == "example.com" + assert url._cache["explicit_port"] == 80 + assert url._cache["raw_query_string"] == "a=b" + assert url._cache["raw_fragment"] == "frag" + assert url._cache["scheme"] == "http" + + +@pytest.mark.parametrize( + ("host", "is_authority"), + [ + *(("other_gen_delim_" + c, False) for c in "[]"), + ], +) +def test_build_with_invalid_ipv6_host(host: str, is_authority: bool): + with pytest.raises(ValueError, match="Invalid IPv6 URL"): + URL(f"http://{host}/") diff --git a/tests/test_url_build.py b/tests/test_url_build.py index fc9ccc1..cc9b15f 100644 --- a/tests/test_url_build.py +++ b/tests/test_url_build.py @@ -15,6 +15,26 @@ def test_build_simple(): assert str(u) == "http://127.0.0.1" +def test_url_build_ipv6(): + u = URL.build(scheme="http", host="::1") + assert str(u) == "http://[::1]" + + +def test_url_build_ipv6_brackets_encoded(): + u = URL.build(scheme="http", host="[::1]", encoded=True) + assert str(u) == "http://[::1]" + + +def test_url_build_ipv6_brackets_not_encoded(): + u = URL.build(scheme="http", host="::1", encoded=False) + assert str(u) == "http://[::1]" + + +def test_url_ipv4_in_ipv6(): + u = URL.build(scheme="http", host="2001:db8:122:344::192.0.2.33") + assert str(u) == "http://[2001:db8:122:344::c000:221]" + + def test_build_with_scheme(): u = URL.build(scheme="blob", path="path") assert str(u) == "blob:path" @@ -32,12 +52,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(): @@ -84,9 +120,30 @@ def test_build_with_authority_and_host(): URL.build(authority="host.com", host="example.com") +@pytest.mark.parametrize( + ("host", "is_authority"), + [ + ("user:pass@host.com", True), + ("user@host.com", True), + ("host:com", False), + ("not_percent_encoded%Zf", False), + ("still_not_percent_encoded%fZ", False), + *(("other_gen_delim_" + c, False) for c in "/?#[]"), + ], +) +def test_build_with_invalid_host(host: str, is_authority: bool): + match = r"Host '[^']+' cannot contain '[^']+' \(at position \d+\)" + if is_authority: + match += ", if .* use 'authority' instead of 'host'" + with pytest.raises(ValueError, match=f"{match}$"): + URL.build(host=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(): @@ -96,6 +153,31 @@ def test_build_with_authority_without_encoding(): assert str(url) == "http://foo:bar@host.com:8000/path" +def test_build_with_authority_empty_host_no_scheme(): + url = URL.build(authority="", path="path") + assert str(url) == "path" + + +def test_build_with_authority_and_only_user(): + url = URL.build(scheme="https", authority="user:@foo.com", path="/path") + assert str(url) == "https://user:@foo.com/path" + + +def test_build_with_authority_with_port(): + url = URL.build(scheme="https", authority="foo.com:8080", path="/path") + assert str(url) == "https://foo.com:8080/path" + + +def test_build_with_authority_with_ipv6(): + url = URL.build(scheme="https", authority="[::1]", path="/path") + assert str(url) == "https://[::1]/path" + + +def test_build_with_authority_with_ipv6_and_port(): + url = URL.build(scheme="https", authority="[::1]:81", path="/path") + assert str(url) == "https://[::1]:81/path" + + def test_query_str(): u = URL.build(scheme="http", host="127.0.0.1", path="/", query_string="arg=value1") assert str(u) == "http://127.0.0.1/?arg=value1" @@ -109,23 +191,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 +235,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 +253,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(): @@ -239,6 +331,11 @@ def test_build_with_authority_with_path_without_leading_slash(): URL.build(scheme="http", host="example.com", path="path_without_leading_slash") +def test_build_with_none_host(): + with pytest.raises(TypeError, match="NoneType is illegal for.*host"): + URL.build(scheme="http", host=None) + + def test_build_with_none_path(): with pytest.raises(TypeError): URL.build(scheme="http", host="example.com", path=None) diff --git a/tests/test_url_parsing.py b/tests/test_url_parsing.py index 0a7f5f1..0d58c9d 100644 --- a/tests/test_url_parsing.py +++ b/tests/test_url_parsing.py @@ -41,11 +41,7 @@ def test_scheme_only(self): def test_no_scheme1(self): u = URL("google.com:80") # See: https://bugs.python.org/issue27657 - if ( - sys.version_info[:3] == (3, 7, 6) - or sys.version_info[:3] == (3, 8, 1) - or sys.version_info >= (3, 9, 0) - ): + if sys.version_info[:3] == (3, 8, 1) or sys.version_info >= (3, 9, 0): assert u.scheme == "google.com" assert u.host is None assert u.path == "80" @@ -73,8 +69,8 @@ def test_not_a_scheme1(self): assert u.fragment == "" def test_not_a_scheme2(self): - u = URL("37signals:book") - assert u.scheme == "37signals" + u = URL("signals37:book") + assert u.scheme == "signals37" assert u.host is None assert u.path == "book" assert u.query_string == "" @@ -178,14 +174,6 @@ def test_ipv4(self): assert u.query_string == "" assert u.fragment == "" - def test_masked_ipv4(self): - u = URL("//[127.0.0.1]/") - assert u.scheme == "" - assert u.host == "127.0.0.1" - assert u.path == "/" - assert u.query_string == "" - assert u.fragment == "" - def test_ipv6(self): u = URL("//[::1]/") assert u.scheme == "" @@ -194,15 +182,7 @@ def test_ipv6(self): assert u.query_string == "" assert u.fragment == "" - def test_strange_ip(self): - u = URL("//[-1]/") - assert u.scheme == "" - assert u.host == "-1" - assert u.path == "/" - assert u.query_string == "" - assert u.fragment == "" - - def test_strange_ip_2(self): + def test_ipvfuture_address(self): u = URL("//[v1.-1]/") assert u.scheme == "" assert u.host == "v1.-1" @@ -210,14 +190,6 @@ def test_strange_ip_2(self): assert u.query_string == "" assert u.fragment == "" - def test_strange_ip_3(self): - u = URL("//v1.[::1]/") - assert u.scheme == "" - assert u.host == "::1" - assert u.path == "/" - assert u.query_string == "" - assert u.fragment == "" - class TestPort: def test_canonical(self): @@ -239,8 +211,13 @@ def test_no_path(self): assert u.fragment == "" def test_no_host(self): - with pytest.raises(ValueError): - URL("//:80") + u = URL("//:77") + assert u.scheme == "" + assert u.host == "" + assert u.port == 77 + assert u.path == "/" + assert u.query_string == "" + assert u.fragment == "" def test_double_port(self): with pytest.raises(ValueError): @@ -320,7 +297,7 @@ def test_weird_user2(self): assert u.fragment == "" def test_weird_user3(self): - u = URL("//[some]@host") + u = URL("//%5Bsome%5D@host") assert u.scheme == "" assert u.user == "[some]" assert u.password is None @@ -475,9 +452,19 @@ def test_complex_frag(self): class TestStripEmptyParts: - def test_all_empty(self): + def test_all_empty_http(self): with pytest.raises(ValueError): - URL("//@:?#") + URL("http://@:?#") + + def test_all_empty(self): + u = URL("//@:?#") + assert u.scheme == "" + assert u.user is None + assert u.password is None + assert u.host == "" + assert u.path == "" + assert u.query_string == "" + assert u.fragment == "" def test_path_only(self): u = URL("///path") @@ -598,3 +585,47 @@ def test_empty_path(self): assert u.path == "" assert u.query_string == "" assert u.fragment == "" + + +@pytest.mark.parametrize( + ("scheme"), + [ + ("http"), + ("https"), + ("ws"), + ("wss"), + ("ftp"), + ], +) +def test_schemes_that_require_host(scheme: str) -> None: + """Verify that schemes that require a host raise with empty host.""" + expect = ( + "Invalid URL: host is required for " f"absolute urls with the {scheme} scheme" + ) + with pytest.raises(ValueError, match=expect): + URL(f"{scheme}://:1") + + +@pytest.mark.parametrize( + ("url", "hostname", "hostname_without_brackets"), + [ + ("http://[::1]", "[::1]", "::1"), + ("http://[::1]:8080", "[::1]", "::1"), + ("http://127.0.0.1:8080", "127.0.0.1", "127.0.0.1"), + ( + "http://xn--jxagkqfkduily1i.eu", + "xn--jxagkqfkduily1i.eu", + "xn--jxagkqfkduily1i.eu", + ), + ], +) +def test_url_round_trips( + url: str, hostname: str, hostname_without_brackets: str +) -> None: + """Verify that URLs round-trip correctly.""" + parsed = URL(url) + assert parsed._val.hostname == hostname_without_brackets + assert parsed.raw_host == hostname_without_brackets + assert parsed.host_subcomponent == hostname + assert str(parsed) == url + assert str(URL(str(parsed))) == url diff --git a/tests/test_url_query.py b/tests/test_url_query.py index 776fea1..cf4959e 100644 --- a/tests/test_url_query.py +++ b/tests/test_url_query.py @@ -1,36 +1,71 @@ -from urllib.parse import urlencode +from typing import List, Sequence, Tuple +from urllib.parse import parse_qs, urlencode +import pytest from multidict import MultiDict, MultiDictProxy from yarl import URL -# query - - -def test_query_spaces(): - url = URL("http://example.com?a+b=c+d") - assert url.query == MultiDict({"a b": "c d"}) - - -def test_query_empty(): - url = URL("http://example.com") - assert isinstance(url.query, MultiDictProxy) - assert url.query == MultiDict() - - -def test_query(): - url = URL("http://example.com?a=1&b=2") - assert url.query == MultiDict([("a", "1"), ("b", "2")]) - - -def test_query_repeated_args(): - url = URL("http://example.com?a=1&b=2&a=3") - assert url.query == MultiDict([("a", "1"), ("b", "2"), ("a", "3")]) - - -def test_query_empty_arg(): - url = URL("http://example.com?a") - assert url.query == MultiDict([("a", "")]) +# ======================================== +# Basic chars in query values +# ======================================== + +URLS_WITH_BASIC_QUERY_VALUES: List[Tuple[URL, MultiDict]] = [ + # Empty strings, keys and values + ( + URL("http://example.com"), + MultiDict(), + ), + ( + URL("http://example.com?a="), + MultiDict([("a", "")]), + ), + # ASCII chars + ( + URL("http://example.com?a+b=c+d"), + MultiDict({"a b": "c d"}), + ), + ( + URL("http://example.com?a=1&b=2"), + MultiDict([("a", "1"), ("b", "2")]), + ), + ( + URL("http://example.com?a=1&b=2&a=3"), + MultiDict([("a", "1"), ("b", "2"), ("a", "3")]), + ), + # Non-ASCI BMP chars + ( + URL("http://example.com?ключ=знач"), + MultiDict({"ключ": "знач"}), + ), + ( + URL("http://example.com?foo=ᴜɴɪᴄᴏᴅᴇ"), + MultiDict({"foo": "ᴜɴɪᴄᴏᴅᴇ"}), + ), + # Non-BMP chars + ( + URL("http://example.com?bar=𝕦𝕟𝕚𝕔𝕠𝕕𝕖"), + MultiDict({"bar": "𝕦𝕟𝕚𝕔𝕠𝕕𝕖"}), + ), +] + + +@pytest.mark.parametrize( + "original_url, expected_query", + URLS_WITH_BASIC_QUERY_VALUES, +) +def test_query_basic_parsing(original_url, expected_query): + assert isinstance(original_url.query, MultiDictProxy) + assert original_url.query == expected_query + + +@pytest.mark.parametrize( + "original_url, expected_query", + URLS_WITH_BASIC_QUERY_VALUES, +) +def test_query_basic_update_query(original_url, expected_query): + new_url = original_url.update_query({}) + assert new_url == original_url def test_query_dont_unqoute_twice(): @@ -42,20 +77,135 @@ def test_query_dont_unqoute_twice(): assert url.query["url"] == sample_url -def test_query_nonascii(): - url = URL("http://example.com?ключ=знач") - assert url.query == MultiDict({"ключ": "знач"}) - - -# query separators - - -def test_ampersand_as_separator(): - u = URL("http://127.0.0.1/?a=1&b=2") - assert len(u.query) == 2 - - -def test_ampersand_as_value(): - u = URL("http://127.0.0.1/?a=1%26b=2") - assert len(u.query) == 1 - assert u.query["a"] == "1&b=2" +# ======================================== +# Reserved chars in query values +# ======================================== + +# See https://github.com/python/cpython#87133, which introduced a new +# `separator` keyword argument to `urllib.parse.parse_qs` (among others). +# If the name doesn't exist as a variable in the function bytecode, the +# test is expected to fail. +_SEMICOLON_XFAIL = pytest.mark.xfail( + condition="separator" not in parse_qs.__code__.co_varnames, + reason=( + "Python versions < 3.8.8 and < 3.9.2 lack a fix for " + 'CVE-2021-23336 dropping ";" as a valid query parameter separator, ' + "making this test fail." + ), + strict=True, +) + + +URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES = [ + # Ampersand + (URL("http://127.0.0.1/?a=10&b=20"), 2, "10"), + (URL("http://127.0.0.1/?a=10%26b=20"), 1, "10&b=20"), + (URL("http://127.0.0.1/?a=10%3Bb=20"), 1, "10;b=20"), + # Semicolon, which is *not* a query parameter separator as of RFC3986 + (URL("http://127.0.0.1/?a=10;b=20"), 1, "10;b=20"), + (URL("http://127.0.0.1/?a=10%26b=20"), 1, "10&b=20"), + (URL("http://127.0.0.1/?a=10%3Bb=20"), 1, "10;b=20"), +] +URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES_W_XFAIL = [ + # Ampersand + *URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES[:3], + # Semicolon, which is *not* a query parameter separator as of RFC3986 + # Mark the first of these as expecting to fail on old Python patch releases. + pytest.param(*URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES[3], marks=_SEMICOLON_XFAIL), + *URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES[4:], +] + + +@pytest.mark.parametrize( + "original_url, expected_query_len, expected_value_a", + URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES_W_XFAIL, +) +def test_query_separators_from_parsing( + original_url, + expected_query_len, + expected_value_a, +): + assert len(original_url.query) == expected_query_len + assert original_url.query["a"] == expected_value_a + + +@pytest.mark.parametrize( + "original_url, expected_query_len, expected_value_a", + URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES_W_XFAIL, +) +def test_query_separators_from_update_query( + original_url: URL, + expected_query_len: int, + expected_value_a: str, +) -> None: + new_url = original_url.update_query({"c": expected_value_a}) + assert new_url.query["a"] == expected_value_a + assert new_url.query["c"] == expected_value_a + + +@pytest.mark.parametrize( + "original_url, expected_query_len, expected_value_a", + URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES, +) +def test_query_separators_from_with_query( + original_url: URL, + expected_query_len: int, + expected_value_a: int, +) -> None: + new_url = original_url.with_query({"c": expected_value_a}) + assert new_url.query["c"] == expected_value_a + + +@pytest.mark.parametrize( + "original_url, expected_query_len, expected_value_a", + URLS_WITH_RESERVED_CHARS_IN_QUERY_VALUES, +) +def test_query_from_empty_update_query( + original_url: URL, + expected_query_len: int, + expected_value_a: str, +) -> None: + new_url = original_url.update_query({}) + + assert new_url.query["a"] == original_url.query["a"] + + if "b" in original_url.query: + assert new_url.query["b"] == original_url.query["b"] + + +@pytest.mark.parametrize( + ("original_query_string", "keys_to_drop", "expected_query_string"), + [ + ("a=10&b=M%C3%B9a+xu%C3%A2n&u%E1%BB%91ng=cafe", ["a"], "b=Mùa xuân&uống=cafe"), + ("a=10&b=M%C3%B9a+xu%C3%A2n", ["b"], "a=10"), + ("a=10&b=M%C3%B9a+xu%C3%A2n&c=30", ["b"], "a=10&c=30"), + ( + "a=10&b=M%C3%B9a+xu%C3%A2n&u%E1%BB%91ng=cafe", + ["uống"], + "a=10&b=Mùa xuân", + ), + ("a=10&b=M%C3%B9a+xu%C3%A2n", ["a", "b"], ""), + ], +) +def test_without_query_params( + original_query_string: str, keys_to_drop: Sequence[str], expected_query_string: str +) -> None: + url = URL(f"http://example.com?{original_query_string}") + new_url = url.without_query_params(*keys_to_drop) + assert new_url.query_string == expected_query_string + assert new_url is not url + + +@pytest.mark.parametrize( + ("original_query_string", "keys_to_drop"), + [ + ("a=10&b=M%C3%B9a+xu%C3%A2n&c=30", ["invalid_key"]), + ("a=10&b=M%C3%B9a+xu%C3%A2n", []), + ], +) +def test_skip_dropping_query_params( + original_query_string: str, keys_to_drop: Sequence[str] +) -> None: + url = URL(f"http://example.com?{original_query_string}") + new_url = url.without_query_params(*keys_to_drop) + assert new_url is url diff --git a/tests/test_url_update_netloc.py b/tests/test_url_update_netloc.py index a731305..cdb07a2 100644 --- a/tests/test_url_update_netloc.py +++ b/tests/test_url_update_netloc.py @@ -16,8 +16,13 @@ def test_with_scheme_uppercased(): def test_with_scheme_for_relative_url(): - with pytest.raises(ValueError): - URL("path/to").with_scheme("http") + """Test scheme can be set for relative URL.""" + msg = "scheme replacement is not allowed for " "relative URLs for the http scheme" + with pytest.raises(ValueError, match=msg): + assert URL("path/to").with_scheme("http") + + expected = URL("file:///absolute/path") + assert expected.with_scheme("file") == expected def test_with_scheme_invalid_type(): @@ -33,11 +38,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 +164,31 @@ 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" + + +@pytest.mark.parametrize( + ("host", "is_authority"), + [ + ("user:pass@host.com", True), + ("user@host.com", True), + ("host:com", False), + ("not_percent_encoded%Zf", False), + ("still_not_percent_encoded%fZ", False), + *(("other_gen_delim_" + c, False) for c in "/?#[]"), + ], +) +def test_with_invalid_host(host: str, is_authority: bool): + url = URL("http://example.com:123") + match = r"Host '[^']+' cannot contain '[^']+' \(at position \d+\)" + if is_authority: + match += ", if .* use 'authority' instead of 'host'" + with pytest.raises(ValueError, match=f"{match}$"): + url.with_host(host=host) def test_with_host_percent_encoded(): @@ -191,9 +216,37 @@ def test_with_port(): assert str(url.with_port(8888)) == "http://example.com:8888" +def test_with_default_port_normalization() -> None: + url = URL("http://example.com") + assert str(url.with_scheme("https")) == "https://example.com" + assert str(url.with_scheme("https").with_port(443)) == "https://example.com" + assert str(url.with_port(443).with_scheme("https")) == "https://example.com" + + +def test_with_custom_port_normalization() -> None: + url = URL("http://example.com") + u88 = url.with_port(88) + assert str(u88) == "http://example.com:88" + assert str(u88.with_port(80)) == "http://example.com" + assert str(u88.with_scheme("https")) == "https://example.com:88" + + +def test_with_explicit_port_normalization() -> None: + url = URL("http://example.com") + u80 = url.with_port(80) + assert str(u80) == "http://example.com" + assert str(u80.with_port(81)) == "http://example.com:81" + assert str(u80.with_scheme("https")) == "https://example.com:80" + + +def test_with_port_with_no_port(): + url = URL("http://example.com") + assert str(url.with_port(None)) == "http://example.com" + + def test_with_port_ipv6(): url = URL("http://[::1]:8080/") - assert str(url.with_port(80)) == "http://[::1]:80/" + assert str(url.with_port(81)) == "http://[::1]:81/" def test_with_port_keeps_query_and_fragment(): @@ -214,3 +267,10 @@ def test_with_port_for_relative_url(): def test_with_port_invalid_type(): with pytest.raises(TypeError): URL("http://example.com").with_port("123") + with pytest.raises(TypeError): + URL("http://example.com").with_port(True) + + +def test_with_port_invalid_range(): + with pytest.raises(ValueError): + URL("http://example.com").with_port(-1) diff --git a/towncrier.toml b/towncrier.toml new file mode 100644 index 0000000..deb9e90 --- /dev/null +++ b/towncrier.toml @@ -0,0 +1,68 @@ +[tool.towncrier] + package = "yarl" + filename = "CHANGES.rst" + directory = "CHANGES/" + title_format = "v{version}" + template = "CHANGES/.TEMPLATE.rst" + issue_format = "{issue}" + + # NOTE: The types are declared because: + # NOTE: - there is no mechanism to override just the value of + # NOTE: `tool.towncrier.type.misc.showcontent`; + # NOTE: - and, we want to declare extra non-default types for + # NOTE: clarity and flexibility. + + [[tool.towncrier.section]] + path = "" + + [[tool.towncrier.type]] + # Something we deemed an improper undesired behavior that got corrected + # in the release to match pre-agreed expectations. + directory = "bugfix" + name = "Bug fixes" + showcontent = true + + [[tool.towncrier.type]] + # New behaviors, public APIs. That sort of stuff. + directory = "feature" + name = "Features" + showcontent = true + + [[tool.towncrier.type]] + # Declarations of future API removals and breaking changes in behavior. + directory = "deprecation" + name = "Deprecations (removal in next major release)" + showcontent = true + + [[tool.towncrier.type]] + # When something public gets removed in a breaking way. Could be + # deprecated in an earlier release. + directory = "breaking" + name = "Removals and backward incompatible breaking changes" + showcontent = true + + [[tool.towncrier.type]] + # Notable updates to the documentation structure or build process. + directory = "doc" + name = "Improved documentation" + showcontent = true + + [[tool.towncrier.type]] + # Notes for downstreams about unobvious side effects and tooling. Changes + # in the test invocation considerations and runtime assumptions. + directory = "packaging" + name = "Packaging updates and notes for downstreams" + showcontent = true + + [[tool.towncrier.type]] + # Stuff that affects the contributor experience. e.g. Running tests, + # building the docs, setting up the development environment. + directory = "contrib" + name = "Contributor-facing changes" + showcontent = true + + [[tool.towncrier.type]] + # Changes that are hard to assign to any of the above categories. + directory = "misc" + name = "Miscellaneous internal changes" + showcontent = true diff --git a/yarl.egg-info/PKG-INFO b/yarl.egg-info/PKG-INFO index e51f20e..23a3ff7 100644 --- a/yarl.egg-info/PKG-INFO +++ b/yarl.egg-info/PKG-INFO @@ -1,28 +1,49 @@ Metadata-Version: 2.1 Name: yarl -Version: 1.8.2 +Version: 1.13.1 Summary: Yet another URL library -Home-page: https://github.com/aio-libs/yarl/ +Home-page: https://github.com/aio-libs/yarl Author: Andrew Svetlov Author-email: andrew.svetlov@gmail.com -License: Apache 2 -Classifier: License :: OSI Approved :: Apache Software License +Maintainer: aiohttp team +Maintainer-email: team@aiohttp.org +License: Apache-2.0 +Project-URL: Chat: Matrix, https://matrix.to/#/#aio-libs:matrix.org +Project-URL: Chat: Matrix Space, https://matrix.to/#/#aio-libs-space:matrix.org +Project-URL: CI: GitHub Workflows, https://github.com/aio-libs/yarl/actions?query=branch:master +Project-URL: Code of Conduct, https://github.com/aio-libs/.github/blob/master/CODE_OF_CONDUCT.md +Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/yarl +Project-URL: Docs: Changelog, https://yarl.aio-libs.org/en/latest/changes/ +Project-URL: Docs: RTD, https://yarl.aio-libs.org +Project-URL: GitHub: issues, https://github.com/aio-libs/yarl/issues +Project-URL: GitHub: repo, https://github.com/aio-libs/yarl +Keywords: cython,cext,yarl +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Programming Language :: Cython Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 Classifier: Topic :: Internet :: WWW/HTTP -Requires-Python: >=3.7 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.8 Description-Content-Type: text/x-rst License-File: LICENSE +License-File: NOTICE +Requires-Dist: idna>=2.0 +Requires-Dist: multidict>=4.0 yarl ==== +The module provides handy URL class for URL parsing and changing. + .. image:: https://github.com/aio-libs/yarl/workflows/CI/badge.svg :target: https://github.com/aio-libs/yarl/actions?query=workflow%3ACI :align: right @@ -35,15 +56,19 @@ yarl .. image:: https://readthedocs.org/projects/yarl/badge/?version=latest - :target: https://yarl.readthedocs.io + :target: https://yarl.aio-libs.org .. image:: https://img.shields.io/pypi/pyversions/yarl.svg :target: https://pypi.python.org/pypi/yarl -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/aio-libs/Lobby - :alt: Chat on Gitter +.. image:: https://img.shields.io/matrix/aio-libs:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs:matrix.org + :alt: Matrix Room — #aio-libs:matrix.org + +.. image:: https://img.shields.io/matrix/aio-libs-space:matrix.org?label=Discuss%20on%20Matrix%20at%20%23aio-libs-space%3Amatrix.org&logo=matrix&server_fqdn=matrix.org&style=flat + :target: https://matrix.to/#/%23aio-libs-space:matrix.org + :alt: Matrix Space — #aio-libs-space:matrix.org Introduction ------------ @@ -90,9 +115,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: @@ -100,19 +125,19 @@ 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.readthedocs.org. +For full documentation please read https://yarl.aio-libs.org. Installation @@ -130,12 +155,13 @@ manylinux-compliant because of the missing glibc and therefore, cannot be 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 setting the `YARL_NO_EXTENSIONS` +To skip the compilation you must explicitly opt-in by using a PEP 517 +configuration setting ``pure-python``, or setting the ``YARL_NO_EXTENSIONS`` environment variable to a non-empty value, e.g.: -.. code-block:: bash +.. code-block:: console - $ YARL_NO_EXTENSIONS=1 pip install yarl + $ 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 @@ -150,7 +176,7 @@ YARL requires multidict_ library. API documentation ------------------ -The documentation is located at https://yarl.readthedocs.org +The documentation is located at https://yarl.aio-libs.org. Why isn't boolean supported by the URL query API? @@ -200,9 +226,6 @@ Please file an issue on the `bug tracker `_ if you have found a bug or have some suggestion in order to improve the library. -The library uses `Azure Pipelines `_ for -Continuous Integration. - Discussion list --------------- @@ -223,7 +246,6 @@ It's *Apache 2* licensed and freely available. .. _multidict: https://github.com/aio-libs/multidict - ========= Changelog ========= @@ -240,6 +262,821 @@ Changelog .. towncrier release notes start +1.13.1 +====== + +*(2024-09-27)* + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of calling ``yarl.URL.build()`` with ``authority`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1163 `__. + + +---- + + +1.13.0 +====== + +*(2024-09-26)* + + +Bug fixes +--------- + +- Started rejecting ASCII hostnames with invalid characters. For host strings that + look like authority strings, the exception message includes advice on what to do + instead -- by `@mjpieters `__. + + *Related issues and pull requests on GitHub:* + `#880 `__, `#954 `__. + +- Fixed IPv6 addresses missing brackets when the ``~yarl.URL`` was converted to a string -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1157 `__, `#1158 `__. + + +Features +-------- + +- Added ``~yarl.URL.host_subcomponent`` which returns the ``3986#section-3.2.2`` host subcomponent -- by `@bdraco `__. + + The only current practical difference between ``~yarl.URL.raw_host`` and ``~yarl.URL.host_subcomponent`` is that IPv6 addresses are returned bracketed. + + *Related issues and pull requests on GitHub:* + `#1159 `__. + + +---- + + +1.12.1 +====== + +*(2024-09-23)* + + +No significant changes. + + +---- + + +1.12.0 +====== + +*(2024-09-23)* + + +Features +-------- + +- Added ``~yarl.URL.path_safe`` to be able to fetch the path without ``%2F`` and ``%25`` decoded -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1150 `__. + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Restore decoding ``%2F`` (``/``) in ``URL.path`` -- by `@bdraco `__. + + This change restored the behavior before `#1057 `__. + + *Related issues and pull requests on GitHub:* + `#1151 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of processing paths -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1143 `__. + + +---- + + +1.11.1 +====== + +*(2024-09-09)* + + +Bug fixes +--------- + +- Allowed scheme replacement for relative URLs if the scheme does not require a host -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#280 `__, `#1138 `__. + +- Allowed empty host for URL schemes other than the special schemes listed in the WHATWG URL spec -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1136 `__. + + +Features +-------- + +- Loosened restriction on integers as query string values to allow classes that implement ``__int__`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1139 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of normalizing paths -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1137 `__. + + +---- + + +1.11.0 +====== + +*(2024-09-08)* + + +Features +-------- + +- Added ``URL.extend_query()()`` method, which can be used to extend parameters without replacing same named keys -- by `@bdraco `__. + + This method was primarily added to replace the inefficient hand rolled method currently used in ``aiohttp``. + + *Related issues and pull requests on GitHub:* + `#1128 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of the Cython ``cached_property`` implementation -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1122 `__. + +- Simplified computing ports by removing unnecessary code -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1123 `__. + +- Improved performance of encoding non IPv6 hosts -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1125 `__. + +- Improved performance of ``URL.build()()`` when the path, query string, or fragment is an empty string -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1126 `__. + +- Improved performance of the ``URL.update_query()()`` method -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1130 `__. + +- Improved performance of processing query string changes when arguments are ``str`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1131 `__. + + +---- + + +1.10.0 +====== + +*(2024-09-06)* + + +Bug fixes +--------- + +- Fixed joining a path when the existing path was empty -- by `@bdraco `__. + + A regression in ``URL.join()()`` was introduced in `#1082 `__. + + *Related issues and pull requests on GitHub:* + `#1118 `__. + + +Features +-------- + +- Added ``URL.without_query_params()()`` method, to drop some parameters from query string -- by `@hongquan `__. + + *Related issues and pull requests on GitHub:* + `#774 `__, `#898 `__, `#1010 `__. + +- The previously protected types ``_SimpleQuery``, ``_QueryVariable``, and ``_Query`` are now available for use externally as ``SimpleQuery``, ``QueryVariable``, and ``Query`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1050 `__, `#1113 `__. + + +Contributor-facing changes +-------------------------- + +- Replaced all ``~typing.Optional`` with ``~typing.Union`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1095 `__. + + +Miscellaneous internal changes +------------------------------ + +- Significantly improved performance of parsing the network location -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1112 `__. + +- Added internal types to the cache to prevent future refactoring errors -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1117 `__. + + +---- + + +1.9.11 +====== + +*(2024-09-04)* + + +Bug fixes +--------- + +- Fixed a ``TypeError`` with ``MultiDictProxy`` and Python 3.8 -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1084 `__, `#1105 `__, `#1107 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of encoding hosts -- by `@bdraco `__. + + Previously, the library would unconditionally try to parse a host as an IP Address. The library now avoids trying to parse a host as an IP Address if the string is not in one of the formats described in ``3986#section-3.2.2``. + + *Related issues and pull requests on GitHub:* + `#1104 `__. + + +---- + + +1.9.10 +====== + +*(2024-09-04)* + + +Bug fixes +--------- + +- ``URL.join()()`` has been changed to match + ``3986`` and align with + ``/ operation()`` and ``URL.joinpath()()`` + when joining URLs with empty segments. + Previously ``urllib.parse.urljoin`` was used, + which has known issues with empty segments + (`python/cpython#84774 `_). + + Due to the semantics of ``URL.join()()``, joining an + URL with scheme requires making it relative, prefixing with ``./``. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/").join(URL("./https://github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + Empty segments are honored in the base as well as the joined part. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/https://").join(URL("github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + + -- by `@commonism `__ + + This change initially appeared in 1.9.5 but was reverted in 1.9.6 to resolve a problem with query string handling. + + *Related issues and pull requests on GitHub:* + `#1039 `__, `#1082 `__. + + +Features +-------- + +- Added ``~yarl.URL.absolute`` which is now preferred over ``URL.is_absolute()`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1100 `__. + + +---- + + +1.9.9 +===== + +*(2024-09-04)* + + +Bug fixes +--------- + +- Added missing type on ``~yarl.URL.port`` -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1097 `__. + + +---- + + +1.9.8 +===== + +*(2024-09-03)* + + +Features +-------- + +- Covered the ``~yarl.URL`` object with types -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1084 `__. + +- Cache parsing of IP Addresses when encoding hosts -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1086 `__. + + +Contributor-facing changes +-------------------------- + +- Covered the ``~yarl.URL`` object with types -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1084 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of handling ports -- by `@bdraco `__. + + *Related issues and pull requests on GitHub:* + `#1081 `__. + + +---- + + +1.9.7 +===== + +*(2024-09-01)* + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Removed support ``3986#section-3.2.3`` port normalization when the scheme is not one of ``http``, ``https``, ``wss``, or ``ws`` -- by `@bdraco `__. + + Support for port normalization was recently added in `#1033 `__ and contained code that would do blocking I/O if the scheme was not one of the four listed above. The code has been removed because this library is intended to be safe for usage with ``asyncio``. + + *Related issues and pull requests on GitHub:* + `#1076 `__. + + +Miscellaneous internal changes +------------------------------ + +- Improved performance of property caching -- by `@bdraco `__. + + The ``reify`` implementation from ``aiohttp`` was adapted to replace the internal ``cached_property`` implementation. + + *Related issues and pull requests on GitHub:* + `#1070 `__. + + +---- + + +1.9.6 +===== + +*(2024-08-30)* + + +Bug fixes +--------- + +- Reverted ``3986`` compatible ``URL.join()()`` honoring empty segments which was introduced in `#1039 `__. + + This change introduced a regression handling query string parameters with joined URLs. The change was reverted to maintain compatibility with the previous behavior. + + *Related issues and pull requests on GitHub:* + `#1067 `__. + + +---- + + +1.9.5 +===== + +*(2024-08-30)* + + +Bug fixes +--------- + +- Joining URLs with empty segments has been changed + to match ``3986``. + + Previously empty segments would be removed from path, + breaking use-cases such as + + .. code-block:: python + + URL("https://web.archive.org/web/") / "https://github.com/" + + Now ``/ operation()`` and ``URL.joinpath()()`` + keep empty segments, but do not introduce new empty segments. + e.g. + + .. code-block:: python + + URL("https://example.org/") / "" + + does not introduce an empty segment. + + -- by `@commonism `__ and `@youtux `__ + + *Related issues and pull requests on GitHub:* + `#1026 `__. + +- The default protocol ports of well-known URI schemes are now taken into account + during the normalization of the URL string representation in accordance with + ``3986#section-3.2.3``. + + Specified ports are removed from the ``str`` representation of a ``~yarl.URL`` + if the port matches the scheme's default port -- by `@commonism `__. + + *Related issues and pull requests on GitHub:* + `#1033 `__. + +- ``URL.join()()`` has been changed to match + ``3986`` and align with + ``/ operation()`` and ``URL.joinpath()()`` + when joining URLs with empty segments. + Previously ``urllib.parse.urljoin`` was used, + which has known issues with empty segments + (`python/cpython#84774 `_). + + Due to the semantics of ``URL.join()()``, joining an + URL with scheme requires making it relative, prefixing with ``./``. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/").join(URL("./https://github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + Empty segments are honored in the base as well as the joined part. + + .. code-block:: pycon + + >>> URL("https://web.archive.org/web/https://").join(URL("github.com/aio-libs/yarl")) + URL('https://web.archive.org/web/https://github.com/aio-libs/yarl') + + + + -- by `@commonism `__ + + *Related issues and pull requests on GitHub:* + `#1039 `__. + + +Removals and backward incompatible breaking changes +--------------------------------------------------- + +- Stopped decoding ``%2F`` (``/``) in ``URL.path``, as this could lead to code incorrectly treating it as a path separator + -- by `@Dreamsorcerer `__. + + *Related issues and pull requests on GitHub:* + `#1057 `__. + +- Dropped support for Python 3.7 -- by `@Dreamsorcerer `__. + + *Related issues and pull requests on GitHub:* + `#1016 `__. + + +Improved documentation +---------------------- + +- On the ``Contributing docs`` page, + a link to the ``Towncrier philosophy`` has been fixed. + + *Related issues and pull requests on GitHub:* + `#981 `__. + +- The pre-existing ``/ magic method()`` + has been documented in the API reference -- by `@commonism `__. + + *Related issues and pull requests on GitHub:* + `#1026 `__. + + +Packaging updates and notes for downstreams +------------------------------------------- + +- A flaw in the logic for copying the project directory into a + temporary folder that led to infinite recursion when ``TMPDIR`` + was set to a project subdirectory path. This was happening in Fedora + and its downstream due to the use of `pyproject-rpm-macros + `__. It was + only reproducible with ``pip wheel`` and was not affecting the + ``pyproject-build`` users. + + -- by `@hroncok `__ and `@webknjaz `__ + + *Related issues and pull requests on GitHub:* + `#992 `__, `#1014 `__. + +- Support Python 3.13 and publish non-free-threaded wheels + + *Related issues and pull requests on GitHub:* + `#1054 `__. + + +Contributor-facing changes +-------------------------- + +- The CI/CD setup has been updated to test ``arm64`` wheels + under macOS 14, except for Python 3.7 that is unsupported + in that environment -- by `@webknjaz `__. + + *Related issues and pull requests on GitHub:* + `#1015 `__. + +- Removed unused type ignores and casts -- by `@hauntsaninja `__. + + *Related issues and pull requests on GitHub:* + `#1031 `__. + + +Miscellaneous internal changes +------------------------------ + +- ``port``, ``scheme``, and ``raw_host`` are now ``cached_property`` -- by `@bdraco `__. + + ``aiohttp`` accesses these properties quite often, which cause ``urllib`` to build the ``_hostinfo`` property every time. ``port``, ``scheme``, and ``raw_host`` are now cached properties, which will improve performance. + + *Related issues and pull requests on GitHub:* + `#1044 `__, `#1058 `__. + + +---- + + +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 `__. + + Previously the empty string as port would create malformed URLs when rendered as string representations. (`#883 `__) + + +Packaging updates and notes for downstreams +------------------------------------------- + +- The leading ``--`` has been dropped from the `PEP 517 `__ in-tree build + backend config setting names. ``--pure-python`` is now just ``pure-python`` + -- by `@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 `__) + + +Contributor-facing changes +-------------------------- + +- A step-by-step ``Release Guide`` guide has + been added, describing how to release *yarl* -- by `@webknjaz `__. + + This is primarily targeting maintainers. (`#960 `__) +- Coverage collection has been implemented for the Cython modules + -- by `@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: + + .. code-block:: console + + $ 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 `__ + +- It is now possible to request line tracing in Cython builds using the + ``with-cython-tracing`` `PEP 517 `__ config setting + -- `@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. + + The following produces C-files required for the Cython coverage + plugin to map the measurements back to the PYX-files: + + .. code-block:: console + + $ python -Im pip install -e . + + Alternatively, the ``YARL_CYTHON_TRACING=1`` environment variable + can be set to do the same as the `PEP 517 `__ config setting. + + `#962 `__ + + +1.9.3 (2023-11-20) +================== + +Bug fixes +--------- + +- Stopped dropping trailing slashes in ``yarl.URL.joinpath()`` -- by `@gmacon `__. (`#862 `__, `#866 `__) +- Started accepting string subclasses in ``yarl.URL.__truediv__()`` operations (``URL / segment``) -- by `@mjpieters `__. (`#871 `__, `#884 `__) +- Fixed the human representation of URLs with square brackets in usernames and passwords -- by `@mjpieters `__. (`#876 `__, `#882 `__) +- Updated type hints to include ``URL.missing_port()``, ``URL.__bytes__()`` + and the ``encoding`` argument to ``yarl.URL.joinpath()`` + -- by `@mjpieters `__. (`#891 `__) + + +Packaging updates and notes for downstreams +------------------------------------------- + +- Integrated Cython 3 to enable building *yarl* under Python 3.12 -- by `@mjpieters `__. (`#829 `__, `#881 `__) +- Declared modern ``setuptools.build_meta`` as the `PEP 517 `__ build + backend in ``pyproject.toml`` explicitly -- by `@webknjaz `__. (`#886 `__) +- Converted most of the packaging setup into a declarative ``setup.cfg`` + config -- by `@webknjaz `__. (`#890 `__) +- The packaging is replaced from an old-fashioned ``setup.py`` to an + in-tree `PEP 517 `__ build backend -- by `@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`` + flag ``--pure-python``. If this flag is not set, a C-extension will be built + and included into the distribution. + + Here is how this can be done with ``pip``: + + .. code-block:: console + + $ python -m pip install . --config-settings=--pure-python=false + + This will also work with ``-e | --editable``. + + The same can be achieved via ``pypa/build``: + + .. code-block:: console + + $ 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 `__) + + .. 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 `__. (`#942 `__) + + +Contributor-facing changes +-------------------------- + +- A regression test for no-host URLs was added per `#821 `__ + and ``3986`` -- by `@kenballus `__. (`#821 `__, `#822 `__) +- Started testing *yarl* against Python 3.12 in CI -- by `@mjpieters `__. (`#881 `__) +- All Python 3.12 jobs are now marked as required to pass in CI + -- by `@edgarrmondragon `__. (`#942 `__) +- MyST is now integrated in Sphinx -- by `@webknjaz `__. + + This allows the contributors to author new documents in Markdown + when they have difficulties with going straight RST. (`#953 `__) + + +1.9.2 (2023-04-25) +================== + +Bugfixes +-------- + +- Fix regression with ``yarl.URL.__truediv__()`` and absolute URLs with empty paths causing the raw path to lack the leading ``/``. + (`#854 `_) + + +1.9.1 (2023-04-21) +================== + +Bugfixes +-------- + +- Marked tests that fail on older Python patch releases (< 3.7.10, < 3.8.8 and < 3.9.2) as expected to fail due to missing a security fix for CVE-2021-23336. (`#850 `_) + + +1.9.0 (2023-04-19) +================== + +This release was never published to PyPI, due to issues with the build process. + +Features +-------- + +- Added ``URL.joinpath(*elements)``, to create a new URL appending multiple path elements. (`#704 `_) +- Made ``URL.__truediv__()()`` return ``NotImplemented`` if called with an + unsupported type — by `@michaeljpeters `__. + (`#832 `_) + + +Bugfixes +-------- + +- Path normalization for absolute URLs no longer raises a ValueError exception + when ``..`` segments would otherwise go beyond the URL path root. + (`#536 `_) +- Fixed an issue with update_query() not getting rid of the query when argument is None. (`#792 `_) +- Added some input restrictions on with_port() function to prevent invalid boolean inputs or out of valid port inputs; handled incorrect 0 port representation. (`#793 `_) +- Made ``yarl.URL.build()`` raise a ``TypeError`` if the ``host`` argument is ``None`` — by `@paulpapacz `__. (`#808 `_) +- Fixed an issue with ``update_query()`` getting rid of the query when the argument + is empty but not ``None``. (`#845 `_) + + +Misc +---- + +- `#220 `_ + + 1.8.2 (2022-12-03) ================== @@ -267,8 +1104,9 @@ Features Improved Documentation ---------------------- -- Fixed broken internal references to ``(?P=rendered_text)``. (`#665 `_) -- Fixed broken external references to ``(?P=rendered_text)`` docs. (`#665 `_) +- Fixed broken internal references to ``yarl.URL.human_repr()``. + (`#665 `_) +- Fixed broken external references to ``multidict:index`` docs. (`#665 `_) Deprecations and Removals @@ -306,7 +1144,8 @@ Bugfixes Features -------- -- Add `__bytes__()` magic method so that `bytes(url)` will work and use optimal ASCII encoding. (`#582 `_) +- Add ``__bytes__()`` magic method so that ``bytes(url)`` will work and use optimal ASCII encoding. + (`#582 `_) - Started shipping platform-specific arm64 wheels for Apple Silicon. (`#622 `_) - Started shipping platform-specific wheels with the ``musl`` tag targeting typical Alpine Linux runtimes. (`#622 `_) - Added support for Python 3.10. (`#622 `_) @@ -421,7 +1260,7 @@ Features - Convert host to lowercase on URL building. `#386 `_ -- Allow using ``mod`` operator (`%`) for updating query string (an alias for ``update_query()`` method). +- Allow using ``mod`` operator (``%``) for updating query string (an alias for ``update_query()`` method). `#435 `_ - Allow use of sequences such as ``list`` and ``tuple`` in the values of a mapping such as ``dict`` to represent that a key has many values:: @@ -430,7 +1269,7 @@ Features assert url.with_query({"a": [1, 2]}) == URL("http://example.com/?a=1&a=2") `#443 `_ -- Support URL.build() with scheme and path (creates a relative URL). +- Support ``URL.build()`` with scheme and path (creates a relative URL). `#464 `_ - Cache slow IDNA encode/decode calls. `#476 `_ @@ -449,9 +1288,9 @@ Bugfixes `#409 `_ - Fix a bug where query component, passed in a form of mapping or sequence, is unquoted in unexpected way. `#426 `_ -- Hide `Query` and `QueryVariable` type aliases in `__init__.pyi`, now they are prefixed with underscore. +- Hide ``Query`` and ``QueryVariable`` type aliases in ``__init__.pyi``, now they are prefixed with underscore. `#431 `_ -- Keep ipv6 brackets after updating port/user/password. +- Keep IPv6 brackets after updating port/user/password. `#451 `_ @@ -464,7 +1303,7 @@ Bugfixes Features -------- -- Workaround for missing `str.isascii()` in Python 3.6 +- Workaround for missing ``str.isascii()`` in Python 3.6 `#389 `_ @@ -495,7 +1334,7 @@ Features * Don't create a new URL if fragment is unchanged (#292) -* Included in error msg the path that produces starting slash forbidden error (#376) +* Included in error message the path that produces starting slash forbidden error (#376) * Skip slow IDNA encoding for ASCII-only strings (#387) @@ -554,7 +1393,7 @@ Features 1.1.1 (2018-02-17) ================== -* Fix performance regression: don't encode empty netloc (#170) +* Fix performance regression: don't encode empty ``netloc`` (#170) 1.1.0 (2018-01-21) ================== @@ -616,16 +1455,16 @@ Features * Drop strict mode (#123) -* Fix ``"ValueError: Unallowed PCT %"`` when there's a ``"%"`` in the url (#124) +* Fix ``"ValueError: Unallowed PCT %"`` when there's a ``"%"`` in the URL (#124) 0.13.0 (2017-10-01) =================== * Document ``encoded`` parameter (#102) -* Support relative urls like ``'?key=value'`` (#100) +* Support relative URLs like ``'?key=value'`` (#100) -* Unsafe encoding for QS fixed. Encode ``;`` char in value param (#104) +* Unsafe encoding for QS fixed. Encode ``;`` character in value parameter (#104) * Process passwords without user names (#95) @@ -646,18 +1485,18 @@ Features 0.10.3 (2017-06-13) =================== -* Prevent double URL args unquoting (#83) +* Prevent double URL arguments unquoting (#83) 0.10.2 (2017-05-05) =================== -* Unexpected hash behaviour (#75) +* Unexpected hash behavior (#75) 0.10.1 (2017-05-03) =================== -* Unexpected compare behaviour (#73) +* Unexpected compare behavior (#73) * Do not quote or unquote + if not a query string. (#74) @@ -729,7 +1568,7 @@ Features * Fix core dumps (#41) -* tmpbuf - compiling error (#43) +* ``tmpbuf`` - compiling error (#43) * Added ``URL.update_path()`` method @@ -765,13 +1604,13 @@ Features 0.6.0 (2016-11-07) ================== -* Explicitly use UTF8 encoding in setup.py (#20) +* Explicitly use UTF8 encoding in ``setup.py`` (#20) * Properly unquote non-UTF8 strings (#19) 0.5.3 (2016-11-02) ================== -* Don't use namedtuple fields but indexes on URL construction +* Don't use ``typing.NamedTuple`` fields but indexes on URL construction 0.5.2 (2016-11-02) ================== @@ -786,7 +1625,7 @@ Features 0.5.0 (2016-11-02) ================== -* Add cython optimization for quoting/unquoting +* Add Cython optimization for quoting/unquoting * Provide binary wheels 0.4.3 (2016-09-29) @@ -839,7 +1678,7 @@ Features 0.1.4 (2016-09-09) ================== -* Add kwargs support for ``with_query()`` (#10) +* Add ``kwargs`` support for ``with_query()`` (#10) 0.1.3 (2016-09-07) ================== diff --git a/yarl.egg-info/SOURCES.txt b/yarl.egg-info/SOURCES.txt index 4df97aa..9014350 100644 --- a/yarl.egg-info/SOURCES.txt +++ b/yarl.egg-info/SOURCES.txt @@ -1,20 +1,46 @@ +.coveragerc CHANGES.rst LICENSE MANIFEST.in +NOTICE README.rst pyproject.toml +pytest.ini setup.cfg -setup.py +towncrier.toml +CHANGES/.TEMPLATE.rst +CHANGES/.gitignore +CHANGES/README.rst docs/Makefile docs/api.rst +docs/changes.rst docs/conf.py docs/index.rst docs/make.bat docs/spelling_wordlist.txt docs/yarl-icon-128x128.xcf docs/_static/yarl-icon-128x128.png +docs/contributing/guidelines.rst +docs/contributing/release_guide.rst +packaging/README.md +packaging/pep517_backend/__init__.py +packaging/pep517_backend/__main__.py +packaging/pep517_backend/_backend.py +packaging/pep517_backend/_compat.py +packaging/pep517_backend/_cython_configuration.py +packaging/pep517_backend/_transformers.py +packaging/pep517_backend/cli.py +packaging/pep517_backend/hooks.py +requirements/cython.txt +requirements/dev.txt +requirements/doc-spelling.txt +requirements/doc.txt +requirements/lint.txt +requirements/test.txt +requirements/towncrier.txt tests/test_cache.py tests/test_cached_property.py +tests/test_helpers.py tests/test_normalize_path.py tests/test_pickle.py tests/test_quoting.py @@ -26,9 +52,11 @@ tests/test_url_parsing.py tests/test_url_query.py tests/test_url_update_netloc.py yarl/__init__.py -yarl/__init__.pyi +yarl/_helpers.py +yarl/_helpers_c.pyi +yarl/_helpers_c.pyx +yarl/_helpers_py.py yarl/_quoting.py -yarl/_quoting_c.c yarl/_quoting_c.pyi yarl/_quoting_c.pyx yarl/_quoting_py.py @@ -37,5 +65,6 @@ yarl/py.typed yarl.egg-info/PKG-INFO yarl.egg-info/SOURCES.txt yarl.egg-info/dependency_links.txt +yarl.egg-info/not-zip-safe yarl.egg-info/requires.txt yarl.egg-info/top_level.txt \ No newline at end of file diff --git a/yarl.egg-info/not-zip-safe b/yarl.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/yarl.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/yarl.egg-info/requires.txt b/yarl.egg-info/requires.txt index ee048fd..19976a7 100644 --- a/yarl.egg-info/requires.txt +++ b/yarl.egg-info/requires.txt @@ -1,5 +1,2 @@ -multidict>=4.0 idna>=2.0 - -[:python_version < "3.8"] -typing-extensions>=3.7.4 +multidict>=4.0 diff --git a/yarl/__init__.py b/yarl/__init__.py index c2df0c6..1bc12c9 100644 --- a/yarl/__init__.py +++ b/yarl/__init__.py @@ -1,5 +1,21 @@ -from ._url import URL, cache_clear, cache_configure, cache_info +from ._url import ( + URL, + Query, + QueryVariable, + SimpleQuery, + cache_clear, + cache_configure, + cache_info, +) -__version__ = "1.8.2" +__version__ = "1.13.1" -__all__ = ("URL", "cache_clear", "cache_configure", "cache_info") +__all__ = ( + "URL", + "SimpleQuery", + "QueryVariable", + "Query", + "cache_clear", + "cache_configure", + "cache_info", +) diff --git a/yarl/__init__.pyi b/yarl/__init__.pyi deleted file mode 100644 index fc761b5..0000000 --- a/yarl/__init__.pyi +++ /dev/null @@ -1,118 +0,0 @@ -import sys -from functools import _CacheInfo -from typing import Any, Mapping, Optional, Sequence, Tuple, Type, Union, overload - -import multidict - -if sys.version_info >= (3, 8): - from typing import Final, TypedDict, final -else: - from typing_extensions import Final, TypedDict, final - -_SimpleQuery = Union[str, int, float] -_QueryVariable = Union[_SimpleQuery, Sequence[_SimpleQuery]] -_Query = Union[ - None, str, Mapping[str, _QueryVariable], Sequence[Tuple[str, _QueryVariable]] -] - -@final -class URL: - scheme: Final[str] - raw_user: Final[str] - user: Final[Optional[str]] - raw_password: Final[Optional[str]] - password: Final[Optional[str]] - raw_host: Final[Optional[str]] - host: Final[Optional[str]] - port: Final[Optional[int]] - raw_authority: Final[str] - authority: Final[str] - raw_path: Final[str] - path: Final[str] - raw_query_string: Final[str] - query_string: Final[str] - path_qs: Final[str] - raw_path_qs: Final[str] - raw_fragment: Final[str] - fragment: Final[str] - query: Final[multidict.MultiDict[str]] - raw_name: Final[str] - name: Final[str] - raw_suffix: Final[str] - suffix: Final[str] - raw_suffixes: Final[Tuple[str, ...]] - suffixes: Final[Tuple[str, ...]] - raw_parts: Final[Tuple[str, ...]] - parts: Final[Tuple[str, ...]] - parent: Final[URL] - def __init__( - self, val: Union[str, "URL"] = ..., *, encoded: bool = ... - ) -> None: ... - @classmethod - def build( - cls, - *, - scheme: str = ..., - authority: str = ..., - user: Optional[str] = ..., - password: Optional[str] = ..., - host: str = ..., - port: Optional[int] = ..., - path: str = ..., - query: Optional[_Query] = ..., - query_string: str = ..., - fragment: str = ..., - encoded: bool = ... - ) -> URL: ... - def __str__(self) -> str: ... - def __repr__(self) -> str: ... - def __eq__(self, other: Any) -> bool: ... - def __le__(self, other: Any) -> bool: ... - def __lt__(self, other: Any) -> bool: ... - def __ge__(self, other: Any) -> bool: ... - def __gt__(self, other: Any) -> bool: ... - def __hash__(self) -> int: ... - def __truediv__(self, name: str) -> URL: ... - def __mod__(self, query: _Query) -> URL: ... - def is_absolute(self) -> bool: ... - def is_default_port(self) -> bool: ... - def origin(self) -> URL: ... - def relative(self) -> URL: ... - def with_scheme(self, scheme: str) -> URL: ... - def with_user(self, user: Optional[str]) -> URL: ... - def with_password(self, password: Optional[str]) -> URL: ... - def with_host(self, host: str) -> URL: ... - def with_port(self, port: Optional[int]) -> URL: ... - def with_path(self, path: str, *, encoded: bool = ...) -> URL: ... - @overload - def with_query(self, query: _Query) -> URL: ... - @overload - def with_query(self, **kwargs: _QueryVariable) -> URL: ... - @overload - def update_query(self, query: _Query) -> URL: ... - @overload - def update_query(self, **kwargs: _QueryVariable) -> URL: ... - def with_fragment(self, fragment: Optional[str]) -> URL: ... - def with_name(self, name: str) -> URL: ... - def with_suffix(self, suffix: str) -> URL: ... - def join(self, url: URL) -> URL: ... - def human_repr(self) -> str: ... - # private API - @classmethod - def _normalize_path(cls, path: str) -> str: ... - -@final -class cached_property: - def __init__(self, wrapped: Any) -> None: ... - def __get__(self, inst: URL, owner: Type[URL]) -> Any: ... - def __set__(self, inst: URL, value: Any) -> None: ... - -class CacheInfo(TypedDict): - idna_encode: _CacheInfo - idna_decode: _CacheInfo - -def cache_clear() -> None: ... -def cache_info() -> CacheInfo: ... -def cache_configure( - *, idna_encode_size: Optional[int] = ..., idna_decode_size: Optional[int] = ... -) -> None: ... diff --git a/yarl/_helpers.py b/yarl/_helpers.py new file mode 100644 index 0000000..ac01158 --- /dev/null +++ b/yarl/_helpers.py @@ -0,0 +1,31 @@ +import os +import sys +from typing import TYPE_CHECKING + +__all__ = ("cached_property",) + + +NO_EXTENSIONS = bool(os.environ.get("YARL_NO_EXTENSIONS")) # type: bool +if sys.implementation.name != "cpython": + NO_EXTENSIONS = True + + +# isort: off +if TYPE_CHECKING: + from ._helpers_py import cached_property as cached_property_py + + cached_property = cached_property_py +elif not NO_EXTENSIONS: # pragma: no branch + try: + from ._helpers_c import cached_property as cached_property_c # type: ignore[attr-defined, unused-ignore] # noqa: E501 + + cached_property = cached_property_c + except ImportError: # pragma: no cover + from ._helpers_py import cached_property as cached_property_py + + cached_property = cached_property_py # type: ignore[assignment, misc] +else: + from ._helpers_py import cached_property as cached_property_py + + cached_property = cached_property_py # type: ignore[assignment, misc] +# isort: on diff --git a/yarl/_helpers_c.pyi b/yarl/_helpers_c.pyi new file mode 100644 index 0000000..6903492 --- /dev/null +++ b/yarl/_helpers_c.pyi @@ -0,0 +1,6 @@ +from typing import Any + +class cached_property: + def __init__(self, wrapped: Any) -> None: ... + def __get__(self, inst: Any, owner: Any) -> Any: ... + def __set__(self, inst: Any, value: Any) -> None: ... diff --git a/yarl/_helpers_c.pyx b/yarl/_helpers_c.pyx new file mode 100644 index 0000000..e6eec37 --- /dev/null +++ b/yarl/_helpers_c.pyx @@ -0,0 +1,36 @@ +# cython: language_level=3 + +cdef _sentinel = object() + +cdef class cached_property: + """Use as a class method decorator. It operates almost exactly like + the Python `@property` decorator, but it puts the result of the + method it decorates into the instance dict after the first call, + effectively replacing the function it decorates with an instance + variable. It is, in Python parlance, a data descriptor. + + """ + + cdef object wrapped + cdef object name + + def __init__(self, wrapped): + self.wrapped = wrapped + self.name = wrapped.__name__ + + @property + def __doc__(self): + return self.wrapped.__doc__ + + def __get__(self, inst, owner): + if inst is None: + return self + cdef dict cache = inst._cache + val = cache.get(self.name, _sentinel) + if val is _sentinel: + val = self.wrapped(inst) + cache[self.name] = val + return val + + def __set__(self, inst, value): + raise AttributeError("cached property is read-only") diff --git a/yarl/_helpers_py.py b/yarl/_helpers_py.py new file mode 100644 index 0000000..5a18afb --- /dev/null +++ b/yarl/_helpers_py.py @@ -0,0 +1,41 @@ +"""Various helper functions.""" + +from typing import Any, Callable, Dict, Generic, Optional, Protocol, Type, TypeVar + +_T = TypeVar("_T") + + +class _TSelf(Protocol, Generic[_T]): + _cache: Dict[str, _T] + + +class cached_property(Generic[_T]): + """Use as a class method decorator. + + It operates almost exactly like + the Python `@property` decorator, but it puts the result of the + method it decorates into the instance dict after the first call, + effectively replacing the function it decorates with an instance + variable. It is, in Python parlance, a data descriptor. + """ + + def __init__(self, wrapped: Callable[..., _T]) -> None: + self.wrapped = wrapped + self.__doc__ = wrapped.__doc__ + self.name = wrapped.__name__ + + def __get__(self, inst: _TSelf[_T], owner: Optional[Type[Any]] = None) -> _T: + try: + try: + return inst._cache[self.name] + except KeyError: + val = self.wrapped(inst) + inst._cache[self.name] = val + return val + except AttributeError: + if inst is None: + return self + raise + + def __set__(self, inst: _TSelf[_T], value: _T) -> None: + raise AttributeError("cached property is read-only") diff --git a/yarl/_quoting.py b/yarl/_quoting.py index 46e100a..95e8609 100644 --- a/yarl/_quoting.py +++ b/yarl/_quoting.py @@ -11,8 +11,8 @@ if not NO_EXTENSIONS: # pragma: no branch try: - from ._quoting_c import _Quoter, _Unquoter # type: ignore[misc] + from ._quoting_c import _Quoter, _Unquoter except ImportError: # pragma: no cover - from ._quoting_py import _Quoter, _Unquoter # type: ignore[misc] + from ._quoting_py import _Quoter, _Unquoter # type: ignore[assignment] else: - from ._quoting_py import _Quoter, _Unquoter # type: ignore[misc] + from ._quoting_py import _Quoter, _Unquoter # type: ignore[assignment] diff --git a/yarl/_quoting_c.c b/yarl/_quoting_c.c deleted file mode 100644 index a177c7d..0000000 --- a/yarl/_quoting_c.c +++ /dev/null @@ -1,11939 +0,0 @@ -/* Generated by Cython 0.29.32 */ - -#ifndef PY_SSIZE_T_CLEAN -#define PY_SSIZE_T_CLEAN -#endif /* PY_SSIZE_T_CLEAN */ -#include "Python.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000) - #error Cython requires Python 2.6+ or Python 3.3+. -#else -#define CYTHON_ABI "0_29_32" -#define CYTHON_HEX_VERSION 0x001D20F0 -#define CYTHON_FUTURE_DIVISION 1 -#include -#ifndef offsetof - #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) -#endif -#if !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#endif -#ifndef DL_IMPORT - #define DL_IMPORT(t) t -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif -#define __PYX_COMMA , -#ifndef HAVE_LONG_LONG - #if PY_VERSION_HEX >= 0x02070000 - #define HAVE_LONG_LONG - #endif -#endif -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifndef Py_HUGE_VAL - #define Py_HUGE_VAL HUGE_VAL -#endif -#ifdef PYPY_VERSION - #define CYTHON_COMPILING_IN_PYPY 1 - #define CYTHON_COMPILING_IN_PYSTON 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_NOGIL 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #if PY_VERSION_HEX < 0x03050000 - #undef CYTHON_USE_ASYNC_SLOTS - #define CYTHON_USE_ASYNC_SLOTS 0 - #elif !defined(CYTHON_USE_ASYNC_SLOTS) - #define CYTHON_USE_ASYNC_SLOTS 1 - #endif - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 0 - #undef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC (PYPY_VERSION_HEX >= 0x07030900) - #endif -#elif defined(PYSTON_VERSION) - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_PYSTON 1 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_NOGIL 0 - #ifndef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #endif - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_ASYNC_SLOTS - #define CYTHON_USE_ASYNC_SLOTS 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #ifndef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 1 - #endif - #ifndef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 1 - #endif - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 0 - #undef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif -#elif defined(PY_NOGIL) - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_PYSTON 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_NOGIL 1 - #ifndef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #endif - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #ifndef CYTHON_USE_ASYNC_SLOTS - #define CYTHON_USE_ASYNC_SLOTS 1 - #endif - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #ifndef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 1 - #endif - #ifndef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 1 - #endif - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 1 - #endif - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 -#else - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_PYSTON 0 - #define CYTHON_COMPILING_IN_CPYTHON 1 - #define CYTHON_COMPILING_IN_NOGIL 0 - #ifndef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #endif - #if PY_VERSION_HEX < 0x02070000 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #elif !defined(CYTHON_USE_PYTYPE_LOOKUP) - #define CYTHON_USE_PYTYPE_LOOKUP 1 - #endif - #if PY_MAJOR_VERSION < 3 - #undef CYTHON_USE_ASYNC_SLOTS - #define CYTHON_USE_ASYNC_SLOTS 0 - #elif !defined(CYTHON_USE_ASYNC_SLOTS) - #define CYTHON_USE_ASYNC_SLOTS 1 - #endif - #if PY_VERSION_HEX < 0x02070000 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #elif !defined(CYTHON_USE_PYLONG_INTERNALS) - #define CYTHON_USE_PYLONG_INTERNALS 1 - #endif - #ifndef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 1 - #endif - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif - #if PY_VERSION_HEX < 0x030300F0 || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) - #define CYTHON_USE_UNICODE_WRITER 1 - #endif - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #ifndef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 1 - #endif - #ifndef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 1 - #endif - #if PY_VERSION_HEX >= 0x030B00A4 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #elif !defined(CYTHON_FAST_THREAD_STATE) - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #ifndef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL (PY_VERSION_HEX < 0x030A0000) - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000) - #endif - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1) - #endif - #ifndef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1) - #endif - #if PY_VERSION_HEX >= 0x030B00A4 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #elif !defined(CYTHON_USE_EXC_INFO_STACK) - #define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3) - #endif - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 - #endif -#endif -#if !defined(CYTHON_FAST_PYCCALL) -#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) -#endif -#if CYTHON_USE_PYLONG_INTERNALS - #if PY_MAJOR_VERSION < 3 - #include "longintrepr.h" - #endif - #undef SHIFT - #undef BASE - #undef MASK - #ifdef SIZEOF_VOID_P - enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; - #endif -#endif -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif -#ifndef __has_cpp_attribute - #define __has_cpp_attribute(x) 0 -#endif -#ifndef CYTHON_RESTRICT - #if defined(__GNUC__) - #define CYTHON_RESTRICT __restrict__ - #elif defined(_MSC_VER) && _MSC_VER >= 1400 - #define CYTHON_RESTRICT __restrict - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_RESTRICT restrict - #else - #define CYTHON_RESTRICT - #endif -#endif -#ifndef CYTHON_UNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_MAYBE_UNUSED_VAR -# if defined(__cplusplus) - template void CYTHON_MAYBE_UNUSED_VAR( const T& ) { } -# else -# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x) -# endif -#endif -#ifndef CYTHON_NCP_UNUSED -# if CYTHON_COMPILING_IN_CPYTHON -# define CYTHON_NCP_UNUSED -# else -# define CYTHON_NCP_UNUSED CYTHON_UNUSED -# endif -#endif -#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) -#ifdef _MSC_VER - #ifndef _MSC_STDINT_H_ - #if _MSC_VER < 1300 - typedef unsigned char uint8_t; - typedef unsigned int uint32_t; - #else - typedef unsigned __int8 uint8_t; - typedef unsigned __int32 uint32_t; - #endif - #endif -#else - #include -#endif -#ifndef CYTHON_FALLTHROUGH - #if defined(__cplusplus) && __cplusplus >= 201103L - #if __has_cpp_attribute(fallthrough) - #define CYTHON_FALLTHROUGH [[fallthrough]] - #elif __has_cpp_attribute(clang::fallthrough) - #define CYTHON_FALLTHROUGH [[clang::fallthrough]] - #elif __has_cpp_attribute(gnu::fallthrough) - #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_attribute(fallthrough) - #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) - #else - #define CYTHON_FALLTHROUGH - #endif - #endif - #if defined(__clang__ ) && defined(__apple_build_version__) - #if __apple_build_version__ < 7000000 - #undef CYTHON_FALLTHROUGH - #define CYTHON_FALLTHROUGH - #endif - #endif -#endif - -#ifndef CYTHON_INLINE - #if defined(__clang__) - #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) - #elif defined(__GNUC__) - #define CYTHON_INLINE __inline__ - #elif defined(_MSC_VER) - #define CYTHON_INLINE __inline - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_INLINE inline - #else - #define CYTHON_INLINE - #endif -#endif - -#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) - #define Py_OptimizeFlag 0 -#endif -#define __PYX_BUILD_PY_SSIZE_T "n" -#define CYTHON_FORMAT_SSIZE_T "z" -#if PY_MAJOR_VERSION < 3 - #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) - #define __Pyx_DefaultClassType PyClass_Type -#else - #define __Pyx_BUILTIN_MODULE_NAME "builtins" - #define __Pyx_DefaultClassType PyType_Type -#if PY_VERSION_HEX >= 0x030B00A1 - static CYTHON_INLINE PyCodeObject* __Pyx_PyCode_New(int a, int k, int l, int s, int f, - PyObject *code, PyObject *c, PyObject* n, PyObject *v, - PyObject *fv, PyObject *cell, PyObject* fn, - PyObject *name, int fline, PyObject *lnos) { - PyObject *kwds=NULL, *argcount=NULL, *posonlyargcount=NULL, *kwonlyargcount=NULL; - PyObject *nlocals=NULL, *stacksize=NULL, *flags=NULL, *replace=NULL, *call_result=NULL, *empty=NULL; - const char *fn_cstr=NULL; - const char *name_cstr=NULL; - PyCodeObject* co=NULL; - PyObject *type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); - if (!(kwds=PyDict_New())) goto end; - if (!(argcount=PyLong_FromLong(a))) goto end; - if (PyDict_SetItemString(kwds, "co_argcount", argcount) != 0) goto end; - if (!(posonlyargcount=PyLong_FromLong(0))) goto end; - if (PyDict_SetItemString(kwds, "co_posonlyargcount", posonlyargcount) != 0) goto end; - if (!(kwonlyargcount=PyLong_FromLong(k))) goto end; - if (PyDict_SetItemString(kwds, "co_kwonlyargcount", kwonlyargcount) != 0) goto end; - if (!(nlocals=PyLong_FromLong(l))) goto end; - if (PyDict_SetItemString(kwds, "co_nlocals", nlocals) != 0) goto end; - if (!(stacksize=PyLong_FromLong(s))) goto end; - if (PyDict_SetItemString(kwds, "co_stacksize", stacksize) != 0) goto end; - if (!(flags=PyLong_FromLong(f))) goto end; - if (PyDict_SetItemString(kwds, "co_flags", flags) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_code", code) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_consts", c) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_names", n) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_varnames", v) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_freevars", fv) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_cellvars", cell) != 0) goto end; - if (PyDict_SetItemString(kwds, "co_linetable", lnos) != 0) goto end; - if (!(fn_cstr=PyUnicode_AsUTF8AndSize(fn, NULL))) goto end; - if (!(name_cstr=PyUnicode_AsUTF8AndSize(name, NULL))) goto end; - if (!(co = PyCode_NewEmpty(fn_cstr, name_cstr, fline))) goto end; - if (!(replace = PyObject_GetAttrString((PyObject*)co, "replace"))) goto cleanup_code_too; - if (!(empty = PyTuple_New(0))) goto cleanup_code_too; // unfortunately __pyx_empty_tuple isn't available here - if (!(call_result = PyObject_Call(replace, empty, kwds))) goto cleanup_code_too; - Py_XDECREF((PyObject*)co); - co = (PyCodeObject*)call_result; - call_result = NULL; - if (0) { - cleanup_code_too: - Py_XDECREF((PyObject*)co); - co = NULL; - } - end: - Py_XDECREF(kwds); - Py_XDECREF(argcount); - Py_XDECREF(posonlyargcount); - Py_XDECREF(kwonlyargcount); - Py_XDECREF(nlocals); - Py_XDECREF(stacksize); - Py_XDECREF(replace); - Py_XDECREF(call_result); - Py_XDECREF(empty); - if (type) { - PyErr_Restore(type, value, traceback); - } - return co; - } -#else - #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -#endif - #define __Pyx_DefaultClassType PyType_Type -#endif -#ifndef Py_TPFLAGS_CHECKTYPES - #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif -#ifndef Py_TPFLAGS_HAVE_FINALIZE - #define Py_TPFLAGS_HAVE_FINALIZE 0 -#endif -#ifndef METH_STACKLESS - #define METH_STACKLESS 0 -#endif -#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL) - #ifndef METH_FASTCALL - #define METH_FASTCALL 0x80 - #endif - typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); - typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames); -#else - #define __Pyx_PyCFunctionFast _PyCFunctionFast - #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords -#endif -#if CYTHON_FAST_PYCCALL -#define __Pyx_PyFastCFunction_Check(func)\ - ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))))) -#else -#define __Pyx_PyFastCFunction_Check(func) 0 -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) - #define PyObject_Malloc(s) PyMem_Malloc(s) - #define PyObject_Free(p) PyMem_Free(p) - #define PyObject_Realloc(p) PyMem_Realloc(p) -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030400A1 - #define PyMem_RawMalloc(n) PyMem_Malloc(n) - #define PyMem_RawRealloc(p, n) PyMem_Realloc(p, n) - #define PyMem_RawFree(p) PyMem_Free(p) -#endif -#if CYTHON_COMPILING_IN_PYSTON - #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno) -#else - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) -#endif -#if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000 - #define __Pyx_PyThreadState_Current PyThreadState_GET() -#elif PY_VERSION_HEX >= 0x03060000 - #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() -#elif PY_VERSION_HEX >= 0x03000000 - #define __Pyx_PyThreadState_Current PyThreadState_GET() -#else - #define __Pyx_PyThreadState_Current _PyThreadState_Current -#endif -#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT) -#include "pythread.h" -#define Py_tss_NEEDS_INIT 0 -typedef int Py_tss_t; -static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) { - *key = PyThread_create_key(); - return 0; -} -static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) { - Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t)); - *key = Py_tss_NEEDS_INIT; - return key; -} -static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) { - PyObject_Free(key); -} -static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) { - return *key != Py_tss_NEEDS_INIT; -} -static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) { - PyThread_delete_key(*key); - *key = Py_tss_NEEDS_INIT; -} -static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) { - return PyThread_set_key_value(*key, value); -} -static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) { - return PyThread_get_key_value(*key); -} -#endif -#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) -#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) -#else -#define __Pyx_PyDict_NewPresized(n) PyDict_New() -#endif -#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION - #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#else - #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) - #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS -#define __Pyx_PyDict_GetItemStr(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) -#else -#define __Pyx_PyDict_GetItemStr(dict, name) PyDict_GetItem(dict, name) -#endif -#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) - #define CYTHON_PEP393_ENABLED 1 - #if defined(PyUnicode_IS_READY) - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) - #else - #define __Pyx_PyUnicode_READY(op) (0) - #endif - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) - #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) - #if defined(PyUnicode_IS_READY) && defined(PyUnicode_GET_SIZE) - #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) - #endif - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #endif -#else - #define CYTHON_PEP393_ENABLED 0 - #define PyUnicode_1BYTE_KIND 1 - #define PyUnicode_2BYTE_KIND 2 - #define PyUnicode_4BYTE_KIND 4 - #define __Pyx_PyUnicode_READY(op) (0) - #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) - #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111) - #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) - #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) - #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch) - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) -#endif -#if CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) -#else - #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ - PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) - #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check) - #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format) - #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) -#endif -#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) -#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) -#else - #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) -#endif -#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) - #define PyObject_ASCII(o) PyObject_Repr(o) -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyBaseString_Type PyUnicode_Type - #define PyStringObject PyUnicodeObject - #define PyString_Type PyUnicode_Type - #define PyString_Check PyUnicode_Check - #define PyString_CheckExact PyUnicode_CheckExact -#ifndef PyObject_Unicode - #define PyObject_Unicode PyObject_Str -#endif -#endif -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) - #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) -#else - #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) - #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) -#endif -#ifndef PySet_CheckExact - #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) -#endif -#if PY_VERSION_HEX >= 0x030900A4 - #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -#else - #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -#endif -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) -#else - #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyIntObject PyLongObject - #define PyInt_Type PyLong_Type - #define PyInt_Check(op) PyLong_Check(op) - #define PyInt_CheckExact(op) PyLong_CheckExact(op) - #define PyInt_FromString PyLong_FromString - #define PyInt_FromUnicode PyLong_FromUnicode - #define PyInt_FromLong PyLong_FromLong - #define PyInt_FromSize_t PyLong_FromSize_t - #define PyInt_FromSsize_t PyLong_FromSsize_t - #define PyInt_AsLong PyLong_AsLong - #define PyInt_AS_LONG PyLong_AS_LONG - #define PyInt_AsSsize_t PyLong_AsSsize_t - #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask - #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask - #define PyNumber_Int PyNumber_Long -#endif -#if PY_MAJOR_VERSION >= 3 - #define PyBoolObject PyLongObject -#endif -#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY - #ifndef PyUnicode_InternFromString - #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) - #endif -#endif -#if PY_VERSION_HEX < 0x030200A4 - typedef long Py_hash_t; - #define __Pyx_PyInt_FromHash_t PyInt_FromLong - #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsHash_t -#else - #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t - #define __Pyx_PyInt_AsHash_t __Pyx_PyIndex_AsSsize_t -#endif -#if PY_MAJOR_VERSION >= 3 - #define __Pyx_PyMethod_New(func, self, klass) ((self) ? ((void)(klass), PyMethod_New(func, self)) : __Pyx_NewRef(func)) -#else - #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) -#endif -#if CYTHON_USE_ASYNC_SLOTS - #if PY_VERSION_HEX >= 0x030500B1 - #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods - #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) - #else - #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) - #endif -#else - #define __Pyx_PyType_AsAsync(obj) NULL -#endif -#ifndef __Pyx_PyAsyncMethodsStruct - typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; - } __Pyx_PyAsyncMethodsStruct; -#endif - -#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) - #if !defined(_USE_MATH_DEFINES) - #define _USE_MATH_DEFINES - #endif -#endif -#include -#ifdef NAN -#define __PYX_NAN() ((float) NAN) -#else -static CYTHON_INLINE float __PYX_NAN() { - float value; - memset(&value, 0xFF, sizeof(value)); - return value; -} -#endif -#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) -#define __Pyx_truncl trunc -#else -#define __Pyx_truncl truncl -#endif - -#define __PYX_MARK_ERR_POS(f_index, lineno) \ - { __pyx_filename = __pyx_f[f_index]; (void)__pyx_filename; __pyx_lineno = lineno; (void)__pyx_lineno; __pyx_clineno = __LINE__; (void)__pyx_clineno; } -#define __PYX_ERR(f_index, lineno, Ln_error) \ - { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - -#ifndef __PYX_EXTERN_C - #ifdef __cplusplus - #define __PYX_EXTERN_C extern "C" - #else - #define __PYX_EXTERN_C extern - #endif -#endif - -#define __PYX_HAVE__yarl___quoting_c -#define __PYX_HAVE_API__yarl___quoting_c -/* Early includes */ -#include -#include -#include -#ifdef _OPENMP -#include -#endif /* _OPENMP */ - -#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) -#define CYTHON_WITHOUT_ASSERTIONS -#endif - -typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; - const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; - -#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 -#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 -#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8) -#define __PYX_DEFAULT_STRING_ENCODING "" -#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString -#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#define __Pyx_uchar_cast(c) ((unsigned char)c) -#define __Pyx_long_cast(x) ((long)x) -#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ - (sizeof(type) < sizeof(Py_ssize_t)) ||\ - (sizeof(type) > sizeof(Py_ssize_t) &&\ - likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX) &&\ - (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ - v == (type)PY_SSIZE_T_MIN))) ||\ - (sizeof(type) == sizeof(Py_ssize_t) &&\ - (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX))) ) -static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { - return (size_t) i < (size_t) limit; -} -#if defined (__cplusplus) && __cplusplus >= 201103L - #include - #define __Pyx_sst_abs(value) std::abs(value) -#elif SIZEOF_INT >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) abs(value) -#elif SIZEOF_LONG >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) labs(value) -#elif defined (_MSC_VER) - #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) -#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define __Pyx_sst_abs(value) llabs(value) -#elif defined (__GNUC__) - #define __Pyx_sst_abs(value) __builtin_llabs(value) -#else - #define __Pyx_sst_abs(value) ((value<0) ? -value : value) -#endif -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); -#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) -#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) -#define __Pyx_PyBytes_FromString PyBytes_FromString -#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); -#if PY_MAJOR_VERSION < 3 - #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString - #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#else - #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString - #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize -#endif -#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) -#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) -#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) -#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) -#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) -#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) -#define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) -#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) -#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) -#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) -#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) -static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) { - const Py_UNICODE *u_end = u; - while (*u_end++) ; - return (size_t)(u_end - u - 1); -} -#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) -#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode -#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode -#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) -#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); -static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); -#define __Pyx_PySequence_Tuple(obj)\ - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); -#if CYTHON_ASSUME_SAFE_MACROS -#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) -#else -#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) -#endif -#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) -#if PY_MAJOR_VERSION >= 3 -#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) -#else -#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) -#endif -#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x)) -#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII -static int __Pyx_sys_getdefaultencoding_not_ascii; -static int __Pyx_init_sys_getdefaultencoding_params(void) { - PyObject* sys; - PyObject* default_encoding = NULL; - PyObject* ascii_chars_u = NULL; - PyObject* ascii_chars_b = NULL; - const char* default_encoding_c; - sys = PyImport_ImportModule("sys"); - if (!sys) goto bad; - default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); - Py_DECREF(sys); - if (!default_encoding) goto bad; - default_encoding_c = PyBytes_AsString(default_encoding); - if (!default_encoding_c) goto bad; - if (strcmp(default_encoding_c, "ascii") == 0) { - __Pyx_sys_getdefaultencoding_not_ascii = 0; - } else { - char ascii_chars[128]; - int c; - for (c = 0; c < 128; c++) { - ascii_chars[c] = c; - } - __Pyx_sys_getdefaultencoding_not_ascii = 1; - ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); - if (!ascii_chars_u) goto bad; - ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); - if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { - PyErr_Format( - PyExc_ValueError, - "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", - default_encoding_c); - goto bad; - } - Py_DECREF(ascii_chars_u); - Py_DECREF(ascii_chars_b); - } - Py_DECREF(default_encoding); - return 0; -bad: - Py_XDECREF(default_encoding); - Py_XDECREF(ascii_chars_u); - Py_XDECREF(ascii_chars_b); - return -1; -} -#endif -#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 -#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) -#else -#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) -#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT -static char* __PYX_DEFAULT_STRING_ENCODING; -static int __Pyx_init_sys_getdefaultencoding_params(void) { - PyObject* sys; - PyObject* default_encoding = NULL; - char* default_encoding_c; - sys = PyImport_ImportModule("sys"); - if (!sys) goto bad; - default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); - Py_DECREF(sys); - if (!default_encoding) goto bad; - default_encoding_c = PyBytes_AsString(default_encoding); - if (!default_encoding_c) goto bad; - __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1); - if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; - strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); - Py_DECREF(default_encoding); - return 0; -bad: - Py_XDECREF(default_encoding); - return -1; -} -#endif -#endif - - -/* Test for GCC > 2.95 */ -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) - #define likely(x) __builtin_expect(!!(x), 1) - #define unlikely(x) __builtin_expect(!!(x), 0) -#else /* !__GNUC__ or GCC < 2.95 */ - #define likely(x) (x) - #define unlikely(x) (x) -#endif /* __GNUC__ */ -static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } - -static PyObject *__pyx_m = NULL; -static PyObject *__pyx_d; -static PyObject *__pyx_b; -static PyObject *__pyx_cython_runtime = NULL; -static PyObject *__pyx_empty_tuple; -static PyObject *__pyx_empty_bytes; -static PyObject *__pyx_empty_unicode; -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * __pyx_cfilenm= __FILE__; -static const char *__pyx_filename; - - -static const char *__pyx_f[] = { - "yarl/_quoting_c.pyx", - "stringsource", - "type.pxd", -}; - -/*--- Type declarations ---*/ -struct __pyx_obj_4yarl_10_quoting_c__Quoter; -struct __pyx_obj_4yarl_10_quoting_c__Unquoter; -struct __pyx_t_4yarl_10_quoting_c_Writer; - -/* "yarl/_quoting_c.pyx":79 - * # ----------------- writer --------------------------- - * - * cdef struct Writer: # <<<<<<<<<<<<<< - * char *buf - * Py_ssize_t size - */ -struct __pyx_t_4yarl_10_quoting_c_Writer { - char *buf; - Py_ssize_t size; - Py_ssize_t pos; - int changed; -}; - -/* "yarl/_quoting_c.pyx":169 - * - * - * cdef class _Quoter: # <<<<<<<<<<<<<< - * cdef bint _qs - * cdef bint _requote - */ -struct __pyx_obj_4yarl_10_quoting_c__Quoter { - PyObject_HEAD - struct __pyx_vtabstruct_4yarl_10_quoting_c__Quoter *__pyx_vtab; - int _qs; - int _requote; - uint8_t _safe_table[16]; - uint8_t _protected_table[16]; -}; - - -/* "yarl/_quoting_c.pyx":271 - * - * - * cdef class _Unquoter: # <<<<<<<<<<<<<< - * cdef str _unsafe - * cdef bint _qs - */ -struct __pyx_obj_4yarl_10_quoting_c__Unquoter { - PyObject_HEAD - struct __pyx_vtabstruct_4yarl_10_quoting_c__Unquoter *__pyx_vtab; - PyObject *_unsafe; - int _qs; - struct __pyx_obj_4yarl_10_quoting_c__Quoter *_quoter; - struct __pyx_obj_4yarl_10_quoting_c__Quoter *_qs_quoter; -}; - - - -/* "yarl/_quoting_c.pyx":169 - * - * - * cdef class _Quoter: # <<<<<<<<<<<<<< - * cdef bint _qs - * cdef bint _requote - */ - -struct __pyx_vtabstruct_4yarl_10_quoting_c__Quoter { - PyObject *(*_do_quote)(struct __pyx_obj_4yarl_10_quoting_c__Quoter *, PyObject *, struct __pyx_t_4yarl_10_quoting_c_Writer *); - int (*_write)(struct __pyx_obj_4yarl_10_quoting_c__Quoter *, struct __pyx_t_4yarl_10_quoting_c_Writer *, Py_UCS4); -}; -static struct __pyx_vtabstruct_4yarl_10_quoting_c__Quoter *__pyx_vtabptr_4yarl_10_quoting_c__Quoter; -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c_7_Quoter__write(struct __pyx_obj_4yarl_10_quoting_c__Quoter *, struct __pyx_t_4yarl_10_quoting_c_Writer *, Py_UCS4); - - -/* "yarl/_quoting_c.pyx":271 - * - * - * cdef class _Unquoter: # <<<<<<<<<<<<<< - * cdef str _unsafe - * cdef bint _qs - */ - -struct __pyx_vtabstruct_4yarl_10_quoting_c__Unquoter { - PyObject *(*_do_unquote)(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *, PyObject *); -}; -static struct __pyx_vtabstruct_4yarl_10_quoting_c__Unquoter *__pyx_vtabptr_4yarl_10_quoting_c__Unquoter; - -/* --- Runtime support code (head) --- */ -/* Refnanny.proto */ -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, int); - void (*DECREF)(void*, PyObject*, int); - void (*GOTREF)(void*, PyObject*, int); - void (*GIVEREF)(void*, PyObject*, int); - void* (*SetupContext)(const char*, int, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); - #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; -#ifdef WITH_THREAD - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - if (acquire_gil) {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ - PyGILState_Release(__pyx_gilstate_save);\ - } else {\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ - } -#else - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) -#endif - #define __Pyx_RefNannyFinishContext()\ - __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) - #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) - #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) - #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) -#else - #define __Pyx_RefNannyDeclarations - #define __Pyx_RefNannySetupContext(name, acquire_gil) - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XINCREF(r) Py_XINCREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) - #define __Pyx_XGOTREF(r) - #define __Pyx_XGIVEREF(r) -#endif -#define __Pyx_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_XDECREF(tmp);\ - } while (0) -#define __Pyx_DECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_DECREF(tmp);\ - } while (0) -#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) -#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) - -/* PyObjectGetAttrStr.proto */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); -#else -#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) -#endif - -/* GetBuiltinName.proto */ -static PyObject *__Pyx_GetBuiltinName(PyObject *name); - -/* PyThreadStateGet.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; -#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; -#define __Pyx_PyErr_Occurred() __pyx_tstate->curexc_type -#else -#define __Pyx_PyThreadState_declare -#define __Pyx_PyThreadState_assign -#define __Pyx_PyErr_Occurred() PyErr_Occurred() -#endif - -/* PyErrFetchRestore.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) -#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) -#else -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#endif -#else -#define __Pyx_PyErr_Clear() PyErr_Clear() -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) -#endif - -/* WriteUnraisableException.proto */ -static void __Pyx_WriteUnraisable(const char *name, int clineno, - int lineno, const char *filename, - int full_traceback, int nogil); - -/* RaiseDoubleKeywords.proto */ -static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); - -/* ParseKeywords.proto */ -static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ - PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ - const char* function_name); - -/* RaiseArgTupleInvalid.proto */ -static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, - Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); - -/* ArgTypeTest.proto */ -#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ - ((likely((Py_TYPE(obj) == type) | (none_allowed && (obj == Py_None)))) ? 1 :\ - __Pyx__ArgTypeTest(obj, type, name, exact)) -static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); - -/* unicode_iter.proto */ -static CYTHON_INLINE int __Pyx_init_unicode_iteration( - PyObject* ustring, Py_ssize_t *length, void** data, int *kind); - -/* PyObjectCall.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); -#else -#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) -#endif - -/* RaiseException.proto */ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - -/* PyCFunctionFastCall.proto */ -#if CYTHON_FAST_PYCCALL -static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); -#else -#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) -#endif - -/* PyFunctionFastCall.proto */ -#if CYTHON_FAST_PYCALL -#define __Pyx_PyFunction_FastCall(func, args, nargs)\ - __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) -#if 1 || PY_VERSION_HEX < 0x030600B1 -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs); -#else -#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) -#endif -#define __Pyx_BUILD_ASSERT_EXPR(cond)\ - (sizeof(char [1 - 2*!(cond)]) - 1) -#ifndef Py_MEMBER_SIZE -#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) -#endif -#if CYTHON_FAST_PYCALL - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" -#if PY_VERSION_HEX >= 0x030b00a6 - #ifndef Py_BUILD_CORE - #define Py_BUILD_CORE 1 - #endif - #include "internal/pycore_frame.h" -#endif - #define __Pxy_PyFrame_Initialize_Offsets()\ - ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -#endif // CYTHON_FAST_PYCALL -#endif - -/* PyObjectCallMethO.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); -#endif - -/* PyObjectCallOneArg.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); - -/* GetException.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) -static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#else -static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); -#endif - -/* SwapException.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#else -static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); -#endif - -/* GetTopmostException.proto */ -#if CYTHON_USE_EXC_INFO_STACK -static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -#endif - -/* SaveResetException.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -#else -#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) -#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) -#endif - -/* GetItemIntUnicode.proto */ -#define __Pyx_GetItemInt_Unicode(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_Unicode_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ - (PyErr_SetString(PyExc_IndexError, "string index out of range"), (Py_UCS4)-1)) -static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i, - int wraparound, int boundscheck); - -/* ReRaiseException.proto */ -static CYTHON_INLINE void __Pyx_ReraiseException(void); - -/* PyErrExceptionMatches.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -#else -#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -#endif - -/* GetAttr.proto */ -static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *); - -/* GetAttr3.proto */ -static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); - -/* PyDictVersioning.proto */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) -#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ - (version_var) = __PYX_GET_DICT_VERSION(dict);\ - (cache_var) = (value); -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ - (VAR) = __pyx_dict_cached_value;\ - } else {\ - (VAR) = __pyx_dict_cached_value = (LOOKUP);\ - __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ - }\ -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); -#else -#define __PYX_GET_DICT_VERSION(dict) (0) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); -#endif - -/* GetModuleGlobalName.proto */ -#if CYTHON_USE_DICT_VERSIONS -#define __Pyx_GetModuleGlobalName(var, name) {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\ - (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ - __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ -} -#define __Pyx_GetModuleGlobalNameUncached(var, name) {\ - PY_UINT64_T __pyx_dict_version;\ - PyObject *__pyx_dict_cached_value;\ - (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ -} -static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); -#else -#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) -#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) -static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); -#endif - -/* PyObjectCallNoArg.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); -#else -#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL) -#endif - -/* ListAppend.proto */ -#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS -static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { - PyListObject* L = (PyListObject*) list; - Py_ssize_t len = Py_SIZE(list); - if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { - Py_INCREF(x); - PyList_SET_ITEM(list, len, x); - __Pyx_SET_SIZE(list, len + 1); - return 0; - } - return PyList_Append(list, x); -} -#else -#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) -#endif - -/* PyUnicode_Substring.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( - PyObject* text, Py_ssize_t start, Py_ssize_t stop); - -/* PyUnicodeContains.proto */ -static CYTHON_INLINE int __Pyx_PyUnicode_ContainsTF(PyObject* substring, PyObject* text, int eq) { - int result = PyUnicode_Contains(text, substring); - return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); -} - -/* PyObjectCall2Args.proto */ -static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); - -/* SliceObject.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice( - PyObject* obj, Py_ssize_t cstart, Py_ssize_t cstop, - PyObject** py_start, PyObject** py_stop, PyObject** py_slice, - int has_cstart, int has_cstop, int wraparound); - -/* PySequenceContains.proto */ -static CYTHON_INLINE int __Pyx_PySequence_ContainsTF(PyObject* item, PyObject* seq, int eq) { - int result = PySequence_Contains(seq, item); - return unlikely(result < 0) ? result : (result == (eq == Py_EQ)); -} - -/* Import.proto */ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); - -/* ImportFrom.proto */ -static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); - -/* GetItemInt.proto */ -#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ - (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ - __Pyx_GetItemInt_Generic(o, to_py_func(i)))) -#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ - (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, - int wraparound, int boundscheck); -#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ - (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, - int wraparound, int boundscheck); -static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, - int is_list, int wraparound, int boundscheck); - -/* IncludeStringH.proto */ -#include - -/* HasAttr.proto */ -static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *); - -/* ExtTypeTest.proto */ -static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); - -/* PyObject_GenericGetAttrNoDict.proto */ -#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 -static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name); -#else -#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr -#endif - -/* PyObject_GenericGetAttr.proto */ -#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 -static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name); -#else -#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr -#endif - -/* SetVTable.proto */ -static int __Pyx_SetVtable(PyObject *dict, void *vtable); - -/* PyObjectGetAttrStrNoError.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); - -/* SetupReduce.proto */ -static int __Pyx_setup_reduce(PyObject* type_obj); - -/* TypeImport.proto */ -#ifndef __PYX_HAVE_RT_ImportType_proto -#define __PYX_HAVE_RT_ImportType_proto -enum __Pyx_ImportType_CheckSize { - __Pyx_ImportType_CheckSize_Error = 0, - __Pyx_ImportType_CheckSize_Warn = 1, - __Pyx_ImportType_CheckSize_Ignore = 2 -}; -static PyTypeObject *__Pyx_ImportType(PyObject* module, const char *module_name, const char *class_name, size_t size, enum __Pyx_ImportType_CheckSize check_size); -#endif - -/* CLineInTraceback.proto */ -#ifdef CYTHON_CLINE_IN_TRACEBACK -#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) -#else -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); -#endif - -/* CodeObjectCache.proto */ -typedef struct { - PyCodeObject* code_object; - int code_line; -} __Pyx_CodeObjectCacheEntry; -struct __Pyx_CodeObjectCache { - int count; - int max_count; - __Pyx_CodeObjectCacheEntry* entries; -}; -static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); -static PyCodeObject *__pyx_find_code_object(int code_line); -static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); - -/* AddTraceback.proto */ -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - -/* GCCDiagnostics.proto */ -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define __Pyx_HAS_GCC_DIAGNOSTIC -#endif - -/* PyUCS4InUnicode.proto */ -static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character); - -/* UnicodeAsUCS4.proto */ -static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject*); - -/* CIntFromPy.proto */ -static CYTHON_INLINE uint8_t __Pyx_PyInt_As_uint8_t(PyObject *); - -/* CIntFromPy.proto */ -static CYTHON_INLINE uint64_t __Pyx_PyInt_As_uint64_t(PyObject *); - -/* CIntFromPy.proto */ -static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); - -/* CIntToPy.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value); - -/* CIntToPy.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); - -/* ObjectAsUCS4.proto */ -#define __Pyx_PyObject_AsPy_UCS4(x)\ - (likely(PyUnicode_Check(x)) ? __Pyx_PyUnicode_AsPy_UCS4(x) : __Pyx__PyObject_AsPy_UCS4(x)) -static Py_UCS4 __Pyx__PyObject_AsPy_UCS4(PyObject*); - -/* CIntFromPy.proto */ -static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); - -/* FastTypeChecks.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); -#else -#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) -#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) -#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2)) -#endif -#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) - -/* CheckBinaryVersion.proto */ -static int __Pyx_check_binary_version(void); - -/* InitStrings.proto */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); - -static PyObject *__pyx_f_4yarl_10_quoting_c_7_Quoter__do_quote(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v_val, struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer); /* proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c_7_Quoter__write(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer, Py_UCS4 __pyx_v_ch); /* proto*/ -static PyObject *__pyx_f_4yarl_10_quoting_c_9_Unquoter__do_unquote(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v_val); /* proto*/ - -/* Module declarations from 'libc.string' */ - -/* Module declarations from 'libc.stdio' */ - -/* Module declarations from '__builtin__' */ - -/* Module declarations from 'cpython.type' */ -static PyTypeObject *__pyx_ptype_7cpython_4type_type = 0; - -/* Module declarations from 'cpython' */ - -/* Module declarations from 'cpython.object' */ - -/* Module declarations from 'cpython.exc' */ - -/* Module declarations from 'cpython.mem' */ - -/* Module declarations from 'cpython.unicode' */ - -/* Module declarations from 'libc.stdint' */ - -/* Module declarations from 'yarl._quoting_c' */ -static PyTypeObject *__pyx_ptype_4yarl_10_quoting_c__Quoter = 0; -static PyTypeObject *__pyx_ptype_4yarl_10_quoting_c__Unquoter = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_GEN_DELIMS = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_SUB_DELIMS_WITHOUT_QS = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_SUB_DELIMS = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_RESERVED = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_UNRESERVED = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_ALLOWED = 0; -static PyObject *__pyx_v_4yarl_10_quoting_c_QS = 0; -static char __pyx_v_4yarl_10_quoting_c_BUFFER[0x2000]; -static uint8_t __pyx_v_4yarl_10_quoting_c_ALLOWED_TABLE[16]; -static uint8_t __pyx_v_4yarl_10_quoting_c_ALLOWED_NOTQS_TABLE[16]; -static CYTHON_INLINE Py_UCS4 __pyx_f_4yarl_10_quoting_c__to_hex(uint8_t); /*proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__from_hex(Py_UCS4); /*proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__is_lower_hex(Py_UCS4); /*proto*/ -static CYTHON_INLINE Py_UCS4 __pyx_f_4yarl_10_quoting_c__restore_ch(Py_UCS4, Py_UCS4); /*proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c_bit_at(uint8_t *, uint64_t); /*proto*/ -static CYTHON_INLINE void __pyx_f_4yarl_10_quoting_c_set_bit(uint8_t *, uint64_t); /*proto*/ -static CYTHON_INLINE void __pyx_f_4yarl_10_quoting_c__init_writer(struct __pyx_t_4yarl_10_quoting_c_Writer *); /*proto*/ -static CYTHON_INLINE void __pyx_f_4yarl_10_quoting_c__release_writer(struct __pyx_t_4yarl_10_quoting_c_Writer *); /*proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__write_char(struct __pyx_t_4yarl_10_quoting_c_Writer *, Py_UCS4, int); /*proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__write_pct(struct __pyx_t_4yarl_10_quoting_c_Writer *, uint8_t, int); /*proto*/ -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__write_utf8(struct __pyx_t_4yarl_10_quoting_c_Writer *, Py_UCS4); /*proto*/ -static PyObject *__pyx_f_4yarl_10_quoting_c___pyx_unpickle__Quoter__set_state(struct __pyx_obj_4yarl_10_quoting_c__Quoter *, PyObject *); /*proto*/ -static PyObject *__pyx_f_4yarl_10_quoting_c___pyx_unpickle__Unquoter__set_state(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *, PyObject *); /*proto*/ -static int __Pyx_carray_from_py_uint8_t(PyObject *, uint8_t *, Py_ssize_t); /*proto*/ -#define __Pyx_MODULE_NAME "yarl._quoting_c" -extern int __pyx_module_is_main_yarl___quoting_c; -int __pyx_module_is_main_yarl___quoting_c = 0; - -/* Implementation of 'yarl._quoting_c' */ -static PyObject *__pyx_builtin_range; -static PyObject *__pyx_builtin_chr; -static PyObject *__pyx_builtin_ValueError; -static PyObject *__pyx_builtin_TypeError; -static PyObject *__pyx_builtin_UnicodeDecodeError; -static PyObject *__pyx_builtin_hex; -static PyObject *__pyx_builtin_OverflowError; -static PyObject *__pyx_builtin_enumerate; -static PyObject *__pyx_builtin_IndexError; -static const char __pyx_k_[] = ""; -static const char __pyx_k_i[] = "i"; -static const char __pyx_k__4[] = "+=&;"; -static const char __pyx_k__5[] = "+"; -static const char __pyx_k__6[] = " "; -static const char __pyx_k__7[] = "%"; -static const char __pyx_k_qs[] = "qs"; -static const char __pyx_k__11[] = ":/?#[]@"; -static const char __pyx_k__12[] = "!$'()*,"; -static const char __pyx_k__13[] = "+?=;"; -static const char __pyx_k__14[] = "-._~"; -static const char __pyx_k__15[] = "+&=;"; -static const char __pyx_k_chr[] = "chr"; -static const char __pyx_k_hex[] = "hex"; -static const char __pyx_k_new[] = "__new__"; -static const char __pyx_k_val[] = "val"; -static const char __pyx_k_dict[] = "__dict__"; -static const char __pyx_k_main[] = "__main__"; -static const char __pyx_k_name[] = "__name__"; -static const char __pyx_k_safe[] = "safe"; -static const char __pyx_k_test[] = "__test__"; -static const char __pyx_k_range[] = "range"; -static const char __pyx_k_upper[] = "upper"; -static const char __pyx_k_Quoter[] = "_Quoter"; -static const char __pyx_k_digits[] = "digits"; -static const char __pyx_k_import[] = "__import__"; -static const char __pyx_k_pickle[] = "pickle"; -static const char __pyx_k_reduce[] = "__reduce__"; -static const char __pyx_k_string[] = "string"; -static const char __pyx_k_unsafe[] = "unsafe"; -static const char __pyx_k_update[] = "update"; -static const char __pyx_k_requote[] = "requote"; -static const char __pyx_k_Unquoter[] = "_Unquoter"; -static const char __pyx_k_getstate[] = "__getstate__"; -static const char __pyx_k_pyx_type[] = "__pyx_type"; -static const char __pyx_k_setstate[] = "__setstate__"; -static const char __pyx_k_TypeError[] = "TypeError"; -static const char __pyx_k_enumerate[] = "enumerate"; -static const char __pyx_k_protected[] = "protected"; -static const char __pyx_k_pyx_state[] = "__pyx_state"; -static const char __pyx_k_reduce_ex[] = "__reduce_ex__"; -static const char __pyx_k_IndexError[] = "IndexError"; -static const char __pyx_k_ValueError[] = "ValueError"; -static const char __pyx_k_pyx_result[] = "__pyx_result"; -static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__"; -static const char __pyx_k_PickleError[] = "PickleError"; -static const char __pyx_k_pyx_checksum[] = "__pyx_checksum"; -static const char __pyx_k_stringsource[] = "stringsource"; -static const char __pyx_k_OverflowError[] = "OverflowError"; -static const char __pyx_k_ascii_letters[] = "ascii_letters"; -static const char __pyx_k_reduce_cython[] = "__reduce_cython__"; -static const char __pyx_k_pyx_PickleError[] = "__pyx_PickleError"; -static const char __pyx_k_setstate_cython[] = "__setstate_cython__"; -static const char __pyx_k_yarl__quoting_c[] = "yarl._quoting_c"; -static const char __pyx_k_UnicodeDecodeError[] = "UnicodeDecodeError"; -static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; -static const char __pyx_k_pyx_unpickle__Quoter[] = "__pyx_unpickle__Quoter"; -static const char __pyx_k_Argument_should_be_str[] = "Argument should be str"; -static const char __pyx_k_pyx_unpickle__Unquoter[] = "__pyx_unpickle__Unquoter"; -static const char __pyx_k_Incompatible_checksums_0x_x_vs_0[] = "Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))"; -static const char __pyx_k_Only_safe_symbols_with_ORD_128_a[] = "Only safe symbols with ORD < 128 are allowed"; -static const char __pyx_k_Incompatible_checksums_0x_x_vs_0_2[] = "Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))"; -static PyObject *__pyx_kp_u_; -static PyObject *__pyx_kp_u_Argument_should_be_str; -static PyObject *__pyx_kp_s_Incompatible_checksums_0x_x_vs_0; -static PyObject *__pyx_kp_s_Incompatible_checksums_0x_x_vs_0_2; -static PyObject *__pyx_n_s_IndexError; -static PyObject *__pyx_kp_u_Only_safe_symbols_with_ORD_128_a; -static PyObject *__pyx_n_s_OverflowError; -static PyObject *__pyx_n_s_PickleError; -static PyObject *__pyx_n_s_Quoter; -static PyObject *__pyx_n_s_TypeError; -static PyObject *__pyx_n_s_UnicodeDecodeError; -static PyObject *__pyx_n_s_Unquoter; -static PyObject *__pyx_n_s_ValueError; -static PyObject *__pyx_kp_u__11; -static PyObject *__pyx_kp_u__12; -static PyObject *__pyx_kp_u__13; -static PyObject *__pyx_kp_u__14; -static PyObject *__pyx_kp_u__15; -static PyObject *__pyx_kp_u__4; -static PyObject *__pyx_kp_u__5; -static PyObject *__pyx_kp_u__6; -static PyObject *__pyx_kp_u__7; -static PyObject *__pyx_n_s_ascii_letters; -static PyObject *__pyx_n_s_chr; -static PyObject *__pyx_n_s_cline_in_traceback; -static PyObject *__pyx_n_s_dict; -static PyObject *__pyx_n_s_digits; -static PyObject *__pyx_n_s_enumerate; -static PyObject *__pyx_n_s_getstate; -static PyObject *__pyx_n_s_hex; -static PyObject *__pyx_n_s_i; -static PyObject *__pyx_n_s_import; -static PyObject *__pyx_n_s_main; -static PyObject *__pyx_n_s_name; -static PyObject *__pyx_n_s_new; -static PyObject *__pyx_n_s_pickle; -static PyObject *__pyx_n_s_protected; -static PyObject *__pyx_n_s_pyx_PickleError; -static PyObject *__pyx_n_s_pyx_checksum; -static PyObject *__pyx_n_s_pyx_result; -static PyObject *__pyx_n_s_pyx_state; -static PyObject *__pyx_n_s_pyx_type; -static PyObject *__pyx_n_s_pyx_unpickle__Quoter; -static PyObject *__pyx_n_s_pyx_unpickle__Unquoter; -static PyObject *__pyx_n_s_pyx_vtable; -static PyObject *__pyx_n_s_qs; -static PyObject *__pyx_n_s_range; -static PyObject *__pyx_n_s_reduce; -static PyObject *__pyx_n_s_reduce_cython; -static PyObject *__pyx_n_s_reduce_ex; -static PyObject *__pyx_n_s_requote; -static PyObject *__pyx_n_s_safe; -static PyObject *__pyx_n_s_setstate; -static PyObject *__pyx_n_s_setstate_cython; -static PyObject *__pyx_n_s_string; -static PyObject *__pyx_kp_s_stringsource; -static PyObject *__pyx_n_s_test; -static PyObject *__pyx_n_s_unsafe; -static PyObject *__pyx_n_s_update; -static PyObject *__pyx_n_s_upper; -static PyObject *__pyx_n_s_val; -static PyObject *__pyx_n_s_yarl__quoting_c; -static int __pyx_pf_4yarl_10_quoting_c_7_Quoter___init__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v_safe, PyObject *__pyx_v_protected, int __pyx_v_qs, int __pyx_v_requote); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_7_Quoter_2__call__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v_val); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_7_Quoter_4__reduce_cython__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_7_Quoter_6__setstate_cython__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ -static int __pyx_pf_4yarl_10_quoting_c_9_Unquoter___init__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v_unsafe, PyObject *__pyx_v_qs); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_9_Unquoter_2__call__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v_val); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_9_Unquoter_4__reduce_cython__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_9_Unquoter_6__setstate_cython__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c___pyx_unpickle__Quoter(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ -static PyObject *__pyx_pf_4yarl_10_quoting_c_2__pyx_unpickle__Unquoter(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */ -static PyObject *__pyx_tp_new_4yarl_10_quoting_c__Quoter(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ -static PyObject *__pyx_tp_new_4yarl_10_quoting_c__Unquoter(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/ -static PyObject *__pyx_int_2; -static PyObject *__pyx_int_41310077; -static PyObject *__pyx_int_81650385; -static PyObject *__pyx_int_87395286; -static PyObject *__pyx_int_101395286; -static PyObject *__pyx_int_132655457; -static PyObject *__pyx_int_244432181; -static PyObject *__pyx_slice__8; -static PyObject *__pyx_tuple__2; -static PyObject *__pyx_tuple__3; -static PyObject *__pyx_tuple__9; -static PyObject *__pyx_tuple__10; -static PyObject *__pyx_tuple__16; -static PyObject *__pyx_tuple__18; -static PyObject *__pyx_codeobj__17; -static PyObject *__pyx_codeobj__19; -/* Late includes */ - -/* "yarl/_quoting_c.pyx":23 - * cdef char BUFFER[BUF_SIZE] - * - * cdef inline Py_UCS4 _to_hex(uint8_t v): # <<<<<<<<<<<<<< - * if v < 10: - * return (v+0x30) # ord('0') == 0x30 - */ - -static CYTHON_INLINE Py_UCS4 __pyx_f_4yarl_10_quoting_c__to_hex(uint8_t __pyx_v_v) { - Py_UCS4 __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - __Pyx_RefNannySetupContext("_to_hex", 0); - - /* "yarl/_quoting_c.pyx":24 - * - * cdef inline Py_UCS4 _to_hex(uint8_t v): - * if v < 10: # <<<<<<<<<<<<<< - * return (v+0x30) # ord('0') == 0x30 - * else: - */ - __pyx_t_1 = ((__pyx_v_v < 10) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":25 - * cdef inline Py_UCS4 _to_hex(uint8_t v): - * if v < 10: - * return (v+0x30) # ord('0') == 0x30 # <<<<<<<<<<<<<< - * else: - * return (v+0x41-10) # ord('A') == 0x41 - */ - __pyx_r = ((Py_UCS4)(__pyx_v_v + 0x30)); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":24 - * - * cdef inline Py_UCS4 _to_hex(uint8_t v): - * if v < 10: # <<<<<<<<<<<<<< - * return (v+0x30) # ord('0') == 0x30 - * else: - */ - } - - /* "yarl/_quoting_c.pyx":27 - * return (v+0x30) # ord('0') == 0x30 - * else: - * return (v+0x41-10) # ord('A') == 0x41 # <<<<<<<<<<<<<< - * - * - */ - /*else*/ { - __pyx_r = ((Py_UCS4)((__pyx_v_v + 0x41) - 10)); - goto __pyx_L0; - } - - /* "yarl/_quoting_c.pyx":23 - * cdef char BUFFER[BUF_SIZE] - * - * cdef inline Py_UCS4 _to_hex(uint8_t v): # <<<<<<<<<<<<<< - * if v < 10: - * return (v+0x30) # ord('0') == 0x30 - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":30 - * - * - * cdef inline int _from_hex(Py_UCS4 v): # <<<<<<<<<<<<<< - * if '0' <= v <= '9': - * return (v) - 0x30 # ord('0') == 0x30 - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__from_hex(Py_UCS4 __pyx_v_v) { - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - __Pyx_RefNannySetupContext("_from_hex", 0); - - /* "yarl/_quoting_c.pyx":31 - * - * cdef inline int _from_hex(Py_UCS4 v): - * if '0' <= v <= '9': # <<<<<<<<<<<<<< - * return (v) - 0x30 # ord('0') == 0x30 - * elif 'A' <= v <= 'F': - */ - __pyx_t_1 = (48 <= __pyx_v_v); - if (__pyx_t_1) { - __pyx_t_1 = (__pyx_v_v <= 57); - } - __pyx_t_2 = (__pyx_t_1 != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":32 - * cdef inline int _from_hex(Py_UCS4 v): - * if '0' <= v <= '9': - * return (v) - 0x30 # ord('0') == 0x30 # <<<<<<<<<<<<<< - * elif 'A' <= v <= 'F': - * return (v) - 0x41 + 10 # ord('A') == 0x41 - */ - __pyx_r = (((int)__pyx_v_v) - 0x30); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":31 - * - * cdef inline int _from_hex(Py_UCS4 v): - * if '0' <= v <= '9': # <<<<<<<<<<<<<< - * return (v) - 0x30 # ord('0') == 0x30 - * elif 'A' <= v <= 'F': - */ - } - - /* "yarl/_quoting_c.pyx":33 - * if '0' <= v <= '9': - * return (v) - 0x30 # ord('0') == 0x30 - * elif 'A' <= v <= 'F': # <<<<<<<<<<<<<< - * return (v) - 0x41 + 10 # ord('A') == 0x41 - * elif 'a' <= v <= 'f': - */ - __pyx_t_2 = (65 <= __pyx_v_v); - if (__pyx_t_2) { - __pyx_t_2 = (__pyx_v_v <= 70); - } - __pyx_t_1 = (__pyx_t_2 != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":34 - * return (v) - 0x30 # ord('0') == 0x30 - * elif 'A' <= v <= 'F': - * return (v) - 0x41 + 10 # ord('A') == 0x41 # <<<<<<<<<<<<<< - * elif 'a' <= v <= 'f': - * return (v) - 0x61 + 10 # ord('a') == 0x61 - */ - __pyx_r = ((((int)__pyx_v_v) - 0x41) + 10); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":33 - * if '0' <= v <= '9': - * return (v) - 0x30 # ord('0') == 0x30 - * elif 'A' <= v <= 'F': # <<<<<<<<<<<<<< - * return (v) - 0x41 + 10 # ord('A') == 0x41 - * elif 'a' <= v <= 'f': - */ - } - - /* "yarl/_quoting_c.pyx":35 - * elif 'A' <= v <= 'F': - * return (v) - 0x41 + 10 # ord('A') == 0x41 - * elif 'a' <= v <= 'f': # <<<<<<<<<<<<<< - * return (v) - 0x61 + 10 # ord('a') == 0x61 - * else: - */ - __pyx_t_1 = (97 <= __pyx_v_v); - if (__pyx_t_1) { - __pyx_t_1 = (__pyx_v_v <= 0x66); - } - __pyx_t_2 = (__pyx_t_1 != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":36 - * return (v) - 0x41 + 10 # ord('A') == 0x41 - * elif 'a' <= v <= 'f': - * return (v) - 0x61 + 10 # ord('a') == 0x61 # <<<<<<<<<<<<<< - * else: - * return -1 - */ - __pyx_r = ((((int)__pyx_v_v) - 0x61) + 10); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":35 - * elif 'A' <= v <= 'F': - * return (v) - 0x41 + 10 # ord('A') == 0x41 - * elif 'a' <= v <= 'f': # <<<<<<<<<<<<<< - * return (v) - 0x61 + 10 # ord('a') == 0x61 - * else: - */ - } - - /* "yarl/_quoting_c.pyx":38 - * return (v) - 0x61 + 10 # ord('a') == 0x61 - * else: - * return -1 # <<<<<<<<<<<<<< - * - * - */ - /*else*/ { - __pyx_r = -1; - goto __pyx_L0; - } - - /* "yarl/_quoting_c.pyx":30 - * - * - * cdef inline int _from_hex(Py_UCS4 v): # <<<<<<<<<<<<<< - * if '0' <= v <= '9': - * return (v) - 0x30 # ord('0') == 0x30 - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":41 - * - * - * cdef inline int _is_lower_hex(Py_UCS4 v): # <<<<<<<<<<<<<< - * return 'a' <= v <= 'f' - * - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__is_lower_hex(Py_UCS4 __pyx_v_v) { - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - __Pyx_RefNannySetupContext("_is_lower_hex", 0); - - /* "yarl/_quoting_c.pyx":42 - * - * cdef inline int _is_lower_hex(Py_UCS4 v): - * return 'a' <= v <= 'f' # <<<<<<<<<<<<<< - * - * - */ - __pyx_t_1 = (97 <= __pyx_v_v); - if (__pyx_t_1) { - __pyx_t_1 = (__pyx_v_v <= 0x66); - } - __pyx_r = __pyx_t_1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":41 - * - * - * cdef inline int _is_lower_hex(Py_UCS4 v): # <<<<<<<<<<<<<< - * return 'a' <= v <= 'f' - * - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":45 - * - * - * cdef inline Py_UCS4 _restore_ch(Py_UCS4 d1, Py_UCS4 d2): # <<<<<<<<<<<<<< - * cdef int digit1 = _from_hex(d1) - * if digit1 < 0: - */ - -static CYTHON_INLINE Py_UCS4 __pyx_f_4yarl_10_quoting_c__restore_ch(Py_UCS4 __pyx_v_d1, Py_UCS4 __pyx_v_d2) { - int __pyx_v_digit1; - int __pyx_v_digit2; - Py_UCS4 __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - __Pyx_RefNannySetupContext("_restore_ch", 0); - - /* "yarl/_quoting_c.pyx":46 - * - * cdef inline Py_UCS4 _restore_ch(Py_UCS4 d1, Py_UCS4 d2): - * cdef int digit1 = _from_hex(d1) # <<<<<<<<<<<<<< - * if digit1 < 0: - * return -1 - */ - __pyx_v_digit1 = __pyx_f_4yarl_10_quoting_c__from_hex(__pyx_v_d1); - - /* "yarl/_quoting_c.pyx":47 - * cdef inline Py_UCS4 _restore_ch(Py_UCS4 d1, Py_UCS4 d2): - * cdef int digit1 = _from_hex(d1) - * if digit1 < 0: # <<<<<<<<<<<<<< - * return -1 - * cdef int digit2 = _from_hex(d2) - */ - __pyx_t_1 = ((__pyx_v_digit1 < 0) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":48 - * cdef int digit1 = _from_hex(d1) - * if digit1 < 0: - * return -1 # <<<<<<<<<<<<<< - * cdef int digit2 = _from_hex(d2) - * if digit2 < 0: - */ - __pyx_r = ((Py_UCS4)-1L); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":47 - * cdef inline Py_UCS4 _restore_ch(Py_UCS4 d1, Py_UCS4 d2): - * cdef int digit1 = _from_hex(d1) - * if digit1 < 0: # <<<<<<<<<<<<<< - * return -1 - * cdef int digit2 = _from_hex(d2) - */ - } - - /* "yarl/_quoting_c.pyx":49 - * if digit1 < 0: - * return -1 - * cdef int digit2 = _from_hex(d2) # <<<<<<<<<<<<<< - * if digit2 < 0: - * return -1 - */ - __pyx_v_digit2 = __pyx_f_4yarl_10_quoting_c__from_hex(__pyx_v_d2); - - /* "yarl/_quoting_c.pyx":50 - * return -1 - * cdef int digit2 = _from_hex(d2) - * if digit2 < 0: # <<<<<<<<<<<<<< - * return -1 - * return (digit1 << 4 | digit2) - */ - __pyx_t_1 = ((__pyx_v_digit2 < 0) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":51 - * cdef int digit2 = _from_hex(d2) - * if digit2 < 0: - * return -1 # <<<<<<<<<<<<<< - * return (digit1 << 4 | digit2) - * - */ - __pyx_r = ((Py_UCS4)-1L); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":50 - * return -1 - * cdef int digit2 = _from_hex(d2) - * if digit2 < 0: # <<<<<<<<<<<<<< - * return -1 - * return (digit1 << 4 | digit2) - */ - } - - /* "yarl/_quoting_c.pyx":52 - * if digit2 < 0: - * return -1 - * return (digit1 << 4 | digit2) # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = ((Py_UCS4)((__pyx_v_digit1 << 4) | __pyx_v_digit2)); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":45 - * - * - * cdef inline Py_UCS4 _restore_ch(Py_UCS4 d1, Py_UCS4 d2): # <<<<<<<<<<<<<< - * cdef int digit1 = _from_hex(d1) - * if digit1 < 0: - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":59 - * - * - * cdef inline bint bit_at(uint8_t array[], uint64_t ch): # <<<<<<<<<<<<<< - * return array[ch >> 3] & (1 << (ch & 7)) - * - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c_bit_at(uint8_t *__pyx_v_array, uint64_t __pyx_v_ch) { - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("bit_at", 0); - - /* "yarl/_quoting_c.pyx":60 - * - * cdef inline bint bit_at(uint8_t array[], uint64_t ch): - * return array[ch >> 3] & (1 << (ch & 7)) # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = ((__pyx_v_array[(__pyx_v_ch >> 3)]) & (1 << (__pyx_v_ch & 7))); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":59 - * - * - * cdef inline bint bit_at(uint8_t array[], uint64_t ch): # <<<<<<<<<<<<<< - * return array[ch >> 3] & (1 << (ch & 7)) - * - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":63 - * - * - * cdef inline void set_bit(uint8_t array[], uint64_t ch): # <<<<<<<<<<<<<< - * array[ch >> 3] |= (1 << (ch & 7)) - * - */ - -static CYTHON_INLINE void __pyx_f_4yarl_10_quoting_c_set_bit(uint8_t *__pyx_v_array, uint64_t __pyx_v_ch) { - __Pyx_RefNannyDeclarations - uint64_t __pyx_t_1; - __Pyx_RefNannySetupContext("set_bit", 0); - - /* "yarl/_quoting_c.pyx":64 - * - * cdef inline void set_bit(uint8_t array[], uint64_t ch): - * array[ch >> 3] |= (1 << (ch & 7)) # <<<<<<<<<<<<<< - * - * - */ - __pyx_t_1 = (__pyx_v_ch >> 3); - (__pyx_v_array[__pyx_t_1]) = ((__pyx_v_array[__pyx_t_1]) | (1 << (__pyx_v_ch & 7))); - - /* "yarl/_quoting_c.pyx":63 - * - * - * cdef inline void set_bit(uint8_t array[], uint64_t ch): # <<<<<<<<<<<<<< - * array[ch >> 3] |= (1 << (ch & 7)) - * - */ - - /* function exit code */ - __Pyx_RefNannyFinishContext(); -} - -/* "yarl/_quoting_c.pyx":86 - * - * - * cdef inline void _init_writer(Writer* writer): # <<<<<<<<<<<<<< - * writer.buf = &BUFFER[0] - * writer.size = BUF_SIZE - */ - -static CYTHON_INLINE void __pyx_f_4yarl_10_quoting_c__init_writer(struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("_init_writer", 0); - - /* "yarl/_quoting_c.pyx":87 - * - * cdef inline void _init_writer(Writer* writer): - * writer.buf = &BUFFER[0] # <<<<<<<<<<<<<< - * writer.size = BUF_SIZE - * writer.pos = 0 - */ - __pyx_v_writer->buf = (&(__pyx_v_4yarl_10_quoting_c_BUFFER[0])); - - /* "yarl/_quoting_c.pyx":88 - * cdef inline void _init_writer(Writer* writer): - * writer.buf = &BUFFER[0] - * writer.size = BUF_SIZE # <<<<<<<<<<<<<< - * writer.pos = 0 - * writer.changed = 0 - */ - __pyx_v_writer->size = 0x2000; - - /* "yarl/_quoting_c.pyx":89 - * writer.buf = &BUFFER[0] - * writer.size = BUF_SIZE - * writer.pos = 0 # <<<<<<<<<<<<<< - * writer.changed = 0 - * - */ - __pyx_v_writer->pos = 0; - - /* "yarl/_quoting_c.pyx":90 - * writer.size = BUF_SIZE - * writer.pos = 0 - * writer.changed = 0 # <<<<<<<<<<<<<< - * - * - */ - __pyx_v_writer->changed = 0; - - /* "yarl/_quoting_c.pyx":86 - * - * - * cdef inline void _init_writer(Writer* writer): # <<<<<<<<<<<<<< - * writer.buf = &BUFFER[0] - * writer.size = BUF_SIZE - */ - - /* function exit code */ - __Pyx_RefNannyFinishContext(); -} - -/* "yarl/_quoting_c.pyx":93 - * - * - * cdef inline void _release_writer(Writer* writer): # <<<<<<<<<<<<<< - * if writer.buf != BUFFER: - * PyMem_Free(writer.buf) - */ - -static CYTHON_INLINE void __pyx_f_4yarl_10_quoting_c__release_writer(struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer) { - __Pyx_RefNannyDeclarations - int __pyx_t_1; - __Pyx_RefNannySetupContext("_release_writer", 0); - - /* "yarl/_quoting_c.pyx":94 - * - * cdef inline void _release_writer(Writer* writer): - * if writer.buf != BUFFER: # <<<<<<<<<<<<<< - * PyMem_Free(writer.buf) - * - */ - __pyx_t_1 = ((__pyx_v_writer->buf != __pyx_v_4yarl_10_quoting_c_BUFFER) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":95 - * cdef inline void _release_writer(Writer* writer): - * if writer.buf != BUFFER: - * PyMem_Free(writer.buf) # <<<<<<<<<<<<<< - * - * - */ - PyMem_Free(__pyx_v_writer->buf); - - /* "yarl/_quoting_c.pyx":94 - * - * cdef inline void _release_writer(Writer* writer): - * if writer.buf != BUFFER: # <<<<<<<<<<<<<< - * PyMem_Free(writer.buf) - * - */ - } - - /* "yarl/_quoting_c.pyx":93 - * - * - * cdef inline void _release_writer(Writer* writer): # <<<<<<<<<<<<<< - * if writer.buf != BUFFER: - * PyMem_Free(writer.buf) - */ - - /* function exit code */ - __Pyx_RefNannyFinishContext(); -} - -/* "yarl/_quoting_c.pyx":98 - * - * - * cdef inline int _write_char(Writer* writer, Py_UCS4 ch, bint changed): # <<<<<<<<<<<<<< - * cdef char * buf - * cdef Py_ssize_t size - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__write_char(struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer, Py_UCS4 __pyx_v_ch, int __pyx_v_changed) { - char *__pyx_v_buf; - Py_ssize_t __pyx_v_size; - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - PyObject *__pyx_t_2; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("_write_char", 0); - - /* "yarl/_quoting_c.pyx":102 - * cdef Py_ssize_t size - * - * if writer.pos == writer.size: # <<<<<<<<<<<<<< - * # reallocate - * size = writer.size + BUF_SIZE - */ - __pyx_t_1 = ((__pyx_v_writer->pos == __pyx_v_writer->size) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":104 - * if writer.pos == writer.size: - * # reallocate - * size = writer.size + BUF_SIZE # <<<<<<<<<<<<<< - * if writer.buf == BUFFER: - * buf = PyMem_Malloc(size) - */ - __pyx_v_size = (__pyx_v_writer->size + 0x2000); - - /* "yarl/_quoting_c.pyx":105 - * # reallocate - * size = writer.size + BUF_SIZE - * if writer.buf == BUFFER: # <<<<<<<<<<<<<< - * buf = PyMem_Malloc(size) - * if buf == NULL: - */ - __pyx_t_1 = ((__pyx_v_writer->buf == __pyx_v_4yarl_10_quoting_c_BUFFER) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":106 - * size = writer.size + BUF_SIZE - * if writer.buf == BUFFER: - * buf = PyMem_Malloc(size) # <<<<<<<<<<<<<< - * if buf == NULL: - * PyErr_NoMemory() - */ - __pyx_v_buf = ((char *)PyMem_Malloc(__pyx_v_size)); - - /* "yarl/_quoting_c.pyx":107 - * if writer.buf == BUFFER: - * buf = PyMem_Malloc(size) - * if buf == NULL: # <<<<<<<<<<<<<< - * PyErr_NoMemory() - * return -1 - */ - __pyx_t_1 = ((__pyx_v_buf == NULL) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":108 - * buf = PyMem_Malloc(size) - * if buf == NULL: - * PyErr_NoMemory() # <<<<<<<<<<<<<< - * return -1 - * memcpy(buf, writer.buf, writer.size) - */ - __pyx_t_2 = PyErr_NoMemory(); if (unlikely(__pyx_t_2 == ((PyObject *)NULL))) __PYX_ERR(0, 108, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":109 - * if buf == NULL: - * PyErr_NoMemory() - * return -1 # <<<<<<<<<<<<<< - * memcpy(buf, writer.buf, writer.size) - * else: - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":107 - * if writer.buf == BUFFER: - * buf = PyMem_Malloc(size) - * if buf == NULL: # <<<<<<<<<<<<<< - * PyErr_NoMemory() - * return -1 - */ - } - - /* "yarl/_quoting_c.pyx":110 - * PyErr_NoMemory() - * return -1 - * memcpy(buf, writer.buf, writer.size) # <<<<<<<<<<<<<< - * else: - * buf = PyMem_Realloc(writer.buf, size) - */ - (void)(memcpy(__pyx_v_buf, __pyx_v_writer->buf, __pyx_v_writer->size)); - - /* "yarl/_quoting_c.pyx":105 - * # reallocate - * size = writer.size + BUF_SIZE - * if writer.buf == BUFFER: # <<<<<<<<<<<<<< - * buf = PyMem_Malloc(size) - * if buf == NULL: - */ - goto __pyx_L4; - } - - /* "yarl/_quoting_c.pyx":112 - * memcpy(buf, writer.buf, writer.size) - * else: - * buf = PyMem_Realloc(writer.buf, size) # <<<<<<<<<<<<<< - * if buf == NULL: - * PyErr_NoMemory() - */ - /*else*/ { - __pyx_v_buf = ((char *)PyMem_Realloc(__pyx_v_writer->buf, __pyx_v_size)); - - /* "yarl/_quoting_c.pyx":113 - * else: - * buf = PyMem_Realloc(writer.buf, size) - * if buf == NULL: # <<<<<<<<<<<<<< - * PyErr_NoMemory() - * return -1 - */ - __pyx_t_1 = ((__pyx_v_buf == NULL) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":114 - * buf = PyMem_Realloc(writer.buf, size) - * if buf == NULL: - * PyErr_NoMemory() # <<<<<<<<<<<<<< - * return -1 - * writer.buf = buf - */ - __pyx_t_2 = PyErr_NoMemory(); if (unlikely(__pyx_t_2 == ((PyObject *)NULL))) __PYX_ERR(0, 114, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":115 - * if buf == NULL: - * PyErr_NoMemory() - * return -1 # <<<<<<<<<<<<<< - * writer.buf = buf - * writer.size = size - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":113 - * else: - * buf = PyMem_Realloc(writer.buf, size) - * if buf == NULL: # <<<<<<<<<<<<<< - * PyErr_NoMemory() - * return -1 - */ - } - } - __pyx_L4:; - - /* "yarl/_quoting_c.pyx":116 - * PyErr_NoMemory() - * return -1 - * writer.buf = buf # <<<<<<<<<<<<<< - * writer.size = size - * writer.buf[writer.pos] = ch - */ - __pyx_v_writer->buf = __pyx_v_buf; - - /* "yarl/_quoting_c.pyx":117 - * return -1 - * writer.buf = buf - * writer.size = size # <<<<<<<<<<<<<< - * writer.buf[writer.pos] = ch - * writer.pos += 1 - */ - __pyx_v_writer->size = __pyx_v_size; - - /* "yarl/_quoting_c.pyx":102 - * cdef Py_ssize_t size - * - * if writer.pos == writer.size: # <<<<<<<<<<<<<< - * # reallocate - * size = writer.size + BUF_SIZE - */ - } - - /* "yarl/_quoting_c.pyx":118 - * writer.buf = buf - * writer.size = size - * writer.buf[writer.pos] = ch # <<<<<<<<<<<<<< - * writer.pos += 1 - * writer.changed |= changed - */ - (__pyx_v_writer->buf[__pyx_v_writer->pos]) = ((char)__pyx_v_ch); - - /* "yarl/_quoting_c.pyx":119 - * writer.size = size - * writer.buf[writer.pos] = ch - * writer.pos += 1 # <<<<<<<<<<<<<< - * writer.changed |= changed - * return 0 - */ - __pyx_v_writer->pos = (__pyx_v_writer->pos + 1); - - /* "yarl/_quoting_c.pyx":120 - * writer.buf[writer.pos] = ch - * writer.pos += 1 - * writer.changed |= changed # <<<<<<<<<<<<<< - * return 0 - * - */ - __pyx_v_writer->changed = (__pyx_v_writer->changed | __pyx_v_changed); - - /* "yarl/_quoting_c.pyx":121 - * writer.pos += 1 - * writer.changed |= changed - * return 0 # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = 0; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":98 - * - * - * cdef inline int _write_char(Writer* writer, Py_UCS4 ch, bint changed): # <<<<<<<<<<<<<< - * cdef char * buf - * cdef Py_ssize_t size - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_WriteUnraisable("yarl._quoting_c._write_char", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0); - __pyx_r = 0; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":124 - * - * - * cdef inline int _write_pct(Writer* writer, uint8_t ch, bint changed): # <<<<<<<<<<<<<< - * if _write_char(writer, '%', changed) < 0: - * return -1 - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__write_pct(struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer, uint8_t __pyx_v_ch, int __pyx_v_changed) { - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - __Pyx_RefNannySetupContext("_write_pct", 0); - - /* "yarl/_quoting_c.pyx":125 - * - * cdef inline int _write_pct(Writer* writer, uint8_t ch, bint changed): - * if _write_char(writer, '%', changed) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: - */ - __pyx_t_1 = ((__pyx_f_4yarl_10_quoting_c__write_char(__pyx_v_writer, 37, __pyx_v_changed) < 0) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":126 - * cdef inline int _write_pct(Writer* writer, uint8_t ch, bint changed): - * if _write_char(writer, '%', changed) < 0: - * return -1 # <<<<<<<<<<<<<< - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: - * return -1 - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":125 - * - * cdef inline int _write_pct(Writer* writer, uint8_t ch, bint changed): - * if _write_char(writer, '%', changed) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: - */ - } - - /* "yarl/_quoting_c.pyx":127 - * if _write_char(writer, '%', changed) < 0: - * return -1 - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: # <<<<<<<<<<<<<< - * return -1 - * return _write_char(writer, _to_hex(ch & 0x0f), changed) - */ - __pyx_t_1 = ((__pyx_f_4yarl_10_quoting_c__write_char(__pyx_v_writer, __pyx_f_4yarl_10_quoting_c__to_hex((((uint8_t)__pyx_v_ch) >> 4)), __pyx_v_changed) < 0) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":128 - * return -1 - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: - * return -1 # <<<<<<<<<<<<<< - * return _write_char(writer, _to_hex(ch & 0x0f), changed) - * - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":127 - * if _write_char(writer, '%', changed) < 0: - * return -1 - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: # <<<<<<<<<<<<<< - * return -1 - * return _write_char(writer, _to_hex(ch & 0x0f), changed) - */ - } - - /* "yarl/_quoting_c.pyx":129 - * if _write_char(writer, _to_hex(ch >> 4), changed) < 0: - * return -1 - * return _write_char(writer, _to_hex(ch & 0x0f), changed) # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_char(__pyx_v_writer, __pyx_f_4yarl_10_quoting_c__to_hex((((uint8_t)__pyx_v_ch) & 0x0f)), __pyx_v_changed); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":124 - * - * - * cdef inline int _write_pct(Writer* writer, uint8_t ch, bint changed): # <<<<<<<<<<<<<< - * if _write_char(writer, '%', changed) < 0: - * return -1 - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":132 - * - * - * cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): # <<<<<<<<<<<<<< - * cdef uint64_t utf = symbol - * - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c__write_utf8(struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer, Py_UCS4 __pyx_v_symbol) { - uint64_t __pyx_v_utf; - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - __Pyx_RefNannySetupContext("_write_utf8", 0); - - /* "yarl/_quoting_c.pyx":133 - * - * cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): - * cdef uint64_t utf = symbol # <<<<<<<<<<<<<< - * - * if utf < 0x80: - */ - __pyx_v_utf = ((uint64_t)__pyx_v_symbol); - - /* "yarl/_quoting_c.pyx":135 - * cdef uint64_t utf = symbol - * - * if utf < 0x80: # <<<<<<<<<<<<<< - * return _write_pct(writer, utf, True) - * elif utf < 0x800: - */ - __pyx_t_1 = ((__pyx_v_utf < 0x80) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":136 - * - * if utf < 0x80: - * return _write_pct(writer, utf, True) # <<<<<<<<<<<<<< - * elif utf < 0x800: - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)__pyx_v_utf), 1); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":135 - * cdef uint64_t utf = symbol - * - * if utf < 0x80: # <<<<<<<<<<<<<< - * return _write_pct(writer, utf, True) - * elif utf < 0x800: - */ - } - - /* "yarl/_quoting_c.pyx":137 - * if utf < 0x80: - * return _write_pct(writer, utf, True) - * elif utf < 0x800: # <<<<<<<<<<<<<< - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: - * return -1 - */ - __pyx_t_1 = ((__pyx_v_utf < 0x800) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":138 - * return _write_pct(writer, utf, True) - * elif utf < 0x800: - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: # <<<<<<<<<<<<<< - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - */ - __pyx_t_1 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0xc0 | (__pyx_v_utf >> 6))), 1) < 0) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":139 - * elif utf < 0x800: - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: - * return -1 # <<<<<<<<<<<<<< - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * elif 0xD800 <= utf <= 0xDFFF: - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":138 - * return _write_pct(writer, utf, True) - * elif utf < 0x800: - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: # <<<<<<<<<<<<<< - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - */ - } - - /* "yarl/_quoting_c.pyx":140 - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) # <<<<<<<<<<<<<< - * elif 0xD800 <= utf <= 0xDFFF: - * # surogate pair, ignored - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0x80 | (__pyx_v_utf & 0x3f))), 1); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":137 - * if utf < 0x80: - * return _write_pct(writer, utf, True) - * elif utf < 0x800: # <<<<<<<<<<<<<< - * if _write_pct(writer, (0xc0 | (utf >> 6)), True) < 0: - * return -1 - */ - } - - /* "yarl/_quoting_c.pyx":141 - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * elif 0xD800 <= utf <= 0xDFFF: # <<<<<<<<<<<<<< - * # surogate pair, ignored - * return 0 - */ - __pyx_t_1 = (0xD800 <= __pyx_v_utf); - if (__pyx_t_1) { - __pyx_t_1 = (__pyx_v_utf <= 0xDFFF); - } - __pyx_t_2 = (__pyx_t_1 != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":143 - * elif 0xD800 <= utf <= 0xDFFF: - * # surogate pair, ignored - * return 0 # <<<<<<<<<<<<<< - * elif utf < 0x10000: - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: - */ - __pyx_r = 0; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":141 - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * elif 0xD800 <= utf <= 0xDFFF: # <<<<<<<<<<<<<< - * # surogate pair, ignored - * return 0 - */ - } - - /* "yarl/_quoting_c.pyx":144 - * # surogate pair, ignored - * return 0 - * elif utf < 0x10000: # <<<<<<<<<<<<<< - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: - * return -1 - */ - __pyx_t_2 = ((__pyx_v_utf < 0x10000) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":145 - * return 0 - * elif utf < 0x10000: - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0xe0 | (__pyx_v_utf >> 12))), 1) < 0) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":146 - * elif utf < 0x10000: - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: - * return -1 # <<<<<<<<<<<<<< - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - * True) < 0: - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":145 - * return 0 - * elif utf < 0x10000: - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - */ - } - - /* "yarl/_quoting_c.pyx":148 - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - * True) < 0: # <<<<<<<<<<<<<< - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0x80 | ((__pyx_v_utf >> 6) & 0x3f))), 1) < 0) != 0); - - /* "yarl/_quoting_c.pyx":147 - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), # <<<<<<<<<<<<<< - * True) < 0: - * return -1 - */ - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":149 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - * True) < 0: - * return -1 # <<<<<<<<<<<<<< - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * elif utf > 0x10FFFF: - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":147 - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), # <<<<<<<<<<<<<< - * True) < 0: - * return -1 - */ - } - - /* "yarl/_quoting_c.pyx":150 - * True) < 0: - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) # <<<<<<<<<<<<<< - * elif utf > 0x10FFFF: - * # symbol is too large - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0x80 | (__pyx_v_utf & 0x3f))), 1); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":144 - * # surogate pair, ignored - * return 0 - * elif utf < 0x10000: # <<<<<<<<<<<<<< - * if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: - * return -1 - */ - } - - /* "yarl/_quoting_c.pyx":151 - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * elif utf > 0x10FFFF: # <<<<<<<<<<<<<< - * # symbol is too large - * return 0 - */ - __pyx_t_2 = ((__pyx_v_utf > 0x10FFFF) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":153 - * elif utf > 0x10FFFF: - * # symbol is too large - * return 0 # <<<<<<<<<<<<<< - * else: - * if _write_pct(writer, (0xf0 | (utf >> 18)), True) < 0: - */ - __pyx_r = 0; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":151 - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * elif utf > 0x10FFFF: # <<<<<<<<<<<<<< - * # symbol is too large - * return 0 - */ - } - - /* "yarl/_quoting_c.pyx":155 - * return 0 - * else: - * if _write_pct(writer, (0xf0 | (utf >> 18)), True) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), - */ - /*else*/ { - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0xf0 | (__pyx_v_utf >> 18))), 1) < 0) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":156 - * else: - * if _write_pct(writer, (0xf0 | (utf >> 18)), True) < 0: - * return -1 # <<<<<<<<<<<<<< - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), - * True) < 0: - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":155 - * return 0 - * else: - * if _write_pct(writer, (0xf0 | (utf >> 18)), True) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), - */ - } - - /* "yarl/_quoting_c.pyx":158 - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), - * True) < 0: # <<<<<<<<<<<<<< - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0x80 | ((__pyx_v_utf >> 12) & 0x3f))), 1) < 0) != 0); - - /* "yarl/_quoting_c.pyx":157 - * if _write_pct(writer, (0xf0 | (utf >> 18)), True) < 0: - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), # <<<<<<<<<<<<<< - * True) < 0: - * return -1 - */ - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":159 - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), - * True) < 0: - * return -1 # <<<<<<<<<<<<<< - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - * True) < 0: - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":157 - * if _write_pct(writer, (0xf0 | (utf >> 18)), True) < 0: - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), # <<<<<<<<<<<<<< - * True) < 0: - * return -1 - */ - } - - /* "yarl/_quoting_c.pyx":161 - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - * True) < 0: # <<<<<<<<<<<<<< - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0x80 | ((__pyx_v_utf >> 6) & 0x3f))), 1) < 0) != 0); - - /* "yarl/_quoting_c.pyx":160 - * True) < 0: - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), # <<<<<<<<<<<<<< - * True) < 0: - * return -1 - */ - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":162 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - * True) < 0: - * return -1 # <<<<<<<<<<<<<< - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) - * - */ - __pyx_r = -1; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":160 - * True) < 0: - * return -1 - * if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), # <<<<<<<<<<<<<< - * True) < 0: - * return -1 - */ - } - - /* "yarl/_quoting_c.pyx":163 - * True) < 0: - * return -1 - * return _write_pct(writer, (0x80 | (utf & 0x3f)), True) # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, ((uint8_t)(0x80 | (__pyx_v_utf & 0x3f))), 1); - goto __pyx_L0; - } - - /* "yarl/_quoting_c.pyx":132 - * - * - * cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): # <<<<<<<<<<<<<< - * cdef uint64_t utf = symbol - * - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":176 - * cdef uint8_t _protected_table[16] - * - * def __init__( # <<<<<<<<<<<<<< - * self, *, str safe='', str protected='', bint qs=False, bint requote=True, - * ): - */ - -/* Python wrapper */ -static int __pyx_pw_4yarl_10_quoting_c_7_Quoter_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_pw_4yarl_10_quoting_c_7_Quoter_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_safe = 0; - PyObject *__pyx_v_protected = 0; - int __pyx_v_qs; - int __pyx_v_requote; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_safe,&__pyx_n_s_protected,&__pyx_n_s_qs,&__pyx_n_s_requote,0}; - PyObject* values[4] = {0,0,0,0}; - values[0] = ((PyObject*)__pyx_kp_u_); - values[1] = ((PyObject*)__pyx_kp_u_); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - if (kw_args > 0 && likely(kw_args <= 4)) { - Py_ssize_t index; - for (index = 0; index < 4 && kw_args > 0; index++) { - PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, *__pyx_pyargnames[index]); - if (value) { values[index] = value; kw_args--; } - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, 0, "__init__") < 0)) __PYX_ERR(0, 176, __pyx_L3_error) - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 0) { - goto __pyx_L5_argtuple_error; - } else { - } - __pyx_v_safe = ((PyObject*)values[0]); - __pyx_v_protected = ((PyObject*)values[1]); - if (values[2]) { - __pyx_v_qs = __Pyx_PyObject_IsTrue(values[2]); if (unlikely((__pyx_v_qs == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 177, __pyx_L3_error) - } else { - - /* "yarl/_quoting_c.pyx":177 - * - * def __init__( - * self, *, str safe='', str protected='', bint qs=False, bint requote=True, # <<<<<<<<<<<<<< - * ): - * cdef Py_UCS4 ch - */ - __pyx_v_qs = ((int)0); - } - if (values[3]) { - __pyx_v_requote = __Pyx_PyObject_IsTrue(values[3]); if (unlikely((__pyx_v_requote == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 177, __pyx_L3_error) - } else { - __pyx_v_requote = ((int)1); - } - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 176, __pyx_L3_error) - __pyx_L3_error:; - __Pyx_AddTraceback("yarl._quoting_c._Quoter.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return -1; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_safe), (&PyUnicode_Type), 1, "safe", 1))) __PYX_ERR(0, 177, __pyx_L1_error) - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_protected), (&PyUnicode_Type), 1, "protected", 1))) __PYX_ERR(0, 177, __pyx_L1_error) - __pyx_r = __pyx_pf_4yarl_10_quoting_c_7_Quoter___init__(((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_v_self), __pyx_v_safe, __pyx_v_protected, __pyx_v_qs, __pyx_v_requote); - - /* "yarl/_quoting_c.pyx":176 - * cdef uint8_t _protected_table[16] - * - * def __init__( # <<<<<<<<<<<<<< - * self, *, str safe='', str protected='', bint qs=False, bint requote=True, - * ): - */ - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = -1; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static int __pyx_pf_4yarl_10_quoting_c_7_Quoter___init__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v_safe, PyObject *__pyx_v_protected, int __pyx_v_qs, int __pyx_v_requote) { - Py_UCS4 __pyx_v_ch; - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; - Py_ssize_t __pyx_t_3; - Py_ssize_t __pyx_t_4; - void *__pyx_t_5; - int __pyx_t_6; - int __pyx_t_7; - Py_ssize_t __pyx_t_8; - PyObject *__pyx_t_9 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "yarl/_quoting_c.pyx":181 - * cdef Py_UCS4 ch - * - * self._qs = qs # <<<<<<<<<<<<<< - * self._requote = requote - * - */ - __pyx_v_self->_qs = __pyx_v_qs; - - /* "yarl/_quoting_c.pyx":182 - * - * self._qs = qs - * self._requote = requote # <<<<<<<<<<<<<< - * - * if not self._qs: - */ - __pyx_v_self->_requote = __pyx_v_requote; - - /* "yarl/_quoting_c.pyx":184 - * self._requote = requote - * - * if not self._qs: # <<<<<<<<<<<<<< - * memcpy(self._safe_table, - * ALLOWED_NOTQS_TABLE, - */ - __pyx_t_1 = ((!(__pyx_v_self->_qs != 0)) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":185 - * - * if not self._qs: - * memcpy(self._safe_table, # <<<<<<<<<<<<<< - * ALLOWED_NOTQS_TABLE, - * sizeof(self._safe_table)) - */ - (void)(memcpy(__pyx_v_self->_safe_table, __pyx_v_4yarl_10_quoting_c_ALLOWED_NOTQS_TABLE, (sizeof(__pyx_v_self->_safe_table)))); - - /* "yarl/_quoting_c.pyx":184 - * self._requote = requote - * - * if not self._qs: # <<<<<<<<<<<<<< - * memcpy(self._safe_table, - * ALLOWED_NOTQS_TABLE, - */ - goto __pyx_L3; - } - - /* "yarl/_quoting_c.pyx":189 - * sizeof(self._safe_table)) - * else: - * memcpy(self._safe_table, # <<<<<<<<<<<<<< - * ALLOWED_TABLE, - * sizeof(self._safe_table)) - */ - /*else*/ { - - /* "yarl/_quoting_c.pyx":191 - * memcpy(self._safe_table, - * ALLOWED_TABLE, - * sizeof(self._safe_table)) # <<<<<<<<<<<<<< - * for ch in safe: - * if ord(ch) > 127: - */ - (void)(memcpy(__pyx_v_self->_safe_table, __pyx_v_4yarl_10_quoting_c_ALLOWED_TABLE, (sizeof(__pyx_v_self->_safe_table)))); - } - __pyx_L3:; - - /* "yarl/_quoting_c.pyx":192 - * ALLOWED_TABLE, - * sizeof(self._safe_table)) - * for ch in safe: # <<<<<<<<<<<<<< - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - */ - if (unlikely(__pyx_v_safe == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' is not iterable"); - __PYX_ERR(0, 192, __pyx_L1_error) - } - __Pyx_INCREF(__pyx_v_safe); - __pyx_t_2 = __pyx_v_safe; - __pyx_t_7 = __Pyx_init_unicode_iteration(__pyx_t_2, (&__pyx_t_4), (&__pyx_t_5), (&__pyx_t_6)); if (unlikely(__pyx_t_7 == ((int)-1))) __PYX_ERR(0, 192, __pyx_L1_error) - for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_4; __pyx_t_8++) { - __pyx_t_3 = __pyx_t_8; - __pyx_v_ch = __Pyx_PyUnicode_READ(__pyx_t_6, __pyx_t_5, __pyx_t_3); - - /* "yarl/_quoting_c.pyx":193 - * sizeof(self._safe_table)) - * for ch in safe: - * if ord(ch) > 127: # <<<<<<<<<<<<<< - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) - */ - __pyx_t_1 = ((((long)__pyx_v_ch) > 0x7F) != 0); - if (unlikely(__pyx_t_1)) { - - /* "yarl/_quoting_c.pyx":194 - * for ch in safe: - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") # <<<<<<<<<<<<<< - * set_bit(self._safe_table, ch) - * - */ - __pyx_t_9 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 194, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_Raise(__pyx_t_9, 0, 0, 0); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __PYX_ERR(0, 194, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":193 - * sizeof(self._safe_table)) - * for ch in safe: - * if ord(ch) > 127: # <<<<<<<<<<<<<< - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) - */ - } - - /* "yarl/_quoting_c.pyx":195 - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) # <<<<<<<<<<<<<< - * - * memset(self._protected_table, 0, sizeof(self._protected_table)) - */ - __pyx_f_4yarl_10_quoting_c_set_bit(__pyx_v_self->_safe_table, __pyx_v_ch); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "yarl/_quoting_c.pyx":197 - * set_bit(self._safe_table, ch) - * - * memset(self._protected_table, 0, sizeof(self._protected_table)) # <<<<<<<<<<<<<< - * for ch in protected: - * if ord(ch) > 127: - */ - (void)(memset(__pyx_v_self->_protected_table, 0, (sizeof(__pyx_v_self->_protected_table)))); - - /* "yarl/_quoting_c.pyx":198 - * - * memset(self._protected_table, 0, sizeof(self._protected_table)) - * for ch in protected: # <<<<<<<<<<<<<< - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - */ - if (unlikely(__pyx_v_protected == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' is not iterable"); - __PYX_ERR(0, 198, __pyx_L1_error) - } - __Pyx_INCREF(__pyx_v_protected); - __pyx_t_2 = __pyx_v_protected; - __pyx_t_7 = __Pyx_init_unicode_iteration(__pyx_t_2, (&__pyx_t_3), (&__pyx_t_5), (&__pyx_t_6)); if (unlikely(__pyx_t_7 == ((int)-1))) __PYX_ERR(0, 198, __pyx_L1_error) - for (__pyx_t_8 = 0; __pyx_t_8 < __pyx_t_3; __pyx_t_8++) { - __pyx_t_4 = __pyx_t_8; - __pyx_v_ch = __Pyx_PyUnicode_READ(__pyx_t_6, __pyx_t_5, __pyx_t_4); - - /* "yarl/_quoting_c.pyx":199 - * memset(self._protected_table, 0, sizeof(self._protected_table)) - * for ch in protected: - * if ord(ch) > 127: # <<<<<<<<<<<<<< - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) - */ - __pyx_t_1 = ((((long)__pyx_v_ch) > 0x7F) != 0); - if (unlikely(__pyx_t_1)) { - - /* "yarl/_quoting_c.pyx":200 - * for ch in protected: - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") # <<<<<<<<<<<<<< - * set_bit(self._safe_table, ch) - * set_bit(self._protected_table, ch) - */ - __pyx_t_9 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 200, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_Raise(__pyx_t_9, 0, 0, 0); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __PYX_ERR(0, 200, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":199 - * memset(self._protected_table, 0, sizeof(self._protected_table)) - * for ch in protected: - * if ord(ch) > 127: # <<<<<<<<<<<<<< - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) - */ - } - - /* "yarl/_quoting_c.pyx":201 - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) # <<<<<<<<<<<<<< - * set_bit(self._protected_table, ch) - * - */ - __pyx_f_4yarl_10_quoting_c_set_bit(__pyx_v_self->_safe_table, __pyx_v_ch); - - /* "yarl/_quoting_c.pyx":202 - * raise ValueError("Only safe symbols with ORD < 128 are allowed") - * set_bit(self._safe_table, ch) - * set_bit(self._protected_table, ch) # <<<<<<<<<<<<<< - * - * def __call__(self, val): - */ - __pyx_f_4yarl_10_quoting_c_set_bit(__pyx_v_self->_protected_table, __pyx_v_ch); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "yarl/_quoting_c.pyx":176 - * cdef uint8_t _protected_table[16] - * - * def __init__( # <<<<<<<<<<<<<< - * self, *, str safe='', str protected='', bint qs=False, bint requote=True, - * ): - */ - - /* function exit code */ - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_AddTraceback("yarl._quoting_c._Quoter.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = -1; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":204 - * set_bit(self._protected_table, ch) - * - * def __call__(self, val): # <<<<<<<<<<<<<< - * cdef Writer writer - * if val is None: - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_7_Quoter_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_pw_4yarl_10_quoting_c_7_Quoter_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_val = 0; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__call__ (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_val,0}; - PyObject* values[1] = {0}; - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - switch (pos_args) { - case 0: - if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_val)) != 0)) kw_args--; - else goto __pyx_L5_argtuple_error; - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) __PYX_ERR(0, 204, __pyx_L3_error) - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 1) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - } - __pyx_v_val = values[0]; - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 204, __pyx_L3_error) - __pyx_L3_error:; - __Pyx_AddTraceback("yarl._quoting_c._Quoter.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_4yarl_10_quoting_c_7_Quoter_2__call__(((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_v_self), __pyx_v_val); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_7_Quoter_2__call__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v_val) { - struct __pyx_t_4yarl_10_quoting_c_Writer __pyx_v_writer; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - int __pyx_t_4; - int __pyx_t_5; - char const *__pyx_t_6; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__call__", 0); - __Pyx_INCREF(__pyx_v_val); - - /* "yarl/_quoting_c.pyx":206 - * def __call__(self, val): - * cdef Writer writer - * if val is None: # <<<<<<<<<<<<<< - * return None - * if type(val) is not str: - */ - __pyx_t_1 = (__pyx_v_val == Py_None); - __pyx_t_2 = (__pyx_t_1 != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":207 - * cdef Writer writer - * if val is None: - * return None # <<<<<<<<<<<<<< - * if type(val) is not str: - * if isinstance(val, str): - */ - __Pyx_XDECREF(__pyx_r); - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":206 - * def __call__(self, val): - * cdef Writer writer - * if val is None: # <<<<<<<<<<<<<< - * return None - * if type(val) is not str: - */ - } - - /* "yarl/_quoting_c.pyx":208 - * if val is None: - * return None - * if type(val) is not str: # <<<<<<<<<<<<<< - * if isinstance(val, str): - * # derived from str - */ - __pyx_t_2 = (((PyObject *)Py_TYPE(__pyx_v_val)) != ((PyObject *)(&PyUnicode_Type))); - __pyx_t_1 = (__pyx_t_2 != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":209 - * return None - * if type(val) is not str: - * if isinstance(val, str): # <<<<<<<<<<<<<< - * # derived from str - * val = str(val) - */ - __pyx_t_1 = PyUnicode_Check(__pyx_v_val); - __pyx_t_2 = (__pyx_t_1 != 0); - if (likely(__pyx_t_2)) { - - /* "yarl/_quoting_c.pyx":211 - * if isinstance(val, str): - * # derived from str - * val = str(val) # <<<<<<<<<<<<<< - * else: - * raise TypeError("Argument should be str") - */ - __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)(&PyUnicode_Type)), __pyx_v_val); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 211, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF_SET(__pyx_v_val, __pyx_t_3); - __pyx_t_3 = 0; - - /* "yarl/_quoting_c.pyx":209 - * return None - * if type(val) is not str: - * if isinstance(val, str): # <<<<<<<<<<<<<< - * # derived from str - * val = str(val) - */ - goto __pyx_L5; - } - - /* "yarl/_quoting_c.pyx":213 - * val = str(val) - * else: - * raise TypeError("Argument should be str") # <<<<<<<<<<<<<< - * _init_writer(&writer) - * try: - */ - /*else*/ { - __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 213, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_Raise(__pyx_t_3, 0, 0, 0); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __PYX_ERR(0, 213, __pyx_L1_error) - } - __pyx_L5:; - - /* "yarl/_quoting_c.pyx":208 - * if val is None: - * return None - * if type(val) is not str: # <<<<<<<<<<<<<< - * if isinstance(val, str): - * # derived from str - */ - } - - /* "yarl/_quoting_c.pyx":214 - * else: - * raise TypeError("Argument should be str") - * _init_writer(&writer) # <<<<<<<<<<<<<< - * try: - * return self._do_quote(val, &writer) - */ - __pyx_f_4yarl_10_quoting_c__init_writer((&__pyx_v_writer)); - - /* "yarl/_quoting_c.pyx":215 - * raise TypeError("Argument should be str") - * _init_writer(&writer) - * try: # <<<<<<<<<<<<<< - * return self._do_quote(val, &writer) - * finally: - */ - /*try:*/ { - - /* "yarl/_quoting_c.pyx":216 - * _init_writer(&writer) - * try: - * return self._do_quote(val, &writer) # <<<<<<<<<<<<<< - * finally: - * _release_writer(&writer) - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = ((struct __pyx_vtabstruct_4yarl_10_quoting_c__Quoter *)__pyx_v_self->__pyx_vtab)->_do_quote(__pyx_v_self, ((PyObject*)__pyx_v_val), (&__pyx_v_writer)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 216, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_r = __pyx_t_3; - __pyx_t_3 = 0; - goto __pyx_L6_return; - } - - /* "yarl/_quoting_c.pyx":218 - * return self._do_quote(val, &writer) - * finally: - * _release_writer(&writer) # <<<<<<<<<<<<<< - * - * cdef str _do_quote(self, str val, Writer *writer): - */ - /*finally:*/ { - __pyx_L7_error:; - /*exception exit:*/{ - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __pyx_t_7 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PY_MAJOR_VERSION >= 3) __Pyx_ExceptionSwap(&__pyx_t_10, &__pyx_t_11, &__pyx_t_12); - if ((PY_MAJOR_VERSION < 3) || unlikely(__Pyx_GetException(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9) < 0)) __Pyx_ErrFetch(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9); - __Pyx_XGOTREF(__pyx_t_7); - __Pyx_XGOTREF(__pyx_t_8); - __Pyx_XGOTREF(__pyx_t_9); - __Pyx_XGOTREF(__pyx_t_10); - __Pyx_XGOTREF(__pyx_t_11); - __Pyx_XGOTREF(__pyx_t_12); - __pyx_t_4 = __pyx_lineno; __pyx_t_5 = __pyx_clineno; __pyx_t_6 = __pyx_filename; - { - __pyx_f_4yarl_10_quoting_c__release_writer((&__pyx_v_writer)); - } - if (PY_MAJOR_VERSION >= 3) { - __Pyx_XGIVEREF(__pyx_t_10); - __Pyx_XGIVEREF(__pyx_t_11); - __Pyx_XGIVEREF(__pyx_t_12); - __Pyx_ExceptionReset(__pyx_t_10, __pyx_t_11, __pyx_t_12); - } - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ErrRestore(__pyx_t_7, __pyx_t_8, __pyx_t_9); - __pyx_t_7 = 0; __pyx_t_8 = 0; __pyx_t_9 = 0; __pyx_t_10 = 0; __pyx_t_11 = 0; __pyx_t_12 = 0; - __pyx_lineno = __pyx_t_4; __pyx_clineno = __pyx_t_5; __pyx_filename = __pyx_t_6; - goto __pyx_L1_error; - } - __pyx_L6_return: { - __pyx_t_12 = __pyx_r; - __pyx_r = 0; - __pyx_f_4yarl_10_quoting_c__release_writer((&__pyx_v_writer)); - __pyx_r = __pyx_t_12; - __pyx_t_12 = 0; - goto __pyx_L0; - } - } - - /* "yarl/_quoting_c.pyx":204 - * set_bit(self._protected_table, ch) - * - * def __call__(self, val): # <<<<<<<<<<<<<< - * cdef Writer writer - * if val is None: - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("yarl._quoting_c._Quoter.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_val); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":220 - * _release_writer(&writer) - * - * cdef str _do_quote(self, str val, Writer *writer): # <<<<<<<<<<<<<< - * cdef Py_UCS4 ch - * cdef int changed - */ - -static PyObject *__pyx_f_4yarl_10_quoting_c_7_Quoter__do_quote(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v_val, struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer) { - Py_UCS4 __pyx_v_ch; - int __pyx_v_changed; - int __pyx_v_idx; - int __pyx_v_length; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - Py_ssize_t __pyx_t_1; - int __pyx_t_2; - Py_UCS4 __pyx_t_3; - int __pyx_t_4; - long __pyx_t_5; - Py_UCS4 __pyx_t_6; - int __pyx_t_7; - int __pyx_t_8; - PyObject *__pyx_t_9 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("_do_quote", 0); - - /* "yarl/_quoting_c.pyx":223 - * cdef Py_UCS4 ch - * cdef int changed - * cdef int idx = 0 # <<<<<<<<<<<<<< - * cdef int length = len(val) - * - */ - __pyx_v_idx = 0; - - /* "yarl/_quoting_c.pyx":224 - * cdef int changed - * cdef int idx = 0 - * cdef int length = len(val) # <<<<<<<<<<<<<< - * - * while idx < length: - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); - __PYX_ERR(0, 224, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_PyUnicode_GET_LENGTH(__pyx_v_val); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 224, __pyx_L1_error) - __pyx_v_length = __pyx_t_1; - - /* "yarl/_quoting_c.pyx":226 - * cdef int length = len(val) - * - * while idx < length: # <<<<<<<<<<<<<< - * ch = val[idx] - * idx += 1 - */ - while (1) { - __pyx_t_2 = ((__pyx_v_idx < __pyx_v_length) != 0); - if (!__pyx_t_2) break; - - /* "yarl/_quoting_c.pyx":227 - * - * while idx < length: - * ch = val[idx] # <<<<<<<<<<<<<< - * idx += 1 - * if ch == '%' and self._requote and idx <= length - 2: - */ - __pyx_t_3 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_v_idx, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == (Py_UCS4)-1)) __PYX_ERR(0, 227, __pyx_L1_error) - __pyx_v_ch = __pyx_t_3; - - /* "yarl/_quoting_c.pyx":228 - * while idx < length: - * ch = val[idx] - * idx += 1 # <<<<<<<<<<<<<< - * if ch == '%' and self._requote and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) - */ - __pyx_v_idx = (__pyx_v_idx + 1); - - /* "yarl/_quoting_c.pyx":229 - * ch = val[idx] - * idx += 1 - * if ch == '%' and self._requote and idx <= length - 2: # <<<<<<<<<<<<<< - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: - */ - __pyx_t_4 = ((__pyx_v_ch == 37) != 0); - if (__pyx_t_4) { - } else { - __pyx_t_2 = __pyx_t_4; - goto __pyx_L6_bool_binop_done; - } - __pyx_t_4 = (__pyx_v_self->_requote != 0); - if (__pyx_t_4) { - } else { - __pyx_t_2 = __pyx_t_4; - goto __pyx_L6_bool_binop_done; - } - __pyx_t_4 = ((__pyx_v_idx <= (__pyx_v_length - 2)) != 0); - __pyx_t_2 = __pyx_t_4; - __pyx_L6_bool_binop_done:; - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":230 - * idx += 1 - * if ch == '%' and self._requote and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) # <<<<<<<<<<<<<< - * if ch != -1: - * idx += 2 - */ - __pyx_t_3 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_v_idx, int, 1, __Pyx_PyInt_From_int, 0, 1, 1); if (unlikely(__pyx_t_3 == (Py_UCS4)-1)) __PYX_ERR(0, 230, __pyx_L1_error) - __pyx_t_5 = (__pyx_v_idx + 1); - __pyx_t_6 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_t_5, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(__pyx_t_6 == (Py_UCS4)-1)) __PYX_ERR(0, 230, __pyx_L1_error) - __pyx_v_ch = __pyx_f_4yarl_10_quoting_c__restore_ch(__pyx_t_3, __pyx_t_6); - - /* "yarl/_quoting_c.pyx":231 - * if ch == '%' and self._requote and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: # <<<<<<<<<<<<<< - * idx += 2 - * if ch < 128: - */ - __pyx_t_2 = ((__pyx_v_ch != ((Py_UCS4)-1L)) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":232 - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: - * idx += 2 # <<<<<<<<<<<<<< - * if ch < 128: - * if bit_at(self._protected_table, ch): - */ - __pyx_v_idx = (__pyx_v_idx + 2); - - /* "yarl/_quoting_c.pyx":233 - * if ch != -1: - * idx += 2 - * if ch < 128: # <<<<<<<<<<<<<< - * if bit_at(self._protected_table, ch): - * if _write_pct(writer, ch, True) < 0: - */ - __pyx_t_2 = ((__pyx_v_ch < 0x80) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":234 - * idx += 2 - * if ch < 128: - * if bit_at(self._protected_table, ch): # <<<<<<<<<<<<<< - * if _write_pct(writer, ch, True) < 0: - * raise - */ - __pyx_t_2 = (__pyx_f_4yarl_10_quoting_c_bit_at(__pyx_v_self->_protected_table, __pyx_v_ch) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":235 - * if ch < 128: - * if bit_at(self._protected_table, ch): - * if _write_pct(writer, ch, True) < 0: # <<<<<<<<<<<<<< - * raise - * continue - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, __pyx_v_ch, 1) < 0) != 0); - if (unlikely(__pyx_t_2)) { - - /* "yarl/_quoting_c.pyx":236 - * if bit_at(self._protected_table, ch): - * if _write_pct(writer, ch, True) < 0: - * raise # <<<<<<<<<<<<<< - * continue - * - */ - __Pyx_ReraiseException(); __PYX_ERR(0, 236, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":235 - * if ch < 128: - * if bit_at(self._protected_table, ch): - * if _write_pct(writer, ch, True) < 0: # <<<<<<<<<<<<<< - * raise - * continue - */ - } - - /* "yarl/_quoting_c.pyx":237 - * if _write_pct(writer, ch, True) < 0: - * raise - * continue # <<<<<<<<<<<<<< - * - * if bit_at(self._safe_table, ch): - */ - goto __pyx_L3_continue; - - /* "yarl/_quoting_c.pyx":234 - * idx += 2 - * if ch < 128: - * if bit_at(self._protected_table, ch): # <<<<<<<<<<<<<< - * if _write_pct(writer, ch, True) < 0: - * raise - */ - } - - /* "yarl/_quoting_c.pyx":239 - * continue - * - * if bit_at(self._safe_table, ch): # <<<<<<<<<<<<<< - * if _write_char(writer, ch, True) < 0: - * raise - */ - __pyx_t_2 = (__pyx_f_4yarl_10_quoting_c_bit_at(__pyx_v_self->_safe_table, __pyx_v_ch) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":240 - * - * if bit_at(self._safe_table, ch): - * if _write_char(writer, ch, True) < 0: # <<<<<<<<<<<<<< - * raise - * continue - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_char(__pyx_v_writer, __pyx_v_ch, 1) < 0) != 0); - if (unlikely(__pyx_t_2)) { - - /* "yarl/_quoting_c.pyx":241 - * if bit_at(self._safe_table, ch): - * if _write_char(writer, ch, True) < 0: - * raise # <<<<<<<<<<<<<< - * continue - * - */ - __Pyx_ReraiseException(); __PYX_ERR(0, 241, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":240 - * - * if bit_at(self._safe_table, ch): - * if _write_char(writer, ch, True) < 0: # <<<<<<<<<<<<<< - * raise - * continue - */ - } - - /* "yarl/_quoting_c.pyx":242 - * if _write_char(writer, ch, True) < 0: - * raise - * continue # <<<<<<<<<<<<<< - * - * changed = (_is_lower_hex(val[idx - 2]) or - */ - goto __pyx_L3_continue; - - /* "yarl/_quoting_c.pyx":239 - * continue - * - * if bit_at(self._safe_table, ch): # <<<<<<<<<<<<<< - * if _write_char(writer, ch, True) < 0: - * raise - */ - } - - /* "yarl/_quoting_c.pyx":233 - * if ch != -1: - * idx += 2 - * if ch < 128: # <<<<<<<<<<<<<< - * if bit_at(self._protected_table, ch): - * if _write_pct(writer, ch, True) < 0: - */ - } - - /* "yarl/_quoting_c.pyx":244 - * continue - * - * changed = (_is_lower_hex(val[idx - 2]) or # <<<<<<<<<<<<<< - * _is_lower_hex(val[idx - 1])) - * if _write_pct(writer, ch, changed) < 0: - */ - __pyx_t_5 = (__pyx_v_idx - 2); - __pyx_t_6 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_t_5, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(__pyx_t_6 == (Py_UCS4)-1)) __PYX_ERR(0, 244, __pyx_L1_error) - __pyx_t_8 = __pyx_f_4yarl_10_quoting_c__is_lower_hex(__pyx_t_6); - if (!__pyx_t_8) { - } else { - __pyx_t_7 = __pyx_t_8; - goto __pyx_L15_bool_binop_done; - } - - /* "yarl/_quoting_c.pyx":245 - * - * changed = (_is_lower_hex(val[idx - 2]) or - * _is_lower_hex(val[idx - 1])) # <<<<<<<<<<<<<< - * if _write_pct(writer, ch, changed) < 0: - * raise - */ - __pyx_t_5 = (__pyx_v_idx - 1); - __pyx_t_6 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_t_5, long, 1, __Pyx_PyInt_From_long, 0, 1, 1); if (unlikely(__pyx_t_6 == (Py_UCS4)-1)) __PYX_ERR(0, 245, __pyx_L1_error) - __pyx_t_8 = __pyx_f_4yarl_10_quoting_c__is_lower_hex(__pyx_t_6); - __pyx_t_7 = __pyx_t_8; - __pyx_L15_bool_binop_done:; - __pyx_v_changed = __pyx_t_7; - - /* "yarl/_quoting_c.pyx":246 - * changed = (_is_lower_hex(val[idx - 2]) or - * _is_lower_hex(val[idx - 1])) - * if _write_pct(writer, ch, changed) < 0: # <<<<<<<<<<<<<< - * raise - * continue - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c__write_pct(__pyx_v_writer, __pyx_v_ch, __pyx_v_changed) < 0) != 0); - if (unlikely(__pyx_t_2)) { - - /* "yarl/_quoting_c.pyx":247 - * _is_lower_hex(val[idx - 1])) - * if _write_pct(writer, ch, changed) < 0: - * raise # <<<<<<<<<<<<<< - * continue - * else: - */ - __Pyx_ReraiseException(); __PYX_ERR(0, 247, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":246 - * changed = (_is_lower_hex(val[idx - 2]) or - * _is_lower_hex(val[idx - 1])) - * if _write_pct(writer, ch, changed) < 0: # <<<<<<<<<<<<<< - * raise - * continue - */ - } - - /* "yarl/_quoting_c.pyx":248 - * if _write_pct(writer, ch, changed) < 0: - * raise - * continue # <<<<<<<<<<<<<< - * else: - * ch = '%' - */ - goto __pyx_L3_continue; - - /* "yarl/_quoting_c.pyx":231 - * if ch == '%' and self._requote and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: # <<<<<<<<<<<<<< - * idx += 2 - * if ch < 128: - */ - } - - /* "yarl/_quoting_c.pyx":250 - * continue - * else: - * ch = '%' # <<<<<<<<<<<<<< - * - * if self._write(writer, ch) < 0: - */ - /*else*/ { - __pyx_v_ch = 37; - } - - /* "yarl/_quoting_c.pyx":229 - * ch = val[idx] - * idx += 1 - * if ch == '%' and self._requote and idx <= length - 2: # <<<<<<<<<<<<<< - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: - */ - } - - /* "yarl/_quoting_c.pyx":252 - * ch = '%' - * - * if self._write(writer, ch) < 0: # <<<<<<<<<<<<<< - * raise - * - */ - __pyx_t_2 = ((__pyx_f_4yarl_10_quoting_c_7_Quoter__write(__pyx_v_self, __pyx_v_writer, __pyx_v_ch) < 0) != 0); - if (unlikely(__pyx_t_2)) { - - /* "yarl/_quoting_c.pyx":253 - * - * if self._write(writer, ch) < 0: - * raise # <<<<<<<<<<<<<< - * - * if not writer.changed: - */ - __Pyx_ReraiseException(); __PYX_ERR(0, 253, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":252 - * ch = '%' - * - * if self._write(writer, ch) < 0: # <<<<<<<<<<<<<< - * raise - * - */ - } - __pyx_L3_continue:; - } - - /* "yarl/_quoting_c.pyx":255 - * raise - * - * if not writer.changed: # <<<<<<<<<<<<<< - * return val - * else: - */ - __pyx_t_2 = ((!(__pyx_v_writer->changed != 0)) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":256 - * - * if not writer.changed: - * return val # <<<<<<<<<<<<<< - * else: - * return PyUnicode_DecodeASCII(writer.buf, writer.pos, "strict") - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_val); - __pyx_r = __pyx_v_val; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":255 - * raise - * - * if not writer.changed: # <<<<<<<<<<<<<< - * return val - * else: - */ - } - - /* "yarl/_quoting_c.pyx":258 - * return val - * else: - * return PyUnicode_DecodeASCII(writer.buf, writer.pos, "strict") # <<<<<<<<<<<<<< - * - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); - __pyx_t_9 = PyUnicode_DecodeASCII(__pyx_v_writer->buf, __pyx_v_writer->pos, ((char *)"strict")); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 258, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_r = ((PyObject*)__pyx_t_9); - __pyx_t_9 = 0; - goto __pyx_L0; - } - - /* "yarl/_quoting_c.pyx":220 - * _release_writer(&writer) - * - * cdef str _do_quote(self, str val, Writer *writer): # <<<<<<<<<<<<<< - * cdef Py_UCS4 ch - * cdef int changed - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_9); - __Pyx_AddTraceback("yarl._quoting_c._Quoter._do_quote", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":260 - * return PyUnicode_DecodeASCII(writer.buf, writer.pos, "strict") - * - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): # <<<<<<<<<<<<<< - * if self._qs: - * if ch == ' ': - */ - -static CYTHON_INLINE int __pyx_f_4yarl_10_quoting_c_7_Quoter__write(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, struct __pyx_t_4yarl_10_quoting_c_Writer *__pyx_v_writer, Py_UCS4 __pyx_v_ch) { - int __pyx_r; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - __Pyx_RefNannySetupContext("_write", 0); - - /* "yarl/_quoting_c.pyx":261 - * - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): - * if self._qs: # <<<<<<<<<<<<<< - * if ch == ' ': - * return _write_char(writer, '+', True) - */ - __pyx_t_1 = (__pyx_v_self->_qs != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":262 - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): - * if self._qs: - * if ch == ' ': # <<<<<<<<<<<<<< - * return _write_char(writer, '+', True) - * - */ - __pyx_t_1 = ((__pyx_v_ch == 32) != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":263 - * if self._qs: - * if ch == ' ': - * return _write_char(writer, '+', True) # <<<<<<<<<<<<<< - * - * if ch < 128 and bit_at(self._safe_table, ch): - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_char(__pyx_v_writer, 43, 1); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":262 - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): - * if self._qs: - * if ch == ' ': # <<<<<<<<<<<<<< - * return _write_char(writer, '+', True) - * - */ - } - - /* "yarl/_quoting_c.pyx":261 - * - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): - * if self._qs: # <<<<<<<<<<<<<< - * if ch == ' ': - * return _write_char(writer, '+', True) - */ - } - - /* "yarl/_quoting_c.pyx":265 - * return _write_char(writer, '+', True) - * - * if ch < 128 and bit_at(self._safe_table, ch): # <<<<<<<<<<<<<< - * return _write_char(writer, ch, False) - * - */ - __pyx_t_2 = ((__pyx_v_ch < 0x80) != 0); - if (__pyx_t_2) { - } else { - __pyx_t_1 = __pyx_t_2; - goto __pyx_L6_bool_binop_done; - } - __pyx_t_2 = (__pyx_f_4yarl_10_quoting_c_bit_at(__pyx_v_self->_safe_table, __pyx_v_ch) != 0); - __pyx_t_1 = __pyx_t_2; - __pyx_L6_bool_binop_done:; - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":266 - * - * if ch < 128 and bit_at(self._safe_table, ch): - * return _write_char(writer, ch, False) # <<<<<<<<<<<<<< - * - * return _write_utf8(writer, ch) - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_char(__pyx_v_writer, __pyx_v_ch, 0); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":265 - * return _write_char(writer, '+', True) - * - * if ch < 128 and bit_at(self._safe_table, ch): # <<<<<<<<<<<<<< - * return _write_char(writer, ch, False) - * - */ - } - - /* "yarl/_quoting_c.pyx":268 - * return _write_char(writer, ch, False) - * - * return _write_utf8(writer, ch) # <<<<<<<<<<<<<< - * - * - */ - __pyx_r = __pyx_f_4yarl_10_quoting_c__write_utf8(__pyx_v_writer, __pyx_v_ch); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":260 - * return PyUnicode_DecodeASCII(writer.buf, writer.pos, "strict") - * - * cdef inline int _write(self, Writer *writer, Py_UCS4 ch): # <<<<<<<<<<<<<< - * if self._qs: - * if ch == ' ': - */ - - /* function exit code */ - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":1 - * def __reduce_cython__(self): # <<<<<<<<<<<<<< - * cdef tuple state - * cdef object _dict - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_7_Quoter_5__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ -static PyObject *__pyx_pw_4yarl_10_quoting_c_7_Quoter_5__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); - __pyx_r = __pyx_pf_4yarl_10_quoting_c_7_Quoter_4__reduce_cython__(((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_v_self)); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_7_Quoter_4__reduce_cython__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self) { - PyObject *__pyx_v_state = 0; - PyObject *__pyx_v__dict = 0; - int __pyx_v_use_setstate; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - int __pyx_t_6; - int __pyx_t_7; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":5 - * cdef object _dict - * cdef bint use_setstate - * state = (self._protected_table, self._qs, self._requote, self._safe_table) # <<<<<<<<<<<<<< - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: - */ - __pyx_t_1 = __Pyx_PyObject_FromCString(__pyx_v_self->_protected_table); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyBool_FromLong(__pyx_v_self->_qs); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_PyBool_FromLong(__pyx_v_self->_requote); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_FromCString(__pyx_v_self->_safe_table); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_GIVEREF(__pyx_t_1); - PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); - __Pyx_GIVEREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2); - __Pyx_GIVEREF(__pyx_t_3); - PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_t_3); - __Pyx_GIVEREF(__pyx_t_4); - PyTuple_SET_ITEM(__pyx_t_5, 3, __pyx_t_4); - __pyx_t_1 = 0; - __pyx_t_2 = 0; - __pyx_t_3 = 0; - __pyx_t_4 = 0; - __pyx_v_state = ((PyObject*)__pyx_t_5); - __pyx_t_5 = 0; - - /* "(tree fragment)":6 - * cdef bint use_setstate - * state = (self._protected_table, self._qs, self._requote, self._safe_table) - * _dict = getattr(self, '__dict__', None) # <<<<<<<<<<<<<< - * if _dict is not None: - * state += (_dict,) - */ - __pyx_t_5 = __Pyx_GetAttr3(((PyObject *)__pyx_v_self), __pyx_n_s_dict, Py_None); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_v__dict = __pyx_t_5; - __pyx_t_5 = 0; - - /* "(tree fragment)":7 - * state = (self._protected_table, self._qs, self._requote, self._safe_table) - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: # <<<<<<<<<<<<<< - * state += (_dict,) - * use_setstate = True - */ - __pyx_t_6 = (__pyx_v__dict != Py_None); - __pyx_t_7 = (__pyx_t_6 != 0); - if (__pyx_t_7) { - - /* "(tree fragment)":8 - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: - * state += (_dict,) # <<<<<<<<<<<<<< - * use_setstate = True - * else: - */ - __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_INCREF(__pyx_v__dict); - __Pyx_GIVEREF(__pyx_v__dict); - PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_v__dict); - __pyx_t_4 = PyNumber_InPlaceAdd(__pyx_v_state, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF_SET(__pyx_v_state, ((PyObject*)__pyx_t_4)); - __pyx_t_4 = 0; - - /* "(tree fragment)":9 - * if _dict is not None: - * state += (_dict,) - * use_setstate = True # <<<<<<<<<<<<<< - * else: - * use_setstate = False - */ - __pyx_v_use_setstate = 1; - - /* "(tree fragment)":7 - * state = (self._protected_table, self._qs, self._requote, self._safe_table) - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: # <<<<<<<<<<<<<< - * state += (_dict,) - * use_setstate = True - */ - goto __pyx_L3; - } - - /* "(tree fragment)":11 - * use_setstate = True - * else: - * use_setstate = False # <<<<<<<<<<<<<< - * if use_setstate: - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, None), state - */ - /*else*/ { - __pyx_v_use_setstate = 0; - } - __pyx_L3:; - - /* "(tree fragment)":12 - * else: - * use_setstate = False - * if use_setstate: # <<<<<<<<<<<<<< - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, None), state - * else: - */ - __pyx_t_7 = (__pyx_v_use_setstate != 0); - if (__pyx_t_7) { - - /* "(tree fragment)":13 - * use_setstate = False - * if use_setstate: - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, None), state # <<<<<<<<<<<<<< - * else: - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, state) - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_pyx_unpickle__Quoter); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_INCREF(__pyx_int_244432181); - __Pyx_GIVEREF(__pyx_int_244432181); - PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_int_244432181); - __Pyx_INCREF(Py_None); - __Pyx_GIVEREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_5, 2, Py_None); - __pyx_t_3 = PyTuple_New(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_GIVEREF(__pyx_t_4); - PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_5); - PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_5); - __Pyx_INCREF(__pyx_v_state); - __Pyx_GIVEREF(__pyx_v_state); - PyTuple_SET_ITEM(__pyx_t_3, 2, __pyx_v_state); - __pyx_t_4 = 0; - __pyx_t_5 = 0; - __pyx_r = __pyx_t_3; - __pyx_t_3 = 0; - goto __pyx_L0; - - /* "(tree fragment)":12 - * else: - * use_setstate = False - * if use_setstate: # <<<<<<<<<<<<<< - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, None), state - * else: - */ - } - - /* "(tree fragment)":15 - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, None), state - * else: - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, state) # <<<<<<<<<<<<<< - * def __setstate_cython__(self, __pyx_state): - * __pyx_unpickle__Quoter__set_state(self, __pyx_state) - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_pyx_unpickle__Quoter); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - PyTuple_SET_ITEM(__pyx_t_5, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_INCREF(__pyx_int_244432181); - __Pyx_GIVEREF(__pyx_int_244432181); - PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_int_244432181); - __Pyx_INCREF(__pyx_v_state); - __Pyx_GIVEREF(__pyx_v_state); - PyTuple_SET_ITEM(__pyx_t_5, 2, __pyx_v_state); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_GIVEREF(__pyx_t_3); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_3); - __Pyx_GIVEREF(__pyx_t_5); - PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_5); - __pyx_t_3 = 0; - __pyx_t_5 = 0; - __pyx_r = __pyx_t_4; - __pyx_t_4 = 0; - goto __pyx_L0; - } - - /* "(tree fragment)":1 - * def __reduce_cython__(self): # <<<<<<<<<<<<<< - * cdef tuple state - * cdef object _dict - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_AddTraceback("yarl._quoting_c._Quoter.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_state); - __Pyx_XDECREF(__pyx_v__dict); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":16 - * else: - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, state) - * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< - * __pyx_unpickle__Quoter__set_state(self, __pyx_state) - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_7_Quoter_7__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ -static PyObject *__pyx_pw_4yarl_10_quoting_c_7_Quoter_7__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); - __pyx_r = __pyx_pf_4yarl_10_quoting_c_7_Quoter_6__setstate_cython__(((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_7_Quoter_6__setstate_cython__(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v_self, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":17 - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, state) - * def __setstate_cython__(self, __pyx_state): - * __pyx_unpickle__Quoter__set_state(self, __pyx_state) # <<<<<<<<<<<<<< - */ - if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 17, __pyx_L1_error) - __pyx_t_1 = __pyx_f_4yarl_10_quoting_c___pyx_unpickle__Quoter__set_state(__pyx_v_self, ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "(tree fragment)":16 - * else: - * return __pyx_unpickle__Quoter, (type(self), 0xe91bd35, state) - * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< - * __pyx_unpickle__Quoter__set_state(self, __pyx_state) - */ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("yarl._quoting_c._Quoter.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":277 - * cdef _Quoter _qs_quoter - * - * def __init__(self, *, unsafe='', qs=False): # <<<<<<<<<<<<<< - * self._unsafe = unsafe - * self._qs = qs - */ - -/* Python wrapper */ -static int __pyx_pw_4yarl_10_quoting_c_9_Unquoter_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static int __pyx_pw_4yarl_10_quoting_c_9_Unquoter_1__init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_unsafe = 0; - PyObject *__pyx_v_qs = 0; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - int __pyx_r; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_unsafe,&__pyx_n_s_qs,0}; - PyObject* values[2] = {0,0}; - values[0] = ((PyObject *)__pyx_kp_u_); - values[1] = ((PyObject *)Py_False); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - if (kw_args > 0 && likely(kw_args <= 2)) { - Py_ssize_t index; - for (index = 0; index < 2 && kw_args > 0; index++) { - PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, *__pyx_pyargnames[index]); - if (value) { values[index] = value; kw_args--; } - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, 0, "__init__") < 0)) __PYX_ERR(0, 277, __pyx_L3_error) - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 0) { - goto __pyx_L5_argtuple_error; - } else { - } - __pyx_v_unsafe = values[0]; - __pyx_v_qs = values[1]; - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 277, __pyx_L3_error) - __pyx_L3_error:; - __Pyx_AddTraceback("yarl._quoting_c._Unquoter.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return -1; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_4yarl_10_quoting_c_9_Unquoter___init__(((struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)__pyx_v_self), __pyx_v_unsafe, __pyx_v_qs); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static int __pyx_pf_4yarl_10_quoting_c_9_Unquoter___init__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v_unsafe, PyObject *__pyx_v_qs) { - int __pyx_r; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "yarl/_quoting_c.pyx":278 - * - * def __init__(self, *, unsafe='', qs=False): - * self._unsafe = unsafe # <<<<<<<<<<<<<< - * self._qs = qs - * self._quoter = _Quoter() - */ - if (!(likely(PyUnicode_CheckExact(__pyx_v_unsafe))||((__pyx_v_unsafe) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "unicode", Py_TYPE(__pyx_v_unsafe)->tp_name), 0))) __PYX_ERR(0, 278, __pyx_L1_error) - __pyx_t_1 = __pyx_v_unsafe; - __Pyx_INCREF(__pyx_t_1); - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(__pyx_v_self->_unsafe); - __Pyx_DECREF(__pyx_v_self->_unsafe); - __pyx_v_self->_unsafe = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "yarl/_quoting_c.pyx":279 - * def __init__(self, *, unsafe='', qs=False): - * self._unsafe = unsafe - * self._qs = qs # <<<<<<<<<<<<<< - * self._quoter = _Quoter() - * self._qs_quoter = _Quoter(qs=True) - */ - __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_v_qs); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 279, __pyx_L1_error) - __pyx_v_self->_qs = __pyx_t_2; - - /* "yarl/_quoting_c.pyx":280 - * self._unsafe = unsafe - * self._qs = qs - * self._quoter = _Quoter() # <<<<<<<<<<<<<< - * self._qs_quoter = _Quoter(qs=True) - * - */ - __pyx_t_1 = __Pyx_PyObject_CallNoArg(((PyObject *)__pyx_ptype_4yarl_10_quoting_c__Quoter)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 280, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(__pyx_v_self->_quoter); - __Pyx_DECREF(((PyObject *)__pyx_v_self->_quoter)); - __pyx_v_self->_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_t_1); - __pyx_t_1 = 0; - - /* "yarl/_quoting_c.pyx":281 - * self._qs = qs - * self._quoter = _Quoter() - * self._qs_quoter = _Quoter(qs=True) # <<<<<<<<<<<<<< - * - * def __call__(self, val): - */ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_qs, Py_True) < 0) __PYX_ERR(0, 281, __pyx_L1_error) - __pyx_t_3 = __Pyx_PyObject_Call(((PyObject *)__pyx_ptype_4yarl_10_quoting_c__Quoter), __pyx_empty_tuple, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_GIVEREF(__pyx_t_3); - __Pyx_GOTREF(__pyx_v_self->_qs_quoter); - __Pyx_DECREF(((PyObject *)__pyx_v_self->_qs_quoter)); - __pyx_v_self->_qs_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_t_3); - __pyx_t_3 = 0; - - /* "yarl/_quoting_c.pyx":277 - * cdef _Quoter _qs_quoter - * - * def __init__(self, *, unsafe='', qs=False): # <<<<<<<<<<<<<< - * self._unsafe = unsafe - * self._qs = qs - */ - - /* function exit code */ - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("yarl._quoting_c._Unquoter.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = -1; - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":283 - * self._qs_quoter = _Quoter(qs=True) - * - * def __call__(self, val): # <<<<<<<<<<<<<< - * if val is None: - * return None - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_9_Unquoter_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyObject *__pyx_pw_4yarl_10_quoting_c_9_Unquoter_3__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v_val = 0; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__call__ (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_val,0}; - PyObject* values[1] = {0}; - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - switch (pos_args) { - case 0: - if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_val)) != 0)) kw_args--; - else goto __pyx_L5_argtuple_error; - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) __PYX_ERR(0, 283, __pyx_L3_error) - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 1) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - } - __pyx_v_val = values[0]; - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 283, __pyx_L3_error) - __pyx_L3_error:; - __Pyx_AddTraceback("yarl._quoting_c._Unquoter.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_4yarl_10_quoting_c_9_Unquoter_2__call__(((struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)__pyx_v_self), __pyx_v_val); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_9_Unquoter_2__call__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v_val) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__call__", 0); - __Pyx_INCREF(__pyx_v_val); - - /* "yarl/_quoting_c.pyx":284 - * - * def __call__(self, val): - * if val is None: # <<<<<<<<<<<<<< - * return None - * if type(val) is not str: - */ - __pyx_t_1 = (__pyx_v_val == Py_None); - __pyx_t_2 = (__pyx_t_1 != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":285 - * def __call__(self, val): - * if val is None: - * return None # <<<<<<<<<<<<<< - * if type(val) is not str: - * if isinstance(val, str): - */ - __Pyx_XDECREF(__pyx_r); - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":284 - * - * def __call__(self, val): - * if val is None: # <<<<<<<<<<<<<< - * return None - * if type(val) is not str: - */ - } - - /* "yarl/_quoting_c.pyx":286 - * if val is None: - * return None - * if type(val) is not str: # <<<<<<<<<<<<<< - * if isinstance(val, str): - * # derived from str - */ - __pyx_t_2 = (((PyObject *)Py_TYPE(__pyx_v_val)) != ((PyObject *)(&PyUnicode_Type))); - __pyx_t_1 = (__pyx_t_2 != 0); - if (__pyx_t_1) { - - /* "yarl/_quoting_c.pyx":287 - * return None - * if type(val) is not str: - * if isinstance(val, str): # <<<<<<<<<<<<<< - * # derived from str - * val = str(val) - */ - __pyx_t_1 = PyUnicode_Check(__pyx_v_val); - __pyx_t_2 = (__pyx_t_1 != 0); - if (likely(__pyx_t_2)) { - - /* "yarl/_quoting_c.pyx":289 - * if isinstance(val, str): - * # derived from str - * val = str(val) # <<<<<<<<<<<<<< - * else: - * raise TypeError("Argument should be str") - */ - __pyx_t_3 = __Pyx_PyObject_CallOneArg(((PyObject *)(&PyUnicode_Type)), __pyx_v_val); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 289, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF_SET(__pyx_v_val, __pyx_t_3); - __pyx_t_3 = 0; - - /* "yarl/_quoting_c.pyx":287 - * return None - * if type(val) is not str: - * if isinstance(val, str): # <<<<<<<<<<<<<< - * # derived from str - * val = str(val) - */ - goto __pyx_L5; - } - - /* "yarl/_quoting_c.pyx":291 - * val = str(val) - * else: - * raise TypeError("Argument should be str") # <<<<<<<<<<<<<< - * return self._do_unquote(val) - * - */ - /*else*/ { - __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 291, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_Raise(__pyx_t_3, 0, 0, 0); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __PYX_ERR(0, 291, __pyx_L1_error) - } - __pyx_L5:; - - /* "yarl/_quoting_c.pyx":286 - * if val is None: - * return None - * if type(val) is not str: # <<<<<<<<<<<<<< - * if isinstance(val, str): - * # derived from str - */ - } - - /* "yarl/_quoting_c.pyx":292 - * else: - * raise TypeError("Argument should be str") - * return self._do_unquote(val) # <<<<<<<<<<<<<< - * - * cdef str _do_unquote(self, str val): - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = ((struct __pyx_vtabstruct_4yarl_10_quoting_c__Unquoter *)__pyx_v_self->__pyx_vtab)->_do_unquote(__pyx_v_self, ((PyObject*)__pyx_v_val)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 292, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_r = __pyx_t_3; - __pyx_t_3 = 0; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":283 - * self._qs_quoter = _Quoter(qs=True) - * - * def __call__(self, val): # <<<<<<<<<<<<<< - * if val is None: - * return None - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("yarl._quoting_c._Unquoter.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_val); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "yarl/_quoting_c.pyx":294 - * return self._do_unquote(val) - * - * cdef str _do_unquote(self, str val): # <<<<<<<<<<<<<< - * if len(val) == 0: - * return val - */ - -static PyObject *__pyx_f_4yarl_10_quoting_c_9_Unquoter__do_unquote(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v_val) { - PyObject *__pyx_v_ret = 0; - char __pyx_v_buffer[4]; - Py_ssize_t __pyx_v_buflen; - Py_ssize_t __pyx_v_consumed; - PyObject *__pyx_v_unquoted = 0; - Py_UCS4 __pyx_v_ch; - Py_ssize_t __pyx_v_idx; - Py_ssize_t __pyx_v_length; - Py_ssize_t __pyx_v_start_pct; - PyObject *__pyx_v_h = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - Py_ssize_t __pyx_t_1; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - Py_UCS4 __pyx_t_4; - int __pyx_t_5; - Py_UCS4 __pyx_t_6; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - int __pyx_t_10; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - int __pyx_t_14; - PyObject *__pyx_t_15 = NULL; - PyObject *__pyx_t_16 = NULL; - PyObject *__pyx_t_17 = NULL; - PyObject *__pyx_t_18 = NULL; - PyObject *__pyx_t_19 = NULL; - PyObject *__pyx_t_20 = NULL; - int __pyx_t_21; - PyObject *(*__pyx_t_22)(PyObject *); - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("_do_unquote", 0); - - /* "yarl/_quoting_c.pyx":295 - * - * cdef str _do_unquote(self, str val): - * if len(val) == 0: # <<<<<<<<<<<<<< - * return val - * cdef list ret = [] - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); - __PYX_ERR(0, 295, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_PyUnicode_GET_LENGTH(__pyx_v_val); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 295, __pyx_L1_error) - __pyx_t_2 = ((__pyx_t_1 == 0) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":296 - * cdef str _do_unquote(self, str val): - * if len(val) == 0: - * return val # <<<<<<<<<<<<<< - * cdef list ret = [] - * cdef char buffer[4] - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_val); - __pyx_r = __pyx_v_val; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":295 - * - * cdef str _do_unquote(self, str val): - * if len(val) == 0: # <<<<<<<<<<<<<< - * return val - * cdef list ret = [] - */ - } - - /* "yarl/_quoting_c.pyx":297 - * if len(val) == 0: - * return val - * cdef list ret = [] # <<<<<<<<<<<<<< - * cdef char buffer[4] - * cdef Py_ssize_t buflen = 0 - */ - __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 297, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_v_ret = ((PyObject*)__pyx_t_3); - __pyx_t_3 = 0; - - /* "yarl/_quoting_c.pyx":299 - * cdef list ret = [] - * cdef char buffer[4] - * cdef Py_ssize_t buflen = 0 # <<<<<<<<<<<<<< - * cdef Py_ssize_t consumed - * cdef str unquoted - */ - __pyx_v_buflen = 0; - - /* "yarl/_quoting_c.pyx":302 - * cdef Py_ssize_t consumed - * cdef str unquoted - * cdef Py_UCS4 ch = 0 # <<<<<<<<<<<<<< - * cdef Py_ssize_t idx = 0 - * cdef Py_ssize_t length = len(val) - */ - __pyx_v_ch = 0; - - /* "yarl/_quoting_c.pyx":303 - * cdef str unquoted - * cdef Py_UCS4 ch = 0 - * cdef Py_ssize_t idx = 0 # <<<<<<<<<<<<<< - * cdef Py_ssize_t length = len(val) - * cdef Py_ssize_t start_pct - */ - __pyx_v_idx = 0; - - /* "yarl/_quoting_c.pyx":304 - * cdef Py_UCS4 ch = 0 - * cdef Py_ssize_t idx = 0 - * cdef Py_ssize_t length = len(val) # <<<<<<<<<<<<<< - * cdef Py_ssize_t start_pct - * - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); - __PYX_ERR(0, 304, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_PyUnicode_GET_LENGTH(__pyx_v_val); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(0, 304, __pyx_L1_error) - __pyx_v_length = __pyx_t_1; - - /* "yarl/_quoting_c.pyx":307 - * cdef Py_ssize_t start_pct - * - * while idx < length: # <<<<<<<<<<<<<< - * ch = val[idx] - * idx += 1 - */ - while (1) { - __pyx_t_2 = ((__pyx_v_idx < __pyx_v_length) != 0); - if (!__pyx_t_2) break; - - /* "yarl/_quoting_c.pyx":308 - * - * while idx < length: - * ch = val[idx] # <<<<<<<<<<<<<< - * idx += 1 - * if ch == '%' and idx <= length - 2: - */ - __pyx_t_4 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_v_idx, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(__pyx_t_4 == (Py_UCS4)-1)) __PYX_ERR(0, 308, __pyx_L1_error) - __pyx_v_ch = __pyx_t_4; - - /* "yarl/_quoting_c.pyx":309 - * while idx < length: - * ch = val[idx] - * idx += 1 # <<<<<<<<<<<<<< - * if ch == '%' and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) - */ - __pyx_v_idx = (__pyx_v_idx + 1); - - /* "yarl/_quoting_c.pyx":310 - * ch = val[idx] - * idx += 1 - * if ch == '%' and idx <= length - 2: # <<<<<<<<<<<<<< - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: - */ - __pyx_t_5 = ((__pyx_v_ch == 37) != 0); - if (__pyx_t_5) { - } else { - __pyx_t_2 = __pyx_t_5; - goto __pyx_L7_bool_binop_done; - } - __pyx_t_5 = ((__pyx_v_idx <= (__pyx_v_length - 2)) != 0); - __pyx_t_2 = __pyx_t_5; - __pyx_L7_bool_binop_done:; - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":311 - * idx += 1 - * if ch == '%' and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) # <<<<<<<<<<<<<< - * if ch != -1: - * idx += 2 - */ - __pyx_t_4 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_v_idx, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(__pyx_t_4 == (Py_UCS4)-1)) __PYX_ERR(0, 311, __pyx_L1_error) - __pyx_t_1 = (__pyx_v_idx + 1); - __pyx_t_6 = __Pyx_GetItemInt_Unicode(__pyx_v_val, __pyx_t_1, Py_ssize_t, 1, PyInt_FromSsize_t, 0, 1, 1); if (unlikely(__pyx_t_6 == (Py_UCS4)-1)) __PYX_ERR(0, 311, __pyx_L1_error) - __pyx_v_ch = __pyx_f_4yarl_10_quoting_c__restore_ch(__pyx_t_4, __pyx_t_6); - - /* "yarl/_quoting_c.pyx":312 - * if ch == '%' and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: # <<<<<<<<<<<<<< - * idx += 2 - * assert buflen < 4 - */ - __pyx_t_2 = ((__pyx_v_ch != ((Py_UCS4)-1L)) != 0); - if (__pyx_t_2) { - - /* "yarl/_quoting_c.pyx":313 - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: - * idx += 2 # <<<<<<<<<<<<<< - * assert buflen < 4 - * buffer[buflen] = ch - */ - __pyx_v_idx = (__pyx_v_idx + 2); - - /* "yarl/_quoting_c.pyx":314 - * if ch != -1: - * idx += 2 - * assert buflen < 4 # <<<<<<<<<<<<<< - * buffer[buflen] = ch - * buflen += 1 - */ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(!Py_OptimizeFlag)) { - if (unlikely(!((__pyx_v_buflen < 4) != 0))) { - PyErr_SetNone(PyExc_AssertionError); - __PYX_ERR(0, 314, __pyx_L1_error) - } - } - #endif - - /* "yarl/_quoting_c.pyx":315 - * idx += 2 - * assert buflen < 4 - * buffer[buflen] = ch # <<<<<<<<<<<<<< - * buflen += 1 - * try: - */ - (__pyx_v_buffer[__pyx_v_buflen]) = __pyx_v_ch; - - /* "yarl/_quoting_c.pyx":316 - * assert buflen < 4 - * buffer[buflen] = ch - * buflen += 1 # <<<<<<<<<<<<<< - * try: - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - */ - __pyx_v_buflen = (__pyx_v_buflen + 1); - - /* "yarl/_quoting_c.pyx":317 - * buffer[buflen] = ch - * buflen += 1 - * try: # <<<<<<<<<<<<<< - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - */ - { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ExceptionSave(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9); - __Pyx_XGOTREF(__pyx_t_7); - __Pyx_XGOTREF(__pyx_t_8); - __Pyx_XGOTREF(__pyx_t_9); - /*try:*/ { - - /* "yarl/_quoting_c.pyx":318 - * buflen += 1 - * try: - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, # <<<<<<<<<<<<<< - * NULL, &consumed) - * except UnicodeDecodeError: - */ - __pyx_t_3 = PyUnicode_DecodeUTF8Stateful(__pyx_v_buffer, __pyx_v_buflen, NULL, (&__pyx_v_consumed)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 318, __pyx_L10_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_XDECREF_SET(__pyx_v_unquoted, ((PyObject*)__pyx_t_3)); - __pyx_t_3 = 0; - - /* "yarl/_quoting_c.pyx":317 - * buffer[buflen] = ch - * buflen += 1 - * try: # <<<<<<<<<<<<<< - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - */ - } - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - goto __pyx_L17_try_end; - __pyx_L10_error:; - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "yarl/_quoting_c.pyx":320 - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - * except UnicodeDecodeError: # <<<<<<<<<<<<<< - * start_pct = idx - buflen * 3 - * buffer[0] = ch - */ - __pyx_t_10 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_UnicodeDecodeError); - if (__pyx_t_10) { - __Pyx_AddTraceback("yarl._quoting_c._Unquoter._do_unquote", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_11, &__pyx_t_12) < 0) __PYX_ERR(0, 320, __pyx_L12_except_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_GOTREF(__pyx_t_11); - __Pyx_GOTREF(__pyx_t_12); - - /* "yarl/_quoting_c.pyx":321 - * NULL, &consumed) - * except UnicodeDecodeError: - * start_pct = idx - buflen * 3 # <<<<<<<<<<<<<< - * buffer[0] = ch - * buflen = 1 - */ - __pyx_v_start_pct = (__pyx_v_idx - (__pyx_v_buflen * 3)); - - /* "yarl/_quoting_c.pyx":322 - * except UnicodeDecodeError: - * start_pct = idx - buflen * 3 - * buffer[0] = ch # <<<<<<<<<<<<<< - * buflen = 1 - * ret.append(val[start_pct : idx - 3]) - */ - (__pyx_v_buffer[0]) = __pyx_v_ch; - - /* "yarl/_quoting_c.pyx":323 - * start_pct = idx - buflen * 3 - * buffer[0] = ch - * buflen = 1 # <<<<<<<<<<<<<< - * ret.append(val[start_pct : idx - 3]) - * try: - */ - __pyx_v_buflen = 1; - - /* "yarl/_quoting_c.pyx":324 - * buffer[0] = ch - * buflen = 1 - * ret.append(val[start_pct : idx - 3]) # <<<<<<<<<<<<<< - * try: - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 324, __pyx_L12_except_error) - } - __pyx_t_13 = __Pyx_PyUnicode_Substring(__pyx_v_val, __pyx_v_start_pct, (__pyx_v_idx - 3)); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 324, __pyx_L12_except_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_13); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 324, __pyx_L12_except_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - - /* "yarl/_quoting_c.pyx":325 - * buflen = 1 - * ret.append(val[start_pct : idx - 3]) - * try: # <<<<<<<<<<<<<< - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - */ - { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ExceptionSave(&__pyx_t_15, &__pyx_t_16, &__pyx_t_17); - __Pyx_XGOTREF(__pyx_t_15); - __Pyx_XGOTREF(__pyx_t_16); - __Pyx_XGOTREF(__pyx_t_17); - /*try:*/ { - - /* "yarl/_quoting_c.pyx":326 - * ret.append(val[start_pct : idx - 3]) - * try: - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, # <<<<<<<<<<<<<< - * NULL, &consumed) - * except UnicodeDecodeError: - */ - __pyx_t_13 = PyUnicode_DecodeUTF8Stateful(__pyx_v_buffer, __pyx_v_buflen, NULL, (&__pyx_v_consumed)); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 326, __pyx_L20_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_XDECREF_SET(__pyx_v_unquoted, ((PyObject*)__pyx_t_13)); - __pyx_t_13 = 0; - - /* "yarl/_quoting_c.pyx":325 - * buflen = 1 - * ret.append(val[start_pct : idx - 3]) - * try: # <<<<<<<<<<<<<< - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - */ - } - __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_XDECREF(__pyx_t_16); __pyx_t_16 = 0; - __Pyx_XDECREF(__pyx_t_17); __pyx_t_17 = 0; - goto __pyx_L27_try_end; - __pyx_L20_error:; - __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; - - /* "yarl/_quoting_c.pyx":328 - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - * except UnicodeDecodeError: # <<<<<<<<<<<<<< - * buflen = 0 - * ret.append(val[idx - 3 : idx]) - */ - __pyx_t_10 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_UnicodeDecodeError); - if (__pyx_t_10) { - __Pyx_AddTraceback("yarl._quoting_c._Unquoter._do_unquote", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_13, &__pyx_t_18, &__pyx_t_19) < 0) __PYX_ERR(0, 328, __pyx_L22_except_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_GOTREF(__pyx_t_18); - __Pyx_GOTREF(__pyx_t_19); - - /* "yarl/_quoting_c.pyx":329 - * NULL, &consumed) - * except UnicodeDecodeError: - * buflen = 0 # <<<<<<<<<<<<<< - * ret.append(val[idx - 3 : idx]) - * continue - */ - __pyx_v_buflen = 0; - - /* "yarl/_quoting_c.pyx":330 - * except UnicodeDecodeError: - * buflen = 0 - * ret.append(val[idx - 3 : idx]) # <<<<<<<<<<<<<< - * continue - * if not unquoted: - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 330, __pyx_L22_except_error) - } - __pyx_t_20 = __Pyx_PyUnicode_Substring(__pyx_v_val, (__pyx_v_idx - 3), __pyx_v_idx); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 330, __pyx_L22_except_error) - __Pyx_GOTREF(__pyx_t_20); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_20); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 330, __pyx_L22_except_error) - __Pyx_DECREF(__pyx_t_20); __pyx_t_20 = 0; - - /* "yarl/_quoting_c.pyx":331 - * buflen = 0 - * ret.append(val[idx - 3 : idx]) - * continue # <<<<<<<<<<<<<< - * if not unquoted: - * assert consumed == 0 - */ - goto __pyx_L29_except_continue; - __pyx_L29_except_continue:; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; - __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; - goto __pyx_L26_try_continue; - } - goto __pyx_L22_except_error; - __pyx_L22_except_error:; - - /* "yarl/_quoting_c.pyx":325 - * buflen = 1 - * ret.append(val[start_pct : idx - 3]) - * try: # <<<<<<<<<<<<<< - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - */ - __Pyx_XGIVEREF(__pyx_t_15); - __Pyx_XGIVEREF(__pyx_t_16); - __Pyx_XGIVEREF(__pyx_t_17); - __Pyx_ExceptionReset(__pyx_t_15, __pyx_t_16, __pyx_t_17); - goto __pyx_L12_except_error; - __pyx_L26_try_continue:; - __Pyx_XGIVEREF(__pyx_t_15); - __Pyx_XGIVEREF(__pyx_t_16); - __Pyx_XGIVEREF(__pyx_t_17); - __Pyx_ExceptionReset(__pyx_t_15, __pyx_t_16, __pyx_t_17); - goto __pyx_L19_except_continue; - __pyx_L27_try_end:; - } - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - goto __pyx_L11_exception_handled; - __pyx_L19_except_continue:; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - goto __pyx_L16_try_continue; - } - goto __pyx_L12_except_error; - __pyx_L12_except_error:; - - /* "yarl/_quoting_c.pyx":317 - * buffer[buflen] = ch - * buflen += 1 - * try: # <<<<<<<<<<<<<< - * unquoted = PyUnicode_DecodeUTF8Stateful(buffer, buflen, - * NULL, &consumed) - */ - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - goto __pyx_L1_error; - __pyx_L16_try_continue:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - goto __pyx_L4_continue; - __pyx_L11_exception_handled:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - __pyx_L17_try_end:; - } - - /* "yarl/_quoting_c.pyx":332 - * ret.append(val[idx - 3 : idx]) - * continue - * if not unquoted: # <<<<<<<<<<<<<< - * assert consumed == 0 - * continue - */ - __pyx_t_2 = (__pyx_v_unquoted != Py_None)&&(__Pyx_PyUnicode_IS_TRUE(__pyx_v_unquoted) != 0); - __pyx_t_5 = ((!__pyx_t_2) != 0); - if (__pyx_t_5) { - - /* "yarl/_quoting_c.pyx":333 - * continue - * if not unquoted: - * assert consumed == 0 # <<<<<<<<<<<<<< - * continue - * assert consumed == buflen - */ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(!Py_OptimizeFlag)) { - if (unlikely(!((__pyx_v_consumed == 0) != 0))) { - PyErr_SetNone(PyExc_AssertionError); - __PYX_ERR(0, 333, __pyx_L1_error) - } - } - #endif - - /* "yarl/_quoting_c.pyx":334 - * if not unquoted: - * assert consumed == 0 - * continue # <<<<<<<<<<<<<< - * assert consumed == buflen - * buflen = 0 - */ - goto __pyx_L4_continue; - - /* "yarl/_quoting_c.pyx":332 - * ret.append(val[idx - 3 : idx]) - * continue - * if not unquoted: # <<<<<<<<<<<<<< - * assert consumed == 0 - * continue - */ - } - - /* "yarl/_quoting_c.pyx":335 - * assert consumed == 0 - * continue - * assert consumed == buflen # <<<<<<<<<<<<<< - * buflen = 0 - * if self._qs and unquoted in '+=&;': - */ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(!Py_OptimizeFlag)) { - if (unlikely(!((__pyx_v_consumed == __pyx_v_buflen) != 0))) { - PyErr_SetNone(PyExc_AssertionError); - __PYX_ERR(0, 335, __pyx_L1_error) - } - } - #endif - - /* "yarl/_quoting_c.pyx":336 - * continue - * assert consumed == buflen - * buflen = 0 # <<<<<<<<<<<<<< - * if self._qs and unquoted in '+=&;': - * ret.append(self._qs_quoter(unquoted)) - */ - __pyx_v_buflen = 0; - - /* "yarl/_quoting_c.pyx":337 - * assert consumed == buflen - * buflen = 0 - * if self._qs and unquoted in '+=&;': # <<<<<<<<<<<<<< - * ret.append(self._qs_quoter(unquoted)) - * elif unquoted in self._unsafe: - */ - __pyx_t_2 = (__pyx_v_self->_qs != 0); - if (__pyx_t_2) { - } else { - __pyx_t_5 = __pyx_t_2; - goto __pyx_L32_bool_binop_done; - } - __pyx_t_2 = (__Pyx_PyUnicode_ContainsTF(__pyx_v_unquoted, __pyx_kp_u__4, Py_EQ)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(0, 337, __pyx_L1_error) - __pyx_t_21 = (__pyx_t_2 != 0); - __pyx_t_5 = __pyx_t_21; - __pyx_L32_bool_binop_done:; - if (__pyx_t_5) { - - /* "yarl/_quoting_c.pyx":338 - * buflen = 0 - * if self._qs and unquoted in '+=&;': - * ret.append(self._qs_quoter(unquoted)) # <<<<<<<<<<<<<< - * elif unquoted in self._unsafe: - * ret.append(self._quoter(unquoted)) - */ - __Pyx_INCREF(((PyObject *)__pyx_v_self->_qs_quoter)); - __pyx_t_11 = ((PyObject *)__pyx_v_self->_qs_quoter); __pyx_t_3 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_11); - if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_11, function); - } - } - __pyx_t_12 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_11, __pyx_t_3, __pyx_v_unquoted) : __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_v_unquoted); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 338, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_12); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 338, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - - /* "yarl/_quoting_c.pyx":337 - * assert consumed == buflen - * buflen = 0 - * if self._qs and unquoted in '+=&;': # <<<<<<<<<<<<<< - * ret.append(self._qs_quoter(unquoted)) - * elif unquoted in self._unsafe: - */ - goto __pyx_L31; - } - - /* "yarl/_quoting_c.pyx":339 - * if self._qs and unquoted in '+=&;': - * ret.append(self._qs_quoter(unquoted)) - * elif unquoted in self._unsafe: # <<<<<<<<<<<<<< - * ret.append(self._quoter(unquoted)) - * else: - */ - if (unlikely(__pyx_v_self->_unsafe == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); - __PYX_ERR(0, 339, __pyx_L1_error) - } - __pyx_t_5 = (__Pyx_PyUnicode_ContainsTF(__pyx_v_unquoted, __pyx_v_self->_unsafe, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 339, __pyx_L1_error) - __pyx_t_21 = (__pyx_t_5 != 0); - if (__pyx_t_21) { - - /* "yarl/_quoting_c.pyx":340 - * ret.append(self._qs_quoter(unquoted)) - * elif unquoted in self._unsafe: - * ret.append(self._quoter(unquoted)) # <<<<<<<<<<<<<< - * else: - * ret.append(unquoted) - */ - __Pyx_INCREF(((PyObject *)__pyx_v_self->_quoter)); - __pyx_t_11 = ((PyObject *)__pyx_v_self->_quoter); __pyx_t_3 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_11); - if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_11, function); - } - } - __pyx_t_12 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_11, __pyx_t_3, __pyx_v_unquoted) : __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_v_unquoted); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 340, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_12); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 340, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - - /* "yarl/_quoting_c.pyx":339 - * if self._qs and unquoted in '+=&;': - * ret.append(self._qs_quoter(unquoted)) - * elif unquoted in self._unsafe: # <<<<<<<<<<<<<< - * ret.append(self._quoter(unquoted)) - * else: - */ - goto __pyx_L31; - } - - /* "yarl/_quoting_c.pyx":342 - * ret.append(self._quoter(unquoted)) - * else: - * ret.append(unquoted) # <<<<<<<<<<<<<< - * continue - * else: - */ - /*else*/ { - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_v_unquoted); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 342, __pyx_L1_error) - } - __pyx_L31:; - - /* "yarl/_quoting_c.pyx":343 - * else: - * ret.append(unquoted) - * continue # <<<<<<<<<<<<<< - * else: - * ch = '%' - */ - goto __pyx_L4_continue; - - /* "yarl/_quoting_c.pyx":312 - * if ch == '%' and idx <= length - 2: - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: # <<<<<<<<<<<<<< - * idx += 2 - * assert buflen < 4 - */ - } - - /* "yarl/_quoting_c.pyx":345 - * continue - * else: - * ch = '%' # <<<<<<<<<<<<<< - * - * if buflen: - */ - /*else*/ { - __pyx_v_ch = 37; - } - - /* "yarl/_quoting_c.pyx":310 - * ch = val[idx] - * idx += 1 - * if ch == '%' and idx <= length - 2: # <<<<<<<<<<<<<< - * ch = _restore_ch(val[idx], val[idx + 1]) - * if ch != -1: - */ - } - - /* "yarl/_quoting_c.pyx":347 - * ch = '%' - * - * if buflen: # <<<<<<<<<<<<<< - * start_pct = idx - 1 - buflen * 3 - * ret.append(val[start_pct : idx - 1]) - */ - __pyx_t_21 = (__pyx_v_buflen != 0); - if (__pyx_t_21) { - - /* "yarl/_quoting_c.pyx":348 - * - * if buflen: - * start_pct = idx - 1 - buflen * 3 # <<<<<<<<<<<<<< - * ret.append(val[start_pct : idx - 1]) - * buflen = 0 - */ - __pyx_v_start_pct = ((__pyx_v_idx - 1) - (__pyx_v_buflen * 3)); - - /* "yarl/_quoting_c.pyx":349 - * if buflen: - * start_pct = idx - 1 - buflen * 3 - * ret.append(val[start_pct : idx - 1]) # <<<<<<<<<<<<<< - * buflen = 0 - * - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 349, __pyx_L1_error) - } - __pyx_t_12 = __Pyx_PyUnicode_Substring(__pyx_v_val, __pyx_v_start_pct, (__pyx_v_idx - 1)); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 349, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_12); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 349, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - - /* "yarl/_quoting_c.pyx":350 - * start_pct = idx - 1 - buflen * 3 - * ret.append(val[start_pct : idx - 1]) - * buflen = 0 # <<<<<<<<<<<<<< - * - * if ch == '+': - */ - __pyx_v_buflen = 0; - - /* "yarl/_quoting_c.pyx":347 - * ch = '%' - * - * if buflen: # <<<<<<<<<<<<<< - * start_pct = idx - 1 - buflen * 3 - * ret.append(val[start_pct : idx - 1]) - */ - } - - /* "yarl/_quoting_c.pyx":352 - * buflen = 0 - * - * if ch == '+': # <<<<<<<<<<<<<< - * if not self._qs or ch in self._unsafe: - * ret.append('+') - */ - __pyx_t_21 = ((__pyx_v_ch == 43) != 0); - if (__pyx_t_21) { - - /* "yarl/_quoting_c.pyx":353 - * - * if ch == '+': - * if not self._qs or ch in self._unsafe: # <<<<<<<<<<<<<< - * ret.append('+') - * else: - */ - __pyx_t_5 = ((!(__pyx_v_self->_qs != 0)) != 0); - if (!__pyx_t_5) { - } else { - __pyx_t_21 = __pyx_t_5; - goto __pyx_L37_bool_binop_done; - } - if (unlikely(__pyx_v_self->_unsafe == Py_None)) { - PyErr_SetString(PyExc_TypeError, "argument of type 'NoneType' is not iterable"); - __PYX_ERR(0, 353, __pyx_L1_error) - } - __pyx_t_5 = ((__Pyx_UnicodeContainsUCS4(__pyx_v_self->_unsafe, __pyx_v_ch)) != 0); - __pyx_t_21 = __pyx_t_5; - __pyx_L37_bool_binop_done:; - if (__pyx_t_21) { - - /* "yarl/_quoting_c.pyx":354 - * if ch == '+': - * if not self._qs or ch in self._unsafe: - * ret.append('+') # <<<<<<<<<<<<<< - * else: - * ret.append(' ') - */ - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_kp_u__5); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 354, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":353 - * - * if ch == '+': - * if not self._qs or ch in self._unsafe: # <<<<<<<<<<<<<< - * ret.append('+') - * else: - */ - goto __pyx_L36; - } - - /* "yarl/_quoting_c.pyx":356 - * ret.append('+') - * else: - * ret.append(' ') # <<<<<<<<<<<<<< - * continue - * - */ - /*else*/ { - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_kp_u__6); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 356, __pyx_L1_error) - } - __pyx_L36:; - - /* "yarl/_quoting_c.pyx":357 - * else: - * ret.append(' ') - * continue # <<<<<<<<<<<<<< - * - * if ch in self._unsafe: - */ - goto __pyx_L4_continue; - - /* "yarl/_quoting_c.pyx":352 - * buflen = 0 - * - * if ch == '+': # <<<<<<<<<<<<<< - * if not self._qs or ch in self._unsafe: - * ret.append('+') - */ - } - - /* "yarl/_quoting_c.pyx":359 - * continue - * - * if ch in self._unsafe: # <<<<<<<<<<<<<< - * ret.append('%') - * h = hex(ord(ch)).upper()[2:] - */ - if (unlikely(__pyx_v_self->_unsafe == Py_None)) { - PyErr_SetString(PyExc_TypeError, "argument of type 'NoneType' is not iterable"); - __PYX_ERR(0, 359, __pyx_L1_error) - } - __pyx_t_21 = ((__Pyx_UnicodeContainsUCS4(__pyx_v_self->_unsafe, __pyx_v_ch)) != 0); - if (__pyx_t_21) { - - /* "yarl/_quoting_c.pyx":360 - * - * if ch in self._unsafe: - * ret.append('%') # <<<<<<<<<<<<<< - * h = hex(ord(ch)).upper()[2:] - * for ch in h: - */ - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_kp_u__7); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 360, __pyx_L1_error) - - /* "yarl/_quoting_c.pyx":361 - * if ch in self._unsafe: - * ret.append('%') - * h = hex(ord(ch)).upper()[2:] # <<<<<<<<<<<<<< - * for ch in h: - * ret.append(ch) - */ - __pyx_t_11 = __Pyx_PyInt_From_long(((long)__pyx_v_ch)); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 361, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_hex, __pyx_t_11); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 361, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_upper); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 361, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_11); - if (likely(__pyx_t_3)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_11, function); - } - } - __pyx_t_12 = (__pyx_t_3) ? __Pyx_PyObject_CallOneArg(__pyx_t_11, __pyx_t_3) : __Pyx_PyObject_CallNoArg(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 361, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_11 = __Pyx_PyObject_GetSlice(__pyx_t_12, 2, 0, NULL, NULL, &__pyx_slice__8, 1, 0, 1); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 361, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_XDECREF_SET(__pyx_v_h, __pyx_t_11); - __pyx_t_11 = 0; - - /* "yarl/_quoting_c.pyx":362 - * ret.append('%') - * h = hex(ord(ch)).upper()[2:] - * for ch in h: # <<<<<<<<<<<<<< - * ret.append(ch) - * continue - */ - if (likely(PyList_CheckExact(__pyx_v_h)) || PyTuple_CheckExact(__pyx_v_h)) { - __pyx_t_11 = __pyx_v_h; __Pyx_INCREF(__pyx_t_11); __pyx_t_1 = 0; - __pyx_t_22 = NULL; - } else { - __pyx_t_1 = -1; __pyx_t_11 = PyObject_GetIter(__pyx_v_h); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 362, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_22 = Py_TYPE(__pyx_t_11)->tp_iternext; if (unlikely(!__pyx_t_22)) __PYX_ERR(0, 362, __pyx_L1_error) - } - for (;;) { - if (likely(!__pyx_t_22)) { - if (likely(PyList_CheckExact(__pyx_t_11))) { - if (__pyx_t_1 >= PyList_GET_SIZE(__pyx_t_11)) break; - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_12 = PyList_GET_ITEM(__pyx_t_11, __pyx_t_1); __Pyx_INCREF(__pyx_t_12); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 362, __pyx_L1_error) - #else - __pyx_t_12 = PySequence_ITEM(__pyx_t_11, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 362, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - #endif - } else { - if (__pyx_t_1 >= PyTuple_GET_SIZE(__pyx_t_11)) break; - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_12 = PyTuple_GET_ITEM(__pyx_t_11, __pyx_t_1); __Pyx_INCREF(__pyx_t_12); __pyx_t_1++; if (unlikely(0 < 0)) __PYX_ERR(0, 362, __pyx_L1_error) - #else - __pyx_t_12 = PySequence_ITEM(__pyx_t_11, __pyx_t_1); __pyx_t_1++; if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 362, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - #endif - } - } else { - __pyx_t_12 = __pyx_t_22(__pyx_t_11); - if (unlikely(!__pyx_t_12)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(0, 362, __pyx_L1_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_12); - } - __pyx_t_6 = __Pyx_PyObject_AsPy_UCS4(__pyx_t_12); if (unlikely((__pyx_t_6 == (Py_UCS4)-1) && PyErr_Occurred())) __PYX_ERR(0, 362, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __pyx_v_ch = __pyx_t_6; - - /* "yarl/_quoting_c.pyx":363 - * h = hex(ord(ch)).upper()[2:] - * for ch in h: - * ret.append(ch) # <<<<<<<<<<<<<< - * continue - * - */ - __pyx_t_12 = PyUnicode_FromOrdinal(__pyx_v_ch); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 363, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_12); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 363, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - - /* "yarl/_quoting_c.pyx":362 - * ret.append('%') - * h = hex(ord(ch)).upper()[2:] - * for ch in h: # <<<<<<<<<<<<<< - * ret.append(ch) - * continue - */ - } - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - - /* "yarl/_quoting_c.pyx":364 - * for ch in h: - * ret.append(ch) - * continue # <<<<<<<<<<<<<< - * - * ret.append(ch) - */ - goto __pyx_L4_continue; - - /* "yarl/_quoting_c.pyx":359 - * continue - * - * if ch in self._unsafe: # <<<<<<<<<<<<<< - * ret.append('%') - * h = hex(ord(ch)).upper()[2:] - */ - } - - /* "yarl/_quoting_c.pyx":366 - * continue - * - * ret.append(ch) # <<<<<<<<<<<<<< - * - * if buflen: - */ - __pyx_t_11 = PyUnicode_FromOrdinal(__pyx_v_ch); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 366, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_11); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 366, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_L4_continue:; - } - - /* "yarl/_quoting_c.pyx":368 - * ret.append(ch) - * - * if buflen: # <<<<<<<<<<<<<< - * ret.append(val[length - buflen * 3 : length]) - * - */ - __pyx_t_21 = (__pyx_v_buflen != 0); - if (__pyx_t_21) { - - /* "yarl/_quoting_c.pyx":369 - * - * if buflen: - * ret.append(val[length - buflen * 3 : length]) # <<<<<<<<<<<<<< - * - * return ''.join(ret) - */ - if (unlikely(__pyx_v_val == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(0, 369, __pyx_L1_error) - } - __pyx_t_11 = __Pyx_PyUnicode_Substring(__pyx_v_val, (__pyx_v_length - (__pyx_v_buflen * 3)), __pyx_v_length); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 369, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ret, __pyx_t_11); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 369, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - - /* "yarl/_quoting_c.pyx":368 - * ret.append(ch) - * - * if buflen: # <<<<<<<<<<<<<< - * ret.append(val[length - buflen * 3 : length]) - * - */ - } - - /* "yarl/_quoting_c.pyx":371 - * ret.append(val[length - buflen * 3 : length]) - * - * return ''.join(ret) # <<<<<<<<<<<<<< - */ - __Pyx_XDECREF(__pyx_r); - __pyx_t_11 = PyUnicode_Join(__pyx_kp_u_, __pyx_v_ret); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 371, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_r = ((PyObject*)__pyx_t_11); - __pyx_t_11 = 0; - goto __pyx_L0; - - /* "yarl/_quoting_c.pyx":294 - * return self._do_unquote(val) - * - * cdef str _do_unquote(self, str val): # <<<<<<<<<<<<<< - * if len(val) == 0: - * return val - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_XDECREF(__pyx_t_18); - __Pyx_XDECREF(__pyx_t_19); - __Pyx_XDECREF(__pyx_t_20); - __Pyx_AddTraceback("yarl._quoting_c._Unquoter._do_unquote", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_ret); - __Pyx_XDECREF(__pyx_v_unquoted); - __Pyx_XDECREF(__pyx_v_h); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":1 - * def __reduce_cython__(self): # <<<<<<<<<<<<<< - * cdef tuple state - * cdef object _dict - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_9_Unquoter_5__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/ -static PyObject *__pyx_pw_4yarl_10_quoting_c_9_Unquoter_5__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0); - __pyx_r = __pyx_pf_4yarl_10_quoting_c_9_Unquoter_4__reduce_cython__(((struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)__pyx_v_self)); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_9_Unquoter_4__reduce_cython__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self) { - PyObject *__pyx_v_state = 0; - PyObject *__pyx_v__dict = 0; - int __pyx_v_use_setstate; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - int __pyx_t_3; - int __pyx_t_4; - int __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__reduce_cython__", 0); - - /* "(tree fragment)":5 - * cdef object _dict - * cdef bint use_setstate - * state = (self._qs, self._qs_quoter, self._quoter, self._unsafe) # <<<<<<<<<<<<<< - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: - */ - __pyx_t_1 = __Pyx_PyBool_FromLong(__pyx_v_self->_qs); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyTuple_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_GIVEREF(__pyx_t_1); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1); - __Pyx_INCREF(((PyObject *)__pyx_v_self->_qs_quoter)); - __Pyx_GIVEREF(((PyObject *)__pyx_v_self->_qs_quoter)); - PyTuple_SET_ITEM(__pyx_t_2, 1, ((PyObject *)__pyx_v_self->_qs_quoter)); - __Pyx_INCREF(((PyObject *)__pyx_v_self->_quoter)); - __Pyx_GIVEREF(((PyObject *)__pyx_v_self->_quoter)); - PyTuple_SET_ITEM(__pyx_t_2, 2, ((PyObject *)__pyx_v_self->_quoter)); - __Pyx_INCREF(__pyx_v_self->_unsafe); - __Pyx_GIVEREF(__pyx_v_self->_unsafe); - PyTuple_SET_ITEM(__pyx_t_2, 3, __pyx_v_self->_unsafe); - __pyx_t_1 = 0; - __pyx_v_state = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "(tree fragment)":6 - * cdef bint use_setstate - * state = (self._qs, self._qs_quoter, self._quoter, self._unsafe) - * _dict = getattr(self, '__dict__', None) # <<<<<<<<<<<<<< - * if _dict is not None: - * state += (_dict,) - */ - __pyx_t_2 = __Pyx_GetAttr3(((PyObject *)__pyx_v_self), __pyx_n_s_dict, Py_None); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v__dict = __pyx_t_2; - __pyx_t_2 = 0; - - /* "(tree fragment)":7 - * state = (self._qs, self._qs_quoter, self._quoter, self._unsafe) - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: # <<<<<<<<<<<<<< - * state += (_dict,) - * use_setstate = True - */ - __pyx_t_3 = (__pyx_v__dict != Py_None); - __pyx_t_4 = (__pyx_t_3 != 0); - if (__pyx_t_4) { - - /* "(tree fragment)":8 - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: - * state += (_dict,) # <<<<<<<<<<<<<< - * use_setstate = True - * else: - */ - __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_v__dict); - __Pyx_GIVEREF(__pyx_v__dict); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v__dict); - __pyx_t_1 = PyNumber_InPlaceAdd(__pyx_v_state, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF_SET(__pyx_v_state, ((PyObject*)__pyx_t_1)); - __pyx_t_1 = 0; - - /* "(tree fragment)":9 - * if _dict is not None: - * state += (_dict,) - * use_setstate = True # <<<<<<<<<<<<<< - * else: - * use_setstate = self._qs_quoter is not None or self._quoter is not None or self._unsafe is not None - */ - __pyx_v_use_setstate = 1; - - /* "(tree fragment)":7 - * state = (self._qs, self._qs_quoter, self._quoter, self._unsafe) - * _dict = getattr(self, '__dict__', None) - * if _dict is not None: # <<<<<<<<<<<<<< - * state += (_dict,) - * use_setstate = True - */ - goto __pyx_L3; - } - - /* "(tree fragment)":11 - * use_setstate = True - * else: - * use_setstate = self._qs_quoter is not None or self._quoter is not None or self._unsafe is not None # <<<<<<<<<<<<<< - * if use_setstate: - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, None), state - */ - /*else*/ { - __pyx_t_3 = (((PyObject *)__pyx_v_self->_qs_quoter) != Py_None); - __pyx_t_5 = (__pyx_t_3 != 0); - if (!__pyx_t_5) { - } else { - __pyx_t_4 = __pyx_t_5; - goto __pyx_L4_bool_binop_done; - } - __pyx_t_5 = (((PyObject *)__pyx_v_self->_quoter) != Py_None); - __pyx_t_3 = (__pyx_t_5 != 0); - if (!__pyx_t_3) { - } else { - __pyx_t_4 = __pyx_t_3; - goto __pyx_L4_bool_binop_done; - } - __pyx_t_3 = (__pyx_v_self->_unsafe != ((PyObject*)Py_None)); - __pyx_t_5 = (__pyx_t_3 != 0); - __pyx_t_4 = __pyx_t_5; - __pyx_L4_bool_binop_done:; - __pyx_v_use_setstate = __pyx_t_4; - } - __pyx_L3:; - - /* "(tree fragment)":12 - * else: - * use_setstate = self._qs_quoter is not None or self._quoter is not None or self._unsafe is not None - * if use_setstate: # <<<<<<<<<<<<<< - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, None), state - * else: - */ - __pyx_t_4 = (__pyx_v_use_setstate != 0); - if (__pyx_t_4) { - - /* "(tree fragment)":13 - * use_setstate = self._qs_quoter is not None or self._quoter is not None or self._unsafe is not None - * if use_setstate: - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, None), state # <<<<<<<<<<<<<< - * else: - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, state) - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_pyx_unpickle__Unquoter); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_INCREF(__pyx_int_41310077); - __Pyx_GIVEREF(__pyx_int_41310077); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_int_41310077); - __Pyx_INCREF(Py_None); - __Pyx_GIVEREF(Py_None); - PyTuple_SET_ITEM(__pyx_t_2, 2, Py_None); - __pyx_t_6 = PyTuple_New(3); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_GIVEREF(__pyx_t_1); - PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_1); - __Pyx_GIVEREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_2); - __Pyx_INCREF(__pyx_v_state); - __Pyx_GIVEREF(__pyx_v_state); - PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_v_state); - __pyx_t_1 = 0; - __pyx_t_2 = 0; - __pyx_r = __pyx_t_6; - __pyx_t_6 = 0; - goto __pyx_L0; - - /* "(tree fragment)":12 - * else: - * use_setstate = self._qs_quoter is not None or self._quoter is not None or self._unsafe is not None - * if use_setstate: # <<<<<<<<<<<<<< - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, None), state - * else: - */ - } - - /* "(tree fragment)":15 - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, None), state - * else: - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, state) # <<<<<<<<<<<<<< - * def __setstate_cython__(self, __pyx_state): - * __pyx_unpickle__Unquoter__set_state(self, __pyx_state) - */ - /*else*/ { - __Pyx_XDECREF(__pyx_r); - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_pyx_unpickle__Unquoter); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_2 = PyTuple_New(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(1, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_GIVEREF(((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - PyTuple_SET_ITEM(__pyx_t_2, 0, ((PyObject *)Py_TYPE(((PyObject *)__pyx_v_self)))); - __Pyx_INCREF(__pyx_int_41310077); - __Pyx_GIVEREF(__pyx_int_41310077); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_int_41310077); - __Pyx_INCREF(__pyx_v_state); - __Pyx_GIVEREF(__pyx_v_state); - PyTuple_SET_ITEM(__pyx_t_2, 2, __pyx_v_state); - __pyx_t_1 = PyTuple_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_GIVEREF(__pyx_t_6); - PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_6); - __Pyx_GIVEREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_2); - __pyx_t_6 = 0; - __pyx_t_2 = 0; - __pyx_r = __pyx_t_1; - __pyx_t_1 = 0; - goto __pyx_L0; - } - - /* "(tree fragment)":1 - * def __reduce_cython__(self): # <<<<<<<<<<<<<< - * cdef tuple state - * cdef object _dict - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("yarl._quoting_c._Unquoter.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_state); - __Pyx_XDECREF(__pyx_v__dict); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":16 - * else: - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, state) - * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< - * __pyx_unpickle__Unquoter__set_state(self, __pyx_state) - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_9_Unquoter_7__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/ -static PyObject *__pyx_pw_4yarl_10_quoting_c_9_Unquoter_7__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0); - __pyx_r = __pyx_pf_4yarl_10_quoting_c_9_Unquoter_6__setstate_cython__(((struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state)); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_9_Unquoter_6__setstate_cython__(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v_self, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__setstate_cython__", 0); - - /* "(tree fragment)":17 - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, state) - * def __setstate_cython__(self, __pyx_state): - * __pyx_unpickle__Unquoter__set_state(self, __pyx_state) # <<<<<<<<<<<<<< - */ - if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 17, __pyx_L1_error) - __pyx_t_1 = __pyx_f_4yarl_10_quoting_c___pyx_unpickle__Unquoter__set_state(__pyx_v_self, ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 17, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "(tree fragment)":16 - * else: - * return __pyx_unpickle__Unquoter, (type(self), 0x276577d, state) - * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<< - * __pyx_unpickle__Unquoter__set_state(self, __pyx_state) - */ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("yarl._quoting_c._Unquoter.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":1 - * def __pyx_unpickle__Quoter(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_1__pyx_unpickle__Quoter(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyMethodDef __pyx_mdef_4yarl_10_quoting_c_1__pyx_unpickle__Quoter = {"__pyx_unpickle__Quoter", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_4yarl_10_quoting_c_1__pyx_unpickle__Quoter, METH_VARARGS|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_4yarl_10_quoting_c_1__pyx_unpickle__Quoter(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v___pyx_type = 0; - long __pyx_v___pyx_checksum; - PyObject *__pyx_v___pyx_state = 0; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__pyx_unpickle__Quoter (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_type,&__pyx_n_s_pyx_checksum,&__pyx_n_s_pyx_state,0}; - PyObject* values[3] = {0,0,0}; - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - CYTHON_FALLTHROUGH; - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - CYTHON_FALLTHROUGH; - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - switch (pos_args) { - case 0: - if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_type)) != 0)) kw_args--; - else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_checksum)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__pyx_unpickle__Quoter", 1, 3, 3, 1); __PYX_ERR(1, 1, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_state)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__pyx_unpickle__Quoter", 1, 3, 3, 2); __PYX_ERR(1, 1, __pyx_L3_error) - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__pyx_unpickle__Quoter") < 0)) __PYX_ERR(1, 1, __pyx_L3_error) - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - } - __pyx_v___pyx_type = values[0]; - __pyx_v___pyx_checksum = __Pyx_PyInt_As_long(values[1]); if (unlikely((__pyx_v___pyx_checksum == (long)-1) && PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) - __pyx_v___pyx_state = values[2]; - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__pyx_unpickle__Quoter", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 1, __pyx_L3_error) - __pyx_L3_error:; - __Pyx_AddTraceback("yarl._quoting_c.__pyx_unpickle__Quoter", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_4yarl_10_quoting_c___pyx_unpickle__Quoter(__pyx_self, __pyx_v___pyx_type, __pyx_v___pyx_checksum, __pyx_v___pyx_state); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c___pyx_unpickle__Quoter(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_v___pyx_PickleError = 0; - PyObject *__pyx_v___pyx_result = 0; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; - int __pyx_t_3; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_unpickle__Quoter", 0); - - /* "(tree fragment)":4 - * cdef object __pyx_PickleError - * cdef object __pyx_result - * if __pyx_checksum not in (0xe91bd35, 0x60b2b56, 0x7e82961): # <<<<<<<<<<<<<< - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - */ - __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_t_1, __pyx_tuple__9, Py_NE)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(1, 4, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_3 = (__pyx_t_2 != 0); - if (__pyx_t_3) { - - /* "(tree fragment)":5 - * cdef object __pyx_result - * if __pyx_checksum not in (0xe91bd35, 0x60b2b56, 0x7e82961): - * from pickle import PickleError as __pyx_PickleError # <<<<<<<<<<<<<< - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - * __pyx_result = _Quoter.__new__(__pyx_type) - */ - __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_n_s_PickleError); - __Pyx_GIVEREF(__pyx_n_s_PickleError); - PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_PickleError); - __pyx_t_4 = __Pyx_Import(__pyx_n_s_pickle, __pyx_t_1, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_PickleError); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_t_1); - __pyx_v___pyx_PickleError = __pyx_t_1; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "(tree fragment)":6 - * if __pyx_checksum not in (0xe91bd35, 0x60b2b56, 0x7e82961): - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) # <<<<<<<<<<<<<< - * __pyx_result = _Quoter.__new__(__pyx_type) - * if __pyx_state is not None: - */ - __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = __Pyx_PyString_Format(__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_INCREF(__pyx_v___pyx_PickleError); - __pyx_t_1 = __pyx_v___pyx_PickleError; __pyx_t_6 = NULL; - if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { - __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); - if (likely(__pyx_t_6)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); - __Pyx_INCREF(__pyx_t_6); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_1, function); - } - } - __pyx_t_4 = (__pyx_t_6) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_6, __pyx_t_5) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_Raise(__pyx_t_4, 0, 0, 0); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __PYX_ERR(1, 6, __pyx_L1_error) - - /* "(tree fragment)":4 - * cdef object __pyx_PickleError - * cdef object __pyx_result - * if __pyx_checksum not in (0xe91bd35, 0x60b2b56, 0x7e82961): # <<<<<<<<<<<<<< - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - */ - } - - /* "(tree fragment)":7 - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - * __pyx_result = _Quoter.__new__(__pyx_type) # <<<<<<<<<<<<<< - * if __pyx_state is not None: - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - */ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_4yarl_10_quoting_c__Quoter), __pyx_n_s_new); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); - if (likely(__pyx_t_5)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_1, function); - } - } - __pyx_t_4 = (__pyx_t_5) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_5, __pyx_v___pyx_type) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v___pyx_type); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v___pyx_result = __pyx_t_4; - __pyx_t_4 = 0; - - /* "(tree fragment)":8 - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - * __pyx_result = _Quoter.__new__(__pyx_type) - * if __pyx_state is not None: # <<<<<<<<<<<<<< - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - * return __pyx_result - */ - __pyx_t_3 = (__pyx_v___pyx_state != Py_None); - __pyx_t_2 = (__pyx_t_3 != 0); - if (__pyx_t_2) { - - /* "(tree fragment)":9 - * __pyx_result = _Quoter.__new__(__pyx_type) - * if __pyx_state is not None: - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) # <<<<<<<<<<<<<< - * return __pyx_result - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): - */ - if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 9, __pyx_L1_error) - __pyx_t_4 = __pyx_f_4yarl_10_quoting_c___pyx_unpickle__Quoter__set_state(((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_v___pyx_result), ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "(tree fragment)":8 - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - * __pyx_result = _Quoter.__new__(__pyx_type) - * if __pyx_state is not None: # <<<<<<<<<<<<<< - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - * return __pyx_result - */ - } - - /* "(tree fragment)":10 - * if __pyx_state is not None: - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - * return __pyx_result # <<<<<<<<<<<<<< - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v___pyx_result); - __pyx_r = __pyx_v___pyx_result; - goto __pyx_L0; - - /* "(tree fragment)":1 - * def __pyx_unpickle__Quoter(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("yarl._quoting_c.__pyx_unpickle__Quoter", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v___pyx_PickleError); - __Pyx_XDECREF(__pyx_v___pyx_result); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":11 - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - * return __pyx_result - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - */ - -static PyObject *__pyx_f_4yarl_10_quoting_c___pyx_unpickle__Quoter__set_state(struct __pyx_obj_4yarl_10_quoting_c__Quoter *__pyx_v___pyx_result, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - uint8_t __pyx_t_2[16]; - int __pyx_t_3; - Py_ssize_t __pyx_t_4; - int __pyx_t_5; - int __pyx_t_6; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_unpickle__Quoter__set_state", 0); - - /* "(tree fragment)":12 - * return __pyx_result - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] # <<<<<<<<<<<<<< - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - * __pyx_result.__dict__.update(__pyx_state[4]) - */ - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (unlikely(__Pyx_carray_from_py_uint8_t(__pyx_t_1, __pyx_t_2, 16) < 0)) __PYX_ERR(1, 12, __pyx_L1_error) - memcpy(&(__pyx_v___pyx_result->_protected_table[0]), __pyx_t_2, sizeof(__pyx_v___pyx_result->_protected_table[0]) * (16)); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v___pyx_result->_qs = __pyx_t_3; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v___pyx_result->_requote = __pyx_t_3; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (unlikely(__Pyx_carray_from_py_uint8_t(__pyx_t_1, __pyx_t_2, 16) < 0)) __PYX_ERR(1, 12, __pyx_L1_error) - memcpy(&(__pyx_v___pyx_result->_safe_table[0]), __pyx_t_2, sizeof(__pyx_v___pyx_result->_safe_table[0]) * (16)); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "(tree fragment)":13 - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< - * __pyx_result.__dict__.update(__pyx_state[4]) - */ - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); - __PYX_ERR(1, 13, __pyx_L1_error) - } - __pyx_t_4 = PyTuple_GET_SIZE(__pyx_v___pyx_state); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 13, __pyx_L1_error) - __pyx_t_5 = ((__pyx_t_4 > 4) != 0); - if (__pyx_t_5) { - } else { - __pyx_t_3 = __pyx_t_5; - goto __pyx_L4_bool_binop_done; - } - __pyx_t_5 = __Pyx_HasAttr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(__pyx_t_5 == ((int)-1))) __PYX_ERR(1, 13, __pyx_L1_error) - __pyx_t_6 = (__pyx_t_5 != 0); - __pyx_t_3 = __pyx_t_6; - __pyx_L4_bool_binop_done:; - if (__pyx_t_3) { - - /* "(tree fragment)":14 - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - * __pyx_result.__dict__.update(__pyx_state[4]) # <<<<<<<<<<<<<< - */ - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_update); if (unlikely(!__pyx_t_8)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 14, __pyx_L1_error) - } - __pyx_t_7 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 4, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_9 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_8))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_8); - if (likely(__pyx_t_9)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_8); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_8, function); - } - } - __pyx_t_1 = (__pyx_t_9) ? __Pyx_PyObject_Call2Args(__pyx_t_8, __pyx_t_9, __pyx_t_7) : __Pyx_PyObject_CallOneArg(__pyx_t_8, __pyx_t_7); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "(tree fragment)":13 - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< - * __pyx_result.__dict__.update(__pyx_state[4]) - */ - } - - /* "(tree fragment)":11 - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - * return __pyx_result - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - */ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_AddTraceback("yarl._quoting_c.__pyx_unpickle__Quoter__set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":1 - * def __pyx_unpickle__Unquoter(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ - -/* Python wrapper */ -static PyObject *__pyx_pw_4yarl_10_quoting_c_3__pyx_unpickle__Unquoter(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static PyMethodDef __pyx_mdef_4yarl_10_quoting_c_3__pyx_unpickle__Unquoter = {"__pyx_unpickle__Unquoter", (PyCFunction)(void*)(PyCFunctionWithKeywords)__pyx_pw_4yarl_10_quoting_c_3__pyx_unpickle__Unquoter, METH_VARARGS|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_4yarl_10_quoting_c_3__pyx_unpickle__Unquoter(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - PyObject *__pyx_v___pyx_type = 0; - long __pyx_v___pyx_checksum; - PyObject *__pyx_v___pyx_state = 0; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__pyx_unpickle__Unquoter (wrapper)", 0); - { - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_pyx_type,&__pyx_n_s_pyx_checksum,&__pyx_n_s_pyx_state,0}; - PyObject* values[3] = {0,0,0}; - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args; - const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); - switch (pos_args) { - case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - CYTHON_FALLTHROUGH; - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - CYTHON_FALLTHROUGH; - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - kw_args = PyDict_Size(__pyx_kwds); - switch (pos_args) { - case 0: - if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_type)) != 0)) kw_args--; - else goto __pyx_L5_argtuple_error; - CYTHON_FALLTHROUGH; - case 1: - if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_checksum)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__pyx_unpickle__Unquoter", 1, 3, 3, 1); __PYX_ERR(1, 1, __pyx_L3_error) - } - CYTHON_FALLTHROUGH; - case 2: - if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_pyx_state)) != 0)) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("__pyx_unpickle__Unquoter", 1, 3, 3, 2); __PYX_ERR(1, 1, __pyx_L3_error) - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__pyx_unpickle__Unquoter") < 0)) __PYX_ERR(1, 1, __pyx_L3_error) - } - } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - } - __pyx_v___pyx_type = values[0]; - __pyx_v___pyx_checksum = __Pyx_PyInt_As_long(values[1]); if (unlikely((__pyx_v___pyx_checksum == (long)-1) && PyErr_Occurred())) __PYX_ERR(1, 1, __pyx_L3_error) - __pyx_v___pyx_state = values[2]; - } - goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__pyx_unpickle__Unquoter", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 1, __pyx_L3_error) - __pyx_L3_error:; - __Pyx_AddTraceback("yarl._quoting_c.__pyx_unpickle__Unquoter", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_4yarl_10_quoting_c_2__pyx_unpickle__Unquoter(__pyx_self, __pyx_v___pyx_type, __pyx_v___pyx_checksum, __pyx_v___pyx_state); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_4yarl_10_quoting_c_2__pyx_unpickle__Unquoter(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_v___pyx_PickleError = 0; - PyObject *__pyx_v___pyx_result = 0; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; - int __pyx_t_3; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_unpickle__Unquoter", 0); - - /* "(tree fragment)":4 - * cdef object __pyx_PickleError - * cdef object __pyx_result - * if __pyx_checksum not in (0x276577d, 0x4dde2d1, 0x5358bd6): # <<<<<<<<<<<<<< - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) - */ - __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = (__Pyx_PySequence_ContainsTF(__pyx_t_1, __pyx_tuple__10, Py_NE)); if (unlikely(__pyx_t_2 < 0)) __PYX_ERR(1, 4, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_3 = (__pyx_t_2 != 0); - if (__pyx_t_3) { - - /* "(tree fragment)":5 - * cdef object __pyx_result - * if __pyx_checksum not in (0x276577d, 0x4dde2d1, 0x5358bd6): - * from pickle import PickleError as __pyx_PickleError # <<<<<<<<<<<<<< - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) - * __pyx_result = _Unquoter.__new__(__pyx_type) - */ - __pyx_t_1 = PyList_New(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_n_s_PickleError); - __Pyx_GIVEREF(__pyx_n_s_PickleError); - PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_PickleError); - __pyx_t_4 = __Pyx_Import(__pyx_n_s_pickle, __pyx_t_1, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_4, __pyx_n_s_PickleError); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_t_1); - __pyx_v___pyx_PickleError = __pyx_t_1; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "(tree fragment)":6 - * if __pyx_checksum not in (0x276577d, 0x4dde2d1, 0x5358bd6): - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) # <<<<<<<<<<<<<< - * __pyx_result = _Unquoter.__new__(__pyx_type) - * if __pyx_state is not None: - */ - __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_v___pyx_checksum); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = __Pyx_PyString_Format(__pyx_kp_s_Incompatible_checksums_0x_x_vs_0_2, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_INCREF(__pyx_v___pyx_PickleError); - __pyx_t_1 = __pyx_v___pyx_PickleError; __pyx_t_6 = NULL; - if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) { - __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_1); - if (likely(__pyx_t_6)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); - __Pyx_INCREF(__pyx_t_6); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_1, function); - } - } - __pyx_t_4 = (__pyx_t_6) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_6, __pyx_t_5) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_Raise(__pyx_t_4, 0, 0, 0); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __PYX_ERR(1, 6, __pyx_L1_error) - - /* "(tree fragment)":4 - * cdef object __pyx_PickleError - * cdef object __pyx_result - * if __pyx_checksum not in (0x276577d, 0x4dde2d1, 0x5358bd6): # <<<<<<<<<<<<<< - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) - */ - } - - /* "(tree fragment)":7 - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) - * __pyx_result = _Unquoter.__new__(__pyx_type) # <<<<<<<<<<<<<< - * if __pyx_state is not None: - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) - */ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_ptype_4yarl_10_quoting_c__Unquoter), __pyx_n_s_new); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1); - if (likely(__pyx_t_5)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_1, function); - } - } - __pyx_t_4 = (__pyx_t_5) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_5, __pyx_v___pyx_type) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_v___pyx_type); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v___pyx_result = __pyx_t_4; - __pyx_t_4 = 0; - - /* "(tree fragment)":8 - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) - * __pyx_result = _Unquoter.__new__(__pyx_type) - * if __pyx_state is not None: # <<<<<<<<<<<<<< - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) - * return __pyx_result - */ - __pyx_t_3 = (__pyx_v___pyx_state != Py_None); - __pyx_t_2 = (__pyx_t_3 != 0); - if (__pyx_t_2) { - - /* "(tree fragment)":9 - * __pyx_result = _Unquoter.__new__(__pyx_type) - * if __pyx_state is not None: - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) # <<<<<<<<<<<<<< - * return __pyx_result - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): - */ - if (!(likely(PyTuple_CheckExact(__pyx_v___pyx_state))||((__pyx_v___pyx_state) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "tuple", Py_TYPE(__pyx_v___pyx_state)->tp_name), 0))) __PYX_ERR(1, 9, __pyx_L1_error) - __pyx_t_4 = __pyx_f_4yarl_10_quoting_c___pyx_unpickle__Unquoter__set_state(((struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)__pyx_v___pyx_result), ((PyObject*)__pyx_v___pyx_state)); if (unlikely(!__pyx_t_4)) __PYX_ERR(1, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "(tree fragment)":8 - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0x276577d, 0x4dde2d1, 0x5358bd6) = (_qs, _qs_quoter, _quoter, _unsafe))" % __pyx_checksum) - * __pyx_result = _Unquoter.__new__(__pyx_type) - * if __pyx_state is not None: # <<<<<<<<<<<<<< - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) - * return __pyx_result - */ - } - - /* "(tree fragment)":10 - * if __pyx_state is not None: - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) - * return __pyx_result # <<<<<<<<<<<<<< - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] - */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v___pyx_result); - __pyx_r = __pyx_v___pyx_result; - goto __pyx_L0; - - /* "(tree fragment)":1 - * def __pyx_unpickle__Unquoter(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("yarl._quoting_c.__pyx_unpickle__Unquoter", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v___pyx_PickleError); - __Pyx_XDECREF(__pyx_v___pyx_result); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "(tree fragment)":11 - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) - * return __pyx_result - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - */ - -static PyObject *__pyx_f_4yarl_10_quoting_c___pyx_unpickle__Unquoter__set_state(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *__pyx_v___pyx_result, PyObject *__pyx_v___pyx_state) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_t_2; - Py_ssize_t __pyx_t_3; - int __pyx_t_4; - int __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__pyx_unpickle__Unquoter__set_state", 0); - - /* "(tree fragment)":12 - * return __pyx_result - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] # <<<<<<<<<<<<<< - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - * __pyx_result.__dict__.update(__pyx_state[4]) - */ - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v___pyx_result->_qs = __pyx_t_2; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_4yarl_10_quoting_c__Quoter))))) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(__pyx_v___pyx_result->_qs_quoter); - __Pyx_DECREF(((PyObject *)__pyx_v___pyx_result->_qs_quoter)); - __pyx_v___pyx_result->_qs_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_t_1); - __pyx_t_1 = 0; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 2, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(((__pyx_t_1) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_1, __pyx_ptype_4yarl_10_quoting_c__Quoter))))) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(__pyx_v___pyx_result->_quoter); - __Pyx_DECREF(((PyObject *)__pyx_v___pyx_result->_quoter)); - __pyx_v___pyx_result->_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)__pyx_t_1); - __pyx_t_1 = 0; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 12, __pyx_L1_error) - } - __pyx_t_1 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 3, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyUnicode_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "unicode", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(1, 12, __pyx_L1_error) - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_GOTREF(__pyx_v___pyx_result->_unsafe); - __Pyx_DECREF(__pyx_v___pyx_result->_unsafe); - __pyx_v___pyx_result->_unsafe = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "(tree fragment)":13 - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< - * __pyx_result.__dict__.update(__pyx_state[4]) - */ - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()"); - __PYX_ERR(1, 13, __pyx_L1_error) - } - __pyx_t_3 = PyTuple_GET_SIZE(__pyx_v___pyx_state); if (unlikely(__pyx_t_3 == ((Py_ssize_t)-1))) __PYX_ERR(1, 13, __pyx_L1_error) - __pyx_t_4 = ((__pyx_t_3 > 4) != 0); - if (__pyx_t_4) { - } else { - __pyx_t_2 = __pyx_t_4; - goto __pyx_L4_bool_binop_done; - } - __pyx_t_4 = __Pyx_HasAttr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(1, 13, __pyx_L1_error) - __pyx_t_5 = (__pyx_t_4 != 0); - __pyx_t_2 = __pyx_t_5; - __pyx_L4_bool_binop_done:; - if (__pyx_t_2) { - - /* "(tree fragment)":14 - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - * __pyx_result.__dict__.update(__pyx_state[4]) # <<<<<<<<<<<<<< - */ - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v___pyx_result), __pyx_n_s_dict); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_update); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(__pyx_v___pyx_state == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not subscriptable"); - __PYX_ERR(1, 14, __pyx_L1_error) - } - __pyx_t_6 = __Pyx_GetItemInt_Tuple(__pyx_v___pyx_state, 4, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_6)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_8 = NULL; - if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_7); - if (likely(__pyx_t_8)) { - PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_8); - __Pyx_INCREF(function); - __Pyx_DECREF_SET(__pyx_t_7, function); - } - } - __pyx_t_1 = (__pyx_t_8) ? __Pyx_PyObject_Call2Args(__pyx_t_7, __pyx_t_8, __pyx_t_6) : __Pyx_PyObject_CallOneArg(__pyx_t_7, __pyx_t_6); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "(tree fragment)":13 - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): # <<<<<<<<<<<<<< - * __pyx_result.__dict__.update(__pyx_state[4]) - */ - } - - /* "(tree fragment)":11 - * __pyx_unpickle__Unquoter__set_state(<_Unquoter> __pyx_result, __pyx_state) - * return __pyx_result - * cdef __pyx_unpickle__Unquoter__set_state(_Unquoter __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< - * __pyx_result._qs = __pyx_state[0]; __pyx_result._qs_quoter = __pyx_state[1]; __pyx_result._quoter = __pyx_state[2]; __pyx_result._unsafe = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - */ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_AddTraceback("yarl._quoting_c.__pyx_unpickle__Unquoter__set_state", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = 0; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "carray.from_py":77 - * - * @cname("__Pyx_carray_from_py_uint8_t") - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: # <<<<<<<<<<<<<< - * cdef Py_ssize_t i = length - * try: - */ - -static int __Pyx_carray_from_py_uint8_t(PyObject *__pyx_v_o, uint8_t *__pyx_v_v, Py_ssize_t __pyx_v_length) { - Py_ssize_t __pyx_v_i; - PyObject *__pyx_v_item = NULL; - int __pyx_r; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - Py_ssize_t __pyx_t_4; - int __pyx_t_5; - int __pyx_t_6; - PyObject *__pyx_t_7 = NULL; - Py_ssize_t __pyx_t_8; - PyObject *(*__pyx_t_9)(PyObject *); - PyObject *__pyx_t_10 = NULL; - uint8_t __pyx_t_11; - char const *__pyx_t_12; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_carray_from_py_uint8_t", 0); - - /* "carray.from_py":78 - * @cname("__Pyx_carray_from_py_uint8_t") - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: - * cdef Py_ssize_t i = length # <<<<<<<<<<<<<< - * try: - * i = len(o) - */ - __pyx_v_i = __pyx_v_length; - - /* "carray.from_py":79 - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: - * cdef Py_ssize_t i = length - * try: # <<<<<<<<<<<<<< - * i = len(o) - * except (TypeError, OverflowError): - */ - { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ExceptionSave(&__pyx_t_1, &__pyx_t_2, &__pyx_t_3); - __Pyx_XGOTREF(__pyx_t_1); - __Pyx_XGOTREF(__pyx_t_2); - __Pyx_XGOTREF(__pyx_t_3); - /*try:*/ { - - /* "carray.from_py":80 - * cdef Py_ssize_t i = length - * try: - * i = len(o) # <<<<<<<<<<<<<< - * except (TypeError, OverflowError): - * pass - */ - __pyx_t_4 = PyObject_Length(__pyx_v_o); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(1, 80, __pyx_L3_error) - __pyx_v_i = __pyx_t_4; - - /* "carray.from_py":79 - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: - * cdef Py_ssize_t i = length - * try: # <<<<<<<<<<<<<< - * i = len(o) - * except (TypeError, OverflowError): - */ - } - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - goto __pyx_L8_try_end; - __pyx_L3_error:; - - /* "carray.from_py":81 - * try: - * i = len(o) - * except (TypeError, OverflowError): # <<<<<<<<<<<<<< - * pass - * if i == length: - */ - __pyx_t_5 = __Pyx_PyErr_ExceptionMatches(__pyx_builtin_TypeError) || __Pyx_PyErr_ExceptionMatches(__pyx_builtin_OverflowError); - if (__pyx_t_5) { - __Pyx_ErrRestore(0,0,0); - goto __pyx_L4_exception_handled; - } - goto __pyx_L5_except_error; - __pyx_L5_except_error:; - - /* "carray.from_py":79 - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: - * cdef Py_ssize_t i = length - * try: # <<<<<<<<<<<<<< - * i = len(o) - * except (TypeError, OverflowError): - */ - __Pyx_XGIVEREF(__pyx_t_1); - __Pyx_XGIVEREF(__pyx_t_2); - __Pyx_XGIVEREF(__pyx_t_3); - __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); - goto __pyx_L1_error; - __pyx_L4_exception_handled:; - __Pyx_XGIVEREF(__pyx_t_1); - __Pyx_XGIVEREF(__pyx_t_2); - __Pyx_XGIVEREF(__pyx_t_3); - __Pyx_ExceptionReset(__pyx_t_1, __pyx_t_2, __pyx_t_3); - __pyx_L8_try_end:; - } - - /* "carray.from_py":83 - * except (TypeError, OverflowError): - * pass - * if i == length: # <<<<<<<<<<<<<< - * for i, item in enumerate(o): - * if i >= length: - */ - __pyx_t_6 = ((__pyx_v_i == __pyx_v_length) != 0); - if (__pyx_t_6) { - - /* "carray.from_py":84 - * pass - * if i == length: - * for i, item in enumerate(o): # <<<<<<<<<<<<<< - * if i >= length: - * break - */ - __pyx_t_4 = 0; - if (likely(PyList_CheckExact(__pyx_v_o)) || PyTuple_CheckExact(__pyx_v_o)) { - __pyx_t_7 = __pyx_v_o; __Pyx_INCREF(__pyx_t_7); __pyx_t_8 = 0; - __pyx_t_9 = NULL; - } else { - __pyx_t_8 = -1; __pyx_t_7 = PyObject_GetIter(__pyx_v_o); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 84, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_9 = Py_TYPE(__pyx_t_7)->tp_iternext; if (unlikely(!__pyx_t_9)) __PYX_ERR(1, 84, __pyx_L1_error) - } - for (;;) { - if (likely(!__pyx_t_9)) { - if (likely(PyList_CheckExact(__pyx_t_7))) { - if (__pyx_t_8 >= PyList_GET_SIZE(__pyx_t_7)) break; - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_10 = PyList_GET_ITEM(__pyx_t_7, __pyx_t_8); __Pyx_INCREF(__pyx_t_10); __pyx_t_8++; if (unlikely(0 < 0)) __PYX_ERR(1, 84, __pyx_L1_error) - #else - __pyx_t_10 = PySequence_ITEM(__pyx_t_7, __pyx_t_8); __pyx_t_8++; if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 84, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - #endif - } else { - if (__pyx_t_8 >= PyTuple_GET_SIZE(__pyx_t_7)) break; - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_10 = PyTuple_GET_ITEM(__pyx_t_7, __pyx_t_8); __Pyx_INCREF(__pyx_t_10); __pyx_t_8++; if (unlikely(0 < 0)) __PYX_ERR(1, 84, __pyx_L1_error) - #else - __pyx_t_10 = PySequence_ITEM(__pyx_t_7, __pyx_t_8); __pyx_t_8++; if (unlikely(!__pyx_t_10)) __PYX_ERR(1, 84, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - #endif - } - } else { - __pyx_t_10 = __pyx_t_9(__pyx_t_7); - if (unlikely(!__pyx_t_10)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (likely(__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) PyErr_Clear(); - else __PYX_ERR(1, 84, __pyx_L1_error) - } - break; - } - __Pyx_GOTREF(__pyx_t_10); - } - __Pyx_XDECREF_SET(__pyx_v_item, __pyx_t_10); - __pyx_t_10 = 0; - __pyx_v_i = __pyx_t_4; - __pyx_t_4 = (__pyx_t_4 + 1); - - /* "carray.from_py":85 - * if i == length: - * for i, item in enumerate(o): - * if i >= length: # <<<<<<<<<<<<<< - * break - * v[i] = item - */ - __pyx_t_6 = ((__pyx_v_i >= __pyx_v_length) != 0); - if (__pyx_t_6) { - - /* "carray.from_py":86 - * for i, item in enumerate(o): - * if i >= length: - * break # <<<<<<<<<<<<<< - * v[i] = item - * else: - */ - goto __pyx_L11_break; - - /* "carray.from_py":85 - * if i == length: - * for i, item in enumerate(o): - * if i >= length: # <<<<<<<<<<<<<< - * break - * v[i] = item - */ - } - - /* "carray.from_py":87 - * if i >= length: - * break - * v[i] = item # <<<<<<<<<<<<<< - * else: - * i += 1 # convert index to length - */ - __pyx_t_11 = __Pyx_PyInt_As_uint8_t(__pyx_v_item); if (unlikely((__pyx_t_11 == ((uint8_t)-1)) && PyErr_Occurred())) __PYX_ERR(1, 87, __pyx_L1_error) - (__pyx_v_v[__pyx_v_i]) = __pyx_t_11; - - /* "carray.from_py":84 - * pass - * if i == length: - * for i, item in enumerate(o): # <<<<<<<<<<<<<< - * if i >= length: - * break - */ - } - /*else*/ { - - /* "carray.from_py":89 - * v[i] = item - * else: - * i += 1 # convert index to length # <<<<<<<<<<<<<< - * if i == length: - * return 0 - */ - __pyx_v_i = (__pyx_v_i + 1); - - /* "carray.from_py":90 - * else: - * i += 1 # convert index to length - * if i == length: # <<<<<<<<<<<<<< - * return 0 - * - */ - __pyx_t_6 = ((__pyx_v_i == __pyx_v_length) != 0); - if (__pyx_t_6) { - - /* "carray.from_py":91 - * i += 1 # convert index to length - * if i == length: - * return 0 # <<<<<<<<<<<<<< - * - * PyErr_Format( - */ - __pyx_r = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - goto __pyx_L0; - - /* "carray.from_py":90 - * else: - * i += 1 # convert index to length - * if i == length: # <<<<<<<<<<<<<< - * return 0 - * - */ - } - } - - /* "carray.from_py":84 - * pass - * if i == length: - * for i, item in enumerate(o): # <<<<<<<<<<<<<< - * if i >= length: - * break - */ - __pyx_L11_break:; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - - /* "carray.from_py":83 - * except (TypeError, OverflowError): - * pass - * if i == length: # <<<<<<<<<<<<<< - * for i, item in enumerate(o): - * if i >= length: - */ - } - - /* "carray.from_py":96 - * IndexError, - * ("too many values found during array assignment, expected %zd" - * if i >= length else # <<<<<<<<<<<<<< - * "not enough values found during array assignment, expected %zd, got %zd"), - * length, i) - */ - if (((__pyx_v_i >= __pyx_v_length) != 0)) { - __pyx_t_12 = ((char const *)"too many values found during array assignment, expected %zd"); - } else { - __pyx_t_12 = ((char const *)"not enough values found during array assignment, expected %zd, got %zd"); - } - - /* "carray.from_py":93 - * return 0 - * - * PyErr_Format( # <<<<<<<<<<<<<< - * IndexError, - * ("too many values found during array assignment, expected %zd" - */ - __pyx_t_7 = PyErr_Format(__pyx_builtin_IndexError, __pyx_t_12, __pyx_v_length, __pyx_v_i); if (unlikely(!__pyx_t_7)) __PYX_ERR(1, 93, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - - /* "carray.from_py":77 - * - * @cname("__Pyx_carray_from_py_uint8_t") - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: # <<<<<<<<<<<<<< - * cdef Py_ssize_t i = length - * try: - */ - - /* function exit code */ - __pyx_r = 0; - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_AddTraceback("carray.from_py.__Pyx_carray_from_py_uint8_t", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = -1; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_item); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} -static struct __pyx_vtabstruct_4yarl_10_quoting_c__Quoter __pyx_vtable_4yarl_10_quoting_c__Quoter; - -static PyObject *__pyx_tp_new_4yarl_10_quoting_c__Quoter(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { - struct __pyx_obj_4yarl_10_quoting_c__Quoter *p; - PyObject *o; - if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { - o = (*t->tp_alloc)(t, 0); - } else { - o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); - } - if (unlikely(!o)) return 0; - p = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)o); - p->__pyx_vtab = __pyx_vtabptr_4yarl_10_quoting_c__Quoter; - return o; -} - -static void __pyx_tp_dealloc_4yarl_10_quoting_c__Quoter(PyObject *o) { - #if CYTHON_USE_TP_FINALIZE - if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && (!PyType_IS_GC(Py_TYPE(o)) || !_PyGC_FINALIZED(o))) { - if (PyObject_CallFinalizerFromDealloc(o)) return; - } - #endif - (*Py_TYPE(o)->tp_free)(o); -} - -static PyMethodDef __pyx_methods_4yarl_10_quoting_c__Quoter[] = { - {"__reduce_cython__", (PyCFunction)__pyx_pw_4yarl_10_quoting_c_7_Quoter_5__reduce_cython__, METH_NOARGS, 0}, - {"__setstate_cython__", (PyCFunction)__pyx_pw_4yarl_10_quoting_c_7_Quoter_7__setstate_cython__, METH_O, 0}, - {0, 0, 0, 0} -}; - -static PyTypeObject __pyx_type_4yarl_10_quoting_c__Quoter = { - PyVarObject_HEAD_INIT(0, 0) - "yarl._quoting_c._Quoter", /*tp_name*/ - sizeof(struct __pyx_obj_4yarl_10_quoting_c__Quoter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4yarl_10_quoting_c__Quoter, /*tp_dealloc*/ - #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ - #endif - #if PY_VERSION_HEX >= 0x030800b4 - 0, /*tp_vectorcall_offset*/ - #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 - 0, /*tp_compare*/ - #endif - #if PY_MAJOR_VERSION >= 3 - 0, /*tp_as_async*/ - #endif - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - __pyx_pw_4yarl_10_quoting_c_7_Quoter_3__call__, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_4yarl_10_quoting_c__Quoter, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - __pyx_pw_4yarl_10_quoting_c_7_Quoter_1__init__, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_4yarl_10_quoting_c__Quoter, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0, /*tp_del*/ - 0, /*tp_version_tag*/ - #if PY_VERSION_HEX >= 0x030400a1 - 0, /*tp_finalize*/ - #endif - #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) - 0, /*tp_vectorcall*/ - #endif - #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 - 0, /*tp_print*/ - #endif - #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 - 0, /*tp_pypy_flags*/ - #endif -}; -static struct __pyx_vtabstruct_4yarl_10_quoting_c__Unquoter __pyx_vtable_4yarl_10_quoting_c__Unquoter; - -static PyObject *__pyx_tp_new_4yarl_10_quoting_c__Unquoter(PyTypeObject *t, CYTHON_UNUSED PyObject *a, CYTHON_UNUSED PyObject *k) { - struct __pyx_obj_4yarl_10_quoting_c__Unquoter *p; - PyObject *o; - if (likely((t->tp_flags & Py_TPFLAGS_IS_ABSTRACT) == 0)) { - o = (*t->tp_alloc)(t, 0); - } else { - o = (PyObject *) PyBaseObject_Type.tp_new(t, __pyx_empty_tuple, 0); - } - if (unlikely(!o)) return 0; - p = ((struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)o); - p->__pyx_vtab = __pyx_vtabptr_4yarl_10_quoting_c__Unquoter; - p->_unsafe = ((PyObject*)Py_None); Py_INCREF(Py_None); - p->_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)Py_None); Py_INCREF(Py_None); - p->_qs_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)Py_None); Py_INCREF(Py_None); - return o; -} - -static void __pyx_tp_dealloc_4yarl_10_quoting_c__Unquoter(PyObject *o) { - struct __pyx_obj_4yarl_10_quoting_c__Unquoter *p = (struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)o; - #if CYTHON_USE_TP_FINALIZE - if (unlikely(PyType_HasFeature(Py_TYPE(o), Py_TPFLAGS_HAVE_FINALIZE) && Py_TYPE(o)->tp_finalize) && !_PyGC_FINALIZED(o)) { - if (PyObject_CallFinalizerFromDealloc(o)) return; - } - #endif - PyObject_GC_UnTrack(o); - Py_CLEAR(p->_unsafe); - Py_CLEAR(p->_quoter); - Py_CLEAR(p->_qs_quoter); - (*Py_TYPE(o)->tp_free)(o); -} - -static int __pyx_tp_traverse_4yarl_10_quoting_c__Unquoter(PyObject *o, visitproc v, void *a) { - int e; - struct __pyx_obj_4yarl_10_quoting_c__Unquoter *p = (struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)o; - if (p->_quoter) { - e = (*v)(((PyObject *)p->_quoter), a); if (e) return e; - } - if (p->_qs_quoter) { - e = (*v)(((PyObject *)p->_qs_quoter), a); if (e) return e; - } - return 0; -} - -static int __pyx_tp_clear_4yarl_10_quoting_c__Unquoter(PyObject *o) { - PyObject* tmp; - struct __pyx_obj_4yarl_10_quoting_c__Unquoter *p = (struct __pyx_obj_4yarl_10_quoting_c__Unquoter *)o; - tmp = ((PyObject*)p->_quoter); - p->_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - tmp = ((PyObject*)p->_qs_quoter); - p->_qs_quoter = ((struct __pyx_obj_4yarl_10_quoting_c__Quoter *)Py_None); Py_INCREF(Py_None); - Py_XDECREF(tmp); - return 0; -} - -static PyMethodDef __pyx_methods_4yarl_10_quoting_c__Unquoter[] = { - {"__reduce_cython__", (PyCFunction)__pyx_pw_4yarl_10_quoting_c_9_Unquoter_5__reduce_cython__, METH_NOARGS, 0}, - {"__setstate_cython__", (PyCFunction)__pyx_pw_4yarl_10_quoting_c_9_Unquoter_7__setstate_cython__, METH_O, 0}, - {0, 0, 0, 0} -}; - -static PyTypeObject __pyx_type_4yarl_10_quoting_c__Unquoter = { - PyVarObject_HEAD_INIT(0, 0) - "yarl._quoting_c._Unquoter", /*tp_name*/ - sizeof(struct __pyx_obj_4yarl_10_quoting_c__Unquoter), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - __pyx_tp_dealloc_4yarl_10_quoting_c__Unquoter, /*tp_dealloc*/ - #if PY_VERSION_HEX < 0x030800b4 - 0, /*tp_print*/ - #endif - #if PY_VERSION_HEX >= 0x030800b4 - 0, /*tp_vectorcall_offset*/ - #endif - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - #if PY_MAJOR_VERSION < 3 - 0, /*tp_compare*/ - #endif - #if PY_MAJOR_VERSION >= 3 - 0, /*tp_as_async*/ - #endif - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - __pyx_pw_4yarl_10_quoting_c_9_Unquoter_3__call__, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_VERSION_TAG|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - 0, /*tp_doc*/ - __pyx_tp_traverse_4yarl_10_quoting_c__Unquoter, /*tp_traverse*/ - __pyx_tp_clear_4yarl_10_quoting_c__Unquoter, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - __pyx_methods_4yarl_10_quoting_c__Unquoter, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - __pyx_pw_4yarl_10_quoting_c_9_Unquoter_1__init__, /*tp_init*/ - 0, /*tp_alloc*/ - __pyx_tp_new_4yarl_10_quoting_c__Unquoter, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ - 0, /*tp_bases*/ - 0, /*tp_mro*/ - 0, /*tp_cache*/ - 0, /*tp_subclasses*/ - 0, /*tp_weaklist*/ - 0, /*tp_del*/ - 0, /*tp_version_tag*/ - #if PY_VERSION_HEX >= 0x030400a1 - 0, /*tp_finalize*/ - #endif - #if PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800) - 0, /*tp_vectorcall*/ - #endif - #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 - 0, /*tp_print*/ - #endif - #if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 - 0, /*tp_pypy_flags*/ - #endif -}; - -static PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; - -#if PY_MAJOR_VERSION >= 3 -#if CYTHON_PEP489_MULTI_PHASE_INIT -static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ -static int __pyx_pymod_exec__quoting_c(PyObject* module); /*proto*/ -static PyModuleDef_Slot __pyx_moduledef_slots[] = { - {Py_mod_create, (void*)__pyx_pymod_create}, - {Py_mod_exec, (void*)__pyx_pymod_exec__quoting_c}, - {0, NULL} -}; -#endif - -static struct PyModuleDef __pyx_moduledef = { - PyModuleDef_HEAD_INIT, - "_quoting_c", - 0, /* m_doc */ - #if CYTHON_PEP489_MULTI_PHASE_INIT - 0, /* m_size */ - #else - -1, /* m_size */ - #endif - __pyx_methods /* m_methods */, - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_moduledef_slots, /* m_slots */ - #else - NULL, /* m_reload */ - #endif - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ -}; -#endif -#ifndef CYTHON_SMALL_CODE -#if defined(__clang__) - #define CYTHON_SMALL_CODE -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define CYTHON_SMALL_CODE __attribute__((cold)) -#else - #define CYTHON_SMALL_CODE -#endif -#endif - -static __Pyx_StringTabEntry __pyx_string_tab[] = { - {&__pyx_kp_u_, __pyx_k_, sizeof(__pyx_k_), 0, 1, 0, 0}, - {&__pyx_kp_u_Argument_should_be_str, __pyx_k_Argument_should_be_str, sizeof(__pyx_k_Argument_should_be_str), 0, 1, 0, 0}, - {&__pyx_kp_s_Incompatible_checksums_0x_x_vs_0, __pyx_k_Incompatible_checksums_0x_x_vs_0, sizeof(__pyx_k_Incompatible_checksums_0x_x_vs_0), 0, 0, 1, 0}, - {&__pyx_kp_s_Incompatible_checksums_0x_x_vs_0_2, __pyx_k_Incompatible_checksums_0x_x_vs_0_2, sizeof(__pyx_k_Incompatible_checksums_0x_x_vs_0_2), 0, 0, 1, 0}, - {&__pyx_n_s_IndexError, __pyx_k_IndexError, sizeof(__pyx_k_IndexError), 0, 0, 1, 1}, - {&__pyx_kp_u_Only_safe_symbols_with_ORD_128_a, __pyx_k_Only_safe_symbols_with_ORD_128_a, sizeof(__pyx_k_Only_safe_symbols_with_ORD_128_a), 0, 1, 0, 0}, - {&__pyx_n_s_OverflowError, __pyx_k_OverflowError, sizeof(__pyx_k_OverflowError), 0, 0, 1, 1}, - {&__pyx_n_s_PickleError, __pyx_k_PickleError, sizeof(__pyx_k_PickleError), 0, 0, 1, 1}, - {&__pyx_n_s_Quoter, __pyx_k_Quoter, sizeof(__pyx_k_Quoter), 0, 0, 1, 1}, - {&__pyx_n_s_TypeError, __pyx_k_TypeError, sizeof(__pyx_k_TypeError), 0, 0, 1, 1}, - {&__pyx_n_s_UnicodeDecodeError, __pyx_k_UnicodeDecodeError, sizeof(__pyx_k_UnicodeDecodeError), 0, 0, 1, 1}, - {&__pyx_n_s_Unquoter, __pyx_k_Unquoter, sizeof(__pyx_k_Unquoter), 0, 0, 1, 1}, - {&__pyx_n_s_ValueError, __pyx_k_ValueError, sizeof(__pyx_k_ValueError), 0, 0, 1, 1}, - {&__pyx_kp_u__11, __pyx_k__11, sizeof(__pyx_k__11), 0, 1, 0, 0}, - {&__pyx_kp_u__12, __pyx_k__12, sizeof(__pyx_k__12), 0, 1, 0, 0}, - {&__pyx_kp_u__13, __pyx_k__13, sizeof(__pyx_k__13), 0, 1, 0, 0}, - {&__pyx_kp_u__14, __pyx_k__14, sizeof(__pyx_k__14), 0, 1, 0, 0}, - {&__pyx_kp_u__15, __pyx_k__15, sizeof(__pyx_k__15), 0, 1, 0, 0}, - {&__pyx_kp_u__4, __pyx_k__4, sizeof(__pyx_k__4), 0, 1, 0, 0}, - {&__pyx_kp_u__5, __pyx_k__5, sizeof(__pyx_k__5), 0, 1, 0, 0}, - {&__pyx_kp_u__6, __pyx_k__6, sizeof(__pyx_k__6), 0, 1, 0, 0}, - {&__pyx_kp_u__7, __pyx_k__7, sizeof(__pyx_k__7), 0, 1, 0, 0}, - {&__pyx_n_s_ascii_letters, __pyx_k_ascii_letters, sizeof(__pyx_k_ascii_letters), 0, 0, 1, 1}, - {&__pyx_n_s_chr, __pyx_k_chr, sizeof(__pyx_k_chr), 0, 0, 1, 1}, - {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1}, - {&__pyx_n_s_dict, __pyx_k_dict, sizeof(__pyx_k_dict), 0, 0, 1, 1}, - {&__pyx_n_s_digits, __pyx_k_digits, sizeof(__pyx_k_digits), 0, 0, 1, 1}, - {&__pyx_n_s_enumerate, __pyx_k_enumerate, sizeof(__pyx_k_enumerate), 0, 0, 1, 1}, - {&__pyx_n_s_getstate, __pyx_k_getstate, sizeof(__pyx_k_getstate), 0, 0, 1, 1}, - {&__pyx_n_s_hex, __pyx_k_hex, sizeof(__pyx_k_hex), 0, 0, 1, 1}, - {&__pyx_n_s_i, __pyx_k_i, sizeof(__pyx_k_i), 0, 0, 1, 1}, - {&__pyx_n_s_import, __pyx_k_import, sizeof(__pyx_k_import), 0, 0, 1, 1}, - {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, - {&__pyx_n_s_name, __pyx_k_name, sizeof(__pyx_k_name), 0, 0, 1, 1}, - {&__pyx_n_s_new, __pyx_k_new, sizeof(__pyx_k_new), 0, 0, 1, 1}, - {&__pyx_n_s_pickle, __pyx_k_pickle, sizeof(__pyx_k_pickle), 0, 0, 1, 1}, - {&__pyx_n_s_protected, __pyx_k_protected, sizeof(__pyx_k_protected), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_PickleError, __pyx_k_pyx_PickleError, sizeof(__pyx_k_pyx_PickleError), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_checksum, __pyx_k_pyx_checksum, sizeof(__pyx_k_pyx_checksum), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_result, __pyx_k_pyx_result, sizeof(__pyx_k_pyx_result), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_state, __pyx_k_pyx_state, sizeof(__pyx_k_pyx_state), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_type, __pyx_k_pyx_type, sizeof(__pyx_k_pyx_type), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_unpickle__Quoter, __pyx_k_pyx_unpickle__Quoter, sizeof(__pyx_k_pyx_unpickle__Quoter), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_unpickle__Unquoter, __pyx_k_pyx_unpickle__Unquoter, sizeof(__pyx_k_pyx_unpickle__Unquoter), 0, 0, 1, 1}, - {&__pyx_n_s_pyx_vtable, __pyx_k_pyx_vtable, sizeof(__pyx_k_pyx_vtable), 0, 0, 1, 1}, - {&__pyx_n_s_qs, __pyx_k_qs, sizeof(__pyx_k_qs), 0, 0, 1, 1}, - {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, - {&__pyx_n_s_reduce, __pyx_k_reduce, sizeof(__pyx_k_reduce), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_cython, __pyx_k_reduce_cython, sizeof(__pyx_k_reduce_cython), 0, 0, 1, 1}, - {&__pyx_n_s_reduce_ex, __pyx_k_reduce_ex, sizeof(__pyx_k_reduce_ex), 0, 0, 1, 1}, - {&__pyx_n_s_requote, __pyx_k_requote, sizeof(__pyx_k_requote), 0, 0, 1, 1}, - {&__pyx_n_s_safe, __pyx_k_safe, sizeof(__pyx_k_safe), 0, 0, 1, 1}, - {&__pyx_n_s_setstate, __pyx_k_setstate, sizeof(__pyx_k_setstate), 0, 0, 1, 1}, - {&__pyx_n_s_setstate_cython, __pyx_k_setstate_cython, sizeof(__pyx_k_setstate_cython), 0, 0, 1, 1}, - {&__pyx_n_s_string, __pyx_k_string, sizeof(__pyx_k_string), 0, 0, 1, 1}, - {&__pyx_kp_s_stringsource, __pyx_k_stringsource, sizeof(__pyx_k_stringsource), 0, 0, 1, 0}, - {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, - {&__pyx_n_s_unsafe, __pyx_k_unsafe, sizeof(__pyx_k_unsafe), 0, 0, 1, 1}, - {&__pyx_n_s_update, __pyx_k_update, sizeof(__pyx_k_update), 0, 0, 1, 1}, - {&__pyx_n_s_upper, __pyx_k_upper, sizeof(__pyx_k_upper), 0, 0, 1, 1}, - {&__pyx_n_s_val, __pyx_k_val, sizeof(__pyx_k_val), 0, 0, 1, 1}, - {&__pyx_n_s_yarl__quoting_c, __pyx_k_yarl__quoting_c, sizeof(__pyx_k_yarl__quoting_c), 0, 0, 1, 1}, - {0, 0, 0, 0, 0, 0, 0} -}; -static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 70, __pyx_L1_error) - __pyx_builtin_chr = __Pyx_GetBuiltinName(__pyx_n_s_chr); if (!__pyx_builtin_chr) __PYX_ERR(0, 71, __pyx_L1_error) - __pyx_builtin_ValueError = __Pyx_GetBuiltinName(__pyx_n_s_ValueError); if (!__pyx_builtin_ValueError) __PYX_ERR(0, 194, __pyx_L1_error) - __pyx_builtin_TypeError = __Pyx_GetBuiltinName(__pyx_n_s_TypeError); if (!__pyx_builtin_TypeError) __PYX_ERR(0, 213, __pyx_L1_error) - __pyx_builtin_UnicodeDecodeError = __Pyx_GetBuiltinName(__pyx_n_s_UnicodeDecodeError); if (!__pyx_builtin_UnicodeDecodeError) __PYX_ERR(0, 320, __pyx_L1_error) - __pyx_builtin_hex = __Pyx_GetBuiltinName(__pyx_n_s_hex); if (!__pyx_builtin_hex) __PYX_ERR(0, 361, __pyx_L1_error) - __pyx_builtin_OverflowError = __Pyx_GetBuiltinName(__pyx_n_s_OverflowError); if (!__pyx_builtin_OverflowError) __PYX_ERR(1, 81, __pyx_L1_error) - __pyx_builtin_enumerate = __Pyx_GetBuiltinName(__pyx_n_s_enumerate); if (!__pyx_builtin_enumerate) __PYX_ERR(1, 84, __pyx_L1_error) - __pyx_builtin_IndexError = __Pyx_GetBuiltinName(__pyx_n_s_IndexError); if (!__pyx_builtin_IndexError) __PYX_ERR(1, 94, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -} - -static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - - /* "yarl/_quoting_c.pyx":194 - * for ch in safe: - * if ord(ch) > 127: - * raise ValueError("Only safe symbols with ORD < 128 are allowed") # <<<<<<<<<<<<<< - * set_bit(self._safe_table, ch) - * - */ - __pyx_tuple__2 = PyTuple_Pack(1, __pyx_kp_u_Only_safe_symbols_with_ORD_128_a); if (unlikely(!__pyx_tuple__2)) __PYX_ERR(0, 194, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__2); - __Pyx_GIVEREF(__pyx_tuple__2); - - /* "yarl/_quoting_c.pyx":213 - * val = str(val) - * else: - * raise TypeError("Argument should be str") # <<<<<<<<<<<<<< - * _init_writer(&writer) - * try: - */ - __pyx_tuple__3 = PyTuple_Pack(1, __pyx_kp_u_Argument_should_be_str); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 213, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__3); - __Pyx_GIVEREF(__pyx_tuple__3); - - /* "yarl/_quoting_c.pyx":361 - * if ch in self._unsafe: - * ret.append('%') - * h = hex(ord(ch)).upper()[2:] # <<<<<<<<<<<<<< - * for ch in h: - * ret.append(ch) - */ - __pyx_slice__8 = PySlice_New(__pyx_int_2, Py_None, Py_None); if (unlikely(!__pyx_slice__8)) __PYX_ERR(0, 361, __pyx_L1_error) - __Pyx_GOTREF(__pyx_slice__8); - __Pyx_GIVEREF(__pyx_slice__8); - - /* "(tree fragment)":4 - * cdef object __pyx_PickleError - * cdef object __pyx_result - * if __pyx_checksum not in (0xe91bd35, 0x60b2b56, 0x7e82961): # <<<<<<<<<<<<<< - * from pickle import PickleError as __pyx_PickleError - * raise __pyx_PickleError("Incompatible checksums (0x%x vs (0xe91bd35, 0x60b2b56, 0x7e82961) = (_protected_table, _qs, _requote, _safe_table))" % __pyx_checksum) - */ - __pyx_tuple__9 = PyTuple_Pack(3, __pyx_int_244432181, __pyx_int_101395286, __pyx_int_132655457); if (unlikely(!__pyx_tuple__9)) __PYX_ERR(1, 4, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__9); - __Pyx_GIVEREF(__pyx_tuple__9); - __pyx_tuple__10 = PyTuple_Pack(3, __pyx_int_41310077, __pyx_int_81650385, __pyx_int_87395286); if (unlikely(!__pyx_tuple__10)) __PYX_ERR(1, 4, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__10); - __Pyx_GIVEREF(__pyx_tuple__10); - - /* "(tree fragment)":1 - * def __pyx_unpickle__Quoter(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ - __pyx_tuple__16 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__16)) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__16); - __Pyx_GIVEREF(__pyx_tuple__16); - __pyx_codeobj__17 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__16, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle__Quoter, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__17)) __PYX_ERR(1, 1, __pyx_L1_error) - __pyx_tuple__18 = PyTuple_Pack(5, __pyx_n_s_pyx_type, __pyx_n_s_pyx_checksum, __pyx_n_s_pyx_state, __pyx_n_s_pyx_PickleError, __pyx_n_s_pyx_result); if (unlikely(!__pyx_tuple__18)) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_tuple__18); - __Pyx_GIVEREF(__pyx_tuple__18); - __pyx_codeobj__19 = (PyObject*)__Pyx_PyCode_New(3, 0, 5, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__18, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_stringsource, __pyx_n_s_pyx_unpickle__Unquoter, 1, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__19)) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; - __Pyx_RefNannyFinishContext(); - return -1; -} - -static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void) { - if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error); - __pyx_int_2 = PyInt_FromLong(2); if (unlikely(!__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_int_41310077 = PyInt_FromLong(41310077L); if (unlikely(!__pyx_int_41310077)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_int_81650385 = PyInt_FromLong(81650385L); if (unlikely(!__pyx_int_81650385)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_int_87395286 = PyInt_FromLong(87395286L); if (unlikely(!__pyx_int_87395286)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_int_101395286 = PyInt_FromLong(101395286L); if (unlikely(!__pyx_int_101395286)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_int_132655457 = PyInt_FromLong(132655457L); if (unlikely(!__pyx_int_132655457)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_int_244432181 = PyInt_FromLong(244432181L); if (unlikely(!__pyx_int_244432181)) __PYX_ERR(0, 1, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -} - -static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(void); /*proto*/ - -static int __Pyx_modinit_global_init_code(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); - /*--- Global init code ---*/ - __pyx_v_4yarl_10_quoting_c_GEN_DELIMS = ((PyObject*)Py_None); Py_INCREF(Py_None); - __pyx_v_4yarl_10_quoting_c_SUB_DELIMS_WITHOUT_QS = ((PyObject*)Py_None); Py_INCREF(Py_None); - __pyx_v_4yarl_10_quoting_c_SUB_DELIMS = ((PyObject*)Py_None); Py_INCREF(Py_None); - __pyx_v_4yarl_10_quoting_c_RESERVED = ((PyObject*)Py_None); Py_INCREF(Py_None); - __pyx_v_4yarl_10_quoting_c_UNRESERVED = ((PyObject*)Py_None); Py_INCREF(Py_None); - __pyx_v_4yarl_10_quoting_c_ALLOWED = ((PyObject*)Py_None); Py_INCREF(Py_None); - __pyx_v_4yarl_10_quoting_c_QS = ((PyObject*)Py_None); Py_INCREF(Py_None); - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_export_code(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); - /*--- Variable export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_export_code(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_init_code(void) { - __Pyx_RefNannyDeclarations - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __pyx_vtabptr_4yarl_10_quoting_c__Quoter = &__pyx_vtable_4yarl_10_quoting_c__Quoter; - __pyx_vtable_4yarl_10_quoting_c__Quoter._do_quote = (PyObject *(*)(struct __pyx_obj_4yarl_10_quoting_c__Quoter *, PyObject *, struct __pyx_t_4yarl_10_quoting_c_Writer *))__pyx_f_4yarl_10_quoting_c_7_Quoter__do_quote; - __pyx_vtable_4yarl_10_quoting_c__Quoter._write = (int (*)(struct __pyx_obj_4yarl_10_quoting_c__Quoter *, struct __pyx_t_4yarl_10_quoting_c_Writer *, Py_UCS4))__pyx_f_4yarl_10_quoting_c_7_Quoter__write; - if (PyType_Ready(&__pyx_type_4yarl_10_quoting_c__Quoter) < 0) __PYX_ERR(0, 169, __pyx_L1_error) - #if PY_VERSION_HEX < 0x030800B1 - __pyx_type_4yarl_10_quoting_c__Quoter.tp_print = 0; - #endif - if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_4yarl_10_quoting_c__Quoter.tp_dictoffset && __pyx_type_4yarl_10_quoting_c__Quoter.tp_getattro == PyObject_GenericGetAttr)) { - __pyx_type_4yarl_10_quoting_c__Quoter.tp_getattro = __Pyx_PyObject_GenericGetAttr; - } - if (__Pyx_SetVtable(__pyx_type_4yarl_10_quoting_c__Quoter.tp_dict, __pyx_vtabptr_4yarl_10_quoting_c__Quoter) < 0) __PYX_ERR(0, 169, __pyx_L1_error) - if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Quoter, (PyObject *)&__pyx_type_4yarl_10_quoting_c__Quoter) < 0) __PYX_ERR(0, 169, __pyx_L1_error) - if (__Pyx_setup_reduce((PyObject*)&__pyx_type_4yarl_10_quoting_c__Quoter) < 0) __PYX_ERR(0, 169, __pyx_L1_error) - __pyx_ptype_4yarl_10_quoting_c__Quoter = &__pyx_type_4yarl_10_quoting_c__Quoter; - __pyx_vtabptr_4yarl_10_quoting_c__Unquoter = &__pyx_vtable_4yarl_10_quoting_c__Unquoter; - __pyx_vtable_4yarl_10_quoting_c__Unquoter._do_unquote = (PyObject *(*)(struct __pyx_obj_4yarl_10_quoting_c__Unquoter *, PyObject *))__pyx_f_4yarl_10_quoting_c_9_Unquoter__do_unquote; - if (PyType_Ready(&__pyx_type_4yarl_10_quoting_c__Unquoter) < 0) __PYX_ERR(0, 271, __pyx_L1_error) - #if PY_VERSION_HEX < 0x030800B1 - __pyx_type_4yarl_10_quoting_c__Unquoter.tp_print = 0; - #endif - if ((CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP) && likely(!__pyx_type_4yarl_10_quoting_c__Unquoter.tp_dictoffset && __pyx_type_4yarl_10_quoting_c__Unquoter.tp_getattro == PyObject_GenericGetAttr)) { - __pyx_type_4yarl_10_quoting_c__Unquoter.tp_getattro = __Pyx_PyObject_GenericGetAttr; - } - if (__Pyx_SetVtable(__pyx_type_4yarl_10_quoting_c__Unquoter.tp_dict, __pyx_vtabptr_4yarl_10_quoting_c__Unquoter) < 0) __PYX_ERR(0, 271, __pyx_L1_error) - if (PyObject_SetAttr(__pyx_m, __pyx_n_s_Unquoter, (PyObject *)&__pyx_type_4yarl_10_quoting_c__Unquoter) < 0) __PYX_ERR(0, 271, __pyx_L1_error) - if (__Pyx_setup_reduce((PyObject*)&__pyx_type_4yarl_10_quoting_c__Unquoter) < 0) __PYX_ERR(0, 271, __pyx_L1_error) - __pyx_ptype_4yarl_10_quoting_c__Unquoter = &__pyx_type_4yarl_10_quoting_c__Unquoter; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; - __Pyx_RefNannyFinishContext(); - return -1; -} - -static int __Pyx_modinit_type_import_code(void) { - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __pyx_t_1 = PyImport_ImportModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_t_1)) __PYX_ERR(2, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_ptype_7cpython_4type_type = __Pyx_ImportType(__pyx_t_1, __Pyx_BUILTIN_MODULE_NAME, "type", - #if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x050B0000 - sizeof(PyTypeObject), - #else - sizeof(PyHeapTypeObject), - #endif - __Pyx_ImportType_CheckSize_Warn); - if (!__pyx_ptype_7cpython_4type_type) __PYX_ERR(2, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_RefNannyFinishContext(); - return -1; -} - -static int __Pyx_modinit_variable_import_code(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); - /*--- Variable import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_import_code(void) { - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - - -#ifndef CYTHON_NO_PYINIT_EXPORT -#define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -#elif PY_MAJOR_VERSION < 3 -#ifdef __cplusplus -#define __Pyx_PyMODINIT_FUNC extern "C" void -#else -#define __Pyx_PyMODINIT_FUNC void -#endif -#else -#ifdef __cplusplus -#define __Pyx_PyMODINIT_FUNC extern "C" PyObject * -#else -#define __Pyx_PyMODINIT_FUNC PyObject * -#endif -#endif - - -#if PY_MAJOR_VERSION < 3 -__Pyx_PyMODINIT_FUNC init_quoting_c(void) CYTHON_SMALL_CODE; /*proto*/ -__Pyx_PyMODINIT_FUNC init_quoting_c(void) -#else -__Pyx_PyMODINIT_FUNC PyInit__quoting_c(void) CYTHON_SMALL_CODE; /*proto*/ -__Pyx_PyMODINIT_FUNC PyInit__quoting_c(void) -#if CYTHON_PEP489_MULTI_PHASE_INIT -{ - return PyModuleDef_Init(&__pyx_moduledef); -} -static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { - #if PY_VERSION_HEX >= 0x030700A1 - static PY_INT64_T main_interpreter_id = -1; - PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); - if (main_interpreter_id == -1) { - main_interpreter_id = current_id; - return (unlikely(current_id == -1)) ? -1 : 0; - } else if (unlikely(main_interpreter_id != current_id)) - #else - static PyInterpreterState *main_interpreter = NULL; - PyInterpreterState *current_interpreter = PyThreadState_Get()->interp; - if (!main_interpreter) { - main_interpreter = current_interpreter; - } else if (unlikely(main_interpreter != current_interpreter)) - #endif - { - PyErr_SetString( - PyExc_ImportError, - "Interpreter change detected - this module can only be loaded into one interpreter per process."); - return -1; - } - return 0; -} -static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) { - PyObject *value = PyObject_GetAttrString(spec, from_name); - int result = 0; - if (likely(value)) { - if (allow_none || value != Py_None) { - result = PyDict_SetItemString(moddict, to_name, value); - } - Py_DECREF(value); - } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } else { - result = -1; - } - return result; -} -static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, CYTHON_UNUSED PyModuleDef *def) { - PyObject *module = NULL, *moddict, *modname; - if (__Pyx_check_single_interpreter()) - return NULL; - if (__pyx_m) - return __Pyx_NewRef(__pyx_m); - modname = PyObject_GetAttrString(spec, "name"); - if (unlikely(!modname)) goto bad; - module = PyModule_NewObject(modname); - Py_DECREF(modname); - if (unlikely(!module)) goto bad; - moddict = PyModule_GetDict(module); - if (unlikely(!moddict)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; - return module; -bad: - Py_XDECREF(module); - return NULL; -} - - -static CYTHON_SMALL_CODE int __pyx_pymod_exec__quoting_c(PyObject *__pyx_pyinit_module) -#endif -#endif -{ - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - long __pyx_t_4; - int __pyx_t_5; - int __pyx_t_6; - uint64_t __pyx_t_7; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { - if (__pyx_m == __pyx_pyinit_module) return 0; - PyErr_SetString(PyExc_RuntimeError, "Module '_quoting_c' has already been imported. Re-initialisation is not supported."); - return -1; - } - #elif PY_MAJOR_VERSION >= 3 - if (__pyx_m) return __Pyx_NewRef(__pyx_m); - #endif - #if CYTHON_REFNANNY -__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); -if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); -} -#endif - __Pyx_RefNannySetupContext("__Pyx_PyMODINIT_FUNC PyInit__quoting_c(void)", 0); - if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pxy_PyFrame_Initialize_Offsets - __Pxy_PyFrame_Initialize_Offsets(); - #endif - __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pyx_CyFunction_USED - if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_FusedFunction_USED - if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Coroutine_USED - if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Generator_USED - if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_AsyncGen_USED - if (__pyx_AsyncGen_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_StopAsyncIteration_USED - if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - /*--- Library function declarations ---*/ - /*--- Threads initialization code ---*/ - #if defined(WITH_THREAD) && PY_VERSION_HEX < 0x030700F0 && defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS - PyEval_InitThreads(); - #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_m = __pyx_pyinit_module; - Py_INCREF(__pyx_m); - #else - #if PY_MAJOR_VERSION < 3 - __pyx_m = Py_InitModule4("_quoting_c", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); - #else - __pyx_m = PyModule_Create(&__pyx_moduledef); - #endif - if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) - Py_INCREF(__pyx_d); - __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) - Py_INCREF(__pyx_b); - __pyx_cython_runtime = PyImport_AddModule((char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) - Py_INCREF(__pyx_cython_runtime); - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error); - /*--- Initialize various global constants etc. ---*/ - if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) - if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - if (__pyx_module_is_main_yarl___quoting_c) { - if (PyObject_SetAttr(__pyx_m, __pyx_n_s_name, __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - } - #if PY_MAJOR_VERSION >= 3 - { - PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) - if (!PyDict_GetItemString(modules, "yarl._quoting_c")) { - if (unlikely(PyDict_SetItemString(modules, "yarl._quoting_c", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error) - } - } - #endif - /*--- Builtin init code ---*/ - if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Constants init code ---*/ - if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(); - (void)__Pyx_modinit_variable_export_code(); - (void)__Pyx_modinit_function_export_code(); - if (unlikely(__Pyx_modinit_type_init_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) - if (unlikely(__Pyx_modinit_type_import_code() < 0)) __PYX_ERR(0, 1, __pyx_L1_error) - (void)__Pyx_modinit_variable_import_code(); - (void)__Pyx_modinit_function_import_code(); - /*--- Execution code ---*/ - #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) - if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - - /* "yarl/_quoting_c.pyx":9 - * from libc.string cimport memcpy, memset - * - * from string import ascii_letters, digits # <<<<<<<<<<<<<< - * - * - */ - __pyx_t_1 = PyList_New(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_n_s_ascii_letters); - __Pyx_GIVEREF(__pyx_n_s_ascii_letters); - PyList_SET_ITEM(__pyx_t_1, 0, __pyx_n_s_ascii_letters); - __Pyx_INCREF(__pyx_n_s_digits); - __Pyx_GIVEREF(__pyx_n_s_digits); - PyList_SET_ITEM(__pyx_t_1, 1, __pyx_n_s_digits); - __pyx_t_2 = __Pyx_Import(__pyx_n_s_string, __pyx_t_1, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_ascii_letters); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_ascii_letters, __pyx_t_1) < 0) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = __Pyx_ImportFrom(__pyx_t_2, __pyx_n_s_digits); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_digits, __pyx_t_1) < 0) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "yarl/_quoting_c.pyx":12 - * - * - * cdef str GEN_DELIMS = ":/?#[]@" # <<<<<<<<<<<<<< - * cdef str SUB_DELIMS_WITHOUT_QS = "!$'()*," - * cdef str SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + '+?=;' - */ - __Pyx_INCREF(__pyx_kp_u__11); - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_GEN_DELIMS); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_GEN_DELIMS, __pyx_kp_u__11); - __Pyx_GIVEREF(__pyx_kp_u__11); - - /* "yarl/_quoting_c.pyx":13 - * - * cdef str GEN_DELIMS = ":/?#[]@" - * cdef str SUB_DELIMS_WITHOUT_QS = "!$'()*," # <<<<<<<<<<<<<< - * cdef str SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + '+?=;' - * cdef str RESERVED = GEN_DELIMS + SUB_DELIMS - */ - __Pyx_INCREF(__pyx_kp_u__12); - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_SUB_DELIMS_WITHOUT_QS); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_SUB_DELIMS_WITHOUT_QS, __pyx_kp_u__12); - __Pyx_GIVEREF(__pyx_kp_u__12); - - /* "yarl/_quoting_c.pyx":14 - * cdef str GEN_DELIMS = ":/?#[]@" - * cdef str SUB_DELIMS_WITHOUT_QS = "!$'()*," - * cdef str SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + '+?=;' # <<<<<<<<<<<<<< - * cdef str RESERVED = GEN_DELIMS + SUB_DELIMS - * cdef str UNRESERVED = ascii_letters + digits + '-._~' - */ - __pyx_t_2 = __Pyx_PyUnicode_ConcatSafe(__pyx_v_4yarl_10_quoting_c_SUB_DELIMS_WITHOUT_QS, __pyx_kp_u__13); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_SUB_DELIMS); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_SUB_DELIMS, ((PyObject*)__pyx_t_2)); - __Pyx_GIVEREF(__pyx_t_2); - __pyx_t_2 = 0; - - /* "yarl/_quoting_c.pyx":15 - * cdef str SUB_DELIMS_WITHOUT_QS = "!$'()*," - * cdef str SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + '+?=;' - * cdef str RESERVED = GEN_DELIMS + SUB_DELIMS # <<<<<<<<<<<<<< - * cdef str UNRESERVED = ascii_letters + digits + '-._~' - * cdef str ALLOWED = UNRESERVED + SUB_DELIMS_WITHOUT_QS - */ - __pyx_t_2 = __Pyx_PyUnicode_ConcatSafe(__pyx_v_4yarl_10_quoting_c_GEN_DELIMS, __pyx_v_4yarl_10_quoting_c_SUB_DELIMS); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_RESERVED); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_RESERVED, ((PyObject*)__pyx_t_2)); - __Pyx_GIVEREF(__pyx_t_2); - __pyx_t_2 = 0; - - /* "yarl/_quoting_c.pyx":16 - * cdef str SUB_DELIMS = SUB_DELIMS_WITHOUT_QS + '+?=;' - * cdef str RESERVED = GEN_DELIMS + SUB_DELIMS - * cdef str UNRESERVED = ascii_letters + digits + '-._~' # <<<<<<<<<<<<<< - * cdef str ALLOWED = UNRESERVED + SUB_DELIMS_WITHOUT_QS - * cdef str QS = '+&=;' - */ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ascii_letters); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_digits); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = PyNumber_Add(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyNumber_Add(__pyx_t_3, __pyx_kp_u__14); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (!(likely(PyUnicode_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None)||(PyErr_Format(PyExc_TypeError, "Expected %.16s, got %.200s", "unicode", Py_TYPE(__pyx_t_1)->tp_name), 0))) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_UNRESERVED); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_UNRESERVED, ((PyObject*)__pyx_t_1)); - __Pyx_GIVEREF(__pyx_t_1); - __pyx_t_1 = 0; - - /* "yarl/_quoting_c.pyx":17 - * cdef str RESERVED = GEN_DELIMS + SUB_DELIMS - * cdef str UNRESERVED = ascii_letters + digits + '-._~' - * cdef str ALLOWED = UNRESERVED + SUB_DELIMS_WITHOUT_QS # <<<<<<<<<<<<<< - * cdef str QS = '+&=;' - * - */ - __pyx_t_1 = __Pyx_PyUnicode_ConcatSafe(__pyx_v_4yarl_10_quoting_c_UNRESERVED, __pyx_v_4yarl_10_quoting_c_SUB_DELIMS_WITHOUT_QS); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 17, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_ALLOWED); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_ALLOWED, ((PyObject*)__pyx_t_1)); - __Pyx_GIVEREF(__pyx_t_1); - __pyx_t_1 = 0; - - /* "yarl/_quoting_c.pyx":18 - * cdef str UNRESERVED = ascii_letters + digits + '-._~' - * cdef str ALLOWED = UNRESERVED + SUB_DELIMS_WITHOUT_QS - * cdef str QS = '+&=;' # <<<<<<<<<<<<<< - * - * DEF BUF_SIZE = 8 * 1024 # 8KiB - */ - __Pyx_INCREF(__pyx_kp_u__15); - __Pyx_XGOTREF(__pyx_v_4yarl_10_quoting_c_QS); - __Pyx_DECREF_SET(__pyx_v_4yarl_10_quoting_c_QS, __pyx_kp_u__15); - __Pyx_GIVEREF(__pyx_kp_u__15); - - /* "yarl/_quoting_c.pyx":67 - * - * - * memset(ALLOWED_TABLE, 0, sizeof(ALLOWED_TABLE)) # <<<<<<<<<<<<<< - * memset(ALLOWED_NOTQS_TABLE, 0, sizeof(ALLOWED_NOTQS_TABLE)) - * - */ - (void)(memset(__pyx_v_4yarl_10_quoting_c_ALLOWED_TABLE, 0, (sizeof(__pyx_v_4yarl_10_quoting_c_ALLOWED_TABLE)))); - - /* "yarl/_quoting_c.pyx":68 - * - * memset(ALLOWED_TABLE, 0, sizeof(ALLOWED_TABLE)) - * memset(ALLOWED_NOTQS_TABLE, 0, sizeof(ALLOWED_NOTQS_TABLE)) # <<<<<<<<<<<<<< - * - * for i in range(128): - */ - (void)(memset(__pyx_v_4yarl_10_quoting_c_ALLOWED_NOTQS_TABLE, 0, (sizeof(__pyx_v_4yarl_10_quoting_c_ALLOWED_NOTQS_TABLE)))); - - /* "yarl/_quoting_c.pyx":70 - * memset(ALLOWED_NOTQS_TABLE, 0, sizeof(ALLOWED_NOTQS_TABLE)) - * - * for i in range(128): # <<<<<<<<<<<<<< - * if chr(i) in ALLOWED: - * set_bit(ALLOWED_TABLE, i) - */ - for (__pyx_t_4 = 0; __pyx_t_4 < 0x80; __pyx_t_4+=1) { - __pyx_t_1 = __Pyx_PyInt_From_long(__pyx_t_4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 70, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_i, __pyx_t_1) < 0) __PYX_ERR(0, 70, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "yarl/_quoting_c.pyx":71 - * - * for i in range(128): - * if chr(i) in ALLOWED: # <<<<<<<<<<<<<< - * set_bit(ALLOWED_TABLE, i) - * set_bit(ALLOWED_NOTQS_TABLE, i) - */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_i); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 71, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_builtin_chr, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 71, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(__pyx_v_4yarl_10_quoting_c_ALLOWED == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); - __PYX_ERR(0, 71, __pyx_L1_error) - } - __pyx_t_5 = (__Pyx_PyUnicode_ContainsTF(__pyx_t_3, __pyx_v_4yarl_10_quoting_c_ALLOWED, Py_EQ)); if (unlikely(__pyx_t_5 < 0)) __PYX_ERR(0, 71, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_6 = (__pyx_t_5 != 0); - if (__pyx_t_6) { - - /* "yarl/_quoting_c.pyx":72 - * for i in range(128): - * if chr(i) in ALLOWED: - * set_bit(ALLOWED_TABLE, i) # <<<<<<<<<<<<<< - * set_bit(ALLOWED_NOTQS_TABLE, i) - * if chr(i) in QS: - */ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_i); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_7 = __Pyx_PyInt_As_uint64_t(__pyx_t_3); if (unlikely((__pyx_t_7 == ((uint64_t)-1)) && PyErr_Occurred())) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_f_4yarl_10_quoting_c_set_bit(__pyx_v_4yarl_10_quoting_c_ALLOWED_TABLE, __pyx_t_7); - - /* "yarl/_quoting_c.pyx":73 - * if chr(i) in ALLOWED: - * set_bit(ALLOWED_TABLE, i) - * set_bit(ALLOWED_NOTQS_TABLE, i) # <<<<<<<<<<<<<< - * if chr(i) in QS: - * set_bit(ALLOWED_NOTQS_TABLE, i) - */ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_i); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 73, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_7 = __Pyx_PyInt_As_uint64_t(__pyx_t_3); if (unlikely((__pyx_t_7 == ((uint64_t)-1)) && PyErr_Occurred())) __PYX_ERR(0, 73, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_f_4yarl_10_quoting_c_set_bit(__pyx_v_4yarl_10_quoting_c_ALLOWED_NOTQS_TABLE, __pyx_t_7); - - /* "yarl/_quoting_c.pyx":71 - * - * for i in range(128): - * if chr(i) in ALLOWED: # <<<<<<<<<<<<<< - * set_bit(ALLOWED_TABLE, i) - * set_bit(ALLOWED_NOTQS_TABLE, i) - */ - } - - /* "yarl/_quoting_c.pyx":74 - * set_bit(ALLOWED_TABLE, i) - * set_bit(ALLOWED_NOTQS_TABLE, i) - * if chr(i) in QS: # <<<<<<<<<<<<<< - * set_bit(ALLOWED_NOTQS_TABLE, i) - * - */ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_i); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 74, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_builtin_chr, __pyx_t_3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(__pyx_v_4yarl_10_quoting_c_QS == Py_None)) { - PyErr_SetString(PyExc_TypeError, "'NoneType' object is not iterable"); - __PYX_ERR(0, 74, __pyx_L1_error) - } - __pyx_t_6 = (__Pyx_PyUnicode_ContainsTF(__pyx_t_1, __pyx_v_4yarl_10_quoting_c_QS, Py_EQ)); if (unlikely(__pyx_t_6 < 0)) __PYX_ERR(0, 74, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_5 = (__pyx_t_6 != 0); - if (__pyx_t_5) { - - /* "yarl/_quoting_c.pyx":75 - * set_bit(ALLOWED_NOTQS_TABLE, i) - * if chr(i) in QS: - * set_bit(ALLOWED_NOTQS_TABLE, i) # <<<<<<<<<<<<<< - * - * # ----------------- writer --------------------------- - */ - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_i); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_7 = __Pyx_PyInt_As_uint64_t(__pyx_t_1); if (unlikely((__pyx_t_7 == ((uint64_t)-1)) && PyErr_Occurred())) __PYX_ERR(0, 75, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_f_4yarl_10_quoting_c_set_bit(__pyx_v_4yarl_10_quoting_c_ALLOWED_NOTQS_TABLE, __pyx_t_7); - - /* "yarl/_quoting_c.pyx":74 - * set_bit(ALLOWED_TABLE, i) - * set_bit(ALLOWED_NOTQS_TABLE, i) - * if chr(i) in QS: # <<<<<<<<<<<<<< - * set_bit(ALLOWED_NOTQS_TABLE, i) - * - */ - } - } - - /* "(tree fragment)":1 - * def __pyx_unpickle__Quoter(__pyx_type, long __pyx_checksum, __pyx_state): # <<<<<<<<<<<<<< - * cdef object __pyx_PickleError - * cdef object __pyx_result - */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4yarl_10_quoting_c_1__pyx_unpickle__Quoter, NULL, __pyx_n_s_yarl__quoting_c); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_pyx_unpickle__Quoter, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "(tree fragment)":11 - * __pyx_unpickle__Quoter__set_state(<_Quoter> __pyx_result, __pyx_state) - * return __pyx_result - * cdef __pyx_unpickle__Quoter__set_state(_Quoter __pyx_result, tuple __pyx_state): # <<<<<<<<<<<<<< - * __pyx_result._protected_table = __pyx_state[0]; __pyx_result._qs = __pyx_state[1]; __pyx_result._requote = __pyx_state[2]; __pyx_result._safe_table = __pyx_state[3] - * if len(__pyx_state) > 4 and hasattr(__pyx_result, '__dict__'): - */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_4yarl_10_quoting_c_3__pyx_unpickle__Unquoter, NULL, __pyx_n_s_yarl__quoting_c); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_pyx_unpickle__Unquoter, __pyx_t_1) < 0) __PYX_ERR(1, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "yarl/_quoting_c.pyx":1 - * # cython: language_level=3 # <<<<<<<<<<<<<< - * - * from cpython.exc cimport PyErr_NoMemory - */ - __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "carray.from_py":77 - * - * @cname("__Pyx_carray_from_py_uint8_t") - * cdef int __Pyx_carray_from_py_uint8_t(object o, base_type *v, Py_ssize_t length) except -1: # <<<<<<<<<<<<<< - * cdef Py_ssize_t i = length - * try: - */ - - /*--- Wrapped vars code ---*/ - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - if (__pyx_m) { - if (__pyx_d) { - __Pyx_AddTraceback("init yarl._quoting_c", __pyx_clineno, __pyx_lineno, __pyx_filename); - } - Py_CLEAR(__pyx_m); - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init yarl._quoting_c"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if CYTHON_PEP489_MULTI_PHASE_INIT - return (__pyx_m != NULL) ? 0 : -1; - #elif PY_MAJOR_VERSION >= 3 - return __pyx_m; - #else - return; - #endif -} - -/* --- Runtime support code --- */ -/* Refnanny */ -#if CYTHON_REFNANNY -static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule(modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, "RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); -end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; -} -#endif - -/* PyObjectGetAttrStr */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro)) - return tp->tp_getattro(obj, attr_name); -#if PY_MAJOR_VERSION < 3 - if (likely(tp->tp_getattr)) - return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); -#endif - return PyObject_GetAttr(obj, attr_name); -} -#endif - -/* GetBuiltinName */ -static PyObject *__Pyx_GetBuiltinName(PyObject *name) { - PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name); - if (unlikely(!result)) { - PyErr_Format(PyExc_NameError, -#if PY_MAJOR_VERSION >= 3 - "name '%U' is not defined", name); -#else - "name '%.200s' is not defined", PyString_AS_STRING(name)); -#endif - } - return result; -} - -/* PyErrFetchRestore */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { - PyObject *tmp_type, *tmp_value, *tmp_tb; - tmp_type = tstate->curexc_type; - tmp_value = tstate->curexc_value; - tmp_tb = tstate->curexc_traceback; - tstate->curexc_type = type; - tstate->curexc_value = value; - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -} -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { - *type = tstate->curexc_type; - *value = tstate->curexc_value; - *tb = tstate->curexc_traceback; - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -} -#endif - -/* WriteUnraisableException */ -static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno, - CYTHON_UNUSED int lineno, CYTHON_UNUSED const char *filename, - int full_traceback, CYTHON_UNUSED int nogil) { - PyObject *old_exc, *old_val, *old_tb; - PyObject *ctx; - __Pyx_PyThreadState_declare -#ifdef WITH_THREAD - PyGILState_STATE state; - if (nogil) - state = PyGILState_Ensure(); -#ifdef _MSC_VER - else state = (PyGILState_STATE)-1; -#endif -#endif - __Pyx_PyThreadState_assign - __Pyx_ErrFetch(&old_exc, &old_val, &old_tb); - if (full_traceback) { - Py_XINCREF(old_exc); - Py_XINCREF(old_val); - Py_XINCREF(old_tb); - __Pyx_ErrRestore(old_exc, old_val, old_tb); - PyErr_PrintEx(1); - } - #if PY_MAJOR_VERSION < 3 - ctx = PyString_FromString(name); - #else - ctx = PyUnicode_FromString(name); - #endif - __Pyx_ErrRestore(old_exc, old_val, old_tb); - if (!ctx) { - PyErr_WriteUnraisable(Py_None); - } else { - PyErr_WriteUnraisable(ctx); - Py_DECREF(ctx); - } -#ifdef WITH_THREAD - if (nogil) - PyGILState_Release(state); -#endif -} - -/* RaiseDoubleKeywords */ -static void __Pyx_RaiseDoubleKeywordsError( - const char* func_name, - PyObject* kw_name) -{ - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION >= 3 - "%s() got multiple values for keyword argument '%U'", func_name, kw_name); - #else - "%s() got multiple values for keyword argument '%s'", func_name, - PyString_AsString(kw_name)); - #endif -} - -/* ParseKeywords */ -static int __Pyx_ParseOptionalKeywords( - PyObject *kwds, - PyObject **argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - const char* function_name) -{ - PyObject *key = 0, *value = 0; - Py_ssize_t pos = 0; - PyObject*** name; - PyObject*** first_kw_arg = argnames + num_pos_args; - while (PyDict_Next(kwds, &pos, &key, &value)) { - name = first_kw_arg; - while (*name && (**name != key)) name++; - if (*name) { - values[name-argnames] = value; - continue; - } - name = first_kw_arg; - #if PY_MAJOR_VERSION < 3 - if (likely(PyString_Check(key))) { - while (*name) { - if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) - && _PyString_Eq(**name, key)) { - values[name-argnames] = value; - break; - } - name++; - } - if (*name) continue; - else { - PyObject*** argname = argnames; - while (argname != first_kw_arg) { - if ((**argname == key) || ( - (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) - && _PyString_Eq(**argname, key))) { - goto arg_passed_twice; - } - argname++; - } - } - } else - #endif - if (likely(PyUnicode_Check(key))) { - while (*name) { - int cmp = (**name == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 - (__Pyx_PyUnicode_GET_LENGTH(**name) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**name, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; - if (cmp == 0) { - values[name-argnames] = value; - break; - } - name++; - } - if (*name) continue; - else { - PyObject*** argname = argnames; - while (argname != first_kw_arg) { - int cmp = (**argname == key) ? 0 : - #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 - (__Pyx_PyUnicode_GET_LENGTH(**argname) != __Pyx_PyUnicode_GET_LENGTH(key)) ? 1 : - #endif - PyUnicode_Compare(**argname, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; - if (cmp == 0) goto arg_passed_twice; - argname++; - } - } - } else - goto invalid_keyword_type; - if (kwds2) { - if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; - } else { - goto invalid_keyword; - } - } - return 0; -arg_passed_twice: - __Pyx_RaiseDoubleKeywordsError(function_name, key); - goto bad; -invalid_keyword_type: - PyErr_Format(PyExc_TypeError, - "%.200s() keywords must be strings", function_name); - goto bad; -invalid_keyword: - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION < 3 - "%.200s() got an unexpected keyword argument '%.200s'", - function_name, PyString_AsString(key)); - #else - "%s() got an unexpected keyword argument '%U'", - function_name, key); - #endif -bad: - return -1; -} - -/* RaiseArgTupleInvalid */ -static void __Pyx_RaiseArgtupleInvalid( - const char* func_name, - int exact, - Py_ssize_t num_min, - Py_ssize_t num_max, - Py_ssize_t num_found) -{ - Py_ssize_t num_expected; - const char *more_or_less; - if (num_found < num_min) { - num_expected = num_min; - more_or_less = "at least"; - } else { - num_expected = num_max; - more_or_less = "at most"; - } - if (exact) { - more_or_less = "exactly"; - } - PyErr_Format(PyExc_TypeError, - "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", - func_name, more_or_less, num_expected, - (num_expected == 1) ? "" : "s", num_found); -} - -/* ArgTypeTest */ -static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) -{ - if (unlikely(!type)) { - PyErr_SetString(PyExc_SystemError, "Missing type object"); - return 0; - } - else if (exact) { - #if PY_MAJOR_VERSION == 2 - if ((type == &PyBaseString_Type) && likely(__Pyx_PyBaseString_CheckExact(obj))) return 1; - #endif - } - else { - if (likely(__Pyx_TypeCheck(obj, type))) return 1; - } - PyErr_Format(PyExc_TypeError, - "Argument '%.200s' has incorrect type (expected %.200s, got %.200s)", - name, type->tp_name, Py_TYPE(obj)->tp_name); - return 0; -} - -/* unicode_iter */ -static CYTHON_INLINE int __Pyx_init_unicode_iteration( - PyObject* ustring, Py_ssize_t *length, void** data, int *kind) { -#if CYTHON_PEP393_ENABLED - if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return -1; - *kind = PyUnicode_KIND(ustring); - *length = PyUnicode_GET_LENGTH(ustring); - *data = PyUnicode_DATA(ustring); -#else - *kind = 0; - *length = PyUnicode_GET_SIZE(ustring); - *data = (void*)PyUnicode_AS_UNICODE(ustring); -#endif - return 0; -} - -/* PyObjectCall */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; - ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) - return NULL; - result = (*call)(func, arg, kw); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* RaiseException */ -#if PY_MAJOR_VERSION < 3 -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, - CYTHON_UNUSED PyObject *cause) { - __Pyx_PyThreadState_declare - Py_XINCREF(type); - if (!value || value == Py_None) - value = NULL; - else - Py_INCREF(value); - if (!tb || tb == Py_None) - tb = NULL; - else { - Py_INCREF(tb); - if (!PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto raise_error; - } - } - if (PyType_Check(type)) { -#if CYTHON_COMPILING_IN_PYPY - if (!value) { - Py_INCREF(Py_None); - value = Py_None; - } -#endif - PyErr_NormalizeException(&type, &value, &tb); - } else { - if (value) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto raise_error; - } - value = type; - type = (PyObject*) Py_TYPE(type); - Py_INCREF(type); - if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto raise_error; - } - } - __Pyx_PyThreadState_assign - __Pyx_ErrRestore(type, value, tb); - return; -raise_error: - Py_XDECREF(value); - Py_XDECREF(type); - Py_XDECREF(tb); - return; -} -#else -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { - PyObject* owned_instance = NULL; - if (tb == Py_None) { - tb = 0; - } else if (tb && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto bad; - } - if (value == Py_None) - value = 0; - if (PyExceptionInstance_Check(type)) { - if (value) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto bad; - } - value = type; - type = (PyObject*) Py_TYPE(value); - } else if (PyExceptionClass_Check(type)) { - PyObject *instance_class = NULL; - if (value && PyExceptionInstance_Check(value)) { - instance_class = (PyObject*) Py_TYPE(value); - if (instance_class != type) { - int is_subclass = PyObject_IsSubclass(instance_class, type); - if (!is_subclass) { - instance_class = NULL; - } else if (unlikely(is_subclass == -1)) { - goto bad; - } else { - type = instance_class; - } - } - } - if (!instance_class) { - PyObject *args; - if (!value) - args = PyTuple_New(0); - else if (PyTuple_Check(value)) { - Py_INCREF(value); - args = value; - } else - args = PyTuple_Pack(1, value); - if (!args) - goto bad; - owned_instance = PyObject_Call(type, args, NULL); - Py_DECREF(args); - if (!owned_instance) - goto bad; - value = owned_instance; - if (!PyExceptionInstance_Check(value)) { - PyErr_Format(PyExc_TypeError, - "calling %R should have returned an instance of " - "BaseException, not %R", - type, Py_TYPE(value)); - goto bad; - } - } - } else { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto bad; - } - if (cause) { - PyObject *fixed_cause; - if (cause == Py_None) { - fixed_cause = NULL; - } else if (PyExceptionClass_Check(cause)) { - fixed_cause = PyObject_CallObject(cause, NULL); - if (fixed_cause == NULL) - goto bad; - } else if (PyExceptionInstance_Check(cause)) { - fixed_cause = cause; - Py_INCREF(fixed_cause); - } else { - PyErr_SetString(PyExc_TypeError, - "exception causes must derive from " - "BaseException"); - goto bad; - } - PyException_SetCause(value, fixed_cause); - } - PyErr_SetObject(type, value); - if (tb) { -#if CYTHON_COMPILING_IN_PYPY - PyObject *tmp_type, *tmp_value, *tmp_tb; - PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); - Py_INCREF(tb); - PyErr_Restore(tmp_type, tmp_value, tb); - Py_XDECREF(tmp_tb); -#else - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject* tmp_tb = tstate->curexc_traceback; - if (tb != tmp_tb) { - Py_INCREF(tb); - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_tb); - } -#endif - } -bad: - Py_XDECREF(owned_instance); - return; -} -#endif - -/* PyCFunctionFastCall */ -#if CYTHON_FAST_PYCCALL -static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { - PyCFunctionObject *func = (PyCFunctionObject*)func_obj; - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - int flags = PyCFunction_GET_FLAGS(func); - assert(PyCFunction_Check(func)); - assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS))); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - /* _PyCFunction_FastCallDict() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) { - return (*((__Pyx_PyCFunctionFastWithKeywords)(void*)meth)) (self, args, nargs, NULL); - } else { - return (*((__Pyx_PyCFunctionFast)(void*)meth)) (self, args, nargs); - } -} -#endif - -/* PyFunctionFastCall */ -#if CYTHON_FAST_PYCALL -static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, - PyObject *globals) { - PyFrameObject *f; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - assert(globals != NULL); - /* XXX Perhaps we should create a specialized - PyFrame_New() that doesn't take locals, but does - take builtins without sanity checking them. - */ - assert(tstate != NULL); - f = PyFrame_New(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - fastlocals = __Pyx_PyFrame_GetLocalsplus(f); - for (i = 0; i < na; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - result = PyEval_EvalFrameEx(f,0); - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - return result; -} -#if 1 || PY_VERSION_HEX < 0x030600B1 -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *closure; -#if PY_MAJOR_VERSION >= 3 - PyObject *kwdefs; -#endif - PyObject *kwtuple, **k; - PyObject **d; - Py_ssize_t nd; - Py_ssize_t nk; - PyObject *result; - assert(kwargs == NULL || PyDict_Check(kwargs)); - nk = kwargs ? PyDict_Size(kwargs) : 0; - if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { - return NULL; - } - if ( -#if PY_MAJOR_VERSION >= 3 - co->co_kwonlyargcount == 0 && -#endif - likely(kwargs == NULL || nk == 0) && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { - if (argdefs == NULL && co->co_argcount == nargs) { - result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); - goto done; - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - args = &PyTuple_GET_ITEM(argdefs, 0); - result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); - goto done; - } - } - if (kwargs != NULL) { - Py_ssize_t pos, i; - kwtuple = PyTuple_New(2 * nk); - if (kwtuple == NULL) { - result = NULL; - goto done; - } - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i / 2; - } - else { - kwtuple = NULL; - k = NULL; - } - closure = PyFunction_GET_CLOSURE(func); -#if PY_MAJOR_VERSION >= 3 - kwdefs = PyFunction_GET_KW_DEFAULTS(func); -#endif - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } -#if PY_MAJOR_VERSION >= 3 - result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, - args, (int)nargs, - k, (int)nk, - d, (int)nd, kwdefs, closure); -#else - result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, - args, (int)nargs, - k, (int)nk, - d, (int)nd, closure); -#endif - Py_XDECREF(kwtuple); -done: - Py_LeaveRecursiveCall(); - return result; -} -#endif -#endif - -/* PyObjectCallMethO */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { - PyObject *self, *result; - PyCFunction cfunc; - cfunc = PyCFunction_GET_FUNCTION(func); - self = PyCFunction_GET_SELF(func); - if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) - return NULL; - result = cfunc(self, arg); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectCallOneArg */ -#if CYTHON_COMPILING_IN_CPYTHON -static PyObject* __Pyx__PyObject_CallOneArg(PyObject *func, PyObject *arg) { - PyObject *result; - PyObject *args = PyTuple_New(1); - if (unlikely(!args)) return NULL; - Py_INCREF(arg); - PyTuple_SET_ITEM(args, 0, arg); - result = __Pyx_PyObject_Call(func, args, NULL); - Py_DECREF(args); - return result; -} -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { -#if CYTHON_FAST_PYCALL - if (PyFunction_Check(func)) { - return __Pyx_PyFunction_FastCall(func, &arg, 1); - } -#endif - if (likely(PyCFunction_Check(func))) { - if (likely(PyCFunction_GET_FLAGS(func) & METH_O)) { - return __Pyx_PyObject_CallMethO(func, arg); -#if CYTHON_FAST_PYCCALL - } else if (__Pyx_PyFastCFunction_Check(func)) { - return __Pyx_PyCFunction_FastCall(func, &arg, 1); -#endif - } - } - return __Pyx__PyObject_CallOneArg(func, arg); -} -#else -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { - PyObject *result; - PyObject *args = PyTuple_Pack(1, arg); - if (unlikely(!args)) return NULL; - result = __Pyx_PyObject_Call(func, args, NULL); - Py_DECREF(args); - return result; -} -#endif - -/* GetException */ -#if CYTHON_FAST_THREAD_STATE -static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) -#else -static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) -#endif -{ - PyObject *local_type, *local_value, *local_tb; -#if CYTHON_FAST_THREAD_STATE - PyObject *tmp_type, *tmp_value, *tmp_tb; - local_type = tstate->curexc_type; - local_value = tstate->curexc_value; - local_tb = tstate->curexc_traceback; - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -#else - PyErr_Fetch(&local_type, &local_value, &local_tb); -#endif - PyErr_NormalizeException(&local_type, &local_value, &local_tb); -#if CYTHON_FAST_THREAD_STATE - if (unlikely(tstate->curexc_type)) -#else - if (unlikely(PyErr_Occurred())) -#endif - goto bad; - #if PY_MAJOR_VERSION >= 3 - if (local_tb) { - if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) - goto bad; - } - #endif - Py_XINCREF(local_tb); - Py_XINCREF(local_type); - Py_XINCREF(local_value); - *type = local_type; - *value = local_value; - *tb = local_tb; -#if CYTHON_FAST_THREAD_STATE - #if CYTHON_USE_EXC_INFO_STACK - { - _PyErr_StackItem *exc_info = tstate->exc_info; - tmp_type = exc_info->exc_type; - tmp_value = exc_info->exc_value; - tmp_tb = exc_info->exc_traceback; - exc_info->exc_type = local_type; - exc_info->exc_value = local_value; - exc_info->exc_traceback = local_tb; - } - #else - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - tstate->exc_type = local_type; - tstate->exc_value = local_value; - tstate->exc_traceback = local_tb; - #endif - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -#else - PyErr_SetExcInfo(local_type, local_value, local_tb); -#endif - return 0; -bad: - *type = 0; - *value = 0; - *tb = 0; - Py_XDECREF(local_type); - Py_XDECREF(local_value); - Py_XDECREF(local_tb); - return -1; -} - -/* SwapException */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { - PyObject *tmp_type, *tmp_value, *tmp_tb; - #if CYTHON_USE_EXC_INFO_STACK - _PyErr_StackItem *exc_info = tstate->exc_info; - tmp_type = exc_info->exc_type; - tmp_value = exc_info->exc_value; - tmp_tb = exc_info->exc_traceback; - exc_info->exc_type = *type; - exc_info->exc_value = *value; - exc_info->exc_traceback = *tb; - #else - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - tstate->exc_type = *type; - tstate->exc_value = *value; - tstate->exc_traceback = *tb; - #endif - *type = tmp_type; - *value = tmp_value; - *tb = tmp_tb; -} -#else -static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) { - PyObject *tmp_type, *tmp_value, *tmp_tb; - PyErr_GetExcInfo(&tmp_type, &tmp_value, &tmp_tb); - PyErr_SetExcInfo(*type, *value, *tb); - *type = tmp_type; - *value = tmp_value; - *tb = tmp_tb; -} -#endif - -/* GetTopmostException */ -#if CYTHON_USE_EXC_INFO_STACK -static _PyErr_StackItem * -__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) -{ - _PyErr_StackItem *exc_info = tstate->exc_info; - while ((exc_info->exc_type == NULL || exc_info->exc_type == Py_None) && - exc_info->previous_item != NULL) - { - exc_info = exc_info->previous_item; - } - return exc_info; -} -#endif - -/* SaveResetException */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { - #if CYTHON_USE_EXC_INFO_STACK - _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); - *type = exc_info->exc_type; - *value = exc_info->exc_value; - *tb = exc_info->exc_traceback; - #else - *type = tstate->exc_type; - *value = tstate->exc_value; - *tb = tstate->exc_traceback; - #endif - Py_XINCREF(*type); - Py_XINCREF(*value); - Py_XINCREF(*tb); -} -static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { - PyObject *tmp_type, *tmp_value, *tmp_tb; - #if CYTHON_USE_EXC_INFO_STACK - _PyErr_StackItem *exc_info = tstate->exc_info; - tmp_type = exc_info->exc_type; - tmp_value = exc_info->exc_value; - tmp_tb = exc_info->exc_traceback; - exc_info->exc_type = type; - exc_info->exc_value = value; - exc_info->exc_traceback = tb; - #else - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - tstate->exc_type = type; - tstate->exc_value = value; - tstate->exc_traceback = tb; - #endif - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -} -#endif - -/* GetItemIntUnicode */ -static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i, - int wraparound, int boundscheck) { - Py_ssize_t length; - if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return (Py_UCS4)-1; - if (wraparound | boundscheck) { - length = __Pyx_PyUnicode_GET_LENGTH(ustring); - if (wraparound & unlikely(i < 0)) i += length; - if ((!boundscheck) || likely(__Pyx_is_valid_index(i, length))) { - return __Pyx_PyUnicode_READ_CHAR(ustring, i); - } else { - PyErr_SetString(PyExc_IndexError, "string index out of range"); - return (Py_UCS4)-1; - } - } else { - return __Pyx_PyUnicode_READ_CHAR(ustring, i); - } -} - -/* ReRaiseException */ -static CYTHON_INLINE void __Pyx_ReraiseException(void) { - PyObject *type = NULL, *value = NULL, *tb = NULL; -#if CYTHON_FAST_THREAD_STATE - PyThreadState *tstate = PyThreadState_GET(); - #if CYTHON_USE_EXC_INFO_STACK - _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); - type = exc_info->exc_type; - value = exc_info->exc_value; - tb = exc_info->exc_traceback; - #else - type = tstate->exc_type; - value = tstate->exc_value; - tb = tstate->exc_traceback; - #endif -#else - PyErr_GetExcInfo(&type, &value, &tb); -#endif - if (!type || type == Py_None) { -#if !CYTHON_FAST_THREAD_STATE - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(tb); -#endif - PyErr_SetString(PyExc_RuntimeError, - "No active exception to reraise"); - } else { -#if CYTHON_FAST_THREAD_STATE - Py_INCREF(type); - Py_XINCREF(value); - Py_XINCREF(tb); -#endif - PyErr_Restore(type, value, tb); - } -} - -/* PyErrExceptionMatches */ -#if CYTHON_FAST_THREAD_STATE -static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(tuple); -#if PY_MAJOR_VERSION >= 3 - for (i=0; icurexc_type; - if (exc_type == err) return 1; - if (unlikely(!exc_type)) return 0; - if (unlikely(PyTuple_Check(err))) - return __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); - return __Pyx_PyErr_GivenExceptionMatches(exc_type, err); -} -#endif - -/* GetAttr */ -static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *o, PyObject *n) { -#if CYTHON_USE_TYPE_SLOTS -#if PY_MAJOR_VERSION >= 3 - if (likely(PyUnicode_Check(n))) -#else - if (likely(PyString_Check(n))) -#endif - return __Pyx_PyObject_GetAttrStr(o, n); -#endif - return PyObject_GetAttr(o, n); -} - -/* GetAttr3 */ -static PyObject *__Pyx_GetAttr3Default(PyObject *d) { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - if (unlikely(!__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) - return NULL; - __Pyx_PyErr_Clear(); - Py_INCREF(d); - return d; -} -static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *o, PyObject *n, PyObject *d) { - PyObject *r = __Pyx_GetAttr(o, n); - return (likely(r)) ? r : __Pyx_GetAttr3Default(d); -} - -/* PyDictVersioning */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { - PyObject **dictptr = NULL; - Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; - if (offset) { -#if CYTHON_COMPILING_IN_CPYTHON - dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); -#else - dictptr = _PyObject_GetDictPtr(obj); -#endif - } - return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; -} -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) - return 0; - return obj_dict_version == __Pyx_get_object_dict_version(obj); -} -#endif - -/* GetModuleGlobalName */ -#if CYTHON_USE_DICT_VERSIONS -static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) -#else -static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) -#endif -{ - PyObject *result; -#if !CYTHON_AVOID_BORROWED_REFS -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 - result = _PyDict_GetItem_KnownHash(__pyx_d, name, ((PyASCIIObject *) name)->hash); - __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return __Pyx_NewRef(result); - } else if (unlikely(PyErr_Occurred())) { - return NULL; - } -#else - result = PyDict_GetItem(__pyx_d, name); - __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return __Pyx_NewRef(result); - } -#endif -#else - result = PyObject_GetItem(__pyx_d, name); - __PYX_UPDATE_DICT_CACHE(__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return __Pyx_NewRef(result); - } - PyErr_Clear(); -#endif - return __Pyx_GetBuiltinName(name); -} - -/* PyObjectCallNoArg */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { -#if CYTHON_FAST_PYCALL - if (PyFunction_Check(func)) { - return __Pyx_PyFunction_FastCall(func, NULL, 0); - } -#endif -#ifdef __Pyx_CyFunction_USED - if (likely(PyCFunction_Check(func) || __Pyx_CyFunction_Check(func))) -#else - if (likely(PyCFunction_Check(func))) -#endif - { - if (likely(PyCFunction_GET_FLAGS(func) & METH_NOARGS)) { - return __Pyx_PyObject_CallMethO(func, NULL); - } - } - return __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL); -} -#endif - -/* PyUnicode_Substring */ -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Substring( - PyObject* text, Py_ssize_t start, Py_ssize_t stop) { - Py_ssize_t length; - if (unlikely(__Pyx_PyUnicode_READY(text) == -1)) return NULL; - length = __Pyx_PyUnicode_GET_LENGTH(text); - if (start < 0) { - start += length; - if (start < 0) - start = 0; - } - if (stop < 0) - stop += length; - else if (stop > length) - stop = length; - if (stop <= start) - return __Pyx_NewRef(__pyx_empty_unicode); -#if CYTHON_PEP393_ENABLED - return PyUnicode_FromKindAndData(PyUnicode_KIND(text), - PyUnicode_1BYTE_DATA(text) + start*PyUnicode_KIND(text), stop-start); -#else - return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(text)+start, stop-start); -#endif -} - -/* PyObjectCall2Args */ -static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { - PyObject *args, *result = NULL; - #if CYTHON_FAST_PYCALL - if (PyFunction_Check(function)) { - PyObject *args[2] = {arg1, arg2}; - return __Pyx_PyFunction_FastCall(function, args, 2); - } - #endif - #if CYTHON_FAST_PYCCALL - if (__Pyx_PyFastCFunction_Check(function)) { - PyObject *args[2] = {arg1, arg2}; - return __Pyx_PyCFunction_FastCall(function, args, 2); - } - #endif - args = PyTuple_New(2); - if (unlikely(!args)) goto done; - Py_INCREF(arg1); - PyTuple_SET_ITEM(args, 0, arg1); - Py_INCREF(arg2); - PyTuple_SET_ITEM(args, 1, arg2); - Py_INCREF(function); - result = __Pyx_PyObject_Call(function, args, NULL); - Py_DECREF(args); - Py_DECREF(function); -done: - return result; -} - -/* SliceObject */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetSlice(PyObject* obj, - Py_ssize_t cstart, Py_ssize_t cstop, - PyObject** _py_start, PyObject** _py_stop, PyObject** _py_slice, - int has_cstart, int has_cstop, CYTHON_UNUSED int wraparound) { -#if CYTHON_USE_TYPE_SLOTS - PyMappingMethods* mp; -#if PY_MAJOR_VERSION < 3 - PySequenceMethods* ms = Py_TYPE(obj)->tp_as_sequence; - if (likely(ms && ms->sq_slice)) { - if (!has_cstart) { - if (_py_start && (*_py_start != Py_None)) { - cstart = __Pyx_PyIndex_AsSsize_t(*_py_start); - if ((cstart == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; - } else - cstart = 0; - } - if (!has_cstop) { - if (_py_stop && (*_py_stop != Py_None)) { - cstop = __Pyx_PyIndex_AsSsize_t(*_py_stop); - if ((cstop == (Py_ssize_t)-1) && PyErr_Occurred()) goto bad; - } else - cstop = PY_SSIZE_T_MAX; - } - if (wraparound && unlikely((cstart < 0) | (cstop < 0)) && likely(ms->sq_length)) { - Py_ssize_t l = ms->sq_length(obj); - if (likely(l >= 0)) { - if (cstop < 0) { - cstop += l; - if (cstop < 0) cstop = 0; - } - if (cstart < 0) { - cstart += l; - if (cstart < 0) cstart = 0; - } - } else { - if (!PyErr_ExceptionMatches(PyExc_OverflowError)) - goto bad; - PyErr_Clear(); - } - } - return ms->sq_slice(obj, cstart, cstop); - } -#endif - mp = Py_TYPE(obj)->tp_as_mapping; - if (likely(mp && mp->mp_subscript)) -#endif - { - PyObject* result; - PyObject *py_slice, *py_start, *py_stop; - if (_py_slice) { - py_slice = *_py_slice; - } else { - PyObject* owned_start = NULL; - PyObject* owned_stop = NULL; - if (_py_start) { - py_start = *_py_start; - } else { - if (has_cstart) { - owned_start = py_start = PyInt_FromSsize_t(cstart); - if (unlikely(!py_start)) goto bad; - } else - py_start = Py_None; - } - if (_py_stop) { - py_stop = *_py_stop; - } else { - if (has_cstop) { - owned_stop = py_stop = PyInt_FromSsize_t(cstop); - if (unlikely(!py_stop)) { - Py_XDECREF(owned_start); - goto bad; - } - } else - py_stop = Py_None; - } - py_slice = PySlice_New(py_start, py_stop, Py_None); - Py_XDECREF(owned_start); - Py_XDECREF(owned_stop); - if (unlikely(!py_slice)) goto bad; - } -#if CYTHON_USE_TYPE_SLOTS - result = mp->mp_subscript(obj, py_slice); -#else - result = PyObject_GetItem(obj, py_slice); -#endif - if (!_py_slice) { - Py_DECREF(py_slice); - } - return result; - } - PyErr_Format(PyExc_TypeError, - "'%.200s' object is unsliceable", Py_TYPE(obj)->tp_name); -bad: - return NULL; -} - -/* Import */ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - PyObject *empty_list = 0; - PyObject *module = 0; - PyObject *global_dict = 0; - PyObject *empty_dict = 0; - PyObject *list; - #if PY_MAJOR_VERSION < 3 - PyObject *py_import; - py_import = __Pyx_PyObject_GetAttrStr(__pyx_b, __pyx_n_s_import); - if (!py_import) - goto bad; - #endif - if (from_list) - list = from_list; - else { - empty_list = PyList_New(0); - if (!empty_list) - goto bad; - list = empty_list; - } - global_dict = PyModule_GetDict(__pyx_m); - if (!global_dict) - goto bad; - empty_dict = PyDict_New(); - if (!empty_dict) - goto bad; - { - #if PY_MAJOR_VERSION >= 3 - if (level == -1) { - if ((1) && (strchr(__Pyx_MODULE_NAME, '.'))) { - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, 1); - if (!module) { - if (!PyErr_ExceptionMatches(PyExc_ImportError)) - goto bad; - PyErr_Clear(); - } - } - level = 0; - } - #endif - if (!module) { - #if PY_MAJOR_VERSION < 3 - PyObject *py_level = PyInt_FromLong(level); - if (!py_level) - goto bad; - module = PyObject_CallFunctionObjArgs(py_import, - name, global_dict, empty_dict, list, py_level, (PyObject *)NULL); - Py_DECREF(py_level); - #else - module = PyImport_ImportModuleLevelObject( - name, global_dict, empty_dict, list, level); - #endif - } - } -bad: - #if PY_MAJOR_VERSION < 3 - Py_XDECREF(py_import); - #endif - Py_XDECREF(empty_list); - Py_XDECREF(empty_dict); - return module; -} - -/* ImportFrom */ -static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { - PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); - if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Format(PyExc_ImportError, - #if PY_MAJOR_VERSION < 3 - "cannot import name %.230s", PyString_AS_STRING(name)); - #else - "cannot import name %S", name); - #endif - } - return value; -} - -/* GetItemInt */ -static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { - PyObject *r; - if (!j) return NULL; - r = PyObject_GetItem(o, j); - Py_DECREF(j); - return r; -} -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, - CYTHON_NCP_UNUSED int wraparound, - CYTHON_NCP_UNUSED int boundscheck) { -#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - Py_ssize_t wrapped_i = i; - if (wraparound & unlikely(i < 0)) { - wrapped_i += PyList_GET_SIZE(o); - } - if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { - PyObject *r = PyList_GET_ITEM(o, wrapped_i); - Py_INCREF(r); - return r; - } - return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); -#else - return PySequence_GetItem(o, i); -#endif -} -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, - CYTHON_NCP_UNUSED int wraparound, - CYTHON_NCP_UNUSED int boundscheck) { -#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - Py_ssize_t wrapped_i = i; - if (wraparound & unlikely(i < 0)) { - wrapped_i += PyTuple_GET_SIZE(o); - } - if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { - PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); - Py_INCREF(r); - return r; - } - return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); -#else - return PySequence_GetItem(o, i); -#endif -} -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, - CYTHON_NCP_UNUSED int wraparound, - CYTHON_NCP_UNUSED int boundscheck) { -#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS - if (is_list || PyList_CheckExact(o)) { - Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); - if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { - PyObject *r = PyList_GET_ITEM(o, n); - Py_INCREF(r); - return r; - } - } - else if (PyTuple_CheckExact(o)) { - Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); - if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { - PyObject *r = PyTuple_GET_ITEM(o, n); - Py_INCREF(r); - return r; - } - } else { - PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; - if (likely(m && m->sq_item)) { - if (wraparound && unlikely(i < 0) && likely(m->sq_length)) { - Py_ssize_t l = m->sq_length(o); - if (likely(l >= 0)) { - i += l; - } else { - if (!PyErr_ExceptionMatches(PyExc_OverflowError)) - return NULL; - PyErr_Clear(); - } - } - return m->sq_item(o, i); - } - } -#else - if (is_list || PySequence_Check(o)) { - return PySequence_GetItem(o, i); - } -#endif - return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); -} - -/* HasAttr */ -static CYTHON_INLINE int __Pyx_HasAttr(PyObject *o, PyObject *n) { - PyObject *r; - if (unlikely(!__Pyx_PyBaseString_Check(n))) { - PyErr_SetString(PyExc_TypeError, - "hasattr(): attribute name must be string"); - return -1; - } - r = __Pyx_GetAttr(o, n); - if (unlikely(!r)) { - PyErr_Clear(); - return 0; - } else { - Py_DECREF(r); - return 1; - } -} - -/* ExtTypeTest */ -static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) { - if (unlikely(!type)) { - PyErr_SetString(PyExc_SystemError, "Missing type object"); - return 0; - } - if (likely(__Pyx_TypeCheck(obj, type))) - return 1; - PyErr_Format(PyExc_TypeError, "Cannot convert %.200s to %.200s", - Py_TYPE(obj)->tp_name, type->tp_name); - return 0; -} - -/* PyObject_GenericGetAttrNoDict */ -#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 -static PyObject *__Pyx_RaiseGenericGetAttributeError(PyTypeObject *tp, PyObject *attr_name) { - PyErr_Format(PyExc_AttributeError, -#if PY_MAJOR_VERSION >= 3 - "'%.50s' object has no attribute '%U'", - tp->tp_name, attr_name); -#else - "'%.50s' object has no attribute '%.400s'", - tp->tp_name, PyString_AS_STRING(attr_name)); -#endif - return NULL; -} -static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name) { - PyObject *descr; - PyTypeObject *tp = Py_TYPE(obj); - if (unlikely(!PyString_Check(attr_name))) { - return PyObject_GenericGetAttr(obj, attr_name); - } - assert(!tp->tp_dictoffset); - descr = _PyType_Lookup(tp, attr_name); - if (unlikely(!descr)) { - return __Pyx_RaiseGenericGetAttributeError(tp, attr_name); - } - Py_INCREF(descr); - #if PY_MAJOR_VERSION < 3 - if (likely(PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS))) - #endif - { - descrgetfunc f = Py_TYPE(descr)->tp_descr_get; - if (unlikely(f)) { - PyObject *res = f(descr, obj, (PyObject *)tp); - Py_DECREF(descr); - return res; - } - } - return descr; -} -#endif - -/* PyObject_GenericGetAttr */ -#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000 -static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name) { - if (unlikely(Py_TYPE(obj)->tp_dictoffset)) { - return PyObject_GenericGetAttr(obj, attr_name); - } - return __Pyx_PyObject_GenericGetAttrNoDict(obj, attr_name); -} -#endif - -/* SetVTable */ -static int __Pyx_SetVtable(PyObject *dict, void *vtable) { -#if PY_VERSION_HEX >= 0x02070000 - PyObject *ob = PyCapsule_New(vtable, 0, 0); -#else - PyObject *ob = PyCObject_FromVoidPtr(vtable, 0); -#endif - if (!ob) - goto bad; - if (PyDict_SetItem(dict, __pyx_n_s_pyx_vtable, ob) < 0) - goto bad; - Py_DECREF(ob); - return 0; -bad: - Py_XDECREF(ob); - return -1; -} - -/* PyObjectGetAttrStrNoError */ -static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) - __Pyx_PyErr_Clear(); -} -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { - PyObject *result; -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS && PY_VERSION_HEX >= 0x030700B1 - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { - return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); - } -#endif - result = __Pyx_PyObject_GetAttrStr(obj, attr_name); - if (unlikely(!result)) { - __Pyx_PyObject_GetAttrStr_ClearAttributeError(); - } - return result; -} - -/* SetupReduce */ -static int __Pyx_setup_reduce_is_named(PyObject* meth, PyObject* name) { - int ret; - PyObject *name_attr; - name_attr = __Pyx_PyObject_GetAttrStr(meth, __pyx_n_s_name); - if (likely(name_attr)) { - ret = PyObject_RichCompareBool(name_attr, name, Py_EQ); - } else { - ret = -1; - } - if (unlikely(ret < 0)) { - PyErr_Clear(); - ret = 0; - } - Py_XDECREF(name_attr); - return ret; -} -static int __Pyx_setup_reduce(PyObject* type_obj) { - int ret = 0; - PyObject *object_reduce = NULL; - PyObject *object_getstate = NULL; - PyObject *object_reduce_ex = NULL; - PyObject *reduce = NULL; - PyObject *reduce_ex = NULL; - PyObject *reduce_cython = NULL; - PyObject *setstate = NULL; - PyObject *setstate_cython = NULL; - PyObject *getstate = NULL; -#if CYTHON_USE_PYTYPE_LOOKUP - getstate = _PyType_Lookup((PyTypeObject*)type_obj, __pyx_n_s_getstate); -#else - getstate = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_getstate); - if (!getstate && PyErr_Occurred()) { - goto __PYX_BAD; - } -#endif - if (getstate) { -#if CYTHON_USE_PYTYPE_LOOKUP - object_getstate = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_getstate); -#else - object_getstate = __Pyx_PyObject_GetAttrStrNoError((PyObject*)&PyBaseObject_Type, __pyx_n_s_getstate); - if (!object_getstate && PyErr_Occurred()) { - goto __PYX_BAD; - } -#endif - if (object_getstate != getstate) { - goto __PYX_GOOD; - } - } -#if CYTHON_USE_PYTYPE_LOOKUP - object_reduce_ex = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; -#else - object_reduce_ex = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce_ex); if (!object_reduce_ex) goto __PYX_BAD; -#endif - reduce_ex = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce_ex); if (unlikely(!reduce_ex)) goto __PYX_BAD; - if (reduce_ex == object_reduce_ex) { -#if CYTHON_USE_PYTYPE_LOOKUP - object_reduce = _PyType_Lookup(&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; -#else - object_reduce = __Pyx_PyObject_GetAttrStr((PyObject*)&PyBaseObject_Type, __pyx_n_s_reduce); if (!object_reduce) goto __PYX_BAD; -#endif - reduce = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_reduce); if (unlikely(!reduce)) goto __PYX_BAD; - if (reduce == object_reduce || __Pyx_setup_reduce_is_named(reduce, __pyx_n_s_reduce_cython)) { - reduce_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_reduce_cython); - if (likely(reduce_cython)) { - ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce, reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; - ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_reduce_cython); if (unlikely(ret < 0)) goto __PYX_BAD; - } else if (reduce == object_reduce || PyErr_Occurred()) { - goto __PYX_BAD; - } - setstate = __Pyx_PyObject_GetAttrStr(type_obj, __pyx_n_s_setstate); - if (!setstate) PyErr_Clear(); - if (!setstate || __Pyx_setup_reduce_is_named(setstate, __pyx_n_s_setstate_cython)) { - setstate_cython = __Pyx_PyObject_GetAttrStrNoError(type_obj, __pyx_n_s_setstate_cython); - if (likely(setstate_cython)) { - ret = PyDict_SetItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate, setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; - ret = PyDict_DelItem(((PyTypeObject*)type_obj)->tp_dict, __pyx_n_s_setstate_cython); if (unlikely(ret < 0)) goto __PYX_BAD; - } else if (!setstate || PyErr_Occurred()) { - goto __PYX_BAD; - } - } - PyType_Modified((PyTypeObject*)type_obj); - } - } - goto __PYX_GOOD; -__PYX_BAD: - if (!PyErr_Occurred()) - PyErr_Format(PyExc_RuntimeError, "Unable to initialize pickling for %s", ((PyTypeObject*)type_obj)->tp_name); - ret = -1; -__PYX_GOOD: -#if !CYTHON_USE_PYTYPE_LOOKUP - Py_XDECREF(object_reduce); - Py_XDECREF(object_reduce_ex); - Py_XDECREF(object_getstate); - Py_XDECREF(getstate); -#endif - Py_XDECREF(reduce); - Py_XDECREF(reduce_ex); - Py_XDECREF(reduce_cython); - Py_XDECREF(setstate); - Py_XDECREF(setstate_cython); - return ret; -} - -/* TypeImport */ -#ifndef __PYX_HAVE_RT_ImportType -#define __PYX_HAVE_RT_ImportType -static PyTypeObject *__Pyx_ImportType(PyObject *module, const char *module_name, const char *class_name, - size_t size, enum __Pyx_ImportType_CheckSize check_size) -{ - PyObject *result = 0; - char warning[200]; - Py_ssize_t basicsize; -#ifdef Py_LIMITED_API - PyObject *py_basicsize; -#endif - result = PyObject_GetAttrString(module, class_name); - if (!result) - goto bad; - if (!PyType_Check(result)) { - PyErr_Format(PyExc_TypeError, - "%.200s.%.200s is not a type object", - module_name, class_name); - goto bad; - } -#ifndef Py_LIMITED_API - basicsize = ((PyTypeObject *)result)->tp_basicsize; -#else - py_basicsize = PyObject_GetAttrString(result, "__basicsize__"); - if (!py_basicsize) - goto bad; - basicsize = PyLong_AsSsize_t(py_basicsize); - Py_DECREF(py_basicsize); - py_basicsize = 0; - if (basicsize == (Py_ssize_t)-1 && PyErr_Occurred()) - goto bad; -#endif - if ((size_t)basicsize < size) { - PyErr_Format(PyExc_ValueError, - "%.200s.%.200s size changed, may indicate binary incompatibility. " - "Expected %zd from C header, got %zd from PyObject", - module_name, class_name, size, basicsize); - goto bad; - } - if (check_size == __Pyx_ImportType_CheckSize_Error && (size_t)basicsize != size) { - PyErr_Format(PyExc_ValueError, - "%.200s.%.200s size changed, may indicate binary incompatibility. " - "Expected %zd from C header, got %zd from PyObject", - module_name, class_name, size, basicsize); - goto bad; - } - else if (check_size == __Pyx_ImportType_CheckSize_Warn && (size_t)basicsize > size) { - PyOS_snprintf(warning, sizeof(warning), - "%s.%s size changed, may indicate binary incompatibility. " - "Expected %zd from C header, got %zd from PyObject", - module_name, class_name, size, basicsize); - if (PyErr_WarnEx(NULL, warning, 0) < 0) goto bad; - } - return (PyTypeObject *)result; -bad: - Py_XDECREF(result); - return NULL; -} -#endif - -/* CLineInTraceback */ -#ifndef CYTHON_CLINE_IN_TRACEBACK -static int __Pyx_CLineForTraceback(CYTHON_NCP_UNUSED PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; -#if CYTHON_COMPILING_IN_CPYTHON - PyObject **cython_runtime_dict; -#endif - if (unlikely(!__pyx_cython_runtime)) { - return c_line; - } - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); -#if CYTHON_COMPILING_IN_CPYTHON - cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime); - if (likely(cython_runtime_dict)) { - __PYX_PY_DICT_LOOKUP_IF_MODIFIED( - use_cline, *cython_runtime_dict, - __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_n_s_cline_in_traceback)) - } else -#endif - { - PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback); - if (use_cline_obj) { - use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; - Py_DECREF(use_cline_obj); - } else { - PyErr_Clear(); - use_cline = NULL; - } - } - if (!use_cline) { - c_line = 0; - (void) PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; - } - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - return c_line; -} -#endif - -/* CodeObjectCache */ -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { - int start = 0, mid = 0, end = count - 1; - if (end >= 0 && code_line > entries[end].code_line) { - return count; - } - while (start < end) { - mid = start + (end - start) / 2; - if (code_line < entries[mid].code_line) { - end = mid; - } else if (code_line > entries[mid].code_line) { - start = mid + 1; - } else { - return mid; - } - } - if (code_line <= entries[mid].code_line) { - return mid; - } else { - return mid + 1; - } -} -static PyCodeObject *__pyx_find_code_object(int code_line) { - PyCodeObject* code_object; - int pos; - if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { - return NULL; - } - pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); - if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { - return NULL; - } - code_object = __pyx_code_cache.entries[pos].code_object; - Py_INCREF(code_object); - return code_object; -} -static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { - int pos, i; - __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; - if (unlikely(!code_line)) { - return; - } - if (unlikely(!entries)) { - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); - if (likely(entries)) { - __pyx_code_cache.entries = entries; - __pyx_code_cache.max_count = 64; - __pyx_code_cache.count = 1; - entries[0].code_line = code_line; - entries[0].code_object = code_object; - Py_INCREF(code_object); - } - return; - } - pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); - if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { - PyCodeObject* tmp = entries[pos].code_object; - entries[pos].code_object = code_object; - Py_DECREF(tmp); - return; - } - if (__pyx_code_cache.count == __pyx_code_cache.max_count) { - int new_max = __pyx_code_cache.max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( - __pyx_code_cache.entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } - __pyx_code_cache.entries = entries; - __pyx_code_cache.max_count = new_max; - } - for (i=__pyx_code_cache.count; i>pos; i--) { - entries[i] = entries[i-1]; - } - entries[pos].code_line = code_line; - entries[pos].code_object = code_object; - __pyx_code_cache.count++; - Py_INCREF(code_object); -} - -/* AddTraceback */ -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" -#if PY_VERSION_HEX >= 0x030b00a6 - #ifndef Py_BUILD_CORE - #define Py_BUILD_CORE 1 - #endif - #include "internal/pycore_frame.h" -#endif -static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = NULL; - PyObject *py_funcname = NULL; - #if PY_MAJOR_VERSION < 3 - PyObject *py_srcfile = NULL; - py_srcfile = PyString_FromString(filename); - if (!py_srcfile) goto bad; - #endif - if (c_line) { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - if (!py_funcname) goto bad; - #else - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - if (!py_funcname) goto bad; - funcname = PyUnicode_AsUTF8(py_funcname); - if (!funcname) goto bad; - #endif - } - else { - #if PY_MAJOR_VERSION < 3 - py_funcname = PyString_FromString(funcname); - if (!py_funcname) goto bad; - #endif - } - #if PY_MAJOR_VERSION < 3 - py_code = __Pyx_PyCode_New( - 0, - 0, - 0, - 0, - 0, - __pyx_empty_bytes, /*PyObject *code,*/ - __pyx_empty_tuple, /*PyObject *consts,*/ - __pyx_empty_tuple, /*PyObject *names,*/ - __pyx_empty_tuple, /*PyObject *varnames,*/ - __pyx_empty_tuple, /*PyObject *freevars,*/ - __pyx_empty_tuple, /*PyObject *cellvars,*/ - py_srcfile, /*PyObject *filename,*/ - py_funcname, /*PyObject *name,*/ - py_line, - __pyx_empty_bytes /*PyObject *lnotab*/ - ); - Py_DECREF(py_srcfile); - #else - py_code = PyCode_NewEmpty(filename, funcname, py_line); - #endif - Py_XDECREF(py_funcname); // XDECREF since it's only set on Py3 if cline - return py_code; -bad: - Py_XDECREF(py_funcname); - #if PY_MAJOR_VERSION < 3 - Py_XDECREF(py_srcfile); - #endif - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject *ptype, *pvalue, *ptraceback; - if (c_line) { - c_line = __Pyx_CLineForTraceback(tstate, c_line); - } - py_code = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!py_code) { - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); - py_code = __Pyx_CreateCodeObjectForTraceback( - funcname, c_line, py_line, filename); - if (!py_code) { - /* If the code object creation fails, then we should clear the - fetched exception references and propagate the new exception */ - Py_XDECREF(ptype); - Py_XDECREF(pvalue); - Py_XDECREF(ptraceback); - goto bad; - } - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); - } - py_frame = PyFrame_New( - tstate, /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - __pyx_d, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - __Pyx_PyFrame_SetLineNumber(py_frame, py_line); - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} - -/* CIntFromPyVerify */ -#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ - {\ - func_type value = func_value;\ - if (sizeof(target_type) < sizeof(func_type)) {\ - if (unlikely(value != (func_type) (target_type) value)) {\ - func_type zero = 0;\ - if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ - return (target_type) -1;\ - if (is_unsigned && unlikely(value < zero))\ - goto raise_neg_overflow;\ - else\ - goto raise_overflow;\ - }\ - }\ - return (target_type) value;\ - } - -/* PyUCS4InUnicode */ -#if PY_VERSION_HEX < 0x03090000 || (defined(PyUnicode_WCHAR_KIND) && defined(PyUnicode_AS_UNICODE)) -#if PY_VERSION_HEX < 0x03090000 -#define __Pyx_PyUnicode_AS_UNICODE(op) PyUnicode_AS_UNICODE(op) -#define __Pyx_PyUnicode_GET_SIZE(op) PyUnicode_GET_SIZE(op) -#else -#define __Pyx_PyUnicode_AS_UNICODE(op) (((PyASCIIObject *)(op))->wstr) -#define __Pyx_PyUnicode_GET_SIZE(op) ((PyCompactUnicodeObject *)(op))->wstr_length -#endif -#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2 -static int __Pyx_PyUnicodeBufferContainsUCS4_SP(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) { - Py_UNICODE high_val, low_val; - Py_UNICODE* pos; - high_val = (Py_UNICODE) (0xD800 | (((character - 0x10000) >> 10) & ((1<<10)-1))); - low_val = (Py_UNICODE) (0xDC00 | ( (character - 0x10000) & ((1<<10)-1))); - for (pos=buffer; pos < buffer+length-1; pos++) { - if (unlikely((high_val == pos[0]) & (low_val == pos[1]))) return 1; - } - return 0; -} -#endif -static int __Pyx_PyUnicodeBufferContainsUCS4_BMP(Py_UNICODE* buffer, Py_ssize_t length, Py_UCS4 character) { - Py_UNICODE uchar; - Py_UNICODE* pos; - uchar = (Py_UNICODE) character; - for (pos=buffer; pos < buffer+length; pos++) { - if (unlikely(uchar == pos[0])) return 1; - } - return 0; -} -#endif -static CYTHON_INLINE int __Pyx_UnicodeContainsUCS4(PyObject* unicode, Py_UCS4 character) { -#if CYTHON_PEP393_ENABLED - const int kind = PyUnicode_KIND(unicode); - #ifdef PyUnicode_WCHAR_KIND - if (likely(kind != PyUnicode_WCHAR_KIND)) - #endif - { - Py_ssize_t i; - const void* udata = PyUnicode_DATA(unicode); - const Py_ssize_t length = PyUnicode_GET_LENGTH(unicode); - for (i=0; i < length; i++) { - if (unlikely(character == PyUnicode_READ(kind, udata, i))) return 1; - } - return 0; - } -#elif PY_VERSION_HEX >= 0x03090000 - #error Cannot use "UChar in Unicode" in Python 3.9 without PEP-393 unicode strings. -#elif !defined(PyUnicode_AS_UNICODE) - #error Cannot use "UChar in Unicode" in Python < 3.9 without Py_UNICODE support. -#endif -#if PY_VERSION_HEX < 0x03090000 || (defined(PyUnicode_WCHAR_KIND) && defined(PyUnicode_AS_UNICODE)) -#if !defined(Py_UNICODE_SIZE) || Py_UNICODE_SIZE == 2 - if ((sizeof(Py_UNICODE) == 2) && unlikely(character > 65535)) { - return __Pyx_PyUnicodeBufferContainsUCS4_SP( - __Pyx_PyUnicode_AS_UNICODE(unicode), - __Pyx_PyUnicode_GET_SIZE(unicode), - character); - } else -#endif - { - return __Pyx_PyUnicodeBufferContainsUCS4_BMP( - __Pyx_PyUnicode_AS_UNICODE(unicode), - __Pyx_PyUnicode_GET_SIZE(unicode), - character); - } -#endif -} - -/* UnicodeAsUCS4 */ -static CYTHON_INLINE Py_UCS4 __Pyx_PyUnicode_AsPy_UCS4(PyObject* x) { - Py_ssize_t length; - #if CYTHON_PEP393_ENABLED - length = PyUnicode_GET_LENGTH(x); - if (likely(length == 1)) { - return PyUnicode_READ_CHAR(x, 0); - } - #else - length = PyUnicode_GET_SIZE(x); - if (likely(length == 1)) { - return PyUnicode_AS_UNICODE(x)[0]; - } - #if Py_UNICODE_SIZE == 2 - else if (PyUnicode_GET_SIZE(x) == 2) { - Py_UCS4 high_val = PyUnicode_AS_UNICODE(x)[0]; - if (high_val >= 0xD800 && high_val <= 0xDBFF) { - Py_UCS4 low_val = PyUnicode_AS_UNICODE(x)[1]; - if (low_val >= 0xDC00 && low_val <= 0xDFFF) { - return 0x10000 + (((high_val & ((1<<10)-1)) << 10) | (low_val & ((1<<10)-1))); - } - } - } - #endif - #endif - PyErr_Format(PyExc_ValueError, - "only single character unicode strings can be converted to Py_UCS4, " - "got length %" CYTHON_FORMAT_SSIZE_T "d", length); - return (Py_UCS4)-1; -} - -/* CIntFromPy */ -static CYTHON_INLINE uint8_t __Pyx_PyInt_As_uint8_t(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const uint8_t neg_one = (uint8_t) -1, const_zero = (uint8_t) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { - if (sizeof(uint8_t) < sizeof(long)) { - __PYX_VERIFY_RETURN_INT(uint8_t, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } - return (uint8_t) val; - } - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (uint8_t) 0; - case 1: __PYX_VERIFY_RETURN_INT(uint8_t, digit, digits[0]) - case 2: - if (8 * sizeof(uint8_t) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) >= 2 * PyLong_SHIFT) { - return (uint8_t) (((((uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0])); - } - } - break; - case 3: - if (8 * sizeof(uint8_t) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) >= 3 * PyLong_SHIFT) { - return (uint8_t) (((((((uint8_t)digits[2]) << PyLong_SHIFT) | (uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0])); - } - } - break; - case 4: - if (8 * sizeof(uint8_t) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) >= 4 * PyLong_SHIFT) { - return (uint8_t) (((((((((uint8_t)digits[3]) << PyLong_SHIFT) | (uint8_t)digits[2]) << PyLong_SHIFT) | (uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0])); - } - } - break; - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (uint8_t) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if (sizeof(uint8_t) <= sizeof(unsigned long)) { - __PYX_VERIFY_RETURN_INT_EXC(uint8_t, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(uint8_t) <= sizeof(unsigned PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(uint8_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (uint8_t) 0; - case -1: __PYX_VERIFY_RETURN_INT(uint8_t, sdigit, (sdigit) (-(sdigit)digits[0])) - case 1: __PYX_VERIFY_RETURN_INT(uint8_t, digit, +digits[0]) - case -2: - if (8 * sizeof(uint8_t) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) - 1 > 2 * PyLong_SHIFT) { - return (uint8_t) (((uint8_t)-1)*(((((uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0]))); - } - } - break; - case 2: - if (8 * sizeof(uint8_t) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) - 1 > 2 * PyLong_SHIFT) { - return (uint8_t) ((((((uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0]))); - } - } - break; - case -3: - if (8 * sizeof(uint8_t) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) - 1 > 3 * PyLong_SHIFT) { - return (uint8_t) (((uint8_t)-1)*(((((((uint8_t)digits[2]) << PyLong_SHIFT) | (uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0]))); - } - } - break; - case 3: - if (8 * sizeof(uint8_t) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) - 1 > 3 * PyLong_SHIFT) { - return (uint8_t) ((((((((uint8_t)digits[2]) << PyLong_SHIFT) | (uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0]))); - } - } - break; - case -4: - if (8 * sizeof(uint8_t) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) - 1 > 4 * PyLong_SHIFT) { - return (uint8_t) (((uint8_t)-1)*(((((((((uint8_t)digits[3]) << PyLong_SHIFT) | (uint8_t)digits[2]) << PyLong_SHIFT) | (uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0]))); - } - } - break; - case 4: - if (8 * sizeof(uint8_t) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint8_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint8_t) - 1 > 4 * PyLong_SHIFT) { - return (uint8_t) ((((((((((uint8_t)digits[3]) << PyLong_SHIFT) | (uint8_t)digits[2]) << PyLong_SHIFT) | (uint8_t)digits[1]) << PyLong_SHIFT) | (uint8_t)digits[0]))); - } - } - break; - } -#endif - if (sizeof(uint8_t) <= sizeof(long)) { - __PYX_VERIFY_RETURN_INT_EXC(uint8_t, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(uint8_t) <= sizeof(PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(uint8_t, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { -#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -#else - uint8_t val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { - PyObject *tmp = v; - v = PyNumber_Long(tmp); - Py_DECREF(tmp); - } - #endif - if (likely(v)) { - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - int ret = _PyLong_AsByteArray((PyLongObject *)v, - bytes, sizeof(val), - is_little, !is_unsigned); - Py_DECREF(v); - if (likely(!ret)) - return val; - } -#endif - return (uint8_t) -1; - } - } else { - uint8_t val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); - if (!tmp) return (uint8_t) -1; - val = __Pyx_PyInt_As_uint8_t(tmp); - Py_DECREF(tmp); - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to uint8_t"); - return (uint8_t) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to uint8_t"); - return (uint8_t) -1; -} - -/* CIntFromPy */ -static CYTHON_INLINE uint64_t __Pyx_PyInt_As_uint64_t(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const uint64_t neg_one = (uint64_t) -1, const_zero = (uint64_t) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { - if (sizeof(uint64_t) < sizeof(long)) { - __PYX_VERIFY_RETURN_INT(uint64_t, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } - return (uint64_t) val; - } - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (uint64_t) 0; - case 1: __PYX_VERIFY_RETURN_INT(uint64_t, digit, digits[0]) - case 2: - if (8 * sizeof(uint64_t) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) >= 2 * PyLong_SHIFT) { - return (uint64_t) (((((uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0])); - } - } - break; - case 3: - if (8 * sizeof(uint64_t) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) >= 3 * PyLong_SHIFT) { - return (uint64_t) (((((((uint64_t)digits[2]) << PyLong_SHIFT) | (uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0])); - } - } - break; - case 4: - if (8 * sizeof(uint64_t) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) >= 4 * PyLong_SHIFT) { - return (uint64_t) (((((((((uint64_t)digits[3]) << PyLong_SHIFT) | (uint64_t)digits[2]) << PyLong_SHIFT) | (uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0])); - } - } - break; - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (uint64_t) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if (sizeof(uint64_t) <= sizeof(unsigned long)) { - __PYX_VERIFY_RETURN_INT_EXC(uint64_t, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(uint64_t) <= sizeof(unsigned PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(uint64_t, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (uint64_t) 0; - case -1: __PYX_VERIFY_RETURN_INT(uint64_t, sdigit, (sdigit) (-(sdigit)digits[0])) - case 1: __PYX_VERIFY_RETURN_INT(uint64_t, digit, +digits[0]) - case -2: - if (8 * sizeof(uint64_t) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) - 1 > 2 * PyLong_SHIFT) { - return (uint64_t) (((uint64_t)-1)*(((((uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0]))); - } - } - break; - case 2: - if (8 * sizeof(uint64_t) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) - 1 > 2 * PyLong_SHIFT) { - return (uint64_t) ((((((uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0]))); - } - } - break; - case -3: - if (8 * sizeof(uint64_t) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) - 1 > 3 * PyLong_SHIFT) { - return (uint64_t) (((uint64_t)-1)*(((((((uint64_t)digits[2]) << PyLong_SHIFT) | (uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0]))); - } - } - break; - case 3: - if (8 * sizeof(uint64_t) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) - 1 > 3 * PyLong_SHIFT) { - return (uint64_t) ((((((((uint64_t)digits[2]) << PyLong_SHIFT) | (uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0]))); - } - } - break; - case -4: - if (8 * sizeof(uint64_t) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) - 1 > 4 * PyLong_SHIFT) { - return (uint64_t) (((uint64_t)-1)*(((((((((uint64_t)digits[3]) << PyLong_SHIFT) | (uint64_t)digits[2]) << PyLong_SHIFT) | (uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0]))); - } - } - break; - case 4: - if (8 * sizeof(uint64_t) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(uint64_t, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(uint64_t) - 1 > 4 * PyLong_SHIFT) { - return (uint64_t) ((((((((((uint64_t)digits[3]) << PyLong_SHIFT) | (uint64_t)digits[2]) << PyLong_SHIFT) | (uint64_t)digits[1]) << PyLong_SHIFT) | (uint64_t)digits[0]))); - } - } - break; - } -#endif - if (sizeof(uint64_t) <= sizeof(long)) { - __PYX_VERIFY_RETURN_INT_EXC(uint64_t, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(uint64_t) <= sizeof(PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(uint64_t, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { -#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -#else - uint64_t val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { - PyObject *tmp = v; - v = PyNumber_Long(tmp); - Py_DECREF(tmp); - } - #endif - if (likely(v)) { - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - int ret = _PyLong_AsByteArray((PyLongObject *)v, - bytes, sizeof(val), - is_little, !is_unsigned); - Py_DECREF(v); - if (likely(!ret)) - return val; - } -#endif - return (uint64_t) -1; - } - } else { - uint64_t val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); - if (!tmp) return (uint64_t) -1; - val = __Pyx_PyInt_As_uint64_t(tmp); - Py_DECREF(tmp); - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to uint64_t"); - return (uint64_t) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to uint64_t"); - return (uint64_t) -1; -} - -/* CIntFromPy */ -static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { - if (sizeof(long) < sizeof(long)) { - __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } - return (long) val; - } - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (long) 0; - case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) - case 2: - if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { - return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: - if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { - return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: - if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { - return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if (sizeof(long) <= sizeof(unsigned long)) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (long) 0; - case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) - case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) - case -2: - if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: - if (8 * sizeof(long) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: - if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: - if (8 * sizeof(long) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: - if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: - if (8 * sizeof(long) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } -#endif - if (sizeof(long) <= sizeof(long)) { - __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { -#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -#else - long val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { - PyObject *tmp = v; - v = PyNumber_Long(tmp); - Py_DECREF(tmp); - } - #endif - if (likely(v)) { - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - int ret = _PyLong_AsByteArray((PyLongObject *)v, - bytes, sizeof(val), - is_little, !is_unsigned); - Py_DECREF(v); - if (likely(!ret)) - return val; - } -#endif - return (long) -1; - } - } else { - long val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); - if (!tmp) return (long) -1; - val = __Pyx_PyInt_As_long(tmp); - Py_DECREF(tmp); - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to long"); - return (long) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long) -1; -} - -/* CIntToPy */ -static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const int neg_one = (int) -1, const_zero = (int) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(int) < sizeof(long)) { - return PyInt_FromLong((long) value); - } else if (sizeof(int) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -#endif - } - } else { - if (sizeof(int) <= sizeof(long)) { - return PyInt_FromLong((long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); -#endif - } - } - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; - return _PyLong_FromByteArray(bytes, sizeof(int), - little, !is_unsigned); - } -} - -/* CIntToPy */ -static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { - return PyInt_FromLong((long) value); - } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -#endif - } - } else { - if (sizeof(long) <= sizeof(long)) { - return PyInt_FromLong((long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); -#endif - } - } - { - int one = 1; int little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&value; - return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); - } -} - -/* ObjectAsUCS4 */ -static Py_UCS4 __Pyx__PyObject_AsPy_UCS4_raise_error(long ival) { - if (ival < 0) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_OverflowError, - "cannot convert negative value to Py_UCS4"); - } else { - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to Py_UCS4"); - } - return (Py_UCS4)-1; -} -static Py_UCS4 __Pyx__PyObject_AsPy_UCS4(PyObject* x) { - long ival; - ival = __Pyx_PyInt_As_long(x); - if (unlikely(!__Pyx_is_valid_index(ival, 1114111 + 1))) { - return __Pyx__PyObject_AsPy_UCS4_raise_error(ival); - } - return (Py_UCS4)ival; -} - -/* CIntFromPy */ -static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const int neg_one = (int) -1, const_zero = (int) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x))) { - if (sizeof(int) < sizeof(long)) { - __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) - } else { - long val = PyInt_AS_LONG(x); - if (is_unsigned && unlikely(val < 0)) { - goto raise_neg_overflow; - } - return (int) val; - } - } else -#endif - if (likely(PyLong_Check(x))) { - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (int) 0; - case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) - case 2: - if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { - return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: - if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { - return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: - if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { - return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if (sizeof(int) <= sizeof(unsigned long)) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)x)->ob_digit; - switch (Py_SIZE(x)) { - case 0: return (int) 0; - case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) - case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) - case -2: - if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: - if (8 * sizeof(int) > 1 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: - if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: - if (8 * sizeof(int) > 2 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: - if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { - return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: - if (8 * sizeof(int) > 3 * PyLong_SHIFT) { - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { - return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } -#endif - if (sizeof(int) <= sizeof(long)) { - __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { - __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { -#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) - PyErr_SetString(PyExc_RuntimeError, - "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); -#else - int val; - PyObject *v = __Pyx_PyNumber_IntOrLong(x); - #if PY_MAJOR_VERSION < 3 - if (likely(v) && !PyLong_Check(v)) { - PyObject *tmp = v; - v = PyNumber_Long(tmp); - Py_DECREF(tmp); - } - #endif - if (likely(v)) { - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - int ret = _PyLong_AsByteArray((PyLongObject *)v, - bytes, sizeof(val), - is_little, !is_unsigned); - Py_DECREF(v); - if (likely(!ret)) - return val; - } -#endif - return (int) -1; - } - } else { - int val; - PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); - if (!tmp) return (int) -1; - val = __Pyx_PyInt_As_int(tmp); - Py_DECREF(tmp); - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to int"); - return (int) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to int"); - return (int) -1; -} - -/* FastTypeChecks */ -#if CYTHON_COMPILING_IN_CPYTHON -static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { - while (a) { - a = a->tp_base; - if (a == b) - return 1; - } - return b == &PyBaseObject_Type; -} -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (a == b) return 1; - mro = a->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(a, b); -} -#if PY_MAJOR_VERSION == 2 -static int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject* exc_type2) { - PyObject *exception, *value, *tb; - int res; - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ErrFetch(&exception, &value, &tb); - res = exc_type1 ? PyObject_IsSubclass(err, exc_type1) : 0; - if (unlikely(res == -1)) { - PyErr_WriteUnraisable(err); - res = 0; - } - if (!res) { - res = PyObject_IsSubclass(err, exc_type2); - if (unlikely(res == -1)) { - PyErr_WriteUnraisable(err); - res = 0; - } - } - __Pyx_ErrRestore(exception, value, tb); - return res; -} -#else -static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { - int res = exc_type1 ? __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type1) : 0; - if (!res) { - res = __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); - } - return res; -} -#endif -static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - assert(PyExceptionClass_Check(exc_type)); - n = PyTuple_GET_SIZE(tuple); -#if PY_MAJOR_VERSION >= 3 - for (i=0; i '9'); - break; - } - if (rt_from_call[i] != ctversion[i]) { - same = 0; - break; - } - } - if (!same) { - char rtversion[5] = {'\0'}; - char message[200]; - for (i=0; i<4; ++i) { - if (rt_from_call[i] == '.') { - if (found_dot) break; - found_dot = 1; - } else if (rt_from_call[i] < '0' || rt_from_call[i] > '9') { - break; - } - rtversion[i] = rt_from_call[i]; - } - PyOS_snprintf(message, sizeof(message), - "compiletime version %s of module '%.100s' " - "does not match runtime version %s", - ctversion, __Pyx_MODULE_NAME, rtversion); - return PyErr_WarnEx(NULL, message, 1); - } - return 0; -} - -/* InitStrings */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { - while (t->p) { - #if PY_MAJOR_VERSION < 3 - if (t->is_unicode) { - *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); - } else if (t->intern) { - *t->p = PyString_InternFromString(t->s); - } else { - *t->p = PyString_FromStringAndSize(t->s, t->n - 1); - } - #else - if (t->is_unicode | t->is_str) { - if (t->intern) { - *t->p = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); - } else { - *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - #endif - if (!*t->p) - return -1; - if (PyObject_Hash(*t->p) == -1) - return -1; - ++t; - } - return 0; -} - -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { - return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); -} -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { - Py_ssize_t ignore; - return __Pyx_PyObject_AsStringAndSize(o, &ignore); -} -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT -#if !CYTHON_PEP393_ENABLED -static const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { - char* defenc_c; - PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); - if (!defenc) return NULL; - defenc_c = PyBytes_AS_STRING(defenc); -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - { - char* end = defenc_c + PyBytes_GET_SIZE(defenc); - char* c; - for (c = defenc_c; c < end; c++) { - if ((unsigned char) (*c) >= 128) { - PyUnicode_AsASCIIString(o); - return NULL; - } - } - } -#endif - *length = PyBytes_GET_SIZE(defenc); - return defenc_c; -} -#else -static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { - if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - if (likely(PyUnicode_IS_ASCII(o))) { - *length = PyUnicode_GET_LENGTH(o); - return PyUnicode_AsUTF8(o); - } else { - PyUnicode_AsASCIIString(o); - return NULL; - } -#else - return PyUnicode_AsUTF8AndSize(o, length); -#endif -} -#endif -#endif -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT - if ( -#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - __Pyx_sys_getdefaultencoding_not_ascii && -#endif - PyUnicode_Check(o)) { - return __Pyx_PyUnicode_AsStringAndSize(o, length); - } else -#endif -#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) - if (PyByteArray_Check(o)) { - *length = PyByteArray_GET_SIZE(o); - return PyByteArray_AS_STRING(o); - } else -#endif - { - char* result; - int r = PyBytes_AsStringAndSize(o, &result, length); - if (unlikely(r < 0)) { - return NULL; - } else { - return result; - } - } -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - int is_true = x == Py_True; - if (is_true | (x == Py_False) | (x == Py_None)) return is_true; - else return PyObject_IsTrue(x); -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { - int retval; - if (unlikely(!x)) return -1; - retval = __Pyx_PyObject_IsTrue(x); - Py_DECREF(x); - return retval; -} -static PyObject* __Pyx_PyNumber_IntOrLongWrongResultType(PyObject* result, const char* type_name) { -#if PY_MAJOR_VERSION >= 3 - if (PyLong_Check(result)) { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__int__ returned non-int (type %.200s). " - "The ability to return an instance of a strict subclass of int " - "is deprecated, and may be removed in a future version of Python.", - Py_TYPE(result)->tp_name)) { - Py_DECREF(result); - return NULL; - } - return result; - } -#endif - PyErr_Format(PyExc_TypeError, - "__%.4s__ returned non-%.4s (type %.200s)", - type_name, type_name, Py_TYPE(result)->tp_name); - Py_DECREF(result); - return NULL; -} -static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { -#if CYTHON_USE_TYPE_SLOTS - PyNumberMethods *m; -#endif - const char *name = NULL; - PyObject *res = NULL; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_Check(x) || PyLong_Check(x))) -#else - if (likely(PyLong_Check(x))) -#endif - return __Pyx_NewRef(x); -#if CYTHON_USE_TYPE_SLOTS - m = Py_TYPE(x)->tp_as_number; - #if PY_MAJOR_VERSION < 3 - if (m && m->nb_int) { - name = "int"; - res = m->nb_int(x); - } - else if (m && m->nb_long) { - name = "long"; - res = m->nb_long(x); - } - #else - if (likely(m && m->nb_int)) { - name = "int"; - res = m->nb_int(x); - } - #endif -#else - if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { - res = PyNumber_Int(x); - } -#endif - if (likely(res)) { -#if PY_MAJOR_VERSION < 3 - if (unlikely(!PyInt_Check(res) && !PyLong_Check(res))) { -#else - if (unlikely(!PyLong_CheckExact(res))) { -#endif - return __Pyx_PyNumber_IntOrLongWrongResultType(res, name); - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject *x; -#if PY_MAJOR_VERSION < 3 - if (likely(PyInt_CheckExact(b))) { - if (sizeof(Py_ssize_t) >= sizeof(long)) - return PyInt_AS_LONG(b); - else - return PyInt_AsSsize_t(b); - } -#endif - if (likely(PyLong_CheckExact(b))) { - #if CYTHON_USE_PYLONG_INTERNALS - const digit* digits = ((PyLongObject*)b)->ob_digit; - const Py_ssize_t size = Py_SIZE(b); - if (likely(__Pyx_sst_abs(size) <= 1)) { - ival = likely(size) ? digits[0] : 0; - if (size == -1) ival = -ival; - return ival; - } else { - switch (size) { - case 2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - } - } - #endif - return PyLong_AsSsize_t(b); - } - x = PyNumber_Index(b); - if (!x) return -1; - ival = PyInt_AsSsize_t(x); - Py_DECREF(x); - return ival; -} -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { - if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { - return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); -#if PY_MAJOR_VERSION < 3 - } else if (likely(PyInt_CheckExact(o))) { - return PyInt_AS_LONG(o); -#endif - } else { - Py_ssize_t ival; - PyObject *x; - x = PyNumber_Index(o); - if (!x) return -1; - ival = PyInt_AsLong(x); - Py_DECREF(x); - return ival; - } -} -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); -} -static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { - return PyInt_FromSize_t(ival); -} - - -#endif /* Py_PYTHON_H */ diff --git a/yarl/_quoting_c.pyi b/yarl/_quoting_c.pyi index 1c8fc24..1dc1a5b 100644 --- a/yarl/_quoting_c.pyi +++ b/yarl/_quoting_c.pyi @@ -9,8 +9,10 @@ class _Quoter: qs: bool = ..., requote: bool = ... ) -> None: ... - def __call__(self, val: Optional[str] = ...) -> Optional[str]: ... + def __call__(self, val: str = ...) -> str: ... class _Unquoter: - def __init__(self, *, unsafe: str = ..., qs: bool = ...) -> None: ... - def __call__(self, val: Optional[str] = ...) -> Optional[str]: ... + def __init__( + self, *, ignore: str = ..., unsafe: str = ..., qs: bool = ... + ) -> None: ... + def __call__(self, val: str = ...) -> str: ... diff --git a/yarl/_quoting_c.pyx b/yarl/_quoting_c.pyx index 5335d17..6ac44fd 100644 --- a/yarl/_quoting_c.pyx +++ b/yarl/_quoting_c.pyx @@ -145,7 +145,7 @@ cdef inline int _write_utf8(Writer* writer, Py_UCS4 symbol): if _write_pct(writer, (0xe0 | (utf >> 12)), True) < 0: return -1 if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - True) < 0: + True) < 0: return -1 return _write_pct(writer, (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, (0xf0 | (utf >> 18)), True) < 0: return -1 if _write_pct(writer, (0x80 | ((utf >> 12) & 0x3f)), - True) < 0: - return -1 + True) < 0: + return -1 if _write_pct(writer, (0x80 | ((utf >> 6) & 0x3f)), - True) < 0: + True) < 0: return -1 return _write_pct(writer, (0x80 | (utf & 0x3f)), True) @@ -269,12 +269,14 @@ cdef class _Quoter: cdef class _Unquoter: + cdef str _ignore cdef str _unsafe cdef bint _qs cdef _Quoter _quoter cdef _Quoter _qs_quoter - def __init__(self, *, unsafe='', qs=False): + def __init__(self, *, ignore="", unsafe="", qs=False): + self._ignore = ignore self._unsafe = unsafe self._qs = qs self._quoter = _Quoter() @@ -336,7 +338,7 @@ cdef class _Unquoter: buflen = 0 if self._qs and unquoted in '+=&;': ret.append(self._qs_quoter(unquoted)) - elif unquoted in self._unsafe: + elif unquoted in self._unsafe or unquoted in self._ignore: ret.append(self._quoter(unquoted)) else: ret.append(unquoted) diff --git a/yarl/_quoting_py.py b/yarl/_quoting_py.py index 585a1da..e5b1d3a 100644 --- a/yarl/_quoting_py.py +++ b/yarl/_quoting_py.py @@ -1,7 +1,7 @@ import codecs import re from string import ascii_letters, ascii_lowercase, digits -from typing import Optional, cast +from typing import cast BASCII_LOWERCASE = ascii_lowercase.encode("ascii") BPCT_ALLOWED = {f"%{i:02X}".encode("ascii") for i in range(256)} @@ -33,14 +33,14 @@ def __init__( self._qs = qs self._requote = requote - def __call__(self, val: Optional[str]) -> Optional[str]: + def __call__(self, val: str) -> str: if val is None: return None if not isinstance(val, str): raise TypeError("Argument should be str") if not val: return "" - bval = cast(str, val).encode("utf8", errors="ignore") + bval = val.encode("utf8", errors="ignore") ret = bytearray() pct = bytearray() safe = self._safe @@ -116,13 +116,14 @@ def __call__(self, val: Optional[str]) -> Optional[str]: class _Unquoter: - def __init__(self, *, unsafe: str = "", qs: bool = False) -> None: + def __init__(self, *, ignore: str = "", unsafe: str = "", qs: bool = False) -> None: + self._ignore = ignore self._unsafe = unsafe self._qs = qs self._quoter = _Quoter() self._qs_quoter = _Quoter(qs=True) - def __call__(self, val: Optional[str]) -> Optional[str]: + def __call__(self, val: str) -> str: if val is None: return None if not isinstance(val, str): @@ -158,7 +159,7 @@ def __call__(self, val: Optional[str]) -> Optional[str]: if to_add is None: # pragma: no cover raise RuntimeError("Cannot quote None") ret.append(to_add) - elif unquoted in self._unsafe: + elif unquoted in self._unsafe or unquoted in self._ignore: to_add = self._quoter(unquoted) if to_add is None: # pragma: no cover raise RuntimeError("Cannot quote None") diff --git a/yarl/_url.py b/yarl/_url.py index dfcff2e..65a91bb 100644 --- a/yarl/_url.py +++ b/yarl/_url.py @@ -1,54 +1,162 @@ -import functools import math +import re +import sys import warnings from collections.abc import Mapping, Sequence +from contextlib import suppress +from functools import _CacheInfo, lru_cache from ipaddress import ip_address -from urllib.parse import SplitResult, parse_qsl, quote, urljoin, urlsplit, urlunsplit +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Iterable, + Iterator, + List, + SupportsInt, + Tuple, + TypedDict, + TypeVar, + Union, + overload, +) +from urllib.parse import ( + SplitResult, + parse_qsl, + quote, + urlsplit, + urlunsplit, + uses_netloc, + uses_relative, +) import idna -from multidict import MultiDict, MultiDictProxy +from multidict import MultiDict, MultiDictProxy, istr +from ._helpers import cached_property from ._quoting import _Quoter, _Unquoter -DEFAULT_PORTS = {"http": 80, "https": 443, "ws": 80, "wss": 443} +DEFAULT_PORTS = {"http": 80, "https": 443, "ws": 80, "wss": 443, "ftp": 21} +USES_AUTHORITY = frozenset(uses_netloc) +USES_RELATIVE = frozenset(uses_relative) -sentinel = object() +# Special schemes https://url.spec.whatwg.org/#special-scheme +# are not allowed to have an empty host https://url.spec.whatwg.org/#url-representation +SCHEME_REQUIRES_HOST = frozenset(("http", "https", "ws", "wss", "ftp")) +sentinel = object() -def rewrite_module(obj: object) -> object: +# reg-name: unreserved / pct-encoded / sub-delims +# this pattern matches anything that is *not* in those classes. and is only used +# on lower-cased ASCII values. +_not_reg_name = re.compile( + r""" + # any character not in the unreserved or sub-delims sets, plus % + # (validated with the additional check for pct-encoded sequences below) + [^a-z0-9\-._~!$&'()*+,;=%] + | + # % only allowed if it is part of a pct-encoded + # sequence of 2 hex digits. + %(?![0-9a-f]{2}) + """, + re.VERBOSE, +) + +SimpleQuery = Union[str, int, float] +QueryVariable = Union[SimpleQuery, "Sequence[SimpleQuery]"] +Query = Union[ + None, str, "Mapping[str, QueryVariable]", "Sequence[Tuple[str, QueryVariable]]" +] +_T = TypeVar("_T") + +if sys.version_info >= (3, 11): + from typing import Self +else: + Self = Any + + +class CacheInfo(TypedDict): + """Host encoding cache.""" + + idna_encode: _CacheInfo + idna_decode: _CacheInfo + ip_address: _CacheInfo + host_validate: _CacheInfo + + +class _SplitResultDict(TypedDict, total=False): + + scheme: str + netloc: str + path: str + query: str + fragment: str + + +class _InternalURLCache(TypedDict, total=False): + + absolute: bool + scheme: str + raw_authority: str + _default_port: Union[int, None] + _port_not_default: Union[int, None] + authority: str + raw_user: Union[str, None] + user: Union[str, None] + raw_password: Union[str, None] + password: Union[str, None] + raw_host: Union[str, None] + host: Union[str, None] + port: Union[int, None] + explicit_port: Union[int, None] + raw_path: str + path: str + _parsed_query: List[Tuple[str, str]] + query: "MultiDictProxy[str]" + raw_query_string: str + query_string: str + path_qs: str + raw_path_qs: str + raw_fragment: str + fragment: str + raw_parts: Tuple[str, ...] + parts: Tuple[str, ...] + parent: "URL" + raw_name: str + name: str + raw_suffix: str + suffix: str + raw_suffixes: Tuple[str, ...] + suffixes: Tuple[str, ...] + + +def rewrite_module(obj: _T) -> _T: obj.__module__ = "yarl" return obj -class cached_property: - """Use as a class method decorator. It operates almost exactly like - the Python `@property` decorator, but it puts the result of the - method it decorates into the instance dict after the first call, - effectively replacing the function it decorates with an instance - variable. It is, in Python parlance, a data descriptor. +def _normalize_path_segments(segments: "Sequence[str]") -> List[str]: + """Drop '.' and '..' from a sequence of str segments""" - """ + resolved_path: List[str] = [] - def __init__(self, wrapped): - self.wrapped = wrapped - try: - self.__doc__ = wrapped.__doc__ - except AttributeError: # pragma: no cover - self.__doc__ = "" - self.name = wrapped.__name__ + for seg in segments: + if seg == "..": + # ignore any .. segments that would otherwise cause an + # IndexError when popped from resolved_path if + # resolving for rfc3986 + with suppress(IndexError): + resolved_path.pop() + elif seg != ".": + resolved_path.append(seg) - def __get__(self, inst, owner, _sentinel=sentinel): - if inst is None: - return self - val = inst._cache.get(self.name, _sentinel) - if val is not _sentinel: - return val - val = self.wrapped(inst) - inst._cache[self.name] = val - return val + if segments and segments[-1] in (".", ".."): + # do some post-processing here. + # if the last segment was a relative dir, + # then we need to append the trailing '/' + resolved_path.append("") - def __set__(self, inst, value): - raise AttributeError("cached property is read-only") + return resolved_path @rewrite_module @@ -136,9 +244,18 @@ class URL: _UNQUOTER = _Unquoter() _PATH_UNQUOTER = _Unquoter(unsafe="+") + _PATH_SAFE_UNQUOTER = _Unquoter(ignore="/%", unsafe="+") _QS_UNQUOTER = _Unquoter(qs=True) - def __new__(cls, val="", *, encoded=False, strict=None): + _val: SplitResult + + def __new__( + cls, + val: Union[str, SplitResult, "URL"] = "", + *, + encoded: bool = False, + strict: Union[bool, None] = None, + ) -> Self: if strict is not None: # pragma: no cover warnings.warn("strict parameter is ignored") if type(val) is cls: @@ -153,61 +270,83 @@ def __new__(cls, val="", *, encoded=False, strict=None): else: raise TypeError("Constructor parameter should be str") + cache: _InternalURLCache = {} if not encoded: - if not val[1]: # netloc - netloc = "" + host: Union[str, None] + scheme, netloc, path, query, fragment = val + if not netloc: # netloc host = "" else: - host = val.hostname + username, password, host, port = cls._split_netloc(val[1]) if host is None: - raise ValueError("Invalid URL: host is required for absolute urls") - - try: - port = val.port - except ValueError as e: - raise ValueError( - "Invalid URL: port can't be converted to integer" - ) from e - + if scheme in SCHEME_REQUIRES_HOST: + msg = ( + "Invalid URL: host is required for " + f"absolute urls with the {scheme} scheme" + ) + raise ValueError(msg) + else: + host = "" + host = cls._encode_host(host, validate_host=False) + raw_user = None if username is None else cls._REQUOTER(username) + raw_password = None if password is None else cls._REQUOTER(password) netloc = cls._make_netloc( - val.username, val.password, host, port, encode=True, requote=True + raw_user, raw_password, host, port, encode_host=False ) - path = cls._PATH_REQUOTER(val[2]) - if netloc: - path = cls._normalize_path(path) + if "[" in host: + # Our host encoder adds back brackets for IPv6 addresses + # so we need to remove them here to get the raw host + _, _, bracketed = host.partition("[") + raw_host, _, _ = bracketed.partition("]") + else: + raw_host = host + cache["raw_host"] = raw_host + cache["raw_user"] = raw_user + cache["raw_password"] = raw_password + cache["explicit_port"] = port + + if path: + path = cls._PATH_REQUOTER(path) + if netloc: + path = cls._normalize_path(path) cls._validate_authority_uri_abs_path(host=host, path=path) - query = cls._QUERY_REQUOTER(val[3]) - fragment = cls._FRAGMENT_REQUOTER(val[4]) - val = SplitResult(val[0], netloc, path, query, fragment) + query = cls._QUERY_REQUOTER(query) if query else query + fragment = cls._FRAGMENT_REQUOTER(fragment) if fragment else fragment + cache["scheme"] = scheme + cache["raw_query_string"] = query + cache["raw_fragment"] = fragment + val = SplitResult(scheme, netloc, path, query, fragment) self = object.__new__(cls) self._val = val - self._cache = {} + self._cache = cache return self @classmethod def build( cls, *, - scheme="", - authority="", - user=None, - password=None, - host="", - port=None, - path="", - query=None, - query_string="", - fragment="", - encoded=False, - ): + scheme: str = "", + authority: str = "", + user: Union[str, None] = None, + password: Union[str, None] = None, + host: str = "", + port: Union[int, None] = None, + path: str = "", + query: Union[Query, None] = None, + query_string: str = "", + fragment: str = "", + encoded: bool = False, + ) -> "URL": """Creates and returns a new URL""" if authority and (user or password or host or port): 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: @@ -215,12 +354,13 @@ def build( if ( scheme is None or authority is None + or host is None or path is None or query_string is None or fragment is None ): raise TypeError( - 'NoneType is illegal for "scheme", "authority", "path", ' + 'NoneType is illegal for "scheme", "authority", "host", "path", ' '"query_string", and "fragment" args, use empty string instead.' ) @@ -228,24 +368,33 @@ def build( if encoded: netloc = authority else: - tmp = SplitResult("", authority, "", "", "") + _user, _password, _host, _port = cls._split_netloc(authority) + port = None if _port == DEFAULT_PORTS.get(scheme) else _port + _host = ( + "" + if _host is None + else cls._encode_host(_host, validate_host=False) + ) netloc = cls._make_netloc( - tmp.username, tmp.password, tmp.hostname, tmp.port, encode=True + _user, _password, _host, port, encode=True, encode_host=False ) elif not user and not password and not host and not port: netloc = "" else: + port = None if port == DEFAULT_PORTS.get(scheme) else port 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: + path = cls._PATH_QUOTER(path) if path else path + if path and netloc: path = cls._normalize_path(path) cls._validate_authority_uri_abs_path(host=host, path=path) - query_string = cls._QUERY_QUOTER(query_string) - fragment = cls._FRAGMENT_QUOTER(fragment) + query_string = ( + cls._QUERY_QUOTER(query_string) if query_string else query_string + ) + fragment = cls._FRAGMENT_QUOTER(fragment) if fragment else fragment url = cls( SplitResult(scheme, netloc, path, query_string, fragment), encoded=True @@ -253,89 +402,84 @@ def build( if query: return url.with_query(query) - else: - return url + return url def __init_subclass__(cls): raise TypeError(f"Inheriting a class {cls!r} from URL is forbidden") - def __str__(self): + def __str__(self) -> str: val = self._val - if not val.path and self.is_absolute() and (val.query or val.fragment): + if not val.path and self.absolute and (val.query or val.fragment): val = val._replace(path="/") + if (port := self._port_not_default) is None: + # port normalization - using None for default ports to remove from rendering + # https://datatracker.ietf.org/doc/html/rfc3986.html#section-6.2.3 + val = val._replace( + netloc=self._make_netloc( + self.raw_user, + self.raw_password, + self.host_subcomponent, + port, + encode_host=False, + ) + ) return urlunsplit(val) - def __repr__(self): + def __repr__(self) -> str: return f"{self.__class__.__name__}('{str(self)}')" - def __bytes__(self): + def __bytes__(self) -> bytes: return str(self).encode("ascii") - def __eq__(self, other): - if not type(other) is URL: + def __eq__(self, other: object) -> bool: + if type(other) is not URL: return NotImplemented val1 = self._val - if not val1.path and self.is_absolute(): + if not val1.path and self.absolute: val1 = val1._replace(path="/") val2 = other._val - if not val2.path and other.is_absolute(): + if not val2.path and other.absolute: val2 = val2._replace(path="/") return val1 == val2 - def __hash__(self): + def __hash__(self) -> int: ret = self._cache.get("hash") if ret is None: val = self._val - if not val.path and self.is_absolute(): + if not val.path and self.absolute: val = val._replace(path="/") ret = self._cache["hash"] = hash(val) return ret - def __le__(self, other): - if not type(other) is URL: + def __le__(self, other: object) -> bool: + if type(other) is not URL: return NotImplemented return self._val <= other._val - def __lt__(self, other): - if not type(other) is URL: + def __lt__(self, other: object) -> bool: + if type(other) is not URL: return NotImplemented return self._val < other._val - def __ge__(self, other): - if not type(other) is URL: + def __ge__(self, other: object) -> bool: + if type(other) is not URL: return NotImplemented return self._val >= other._val - def __gt__(self, other): - if not type(other) is URL: + def __gt__(self, other: object) -> bool: + if type(other) is not URL: return NotImplemented return self._val > other._val - def __truediv__(self, name): - name = self._PATH_QUOTER(name) - if name.startswith("/"): - raise ValueError( - f"Appending path {name!r} starting from slash is forbidden" - ) - path = self._val.path - if path == "/": - new_path = "/" + name - elif not path and not self.is_absolute(): - new_path = name - else: - parts = path.rstrip("/").split("/") - parts.append(name) - new_path = "/".join(parts) - if self.is_absolute(): - new_path = self._normalize_path(new_path) - return URL( - self._val._replace(path=new_path, query="", fragment=""), encoded=True - ) + def __truediv__(self, name: str) -> "URL": + if not isinstance(name, str): + return NotImplemented + return self._make_child((str(name),)) - def __mod__(self, query): + def __mod__(self, query: Query) -> "URL": return self.update_query(query) def __bool__(self) -> bool: @@ -343,7 +487,7 @@ def __bool__(self) -> bool: self._val.netloc or self._val.path or self._val.query or self._val.fragment ) - def __getstate__(self): + def __getstate__(self) -> Tuple[SplitResult]: return (self._val,) def __setstate__(self, state): @@ -354,38 +498,52 @@ def __setstate__(self, state): self._val, *unused = state self._cache = {} - def is_absolute(self): + def _cache_netloc(self) -> None: + """Cache the netloc parts of the URL.""" + cache = self._cache + ( + cache["raw_user"], + cache["raw_password"], + cache["raw_host"], + cache["explicit_port"], + ) = self._split_netloc(self._val.netloc) + + def is_absolute(self) -> bool: """A check for absolute URLs. Return True for absolute ones (having scheme or starting with //), False otherwise. + Is is preferred to call the .absolute property instead + as it is cached. """ - return self.raw_host is not None + return self.absolute - def is_default_port(self): + def is_default_port(self) -> bool: """A check for default port. Return True if port is default for specified scheme, e.g. 'http://python.org' or 'http://python.org:80', False otherwise. + Return False for relative URLs. + """ - if self.port is None: - return False - default = DEFAULT_PORTS.get(self.scheme) - if default is None: - return False - return self.port == default - - def origin(self): + default = self._default_port + explicit = self.explicit_port + if explicit is None: + # A relative URL does not have an implicit port / default port + return default is not None + return explicit == default + + def origin(self) -> "URL": """Return an URL with scheme, host and port parts only. user, password, path, query and fragment are removed. """ # TODO: add a keyword-only option for keeping user/pass maybe? - if not self.is_absolute(): + if not self.absolute: raise ValueError("URL should be absolute") if not self._val.scheme: raise ValueError("URL should have scheme") @@ -394,19 +552,33 @@ def origin(self): val = v._replace(netloc=netloc, path="", query="", fragment="") return URL(val, encoded=True) - def relative(self): + def relative(self) -> "URL": """Return a relative part of the URL. scheme, user, password, host and port are removed. """ - if not self.is_absolute(): + if not self.absolute: raise ValueError("URL should be absolute") val = self._val._replace(scheme="", netloc="") return URL(val, encoded=True) - @property - def scheme(self): + @cached_property + def absolute(self) -> bool: + """A check for absolute URLs. + + Return True for absolute ones (having scheme or starting + with //), False otherwise. + + """ + # `netloc`` is an empty string for relative URLs + # Checking `netloc` is faster than checking `hostname` + # because `hostname` is a property that does some extra work + # to parse the host from the `netloc` + return self._val.netloc != "" + + @cached_property + def scheme(self) -> str: """Scheme for absolute URLs. Empty string for relative URLs or URLs starting with // @@ -414,8 +586,8 @@ def scheme(self): """ return self._val.scheme - @property - def raw_authority(self): + @cached_property + def raw_authority(self) -> str: """Encoded authority part of URL. Empty string for relative URLs. @@ -424,7 +596,20 @@ def raw_authority(self): return self._val.netloc @cached_property - def authority(self): + def _default_port(self) -> Union[int, None]: + """Default port for the scheme or None if not known.""" + return DEFAULT_PORTS.get(self.scheme) + + @cached_property + def _port_not_default(self) -> Union[int, None]: + """The port part of URL normalized to None if its the default port.""" + port = self.port + if self._default_port == port: + return None + return port + + @cached_property + def authority(self) -> str: """Decoded authority part of URL. Empty string for relative URLs. @@ -434,107 +619,135 @@ def authority(self): self.user, self.password, self.host, self.port, encode_host=False ) - @property - def raw_user(self): + @cached_property + def raw_user(self) -> Union[str, None]: """Encoded user part of URL. None if user is missing. """ # not .username - ret = self._val.username - if not ret: - return None - return ret + self._cache_netloc() + return self._cache["raw_user"] @cached_property - def user(self): + def user(self) -> Union[str, None]: """Decoded user part of URL. None if user is missing. """ - return self._UNQUOTER(self.raw_user) + raw_user = self.raw_user + if raw_user is None: + return None + return self._UNQUOTER(raw_user) - @property - def raw_password(self): + @cached_property + def raw_password(self) -> Union[str, None]: """Encoded password part of URL. None if password is missing. """ - return self._val.password + self._cache_netloc() + return self._cache["raw_password"] @cached_property - def password(self): + def password(self) -> Union[str, None]: """Decoded password part of URL. None if password is missing. """ - return self._UNQUOTER(self.raw_password) + raw_password = self.raw_password + if raw_password is None: + return None + return self._UNQUOTER(raw_password) - @property - def raw_host(self): + @cached_property + def raw_host(self) -> Union[str, None]: """Encoded host part of URL. None for relative URLs. + When working with IPv6 addresses, use the `host_subcomponent` property instead + as it will return the host subcomponent with brackets. """ # Use host instead of hostname for sake of shortness # May add .hostname prop later - return self._val.hostname + self._cache_netloc() + return self._cache["raw_host"] @cached_property - def host(self): + def host(self) -> Union[str, None]: """Decoded host part of URL. None for relative URLs. """ - raw = self.raw_host - if raw is None: + if (raw := self.raw_host) is None: return None - if "%" in raw: - # Hack for scoped IPv6 addresses like - # fe80::2%Проверка - # presence of '%' sign means only IPv6 address, so idna is useless. + if raw and raw[-1].isdigit() or ":" in raw: + # IP addresses are never IDNA encoded return raw return _idna_decode(raw) - @property - def port(self): + @cached_property + def host_subcomponent(self) -> Union[str, None]: + """Return the host subcomponent part of URL. + + None for relative URLs. + + https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2 + + `IP-literal = "[" ( IPv6address / IPvFuture ) "]"` + + Examples: + - `http://example.com:8080` -> `example.com` + - `http://example.com:80` -> `example.com` + - `https://127.0.0.1:8443` -> `127.0.0.1` + - `https://[::1]:8443` -> `[::1]` + - `http://[::1]` -> `[::1]` + + """ + if (raw := self.raw_host) is None: + return None + return f"[{raw}]" if ":" in raw else raw + + @cached_property + def port(self) -> Union[int, None]: """Port part of URL, with scheme-based fallback. None for relative URLs or URLs without explicit port and scheme without default port substitution. """ - return self._val.port or DEFAULT_PORTS.get(self._val.scheme) + return self.explicit_port or self._default_port - @property - def explicit_port(self): + @cached_property + def explicit_port(self) -> Union[int, None]: """Port part of URL, without scheme-based fallback. None for relative URLs or URLs without explicit port. """ - return self._val.port + self._cache_netloc() + return self._cache["explicit_port"] - @property - def raw_path(self): + @cached_property + def raw_path(self) -> str: """Encoded path of URL. / for absolute URLs without path part. """ ret = self._val.path - if not ret and self.is_absolute(): + if not ret and self.absolute: ret = "/" return ret @cached_property - def path(self): + def path(self) -> str: """Decoded path of URL. / for absolute URLs without path part. @@ -543,18 +756,33 @@ def path(self): return self._PATH_UNQUOTER(self.raw_path) @cached_property - def query(self): + def path_safe(self) -> str: + """Decoded path of URL. + + / for absolute URLs without path part. + + / (%2F) and % (%25) are not decoded + + """ + return self._PATH_SAFE_UNQUOTER(self.raw_path) + + @cached_property + def _parsed_query(self) -> List[Tuple[str, str]]: + """Parse query part of URL.""" + return parse_qsl(self.raw_query_string, keep_blank_values=True) + + @cached_property + def query(self) -> "MultiDictProxy[str]": """A MultiDictProxy representing parsed query parameters in decoded representation. Empty value if URL has no query part. """ - ret = MultiDict(parse_qsl(self.raw_query_string, keep_blank_values=True)) - return MultiDictProxy(ret) + return MultiDictProxy(MultiDict(self._parsed_query)) - @property - def raw_query_string(self): + @cached_property + def raw_query_string(self) -> str: """Encoded query part of URL. Empty string if query is missing. @@ -563,7 +791,7 @@ def raw_query_string(self): return self._val.query @cached_property - def query_string(self): + def query_string(self) -> str: """Decoded query part of URL. Empty string if query is missing. @@ -572,21 +800,21 @@ def query_string(self): return self._QS_UNQUOTER(self.raw_query_string) @cached_property - def path_qs(self): + def path_qs(self) -> str: """Decoded path of URL with query.""" if not self.query_string: return self.path return f"{self.path}?{self.query_string}" @cached_property - def raw_path_qs(self): + def raw_path_qs(self) -> str: """Encoded path of URL with query.""" if not self.raw_query_string: return self.raw_path return f"{self.raw_path}?{self.raw_query_string}" - @property - def raw_fragment(self): + @cached_property + def raw_fragment(self) -> str: """Encoded fragment part of URL. Empty string if fragment is missing. @@ -595,7 +823,7 @@ def raw_fragment(self): return self._val.fragment @cached_property - def fragment(self): + def fragment(self) -> str: """Decoded fragment part of URL. Empty string if fragment is missing. @@ -604,27 +832,27 @@ def fragment(self): return self._UNQUOTER(self.raw_fragment) @cached_property - def raw_parts(self): + def raw_parts(self) -> Tuple[str, ...]: """A tuple containing encoded *path* parts. ('/',) for absolute URLs if *path* is missing. """ path = self._val.path - if self.is_absolute(): + if self.absolute: if not path: parts = ["/"] else: parts = ["/"] + path[1:].split("/") else: - if path.startswith("/"): + if path and path[0] == "/": parts = ["/"] + path[1:].split("/") else: parts = path.split("/") return tuple(parts) @cached_property - def parts(self): + def parts(self) -> Tuple[str, ...]: """A tuple containing decoded *path* parts. ('/',) for absolute URLs if *path* is missing. @@ -633,7 +861,7 @@ def parts(self): return tuple(self._UNQUOTER(part) for part in self.raw_parts) @cached_property - def parent(self): + def parent(self) -> "URL": """A new URL with last part of path removed and cleaned up query and fragment. @@ -648,10 +876,10 @@ def parent(self): return URL(val, encoded=True) @cached_property - def raw_name(self): + def raw_name(self) -> str: """The last part of raw_parts.""" parts = self.raw_parts - if self.is_absolute(): + if self.absolute: parts = parts[1:] if not parts: return "" @@ -661,12 +889,12 @@ def raw_name(self): return parts[-1] @cached_property - def name(self): + def name(self) -> str: """The last part of parts.""" return self._UNQUOTER(self.raw_name) @cached_property - def raw_suffix(self): + def raw_suffix(self) -> str: name = self.raw_name i = name.rfind(".") if 0 < i < len(name) - 1: @@ -675,11 +903,11 @@ def raw_suffix(self): return "" @cached_property - def suffix(self): + def suffix(self) -> str: return self._UNQUOTER(self.raw_suffix) @cached_property - def raw_suffixes(self): + def raw_suffixes(self) -> Tuple[str, ...]: name = self.raw_name if name.endswith("."): return () @@ -687,82 +915,150 @@ def raw_suffixes(self): return tuple("." + suffix for suffix in name.split(".")[1:]) @cached_property - def suffixes(self): + def suffixes(self) -> Tuple[str, ...]: return tuple(self._UNQUOTER(suffix) for suffix in self.raw_suffixes) @staticmethod - def _validate_authority_uri_abs_path(host, path): + def _validate_authority_uri_abs_path(host: str, path: str) -> None: """Ensure that path in URL with authority starts with a leading slash. Raise ValueError if not. """ - if len(host) > 0 and len(path) > 0 and not path.startswith("/"): + if host and path and not path[0] == "/": raise ValueError( "Path in a URL with authority should start with a slash ('/') if set" ) + def _make_child(self, paths: "Sequence[str]", encoded: bool = False) -> "URL": + """ + add paths to self._val.path, accounting for absolute vs relative paths, + keep existing, but do not create new, empty segments + """ + parsed = [] + for idx, path in enumerate(reversed(paths)): + # empty segment of last is not removed + last = idx == 0 + if path and path[0] == "/": + raise ValueError( + f"Appending path {path!r} starting from slash is forbidden" + ) + path = path if encoded else self._PATH_QUOTER(path) + segments = list(reversed(path.split("/"))) + # remove trailing empty segment for all but the last path + segment_slice_start = int(not last and segments[0] == "") + parsed += segments[segment_slice_start:] + parsed.reverse() + + if self._val.path and (old_path_segments := self._val.path.split("/")): + old_path_cutoff = -1 if old_path_segments[-1] == "" else None + parsed = [*old_path_segments[:old_path_cutoff], *parsed] + + if self.absolute: + parsed = _normalize_path_segments(parsed) + if parsed and parsed[0] != "": + # inject a leading slash when adding a path to an absolute URL + # where there was none before + parsed = ["", *parsed] + new_path = "/".join(parsed) + return URL( + self._val._replace(path=new_path, query="", fragment=""), encoded=True + ) + @classmethod - def _normalize_path(cls, path): - # Drop '.' and '..' from path + def _normalize_path(cls, path: str) -> str: + # Drop '.' and '..' from str path + if "." not in path: + # No need to normalize if there are no '.' or '..' segments + return path + + prefix = "" + if path and path[0] == "/": + # preserve the "/" root element of absolute paths, copying it to the + # normalised output as per sections 5.2.4 and 6.2.2.3 of rfc3986. + prefix = "/" + path = path[1:] segments = path.split("/") - resolved_path = [] - - for seg in segments: - if seg == "..": - try: - resolved_path.pop() - except IndexError: - # ignore any .. segments that would otherwise cause an - # IndexError when popped from resolved_path if - # resolving for rfc3986 - pass - elif seg == ".": - continue - else: - resolved_path.append(seg) - - if segments[-1] in (".", ".."): - # do some post-processing here. - # if the last segment was a relative dir, - # then we need to append the trailing '/' - resolved_path.append("") - - return "/".join(resolved_path) + return prefix + "/".join(_normalize_path_segments(segments)) @classmethod - def _encode_host(cls, host, human=False): - try: - ip, sep, zone = host.partition("%") - ip = ip_address(ip) - except ValueError: - host = host.lower() - # IDNA encoding is slow, - # skip it for ASCII-only strings - # Don't move the check into _idna_encode() helper - # to reduce the cache size - if human or host.isascii(): - return host - host = _idna_encode(host) + def _encode_host( + cls, host: str, human: bool = False, validate_host: bool = True + ) -> str: + if "%" in host: + raw_ip, sep, zone = host.partition("%") else: - host = ip.compressed - if sep: - host += "%" + zone - if ip.version == 6: - host = "[" + host + "]" - return host + raw_ip = host + sep = zone = "" + + if raw_ip and raw_ip[-1].isdigit() or ":" in raw_ip: + # Might be an IP address, check it + # + # IP Addresses can look like: + # https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2 + # - 127.0.0.1 (last character is a digit) + # - 2001:db8::ff00:42:8329 (contains a colon) + # - 2001:db8::ff00:42:8329%eth0 (contains a colon) + # - [2001:db8::ff00:42:8329] (contains a colon -- brackets should + # have been removed before it gets here) + # Rare IP Address formats are not supported per: + # https://datatracker.ietf.org/doc/html/rfc3986#section-7.4 + # + # We try to avoid parsing IP addresses as much as possible + # since its orders of magnitude slower than almost any other operation + # this library does. + # + # IP parsing is slow, so its wrapped in an LRU + try: + ip_compressed_version = _ip_compressed_version(raw_ip) + except ValueError: + pass + else: + # These checks should not happen in the + # LRU to keep the cache size small + host, version = ip_compressed_version + if sep: + host += "%" + zone + if version == 6: + return f"[{host}]" + return host + + host = host.lower() + if human: + return host + + # IDNA encoding is slow, + # skip it for ASCII-only strings + # Don't move the check into _idna_encode() helper + # to reduce the cache size + if host.isascii(): + # Check for invalid characters explicitly; _idna_encode() does this + # for non-ascii host names. + if validate_host: + _host_validate(host) + return host + return _idna_encode(host) @classmethod def _make_netloc( - cls, user, password, host, port, encode=False, encode_host=True, requote=False - ): + cls, + user: Union[str, None], + password: Union[str, None], + host: Union[str, None], + port: Union[int, None], + encode: bool = False, + encode_host: bool = True, + requote: bool = False, + ) -> str: + if host is None: + return "" quoter = cls._REQUOTER if requote else cls._QUOTER if encode_host: ret = cls._encode_host(host) else: ret = host - if port: - ret = ret + ":" + str(port) + if port is not None: + ret = f"{ret}:{port}" if password is not None: if not user: user = "" @@ -778,16 +1074,56 @@ def _make_netloc( ret = user + "@" + ret return ret - def with_scheme(self, scheme): + @classmethod + @lru_cache # match the same size as urlsplit + def _split_netloc( + cls, + netloc: str, + ) -> Tuple[Union[str, None], Union[str, None], Union[str, None], Union[int, None]]: + """Split netloc into username, password, host and port.""" + if "@" not in netloc: + username: Union[str, None] = None + password: Union[str, None] = None + hostinfo = netloc + else: + userinfo, _, hostinfo = netloc.rpartition("@") + username, have_password, password = userinfo.partition(":") + if not have_password: + password = None + + if "[" in hostinfo: + _, _, bracketed = hostinfo.partition("[") + hostname, _, port_str = bracketed.partition("]") + _, _, port_str = port_str.partition(":") + else: + hostname, _, port_str = hostinfo.partition(":") + + if not port_str: + port: Union[int, None] = None + else: + try: + port = int(port_str) + except ValueError: + raise ValueError("Invalid URL: port can't be converted to integer") + if not (0 <= port <= 65535): + raise ValueError("Port out of range 0-65535") + + return username or None, password, hostname or None, port + + def with_scheme(self, scheme: str) -> "URL": """Return a new URL with scheme replaced.""" # N.B. doesn't cleanup query/fragment if not isinstance(scheme, str): raise TypeError("Invalid scheme type") - if not self.is_absolute(): - raise ValueError("scheme replacement is not allowed for relative URLs") + if not self.absolute and scheme in SCHEME_REQUIRES_HOST: + msg = ( + "scheme replacement is not allowed for " + f"relative URLs for the {scheme} scheme" + ) + raise ValueError(msg) return URL(self._val._replace(scheme=scheme.lower()), encoded=True) - def with_user(self, user): + def with_user(self, user: Union[str, None]) -> "URL": """Return a new URL with user replaced. Autoencode user if needed. @@ -804,7 +1140,7 @@ def with_user(self, user): password = val.password else: raise TypeError("Invalid user type") - if not self.is_absolute(): + if not self.absolute: raise ValueError("user replacement is not allowed for relative URLs") return URL( self._val._replace( @@ -813,7 +1149,7 @@ def with_user(self, user): encoded=True, ) - def with_password(self, password): + def with_password(self, password: Union[str, None]) -> "URL": """Return a new URL with password replaced. Autoencode password if needed. @@ -828,7 +1164,7 @@ def with_password(self, password): password = self._QUOTER(password) else: raise TypeError("Invalid password type") - if not self.is_absolute(): + if not self.absolute: raise ValueError("password replacement is not allowed for relative URLs") val = self._val return URL( @@ -838,7 +1174,7 @@ def with_password(self, password): encoded=True, ) - def with_host(self, host): + def with_host(self, host: str) -> "URL": """Return a new URL with host replaced. Autoencode host if needed. @@ -850,7 +1186,7 @@ def with_host(self, host): # N.B. doesn't cleanup query/fragment if not isinstance(host, str): raise TypeError("Invalid host type") - if not self.is_absolute(): + if not self.absolute: raise ValueError("host replacement is not allowed for relative URLs") if not host: raise ValueError("host removing is not allowed") @@ -862,16 +1198,19 @@ def with_host(self, host): encoded=True, ) - def with_port(self, port): + def with_port(self, port: Union[int, None]) -> "URL": """Return a new URL with port replaced. Clear port to default if None is passed. """ # N.B. doesn't cleanup query/fragment - if port is not None and not isinstance(port, int): - raise TypeError(f"port should be int or None, got {type(port)}") - if not self.is_absolute(): + if port is not None: + if isinstance(port, bool) or not isinstance(port, int): + raise TypeError(f"port should be int or None, got {type(port)}") + if port < 0 or port > 65535: + raise ValueError(f"port must be between 0 and 65535, got {port}") + if not self.absolute: raise ValueError("port replacement is not allowed for relative URLs") val = self._val return URL( @@ -881,18 +1220,20 @@ def with_port(self, port): encoded=True, ) - def with_path(self, path, *, encoded=False): + def with_path(self, path: str, *, encoded: bool = False) -> "URL": """Return a new URL with path replaced.""" if not encoded: path = self._PATH_QUOTER(path) - if self.is_absolute(): + if self.absolute: path = self._normalize_path(path) if len(path) > 0 and path[0] != "/": path = "/" + path return URL(self._val._replace(path=path, query="", fragment=""), encoded=True) @classmethod - def _query_seq_pairs(cls, quoter, pairs): + def _query_seq_pairs( + cls, quoter: Callable[[str], str], pairs: Iterable[Tuple[str, QueryVariable]] + ) -> Iterator[str]: for key, val in pairs: if isinstance(val, (list, tuple)): for v in val: @@ -901,17 +1242,21 @@ def _query_seq_pairs(cls, quoter, pairs): yield quoter(key) + "=" + quoter(cls._query_var(val)) @staticmethod - def _query_var(v): + def _query_var(v: QueryVariable) -> str: cls = type(v) - if issubclass(cls, str): + if cls is str or issubclass(cls, str): + if TYPE_CHECKING: + assert isinstance(v, str) return v if issubclass(cls, float): + if TYPE_CHECKING: + assert isinstance(v, 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: + if cls is not bool and isinstance(cls, SupportsInt): return str(int(v)) raise TypeError( "Invalid variable type: value " @@ -919,7 +1264,17 @@ def _query_var(v): "of type {}".format(v, cls) ) - def _get_str_query(self, *args, **kwargs): + def _get_str_query_from_iterable( + self, items: Iterable[Tuple[Union[str, istr], str]] + ) -> str: + """Return a query string from an iterable.""" + quoter = self._QUERY_PART_QUOTER + # A listcomp is used since listcomps are inlined on CPython 3.12+ and + # they are a bit faster than a generator expression. + return "&".join([f"{quoter(k)}={quoter(self._query_var(v))}" for k, v in items]) + + def _get_str_query(self, *args: Any, **kwargs: Any) -> Union[str, None]: + query: Union[str, Mapping[str, QueryVariable], None] if kwargs: if len(args) > 0: raise ValueError( @@ -932,34 +1287,35 @@ def _get_str_query(self, *args, **kwargs): raise ValueError("Either kwargs or single query parameter must be present") if query is None: - query = "" - elif isinstance(query, Mapping): + return None + if isinstance(query, Mapping): quoter = self._QUERY_PART_QUOTER - query = "&".join(self._query_seq_pairs(quoter, query.items())) - elif isinstance(query, str): - query = self._QUERY_QUOTER(query) - elif isinstance(query, (bytes, bytearray, memoryview)): + return "&".join(self._query_seq_pairs(quoter, query.items())) + if isinstance(query, str): + return self._QUERY_QUOTER(query) + if isinstance(query, (bytes, bytearray, memoryview)): raise TypeError( "Invalid query type: bytes, bytearray and memoryview are forbidden" ) - elif isinstance(query, Sequence): - quoter = self._QUERY_PART_QUOTER + if isinstance(query, Sequence): # We don't expect sequence values if we're given a list of pairs # already; only mappings like builtin `dict` which can't have the # same key pointing to multiple values are allowed to use # `_query_seq_pairs`. - query = "&".join( - quoter(k) + "=" + quoter(self._query_var(v)) for k, v in query - ) - else: - raise TypeError( - "Invalid query type: only str, mapping or " - "sequence of (key, value) pairs is allowed" - ) + return self._get_str_query_from_iterable(query) - return query + raise TypeError( + "Invalid query type: only str, mapping or " + "sequence of (key, value) pairs is allowed" + ) + + @overload + def with_query(self, query: Query) -> "URL": ... - def with_query(self, *args, **kwargs): + @overload + def with_query(self, **kwargs: QueryVariable) -> "URL": ... + + def with_query(self, *args: Any, **kwargs: Any) -> "URL": """Return a new URL with query part replaced. Accepts any Mapping (e.g. dict, multidict.MultiDict instances) @@ -974,21 +1330,78 @@ def with_query(self, *args, **kwargs): """ # N.B. doesn't cleanup query/fragment - new_query = self._get_str_query(*args, **kwargs) - return URL( - self._val._replace(path=self._val.path, query=new_query), encoded=True - ) + new_query = self._get_str_query(*args, **kwargs) or "" + return URL(self._val._replace(query=new_query), encoded=True) - def update_query(self, *args, **kwargs): - """Return a new URL with query part updated.""" - s = self._get_str_query(*args, **kwargs) - new_query = MultiDict(parse_qsl(s, keep_blank_values=True)) - query = MultiDict(self.query) - query.update(new_query) + @overload + def extend_query(self, query: Query) -> "URL": ... + + @overload + def extend_query(self, **kwargs: QueryVariable) -> "URL": ... + + def extend_query(self, *args: Any, **kwargs: Any) -> "URL": + """Return a new URL with query part combined with the existing. + + This method will not remove existing query parameters. + + Example: + >>> url = URL('http://example.com/?a=1&b=2') + >>> url.extend_query(a=3, c=4) + URL('http://example.com/?a=1&b=2&a=3&c=4') + """ + new_query_string = self._get_str_query(*args, **kwargs) + if not new_query_string: + return self + if current_query := self.raw_query_string: + # both strings are already encoded so we can use a simple + # string join + if current_query[-1] == "&": + combined_query = f"{current_query}{new_query_string}" + else: + combined_query = f"{current_query}&{new_query_string}" + else: + combined_query = new_query_string + return URL(self._val._replace(query=combined_query), encoded=True) + + @overload + def update_query(self, query: Query) -> "URL": ... + + @overload + def update_query(self, **kwargs: QueryVariable) -> "URL": ... + + def update_query(self, *args: Any, **kwargs: Any) -> "URL": + """Return a new URL with query part updated. - return URL(self._val._replace(query=self._get_str_query(query)), encoded=True) + This method will overwrite existing query parameters. - def with_fragment(self, fragment): + Example: + >>> url = URL('http://example.com/?a=1&b=2') + >>> url.update_query(a=3, c=4) + URL('http://example.com/?a=3&b=2&c=4') + """ + s = self._get_str_query(*args, **kwargs) + if s is None: + return URL(self._val._replace(query=""), encoded=True) + + query = MultiDict(self._parsed_query) + query.update(parse_qsl(s, keep_blank_values=True)) + new_str = self._get_str_query_from_iterable(query.items()) + return URL(self._val._replace(query=new_str), encoded=True) + + def without_query_params(self, *query_params: str) -> "URL": + """Remove some keys from query part and return new URL.""" + params_to_remove = set(query_params) & self.query.keys() + if not params_to_remove: + return self + return self.with_query( + tuple( + (name, value) + for name, value in self.query.items() + if name not in params_to_remove + ) + ) + + def with_fragment(self, fragment: Union[str, None]) -> "URL": """Return a new URL with fragment replaced. Autoencode fragment if needed. @@ -1007,7 +1420,7 @@ def with_fragment(self, fragment): return self return URL(self._val._replace(fragment=raw_fragment), encoded=True) - def with_name(self, name): + def with_name(self, name: str) -> "URL": """Return a new URL with name (last part of path) replaced. Query and fragment parts are cleaned up. @@ -1024,7 +1437,7 @@ def with_name(self, name): if name in (".", ".."): raise ValueError(". and .. values are forbidden") parts = list(self.raw_parts) - if self.is_absolute(): + if self.absolute: if len(parts) == 1: parts.append(name) else: @@ -1039,7 +1452,7 @@ def with_name(self, name): encoded=True, ) - def with_suffix(self, suffix): + def with_suffix(self, suffix: str) -> "URL": """Return a new URL with suffix (file extension of name) replaced. Query and fragment parts are cleaned up. @@ -1048,7 +1461,7 @@ def with_suffix(self, suffix): """ if not isinstance(suffix, str): raise TypeError("Invalid suffix type") - if suffix and not suffix.startswith(".") or suffix == ".": + if suffix and not suffix[0] == "." or suffix == ".": raise ValueError(f"Invalid suffix {suffix!r}") name = self.raw_name if not name: @@ -1060,7 +1473,7 @@ def with_suffix(self, suffix): name = name[: -len(old_suffix)] + suffix return self.with_name(name) - def join(self, url): + def join(self, url: "URL") -> "URL": """Join URLs Construct a full (“absolute”) URL by combining a “base URL” @@ -1072,42 +1485,76 @@ def join(self, url): relative URL. """ - # See docs for urllib.parse.urljoin - if not isinstance(url, URL): + if type(url) is not URL: raise TypeError("url should be URL") - return URL(urljoin(str(self), str(url)), encoded=True) + val = self._val + other_val = url._val + scheme = other_val.scheme or val.scheme + + if scheme != val.scheme or scheme not in USES_RELATIVE: + return url - def human_repr(self): + # scheme is in uses_authority as uses_authority is a superset of uses_relative + if other_val.netloc and scheme in USES_AUTHORITY: + return URL(other_val._replace(scheme=scheme), encoded=True) + + parts: _SplitResultDict = {"scheme": scheme} + if other_val.path or other_val.fragment: + parts["fragment"] = other_val.fragment + if other_val.path or other_val.query: + parts["query"] = other_val.query + + if not other_val.path: + return URL(val._replace(**parts), encoded=True) + + if other_val.path[0] == "/": + path = other_val.path + elif not val.path: + path = f"/{other_val.path}" + elif val.path[-1] == "/": + path = f"{val.path}{other_val.path}" + else: + # … + # and relativizing ".." + # parts[0] is / for absolute urls, this join will add a double slash there + path = "/".join([*self.parts[:-1], ""]) + path += other_val.path + # which has to be removed + if val.path[0] == "/": + path = path[1:] + + parts["path"] = self._normalize_path(path) + return URL(val._replace(**parts), encoded=True) + + def joinpath(self, *other: str, encoded: bool = False) -> "URL": + """Return a new URL with the elements in other appended to the path.""" + return self._make_child(other, encoded=encoded) + + def human_repr(self) -> str: """Return decoded human readable string for URL representation.""" - user = _human_quote(self.user, "#/:?@") - password = _human_quote(self.password, "#/:?@") + user = _human_quote(self.user, "#/:?@[]") + password = _human_quote(self.password, "#/:?@[]") host = self.host if host: - host = self._encode_host(self.host, human=True) + host = self._encode_host(host, human=True) path = _human_quote(self.path, "#?") + if TYPE_CHECKING: + assert path is not None query_string = "&".join( "{}={}".format(_human_quote(k, "#&+;="), _human_quote(v, "#&+;=")) for k, v in self.query.items() ) fragment = _human_quote(self.fragment, "") - return urlunsplit( - SplitResult( - self.scheme, - self._make_netloc( - user, - password, - host, - self._val.port, - encode_host=False, - ), - path, - query_string, - fragment, - ) + if TYPE_CHECKING: + assert fragment is not None + netloc = self._make_netloc( + user, password, host, self.explicit_port, encode_host=False ) + val = SplitResult(self.scheme, netloc, path, query_string, fragment) + return urlunsplit(val) -def _human_quote(s, unsafe): +def _human_quote(s: Union[str, None], unsafe: str) -> Union[str, None]: if not s: return s for c in "%" + unsafe: @@ -1121,39 +1568,81 @@ def _human_quote(s, unsafe): _MAXCACHE = 256 -@functools.lru_cache(_MAXCACHE) -def _idna_decode(raw): +@lru_cache(_MAXCACHE) +def _idna_decode(raw: str) -> str: try: return idna.decode(raw.encode("ascii")) except UnicodeError: # e.g. '::1' return raw.encode("ascii").decode("idna") -@functools.lru_cache(_MAXCACHE) -def _idna_encode(host): +@lru_cache(_MAXCACHE) +def _idna_encode(host: str) -> str: try: return idna.encode(host, uts46=True).decode("ascii") except UnicodeError: return host.encode("idna").decode("ascii") +@lru_cache(_MAXCACHE) +def _ip_compressed_version(raw_ip: str) -> Tuple[str, int]: + """Return compressed version of IP address and its version.""" + ip = ip_address(raw_ip) + return ip.compressed, ip.version + + +@lru_cache(_MAXCACHE) +def _host_validate(host: str) -> None: + """Validate an ascii host name.""" + invalid = _not_reg_name.search(host) + if invalid is None: + return + value, pos, extra = invalid.group(), invalid.start(), "" + if value == "@" or (value == ":" and "@" in host[pos:]): + # this looks like an authority string + extra = ( + ", if the value includes a username or password, " + "use 'authority' instead of 'host'" + ) + raise ValueError( + f"Host {host!r} cannot contain {value!r} (at position " f"{pos}){extra}" + ) from None + + @rewrite_module -def cache_clear(): +def cache_clear() -> None: + """Clear all LRU caches.""" _idna_decode.cache_clear() _idna_encode.cache_clear() + _ip_compressed_version.cache_clear() + _host_validate.cache_clear() @rewrite_module -def cache_info(): +def cache_info() -> CacheInfo: + """Report cache statistics.""" return { "idna_encode": _idna_encode.cache_info(), "idna_decode": _idna_decode.cache_info(), + "ip_address": _ip_compressed_version.cache_info(), + "host_validate": _host_validate.cache_info(), } @rewrite_module -def cache_configure(*, idna_encode_size=_MAXCACHE, idna_decode_size=_MAXCACHE): - global _idna_decode, _idna_encode - - _idna_encode = functools.lru_cache(idna_encode_size)(_idna_encode.__wrapped__) - _idna_decode = functools.lru_cache(idna_decode_size)(_idna_decode.__wrapped__) +def cache_configure( + *, + idna_encode_size: Union[int, None] = _MAXCACHE, + idna_decode_size: Union[int, None] = _MAXCACHE, + ip_address_size: Union[int, None] = _MAXCACHE, + host_validate_size: Union[int, None] = _MAXCACHE, +) -> None: + """Configure LRU cache sizes.""" + global _idna_decode, _idna_encode, _ip_compressed_version, _host_validate + + _idna_encode = lru_cache(idna_encode_size)(_idna_encode.__wrapped__) + _idna_decode = lru_cache(idna_decode_size)(_idna_decode.__wrapped__) + _ip_compressed_version = lru_cache(ip_address_size)( + _ip_compressed_version.__wrapped__ + ) + _host_validate = lru_cache(host_validate_size)(_host_validate.__wrapped__)