diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 0000000..90c978b --- /dev/null +++ b/.bazelignore @@ -0,0 +1 @@ +example/ diff --git a/README.md b/README.md index 9761903..0022188 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # Bazel rules for creating Python virtual environments. + See `example/` for an example. ## Installation + Add the following to your `WORKSPACE`. (Note: see the releases page for release-specific `WORKSPACE` config) -``` +```starlark load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( @@ -14,11 +16,36 @@ http_archive( strip_prefix = "rules_pyvenv-main", url = "https://github.com/cedarai/rules_pyvenv/archive/main.tar.gz", ) + +load("@rules_pyvenv//:repositories.bzl", "py_venv_repositories") + +py_venv_repositories( + name = "py_venv", +) +``` + +Add the following to your `BUILD`. + +```starlark +load("@py_venv//:venv.bzl", "py_venv") + +py_venv( + name = "venv", + ... +) + +``` + +Run the following command to create a venv in directory _env_. + +``` +bazel run //:venv env ``` These rules require a recent version of Python 3.6+ and `rules_python`. The environment is built using the `venv` library that ships with the Python standard library. If using the system-provided Python on Debian/Ubuntu, you may need to run + ``` apt install python3.8-venv ``` @@ -26,6 +53,7 @@ apt install python3.8-venv On Windows, [you need to enable symlink support](https://bazel.build/configure/windows#symlink). ## Example + ``` $ cd example $ bazel run //:venv env diff --git a/build_env.py b/build_env.py index 3832461..c9ad0fb 100644 --- a/build_env.py +++ b/build_env.py @@ -144,7 +144,7 @@ def install_data_file(env_path: pathlib.Path, file: EnvFile) -> None: def install_site_file(site_packages_path: pathlib.Path, file: EnvFile) -> None: site_path = site_packages_path / file.site_packages_path - if not site_path.exists(): + if not site_path.exists() and file.path.exists(): site_path.parent.mkdir(parents=True, exist_ok=True) site_path.symlink_to(file.path.resolve()) diff --git a/example/BUILD.bazel b/example/BUILD.bazel index 022b863..7dd479d 100644 --- a/example/BUILD.bazel +++ b/example/BUILD.bazel @@ -12,22 +12,22 @@ # See the License for the specific language governing permissions and # limitations under the License. -package(default_visibility = ["//visibility:public"]) - -load("@rules_pyvenv//:venv.bzl", "py_venv") +load("@py_venv//:venv.bzl", "py_venv") load("@example_deps//:requirements.bzl", "requirement") load("@rules_python//python/pip_install:requirements.bzl", "compile_pip_requirements") +package(default_visibility = ["//visibility:public"]) + py_venv( name = "venv", + extra_pip_commands = [ + # "install ipython jupyter-console", + ], deps = [ - "//libraries/liba", + "//libraries/liba", requirement("black"), requirement("numpy"), ], - extra_pip_commands = [ -# "install ipython jupyter-console", - ] ) py_venv( @@ -40,11 +40,11 @@ py_venv( py_venv( name = "venv_only_local_always_link", + always_link = True, deps = [ "//libraries/liba", "//libraries/libb", ], - always_link = True, ) py_venv( diff --git a/example/WORKSPACE b/example/WORKSPACE index 4365de7..4bb6e13 100644 --- a/example/WORKSPACE +++ b/example/WORKSPACE @@ -36,14 +36,21 @@ python_register_toolchains( # For this example, we load rules_pyvenv locally. But you'd use http_archive. local_repository( name = "rules_pyvenv", - path = "../" + path = "../", +) + +load("@rules_pyvenv//:repositories.bzl", "py_venv_repositories") + +py_venv_repositories( + name = "py_venv", ) # Fetch some python packages to install in the venv, load("@rules_python//python:pip.bzl", "pip_parse") + pip_parse( - name = "example_deps", - requirements_lock = "//:requirements.txt", + name = "example_deps", + requirements_lock = "//:requirements.txt", ) load("@example_deps//:requirements.bzl", "install_deps") diff --git a/repositories.bzl b/repositories.bzl new file mode 100644 index 0000000..080c22d --- /dev/null +++ b/repositories.bzl @@ -0,0 +1,92 @@ +# Copyright 2023 cedar.ai. All rights reserved. +# +# 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. + +def _impl(rctx): + rctx.file("BUILD.bazel", """ +package(default_visibility = ["//visibility:public"]) + +exports_files(["venv.bzl"]) +""") + + rctx.download_and_extract( + output = "importlib_metadata", + sha256 = "9e6fafdbf0601a5825c53a842f7bb6928c8e8eb6c46a228199ca02396cf6007a", + stripPrefix = "importlib_metadata-6.0.0", + url = "https://github.com/python/importlib_metadata/archive/refs/tags/v6.0.0.tar.gz", + ) + + rctx.file("importlib_metadata/BUILD.bazel", """ +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "importlib_metadata", + srcs = glob(["importlib_metadata/*.py"]), + imports = ["."], + deps = [ + "@{name}//typing_extensions", + "@{name}//zipp", + ], +) +""".format( + name = rctx.name, + )) + + rctx.download_and_extract( + output = "typing_extensions", + sha256 = "c8fd5561e1bd88b743ef2ee065a5e661b2fd7b56e9cbe9ae2aeb928f41438819", + stripPrefix = "typing_extensions-4.5.0/src", + url = "https://github.com/python/typing_extensions/archive/refs/tags/4.5.0.tar.gz", + ) + + rctx.file("typing_extensions/BUILD.bazel", """ +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "typing_extensions", + srcs = [ + "typing_extensions.py", + ], + imports = ["."], +) +""") + + rctx.download_and_extract( + output = "zipp", + sha256 = "a2e6a09c22d6d36221e2d37f08d9566554f4de9e6e3ed8eb9ddcc0b0440162c0", + stripPrefix = "zipp-3.15.0", + url = "https://github.com/jaraco/zipp/archive/refs/tags/v3.15.0.tar.gz", + ) + + rctx.file("zipp/BUILD.bazel", """ +package(default_visibility = ["//visibility:public"]) + +py_library( + name = "zipp", + srcs = glob(["zipp/*.py"]), + imports = ["."], +) +""") + + rctx.template("venv.bzl", rctx.attr._template, { + "%%NAME%%": rctx.name, + }) + +py_venv_repositories = repository_rule( + implementation = _impl, + attrs = { + "_template": attr.label( + default = ":venv.bzl.tmpl", + ), + }, +) diff --git a/vendor/importlib_metadata/BUILD.bazel b/vendor/importlib_metadata/BUILD.bazel deleted file mode 100644 index c1d3dea..0000000 --- a/vendor/importlib_metadata/BUILD.bazel +++ /dev/null @@ -1,8 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -py_library( - name = "importlib_metadata", - srcs = glob(["**/*.py"]), - deps = ["//vendor/zipp"], - imports = ["."], -) diff --git a/vendor/importlib_metadata/CHANGES.rst b/vendor/importlib_metadata/CHANGES.rst deleted file mode 100644 index 5aa5776..0000000 --- a/vendor/importlib_metadata/CHANGES.rst +++ /dev/null @@ -1,748 +0,0 @@ -v5.0.0 -====== - -* #97, #284, #300: Removed compatibility shims for deprecated entry - point interfaces. - -v4.13.0 -======= - -* #396: Added compatibility for ``PathDistributions`` originating - from Python 3.8 and 3.9. - -v4.12.0 -======= - -* py-93259: Now raise ``ValueError`` when ``None`` or an empty - string are passed to ``Distribution.from_name`` (and other - callers). - -v4.11.4 -======= - -* #379: In ``PathDistribution._name_from_stem``, avoid including - parts of the extension in the result. -* #381: In ``PathDistribution._normalized_name``, ensure names - loaded from the stem of the filename are also normalized, ensuring - duplicate entry points by packages varying only by non-normalized - name are hidden. - -v4.11.3 -======= - -* #372: Removed cast of path items in FastPath, not needed. - -v4.11.2 -======= - -* #369: Fixed bug where ``EntryPoint.extras`` was returning - match objects and not the extras strings. - -v4.11.1 -======= - -* #367: In ``Distribution.requires`` for egg-info, if ``requires.txt`` - is empty, return an empty list. - -v4.11.0 -======= - -* bpo-46246: Added ``__slots__`` to ``EntryPoints``. - -v4.10.2 -======= - -* #365 and bpo-46546: Avoid leaking ``method_name`` in - ``DeprecatedList``. - -v4.10.1 -======= - -v2.1.3 -======= - -* #361: Avoid potential REDoS in ``EntryPoint.pattern``. - -v4.10.0 -======= - -* #354: Removed ``Distribution._local`` factory. This - functionality was created as a demonstration of the - possible implementation. Now, the - `pep517 `_ package - provides this functionality directly through - `pep517.meta.load `_. - -v4.9.0 -====== - -* Require Python 3.7 or later. - -v4.8.3 -====== - -* #357: Fixed requirement generation from egg-info when a - URL requirement is given. - -v4.8.2 -====== - -v2.1.2 -====== - -* #353: Fixed discovery of distributions when path is empty. - -v4.8.1 -====== - -* #348: Restored support for ``EntryPoint`` access by item, - deprecating support in the process. Users are advised - to use direct member access instead of item-based access:: - - - ep[0] -> ep.name - - ep[1] -> ep.value - - ep[2] -> ep.group - - ep[:] -> ep.name, ep.value, ep.group - -v4.8.0 -====== - -* #337: Rewrote ``EntryPoint`` as a simple class, still - immutable and still with the attributes, but without any - expectation for ``namedtuple`` functionality such as - ``_asdict``. - -v4.7.1 -====== - -* #344: Fixed regression in ``packages_distributions`` when - neither top-level.txt nor a files manifest is present. - -v4.7.0 -====== - -* #330: In ``packages_distributions``, now infer top-level - names from ``.files()`` when a ``top-level.txt`` - (Setuptools-specific metadata) is not present. - -v4.6.4 -====== - -* #334: Correct ``SimplePath`` protocol to match ``pathlib`` - protocol for ``__truediv__``. - -v4.6.3 -====== - -* Moved workaround for #327 to ``_compat`` module. - -v4.6.2 -====== - -* bpo-44784: Avoid errors in test suite when - DeprecationWarnings are treated as errors. - -v4.6.1 -====== - -* #327: Deprecation warnings now honor call stack variance - on PyPy. - -v4.6.0 -====== - -* #326: Performance tests now rely on - `pytest-perf `_. - To disable these tests, which require network access - and a git checkout, pass ``-p no:perf`` to pytest. - -v4.5.0 -====== - -* #319: Remove ``SelectableGroups`` deprecation exception - for flake8. - -v4.4.0 -====== - -* #300: Restore compatibility in the result from - ``Distribution.entry_points`` (``EntryPoints``) to honor - expectations in older implementations and issuing - deprecation warnings for these cases: - - - ``EntryPoints`` objects are once again mutable, allowing - for ``sort()`` and other list-based mutation operations. - Avoid deprecation warnings by casting to a - mutable sequence (e.g. - ``list(dist.entry_points).sort()``). - - - ``EntryPoints`` results once again allow - for access by index. To avoid deprecation warnings, - cast the result to a Sequence first - (e.g. ``tuple(dist.entry_points)[0]``). - -v4.3.1 -====== - -* #320: Fix issue where normalized name for eggs was - incorrectly solicited, leading to metadata being - unavailable for eggs. - -v4.3.0 -====== - -* #317: De-duplication of distributions no longer requires - loading the full metadata for ``PathDistribution`` objects, - entry point loading performance by ~10x. - -v4.2.0 -====== - -* Prefer f-strings to ``.format`` calls. - -v4.1.0 -====== - -* #312: Add support for metadata 2.2 (``Dynamic`` field). - -* #315: Add ``SimplePath`` protocol for interface clarity - in ``PathDistribution``. - -v4.0.1 -====== - -* #306: Clearer guidance about compatibility in readme. - -v4.0.0 -====== - -* #304: ``PackageMetadata`` as returned by ``metadata()`` - and ``Distribution.metadata()`` now provides normalized - metadata honoring PEP 566: - - - If a long description is provided in the payload of the - RFC 822 value, it can be retrieved as the ``Description`` - field. - - Any multi-line values in the metadata will be returned as - such. - - For any multi-line values, line continuation characters - are removed. This backward-incompatible change means - that any projects relying on the RFC 822 line continuation - characters being present must be tolerant to them having - been removed. - - Add a ``json`` property that provides the metadata - converted to a JSON-compatible form per PEP 566. - - -v3.10.1 -======= - -* Minor tweaks from CPython. - -v3.10.0 -======= - -* #295: Internal refactoring to unify section parsing logic. - -v3.9.1 -====== - -* #296: Exclude 'prepare' package. -* #297: Fix ValueError when entry points contains comments. - -v3.9.0 -====== - -* Use of Mapping (dict) interfaces on ``SelectableGroups`` - is now flagged as deprecated. Instead, users are advised - to use the select interface for future compatibility. - - Suppress the warning with this filter: - ``ignore:SelectableGroups dict interface``. - - Or with this invocation in the Python environment: - ``warnings.filterwarnings('ignore', 'SelectableGroups dict interface')``. - - Preferably, switch to the ``select`` interface introduced - in 3.7.0. See the - `entry points documentation `_ and changelog for the 3.6 - release below for more detail. - - For some use-cases, especially those that rely on - ``importlib.metadata`` in Python 3.8 and 3.9 or - those relying on older ``importlib_metadata`` (especially - on Python 3.5 and earlier), - `backports.entry_points_selectable `_ - was created to ease the transition. Please have a look - at that project if simply relying on importlib_metadata 3.6+ - is not straightforward. Background in #298. - -* #283: Entry point parsing no longer relies on ConfigParser - and instead uses a custom, one-pass parser to load the - config, resulting in a ~20% performance improvement when - loading entry points. - -v3.8.2 -====== - -* #293: Re-enabled lazy evaluation of path lookup through - a FreezableDefaultDict. - -v3.8.1 -====== - -* #293: Workaround for error in distribution search. - -v3.8.0 -====== - -* #290: Add mtime-based caching for ``FastPath`` and its - lookups, dramatically increasing performance for repeated - distribution lookups. - -v3.7.3 -====== - -* Docs enhancements and cleanup following review in - `GH-24782 `_. - -v3.7.2 -====== - -* Cleaned up cruft in entry_points docstring. - -v3.7.1 -====== - -* Internal refactoring to facilitate ``entry_points() -> dict`` - deprecation. - -v3.7.0 -====== - -* #131: Added ``packages_distributions`` to conveniently - resolve a top-level package or module to its distribution(s). - -v3.6.0 -====== - -* #284: Introduces new ``EntryPoints`` object, a tuple of - ``EntryPoint`` objects but with convenience properties for - selecting and inspecting the results: - - - ``.select()`` accepts ``group`` or ``name`` keyword - parameters and returns a new ``EntryPoints`` tuple - with only those that match the selection. - - ``.groups`` property presents all of the group names. - - ``.names`` property presents the names of the entry points. - - Item access (e.g. ``eps[name]``) retrieves a single - entry point by name. - - ``entry_points`` now accepts "selection parameters", - same as ``EntryPoint.select()``. - - ``entry_points()`` now provides a future-compatible - ``SelectableGroups`` object that supplies the above interface - (except item access) but remains a dict for compatibility. - - In the future, ``entry_points()`` will return an - ``EntryPoints`` object for all entry points. - - If passing selection parameters to ``entry_points``, the - future behavior is invoked and an ``EntryPoints`` is the - result. - -* #284: Construction of entry points using - ``dict([EntryPoint, ...])`` is now deprecated and raises - an appropriate DeprecationWarning and will be removed in - a future version. - -* #300: ``Distribution.entry_points`` now presents as an - ``EntryPoints`` object and access by index is no longer - allowed. If access by index is required, cast to a sequence - first. - -v3.5.0 -====== - -* #280: ``entry_points`` now only returns entry points for - unique distributions (by name). - -v3.4.0 -====== - -* #10: Project now declares itself as being typed. -* #272: Additional performance enhancements to distribution - discovery. -* #111: For PyPA projects, add test ensuring that - ``MetadataPathFinder._search_paths`` honors the needed - interface. Method is still private. - -v3.3.0 -====== - -* #265: ``EntryPoint`` objects now expose a ``.dist`` object - referencing the ``Distribution`` when constructed from a - Distribution. - -v3.2.0 -====== - -* The object returned by ``metadata()`` now has a - formally-defined protocol called ``PackageMetadata`` - with declared support for the ``.get_all()`` method. - Fixes #126. - -v3.1.1 -====== - -v2.1.1 -====== - -* #261: Restored compatibility for package discovery for - metadata without version in the name and for legacy - eggs. - -v3.1.0 -====== - -* Merge with 2.1.0. - -v2.1.0 -====== - -* #253: When querying for package metadata, the lookup - now honors - `package normalization rules `_. - -v3.0.0 -====== - -* Require Python 3.6 or later. - -v2.0.0 -====== - -* ``importlib_metadata`` no longer presents a - ``__version__`` attribute. Consumers wishing to - resolve the version of the package should query it - directly with - ``importlib_metadata.version('importlib-metadata')``. - Closes #71. - -v1.7.0 -====== - -* ``PathNotFoundError`` now has a custom ``__str__`` - mentioning "package metadata" being missing to help - guide users to the cause when the package is installed - but no metadata is present. Closes #124. - -v1.6.1 -====== - -* Added ``Distribution._local()`` as a provisional - demonstration of how to load metadata for a local - package. Implicitly requires that - `pep517 `_ is - installed. Ref #42. -* Ensure inputs to FastPath are Unicode. Closes #121. -* Tests now rely on ``importlib.resources.files`` (and - backport) instead of the older ``path`` function. -* Support any iterable from ``find_distributions``. - Closes #122. - -v1.6.0 -====== - -* Added ``module`` and ``attr`` attributes to ``EntryPoint`` - -v1.5.2 -====== - -* Fix redundant entries from ``FastPath.zip_children``. - Closes #117. - -v1.5.1 -====== - -* Improve reliability and consistency of compatibility - imports for contextlib and pathlib when running tests. - Closes #116. - -v1.5.0 -====== - -* Additional performance optimizations in FastPath now - saves an additional 20% on a typical call. -* Correct for issue where PyOxidizer finder has no - ``__module__`` attribute. Closes #110. - -v1.4.0 -====== - -* Through careful optimization, ``distribution()`` is - 3-4x faster. Thanks to Antony Lee for the - contribution. Closes #95. - -* When searching through ``sys.path``, if any error - occurs attempting to list a path entry, that entry - is skipped, making the system much more lenient - to errors. Closes #94. - -v1.3.0 -====== - -* Improve custom finders documentation. Closes #105. - -v1.2.0 -====== - -* Once again, drop support for Python 3.4. Ref #104. - -v1.1.3 -====== - -* Restored support for Python 3.4 due to improper version - compatibility declarations in the v1.1.0 and v1.1.1 - releases. Closes #104. - -v1.1.2 -====== - -* Repaired project metadata to correctly declare the - ``python_requires`` directive. Closes #103. - -v1.1.1 -====== - -* Fixed ``repr(EntryPoint)`` on PyPy 3 also. Closes #102. - -v1.1.0 -====== - -* Dropped support for Python 3.4. -* EntryPoints are now pickleable. Closes #96. -* Fixed ``repr(EntryPoint)`` on PyPy 2. Closes #97. - -v1.0.0 -====== - -* Project adopts semver for versioning. - -* Removed compatibility shim introduced in 0.23. - -* For better compatibility with the stdlib implementation and to - avoid the same distributions being discovered by the stdlib and - backport implementations, the backport now disables the - stdlib DistributionFinder during initialization (import time). - Closes #91 and closes #100. - -0.23 -==== - -* Added a compatibility shim to prevent failures on beta releases - of Python before the signature changed to accept the - "context" parameter on find_distributions. This workaround - will have a limited lifespan, not to extend beyond release of - Python 3.8 final. - -0.22 -==== - -* Renamed ``package`` parameter to ``distribution_name`` - as `recommended `_ - in the following functions: ``distribution``, ``metadata``, - ``version``, ``files``, and ``requires``. This - backward-incompatible change is expected to have little impact - as these functions are assumed to be primarily used with - positional parameters. - -0.21 -==== - -* ``importlib.metadata`` now exposes the ``DistributionFinder`` - metaclass and references it in the docs for extending the - search algorithm. -* Add ``Distribution.at`` for constructing a Distribution object - from a known metadata directory on the file system. Closes #80. -* Distribution finders now receive a context object that - supplies ``.path`` and ``.name`` properties. This change - introduces a fundamental backward incompatibility for - any projects implementing a ``find_distributions`` method - on a ``MetaPathFinder``. This new layer of abstraction - allows this context to be supplied directly or constructed - on demand and opens the opportunity for a - ``find_distributions`` method to solicit additional - context from the caller. Closes #85. - -0.20 -==== - -* Clarify in the docs that calls to ``.files`` could return - ``None`` when the metadata is not present. Closes #69. -* Return all requirements and not just the first for dist-info - packages. Closes #67. - -0.19 -==== - -* Restrain over-eager egg metadata resolution. -* Add support for entry points with colons in the name. Closes #75. - -0.18 -==== - -* Parse entry points case sensitively. Closes #68 -* Add a version constraint on the backport configparser package. Closes #66 - -0.17 -==== - -* Fix a permission problem in the tests on Windows. - -0.16 -==== - -* Don't crash if there exists an EGG-INFO directory on sys.path. - -0.15 -==== - -* Fix documentation. - -0.14 -==== - -* Removed ``local_distribution`` function from the API. - **This backward-incompatible change removes this - behavior summarily**. Projects should remove their - reliance on this behavior. A replacement behavior is - under review in the `pep517 project - `_. Closes #42. - -0.13 -==== - -* Update docstrings to match PEP 8. Closes #63. -* Merged modules into one module. Closes #62. - -0.12 -==== - -* Add support for eggs. !65; Closes #19. - -0.11 -==== - -* Support generic zip files (not just wheels). Closes #59 -* Support zip files with multiple distributions in them. Closes #60 -* Fully expose the public API in ``importlib_metadata.__all__``. - -0.10 -==== - -* The ``Distribution`` ABC is now officially part of the public API. - Closes #37. -* Fixed support for older single file egg-info formats. Closes #43. -* Fixed a testing bug when ``$CWD`` has spaces in the path. Closes #50. -* Add Python 3.8 to the ``tox`` testing matrix. - -0.9 -=== - -* Fixed issue where entry points without an attribute would raise an - Exception. Closes #40. -* Removed unused ``name`` parameter from ``entry_points()``. Closes #44. -* ``DistributionFinder`` classes must now be instantiated before - being placed on ``sys.meta_path``. - -0.8 -=== - -* This library can now discover/enumerate all installed packages. **This - backward-incompatible change alters the protocol finders must - implement to support distribution package discovery.** Closes #24. -* The signature of ``find_distributions()`` on custom installer finders - should now accept two parameters, ``name`` and ``path`` and - these parameters must supply defaults. -* The ``entry_points()`` method no longer accepts a package name - but instead returns all entry points in a dictionary keyed by the - ``EntryPoint.group``. The ``resolve`` method has been removed. Instead, - call ``EntryPoint.load()``, which has the same semantics as - ``pkg_resources`` and ``entrypoints``. **This is a backward incompatible - change.** -* Metadata is now always returned as Unicode text regardless of - Python version. Closes #29. -* This library can now discover metadata for a 'local' package (found - in the current-working directory). Closes #27. -* Added ``files()`` function for resolving files from a distribution. -* Added a new ``requires()`` function, which returns the requirements - for a package suitable for parsing by - ``packaging.requirements.Requirement``. Closes #18. -* The top-level ``read_text()`` function has been removed. Use - ``PackagePath.read_text()`` on instances returned by the ``files()`` - function. **This is a backward incompatible change.** -* Release dates are now automatically injected into the changelog - based on SCM tags. - -0.7 -=== - -* Fixed issue where packages with dashes in their names would - not be discovered. Closes #21. -* Distribution lookup is now case-insensitive. Closes #20. -* Wheel distributions can no longer be discovered by their module - name. Like Path distributions, they must be indicated by their - distribution package name. - -0.6 -=== - -* Removed ``importlib_metadata.distribution`` function. Now - the public interface is primarily the utility functions exposed - in ``importlib_metadata.__all__``. Closes #14. -* Added two new utility functions ``read_text`` and - ``metadata``. - -0.5 -=== - -* Updated README and removed details about Distribution - class, now considered private. Closes #15. -* Added test suite support for Python 3.4+. -* Fixed SyntaxErrors on Python 3.4 and 3.5. !12 -* Fixed errors on Windows joining Path elements. !15 - -0.4 -=== - -* Housekeeping. - -0.3 -=== - -* Added usage documentation. Closes #8 -* Add support for getting metadata from wheels on ``sys.path``. Closes #9 - -0.2 -=== - -* Added ``importlib_metadata.entry_points()``. Closes #1 -* Added ``importlib_metadata.resolve()``. Closes #12 -* Add support for Python 2.7. Closes #4 - -0.1 -=== - -* Initial release. - - -.. - Local Variables: - mode: change-log-mode - indent-tabs-mode: nil - sentence-end-double-space: t - fill-column: 78 - coding: utf-8 - End: diff --git a/vendor/importlib_metadata/LICENSE b/vendor/importlib_metadata/LICENSE deleted file mode 100644 index d645695..0000000 --- a/vendor/importlib_metadata/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - 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. - 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/vendor/importlib_metadata/README.rst b/vendor/importlib_metadata/README.rst deleted file mode 100644 index 47fa0cb..0000000 --- a/vendor/importlib_metadata/README.rst +++ /dev/null @@ -1,96 +0,0 @@ -.. image:: https://img.shields.io/pypi/v/importlib_metadata.svg - :target: `PyPI link`_ - -.. image:: https://img.shields.io/pypi/pyversions/importlib_metadata.svg - :target: `PyPI link`_ - -.. _PyPI link: https://pypi.org/project/importlib_metadata - -.. image:: https://github.com/python/importlib_metadata/workflows/tests/badge.svg - :target: https://github.com/python/importlib_metadata/actions?query=workflow%3A%22tests%22 - :alt: tests - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: Black - -.. image:: https://readthedocs.org/projects/importlib-metadata/badge/?version=latest - :target: https://importlib-metadata.readthedocs.io/en/latest/?badge=latest - -.. image:: https://img.shields.io/badge/skeleton-2022-informational - :target: https://blog.jaraco.com/skeleton - -.. image:: https://tidelift.com/badges/package/pypi/importlib-metadata - :target: https://tidelift.com/subscription/pkg/pypi-importlib-metadata?utm_source=pypi-importlib-metadata&utm_medium=readme - -Library to access the metadata for a Python package. - -This package supplies third-party access to the functionality of -`importlib.metadata `_ -including improvements added to subsequent Python versions. - - -Compatibility -============= - -New features are introduced in this third-party library and later merged -into CPython. The following table indicates which versions of this library -were contributed to different versions in the standard library: - -.. list-table:: - :header-rows: 1 - - * - importlib_metadata - - stdlib - * - 4.8 - - 3.11 - * - 4.4 - - 3.10 - * - 1.4 - - 3.8 - - -Usage -===== - -See the `online documentation `_ -for usage details. - -`Finder authors -`_ can -also add support for custom package installers. See the above documentation -for details. - - -Caveats -======= - -This project primarily supports third-party packages installed by PyPA -tools (or other conforming packages). It does not support: - -- Packages in the stdlib. -- Packages installed without metadata. - -Project details -=============== - - * Project home: https://github.com/python/importlib_metadata - * Report bugs at: https://github.com/python/importlib_metadata/issues - * Code hosting: https://github.com/python/importlib_metadata - * Documentation: https://importlib_metadata.readthedocs.io/ - -For Enterprise -============== - -Available as part of the Tidelift Subscription. - -This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. - -`Learn more `_. - -Security Contact -================ - -To report a security vulnerability, please use the -`Tidelift security contact `_. -Tidelift will coordinate the fix and disclosure. diff --git a/vendor/importlib_metadata/importlib_metadata/__init__.py b/vendor/importlib_metadata/importlib_metadata/__init__.py deleted file mode 100644 index 304b6d4..0000000 --- a/vendor/importlib_metadata/importlib_metadata/__init__.py +++ /dev/null @@ -1,904 +0,0 @@ -import os -import re -import abc -import csv -import sys -import zipp -import email -import pathlib -import operator -import textwrap -import warnings -import functools -import itertools -import posixpath -import collections - -from . import _adapters, _meta, _py39compat -from ._collections import FreezableDefaultDict, Pair -from ._compat import ( - NullFinder, - install, - pypy_partial, -) -from ._functools import method_cache, pass_none -from ._itertools import always_iterable, unique_everseen -from ._meta import PackageMetadata, SimplePath - -from contextlib import suppress -from importlib import import_module -from importlib.abc import MetaPathFinder -from itertools import starmap -from typing import List, Mapping, Optional - - -__all__ = [ - 'Distribution', - 'DistributionFinder', - 'PackageMetadata', - 'PackageNotFoundError', - 'distribution', - 'distributions', - 'entry_points', - 'files', - 'metadata', - 'packages_distributions', - 'requires', - 'version', -] - - -class PackageNotFoundError(ModuleNotFoundError): - """The package was not found.""" - - def __str__(self): - return f"No package metadata was found for {self.name}" - - @property - def name(self): - (name,) = self.args - return name - - -class Sectioned: - """ - A simple entry point config parser for performance - - >>> for item in Sectioned.read(Sectioned._sample): - ... print(item) - Pair(name='sec1', value='# comments ignored') - Pair(name='sec1', value='a = 1') - Pair(name='sec1', value='b = 2') - Pair(name='sec2', value='a = 2') - - >>> res = Sectioned.section_pairs(Sectioned._sample) - >>> item = next(res) - >>> item.name - 'sec1' - >>> item.value - Pair(name='a', value='1') - >>> item = next(res) - >>> item.value - Pair(name='b', value='2') - >>> item = next(res) - >>> item.name - 'sec2' - >>> item.value - Pair(name='a', value='2') - >>> list(res) - [] - """ - - _sample = textwrap.dedent( - """ - [sec1] - # comments ignored - a = 1 - b = 2 - - [sec2] - a = 2 - """ - ).lstrip() - - @classmethod - def section_pairs(cls, text): - return ( - section._replace(value=Pair.parse(section.value)) - for section in cls.read(text, filter_=cls.valid) - if section.name is not None - ) - - @staticmethod - def read(text, filter_=None): - lines = filter(filter_, map(str.strip, text.splitlines())) - name = None - for value in lines: - section_match = value.startswith('[') and value.endswith(']') - if section_match: - name = value.strip('[]') - continue - yield Pair(name, value) - - @staticmethod - def valid(line): - return line and not line.startswith('#') - - -class DeprecatedTuple: - """ - Provide subscript item access for backward compatibility. - - >>> recwarn = getfixture('recwarn') - >>> ep = EntryPoint(name='name', value='value', group='group') - >>> ep[:] - ('name', 'value', 'group') - >>> ep[0] - 'name' - >>> len(recwarn) - 1 - """ - - _warn = functools.partial( - warnings.warn, - "EntryPoint tuple interface is deprecated. Access members by name.", - DeprecationWarning, - stacklevel=pypy_partial(2), - ) - - def __getitem__(self, item): - self._warn() - return self._key()[item] - - -class EntryPoint(DeprecatedTuple): - """An entry point as defined by Python packaging conventions. - - See `the packaging docs on entry points - `_ - for more information. - - >>> ep = EntryPoint( - ... name=None, group=None, value='package.module:attr [extra1, extra2]') - >>> ep.module - 'package.module' - >>> ep.attr - 'attr' - >>> ep.extras - ['extra1', 'extra2'] - """ - - pattern = re.compile( - r'(?P[\w.]+)\s*' - r'(:\s*(?P[\w.]+)\s*)?' - r'((?P\[.*\])\s*)?$' - ) - """ - A regular expression describing the syntax for an entry point, - which might look like: - - - module - - package.module - - package.module:attribute - - package.module:object.attribute - - package.module:attr [extra1, extra2] - - Other combinations are possible as well. - - The expression is lenient about whitespace around the ':', - following the attr, and following any extras. - """ - - name: str - value: str - group: str - - dist: Optional['Distribution'] = None - - def __init__(self, name, value, group): - vars(self).update(name=name, value=value, group=group) - - def load(self): - """Load the entry point from its definition. If only a module - is indicated by the value, return that module. Otherwise, - return the named object. - """ - match = self.pattern.match(self.value) - module = import_module(match.group('module')) - attrs = filter(None, (match.group('attr') or '').split('.')) - return functools.reduce(getattr, attrs, module) - - @property - def module(self): - match = self.pattern.match(self.value) - return match.group('module') - - @property - def attr(self): - match = self.pattern.match(self.value) - return match.group('attr') - - @property - def extras(self): - match = self.pattern.match(self.value) - return re.findall(r'\w+', match.group('extras') or '') - - def _for(self, dist): - vars(self).update(dist=dist) - return self - - def matches(self, **params): - """ - EntryPoint matches the given parameters. - - >>> ep = EntryPoint(group='foo', name='bar', value='bing:bong [extra1, extra2]') - >>> ep.matches(group='foo') - True - >>> ep.matches(name='bar', value='bing:bong [extra1, extra2]') - True - >>> ep.matches(group='foo', name='other') - False - >>> ep.matches() - True - >>> ep.matches(extras=['extra1', 'extra2']) - True - >>> ep.matches(module='bing') - True - >>> ep.matches(attr='bong') - True - """ - attrs = (getattr(self, param) for param in params) - return all(map(operator.eq, params.values(), attrs)) - - def _key(self): - return self.name, self.value, self.group - - def __lt__(self, other): - return self._key() < other._key() - - def __eq__(self, other): - return self._key() == other._key() - - def __setattr__(self, name, value): - raise AttributeError("EntryPoint objects are immutable.") - - def __repr__(self): - return ( - f'EntryPoint(name={self.name!r}, value={self.value!r}, ' - f'group={self.group!r})' - ) - - def __hash__(self): - return hash(self._key()) - - -class EntryPoints(tuple): - """ - An immutable collection of selectable EntryPoint objects. - """ - - __slots__ = () - - def __getitem__(self, name): # -> EntryPoint: - """ - Get the EntryPoint in self matching name. - """ - try: - return next(iter(self.select(name=name))) - except StopIteration: - raise KeyError(name) - - def select(self, **params): - """ - Select entry points from self that match the - given parameters (typically group and/or name). - """ - candidates = (_py39compat.ep_matches(ep, **params) for ep in self) - return EntryPoints(ep for ep, predicate in candidates if predicate) - - @property - def names(self): - """ - Return the set of all names of all entry points. - """ - return {ep.name for ep in self} - - @property - def groups(self): - """ - Return the set of all groups of all entry points. - """ - return {ep.group for ep in self} - - @classmethod - def _from_text_for(cls, text, dist): - return cls(ep._for(dist) for ep in cls._from_text(text)) - - @staticmethod - def _from_text(text): - return ( - EntryPoint(name=item.value.name, value=item.value.value, group=item.name) - for item in Sectioned.section_pairs(text or '') - ) - - -class PackagePath(pathlib.PurePosixPath): - """A reference to a path in a package""" - - def read_text(self, encoding='utf-8'): - with self.locate().open(encoding=encoding) as stream: - return stream.read() - - def read_binary(self): - with self.locate().open('rb') as stream: - return stream.read() - - def locate(self): - """Return a path-like object for this path""" - return self.dist.locate_file(self) - - -class FileHash: - def __init__(self, spec): - self.mode, _, self.value = spec.partition('=') - - def __repr__(self): - return f'' - - -class Distribution: - """A Python distribution package.""" - - @abc.abstractmethod - def read_text(self, filename): - """Attempt to load metadata file given by the name. - - :param filename: The name of the file in the distribution info. - :return: The text if found, otherwise None. - """ - - @abc.abstractmethod - def locate_file(self, path): - """ - Given a path to a file in this distribution, return a path - to it. - """ - - @classmethod - def from_name(cls, name: str): - """Return the Distribution for the given package name. - - :param name: The name of the distribution package to search for. - :return: The Distribution instance (or subclass thereof) for the named - package, if found. - :raises PackageNotFoundError: When the named package's distribution - metadata cannot be found. - :raises ValueError: When an invalid value is supplied for name. - """ - if not name: - raise ValueError("A distribution name is required.") - try: - return next(cls.discover(name=name)) - except StopIteration: - raise PackageNotFoundError(name) - - @classmethod - def discover(cls, **kwargs): - """Return an iterable of Distribution objects for all packages. - - Pass a ``context`` or pass keyword arguments for constructing - a context. - - :context: A ``DistributionFinder.Context`` object. - :return: Iterable of Distribution objects for all packages. - """ - context = kwargs.pop('context', None) - if context and kwargs: - raise ValueError("cannot accept context and kwargs") - context = context or DistributionFinder.Context(**kwargs) - return itertools.chain.from_iterable( - resolver(context) for resolver in cls._discover_resolvers() - ) - - @staticmethod - def at(path): - """Return a Distribution for the indicated metadata path - - :param path: a string or path-like object - :return: a concrete Distribution instance for the path - """ - return PathDistribution(pathlib.Path(path)) - - @staticmethod - def _discover_resolvers(): - """Search the meta_path for resolvers.""" - declared = ( - getattr(finder, 'find_distributions', None) for finder in sys.meta_path - ) - return filter(None, declared) - - @property - def metadata(self) -> _meta.PackageMetadata: - """Return the parsed metadata for this Distribution. - - The returned object will have keys that name the various bits of - metadata. See PEP 566 for details. - """ - text = ( - self.read_text('METADATA') - or self.read_text('PKG-INFO') - # This last clause is here to support old egg-info files. Its - # effect is to just end up using the PathDistribution's self._path - # (which points to the egg-info file) attribute unchanged. - or self.read_text('') - ) - return _adapters.Message(email.message_from_string(text)) - - @property - def name(self): - """Return the 'Name' metadata for the distribution package.""" - return self.metadata['Name'] - - @property - def _normalized_name(self): - """Return a normalized version of the name.""" - return Prepared.normalize(self.name) - - @property - def version(self): - """Return the 'Version' metadata for the distribution package.""" - return self.metadata['Version'] - - @property - def entry_points(self): - return EntryPoints._from_text_for(self.read_text('entry_points.txt'), self) - - @property - def files(self): - """Files in this distribution. - - :return: List of PackagePath for this distribution or None - - Result is `None` if the metadata file that enumerates files - (i.e. RECORD for dist-info or SOURCES.txt for egg-info) is - missing. - Result may be empty if the metadata exists but is empty. - """ - - def make_file(name, hash=None, size_str=None): - result = PackagePath(name) - result.hash = FileHash(hash) if hash else None - result.size = int(size_str) if size_str else None - result.dist = self - return result - - @pass_none - def make_files(lines): - return list(starmap(make_file, csv.reader(lines))) - - return make_files(self._read_files_distinfo() or self._read_files_egginfo()) - - def _read_files_distinfo(self): - """ - Read the lines of RECORD - """ - text = self.read_text('RECORD') - return text and text.splitlines() - - def _read_files_egginfo(self): - """ - SOURCES.txt might contain literal commas, so wrap each line - in quotes. - """ - text = self.read_text('SOURCES.txt') - return text and map('"{}"'.format, text.splitlines()) - - @property - def requires(self): - """Generated requirements specified for this Distribution""" - reqs = self._read_dist_info_reqs() or self._read_egg_info_reqs() - return reqs and list(reqs) - - def _read_dist_info_reqs(self): - return self.metadata.get_all('Requires-Dist') - - def _read_egg_info_reqs(self): - source = self.read_text('requires.txt') - return pass_none(self._deps_from_requires_text)(source) - - @classmethod - def _deps_from_requires_text(cls, source): - return cls._convert_egg_info_reqs_to_simple_reqs(Sectioned.read(source)) - - @staticmethod - def _convert_egg_info_reqs_to_simple_reqs(sections): - """ - Historically, setuptools would solicit and store 'extra' - requirements, including those with environment markers, - in separate sections. More modern tools expect each - dependency to be defined separately, with any relevant - extras and environment markers attached directly to that - requirement. This method converts the former to the - latter. See _test_deps_from_requires_text for an example. - """ - - def make_condition(name): - return name and f'extra == "{name}"' - - def quoted_marker(section): - section = section or '' - extra, sep, markers = section.partition(':') - if extra and markers: - markers = f'({markers})' - conditions = list(filter(None, [markers, make_condition(extra)])) - return '; ' + ' and '.join(conditions) if conditions else '' - - def url_req_space(req): - """ - PEP 508 requires a space between the url_spec and the quoted_marker. - Ref python/importlib_metadata#357. - """ - # '@' is uniquely indicative of a url_req. - return ' ' * ('@' in req) - - for section in sections: - space = url_req_space(section.value) - yield section.value + space + quoted_marker(section.name) - - -class DistributionFinder(MetaPathFinder): - """ - A MetaPathFinder capable of discovering installed distributions. - """ - - class Context: - """ - Keyword arguments presented by the caller to - ``distributions()`` or ``Distribution.discover()`` - to narrow the scope of a search for distributions - in all DistributionFinders. - - Each DistributionFinder may expect any parameters - and should attempt to honor the canonical - parameters defined below when appropriate. - """ - - name = None - """ - Specific name for which a distribution finder should match. - A name of ``None`` matches all distributions. - """ - - def __init__(self, **kwargs): - vars(self).update(kwargs) - - @property - def path(self): - """ - The sequence of directory path that a distribution finder - should search. - - Typically refers to Python installed package paths such as - "site-packages" directories and defaults to ``sys.path``. - """ - return vars(self).get('path', sys.path) - - @abc.abstractmethod - def find_distributions(self, context=Context()): - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching the ``context``, - a DistributionFinder.Context instance. - """ - - -class FastPath: - """ - Micro-optimized class for searching a path for - children. - - >>> FastPath('').children() - ['...'] - """ - - @functools.lru_cache() # type: ignore - def __new__(cls, root): - return super().__new__(cls) - - def __init__(self, root): - self.root = root - - def joinpath(self, child): - return pathlib.Path(self.root, child) - - def children(self): - with suppress(Exception): - return os.listdir(self.root or '.') - with suppress(Exception): - return self.zip_children() - return [] - - def zip_children(self): - zip_path = zipp.Path(self.root) - names = zip_path.root.namelist() - self.joinpath = zip_path.joinpath - - return dict.fromkeys(child.split(posixpath.sep, 1)[0] for child in names) - - def search(self, name): - return self.lookup(self.mtime).search(name) - - @property - def mtime(self): - with suppress(OSError): - return os.stat(self.root).st_mtime - self.lookup.cache_clear() - - @method_cache - def lookup(self, mtime): - return Lookup(self) - - -class Lookup: - def __init__(self, path: FastPath): - base = os.path.basename(path.root).lower() - base_is_egg = base.endswith(".egg") - self.infos = FreezableDefaultDict(list) - self.eggs = FreezableDefaultDict(list) - - for child in path.children(): - low = child.lower() - if low.endswith((".dist-info", ".egg-info")): - # rpartition is faster than splitext and suitable for this purpose. - name = low.rpartition(".")[0].partition("-")[0] - normalized = Prepared.normalize(name) - self.infos[normalized].append(path.joinpath(child)) - elif base_is_egg and low == "egg-info": - name = base.rpartition(".")[0].partition("-")[0] - legacy_normalized = Prepared.legacy_normalize(name) - self.eggs[legacy_normalized].append(path.joinpath(child)) - - self.infos.freeze() - self.eggs.freeze() - - def search(self, prepared): - infos = ( - self.infos[prepared.normalized] - if prepared - else itertools.chain.from_iterable(self.infos.values()) - ) - eggs = ( - self.eggs[prepared.legacy_normalized] - if prepared - else itertools.chain.from_iterable(self.eggs.values()) - ) - return itertools.chain(infos, eggs) - - -class Prepared: - """ - A prepared search for metadata on a possibly-named package. - """ - - normalized = None - legacy_normalized = None - - def __init__(self, name): - self.name = name - if name is None: - return - self.normalized = self.normalize(name) - self.legacy_normalized = self.legacy_normalize(name) - - @staticmethod - def normalize(name): - """ - PEP 503 normalization plus dashes as underscores. - """ - return re.sub(r"[-_.]+", "-", name).lower().replace('-', '_') - - @staticmethod - def legacy_normalize(name): - """ - Normalize the package name as found in the convention in - older packaging tools versions and specs. - """ - return name.lower().replace('-', '_') - - def __bool__(self): - return bool(self.name) - - -@install -class MetadataPathFinder(NullFinder, DistributionFinder): - """A degenerate finder for distribution packages on the file system. - - This finder supplies only a find_distributions() method for versions - of Python that do not have a PathFinder find_distributions(). - """ - - def find_distributions(self, context=DistributionFinder.Context()): - """ - Find distributions. - - Return an iterable of all Distribution instances capable of - loading the metadata for packages matching ``context.name`` - (or all names if ``None`` indicated) along the paths in the list - of directories ``context.path``. - """ - found = self._search_paths(context.name, context.path) - return map(PathDistribution, found) - - @classmethod - def _search_paths(cls, name, paths): - """Find metadata directories in paths heuristically.""" - prepared = Prepared(name) - return itertools.chain.from_iterable( - path.search(prepared) for path in map(FastPath, paths) - ) - - def invalidate_caches(cls): - FastPath.__new__.cache_clear() - - -class PathDistribution(Distribution): - def __init__(self, path: SimplePath): - """Construct a distribution. - - :param path: SimplePath indicating the metadata directory. - """ - self._path = path - - def read_text(self, filename): - with suppress( - FileNotFoundError, - IsADirectoryError, - KeyError, - NotADirectoryError, - PermissionError, - ): - return self._path.joinpath(filename).read_text(encoding='utf-8') - - read_text.__doc__ = Distribution.read_text.__doc__ - - def locate_file(self, path): - return self._path.parent / path - - @property - def _normalized_name(self): - """ - Performance optimization: where possible, resolve the - normalized name from the file system path. - """ - stem = os.path.basename(str(self._path)) - return ( - pass_none(Prepared.normalize)(self._name_from_stem(stem)) - or super()._normalized_name - ) - - @staticmethod - def _name_from_stem(stem): - """ - >>> PathDistribution._name_from_stem('foo-3.0.egg-info') - 'foo' - >>> PathDistribution._name_from_stem('CherryPy-3.0.dist-info') - 'CherryPy' - >>> PathDistribution._name_from_stem('face.egg-info') - 'face' - >>> PathDistribution._name_from_stem('foo.bar') - """ - filename, ext = os.path.splitext(stem) - if ext not in ('.dist-info', '.egg-info'): - return - name, sep, rest = filename.partition('-') - return name - - -def distribution(distribution_name): - """Get the ``Distribution`` instance for the named package. - - :param distribution_name: The name of the distribution package as a string. - :return: A ``Distribution`` instance (or subclass thereof). - """ - return Distribution.from_name(distribution_name) - - -def distributions(**kwargs): - """Get all ``Distribution`` instances in the current environment. - - :return: An iterable of ``Distribution`` instances. - """ - return Distribution.discover(**kwargs) - - -def metadata(distribution_name) -> _meta.PackageMetadata: - """Get the metadata for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: A PackageMetadata containing the parsed metadata. - """ - return Distribution.from_name(distribution_name).metadata - - -def version(distribution_name): - """Get the version string for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: The version string for the package as defined in the package's - "Version" metadata key. - """ - return distribution(distribution_name).version - - -_unique = functools.partial( - unique_everseen, - key=_py39compat.normalized_name, -) -""" -Wrapper for ``distributions`` to return unique distributions by name. -""" - - -def entry_points(**params) -> EntryPoints: - """Return EntryPoint objects for all installed packages. - - Pass selection parameters (group or name) to filter the - result to entry points matching those properties (see - EntryPoints.select()). - - :return: EntryPoints for all installed packages. - """ - eps = itertools.chain.from_iterable( - dist.entry_points for dist in _unique(distributions()) - ) - return EntryPoints(eps).select(**params) - - -def files(distribution_name): - """Return a list of files for the named package. - - :param distribution_name: The name of the distribution package to query. - :return: List of files composing the distribution. - """ - return distribution(distribution_name).files - - -def requires(distribution_name): - """ - Return a list of requirements for the named package. - - :return: An iterator of requirements, suitable for - packaging.requirement.Requirement. - """ - return distribution(distribution_name).requires - - -def packages_distributions() -> Mapping[str, List[str]]: - """ - Return a mapping of top-level packages to their - distributions. - - >>> import collections.abc - >>> pkgs = packages_distributions() - >>> all(isinstance(dist, collections.abc.Sequence) for dist in pkgs.values()) - True - """ - pkg_to_dist = collections.defaultdict(list) - for dist in distributions(): - for pkg in _top_level_declared(dist) or _top_level_inferred(dist): - pkg_to_dist[pkg].append(dist.metadata['Name']) - return dict(pkg_to_dist) - - -def _top_level_declared(dist): - return (dist.read_text('top_level.txt') or '').split() - - -def _top_level_inferred(dist): - return { - f.parts[0] if len(f.parts) > 1 else f.with_suffix('').name - for f in always_iterable(dist.files) - if f.suffix == ".py" - } diff --git a/vendor/importlib_metadata/importlib_metadata/_adapters.py b/vendor/importlib_metadata/importlib_metadata/_adapters.py deleted file mode 100644 index aa460d3..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_adapters.py +++ /dev/null @@ -1,68 +0,0 @@ -import re -import textwrap -import email.message - -from ._text import FoldedCase - - -class Message(email.message.Message): - multiple_use_keys = set( - map( - FoldedCase, - [ - 'Classifier', - 'Obsoletes-Dist', - 'Platform', - 'Project-URL', - 'Provides-Dist', - 'Provides-Extra', - 'Requires-Dist', - 'Requires-External', - 'Supported-Platform', - 'Dynamic', - ], - ) - ) - """ - Keys that may be indicated multiple times per PEP 566. - """ - - def __new__(cls, orig: email.message.Message): - res = super().__new__(cls) - vars(res).update(vars(orig)) - return res - - def __init__(self, *args, **kwargs): - self._headers = self._repair_headers() - - # suppress spurious error from mypy - def __iter__(self): - return super().__iter__() - - def _repair_headers(self): - def redent(value): - "Correct for RFC822 indentation" - if not value or '\n' not in value: - return value - return textwrap.dedent(' ' * 8 + value) - - headers = [(key, redent(value)) for key, value in vars(self)['_headers']] - if self._payload: - headers.append(('Description', self.get_payload())) - return headers - - @property - def json(self): - """ - Convert PackageMetadata to a JSON-compatible format - per PEP 0566. - """ - - def transform(key): - value = self.get_all(key) if key in self.multiple_use_keys else self[key] - if key == 'Keywords': - value = re.split(r'\s+', value) - tk = key.lower().replace('-', '_') - return tk, value - - return dict(map(transform, map(FoldedCase, self))) diff --git a/vendor/importlib_metadata/importlib_metadata/_collections.py b/vendor/importlib_metadata/importlib_metadata/_collections.py deleted file mode 100644 index cf0954e..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_collections.py +++ /dev/null @@ -1,30 +0,0 @@ -import collections - - -# from jaraco.collections 3.3 -class FreezableDefaultDict(collections.defaultdict): - """ - Often it is desirable to prevent the mutation of - a default dict after its initial construction, such - as to prevent mutation during iteration. - - >>> dd = FreezableDefaultDict(list) - >>> dd[0].append('1') - >>> dd.freeze() - >>> dd[1] - [] - >>> len(dd) - 1 - """ - - def __missing__(self, key): - return getattr(self, '_frozen', super().__missing__)(key) - - def freeze(self): - self._frozen = lambda key: self.default_factory() - - -class Pair(collections.namedtuple('Pair', 'name value')): - @classmethod - def parse(cls, text): - return cls(*map(str.strip, text.split("=", 1))) diff --git a/vendor/importlib_metadata/importlib_metadata/_compat.py b/vendor/importlib_metadata/importlib_metadata/_compat.py deleted file mode 100644 index 3d78566..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_compat.py +++ /dev/null @@ -1,72 +0,0 @@ -import sys -import platform - - -__all__ = ['install', 'NullFinder', 'Protocol'] - - -try: - from typing import Protocol -except ImportError: # pragma: no cover - # Python 3.7 compatibility - from typing_extensions import Protocol # type: ignore - - -def install(cls): - """ - Class decorator for installation on sys.meta_path. - - Adds the backport DistributionFinder to sys.meta_path and - attempts to disable the finder functionality of the stdlib - DistributionFinder. - """ - sys.meta_path.append(cls()) - disable_stdlib_finder() - return cls - - -def disable_stdlib_finder(): - """ - Give the backport primacy for discovering path-based distributions - by monkey-patching the stdlib O_O. - - See #91 for more background for rationale on this sketchy - behavior. - """ - - def matches(finder): - return getattr( - finder, '__module__', None - ) == '_frozen_importlib_external' and hasattr(finder, 'find_distributions') - - for finder in filter(matches, sys.meta_path): # pragma: nocover - del finder.find_distributions - - -class NullFinder: - """ - A "Finder" (aka "MetaClassFinder") that never finds any modules, - but may find distributions. - """ - - @staticmethod - def find_spec(*args, **kwargs): - return None - - # In Python 2, the import system requires finders - # to have a find_module() method, but this usage - # is deprecated in Python 3 in favor of find_spec(). - # For the purposes of this finder (i.e. being present - # on sys.meta_path but having no other import - # system functionality), the two methods are identical. - find_module = find_spec - - -def pypy_partial(val): - """ - Adjust for variable stacklevel on partial under PyPy. - - Workaround for #327. - """ - is_pypy = platform.python_implementation() == 'PyPy' - return val + is_pypy diff --git a/vendor/importlib_metadata/importlib_metadata/_functools.py b/vendor/importlib_metadata/importlib_metadata/_functools.py deleted file mode 100644 index 71f66bd..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_functools.py +++ /dev/null @@ -1,104 +0,0 @@ -import types -import functools - - -# from jaraco.functools 3.3 -def method_cache(method, cache_wrapper=None): - """ - Wrap lru_cache to support storing the cache data in the object instances. - - Abstracts the common paradigm where the method explicitly saves an - underscore-prefixed protected property on first call and returns that - subsequently. - - >>> class MyClass: - ... calls = 0 - ... - ... @method_cache - ... def method(self, value): - ... self.calls += 1 - ... return value - - >>> a = MyClass() - >>> a.method(3) - 3 - >>> for x in range(75): - ... res = a.method(x) - >>> a.calls - 75 - - Note that the apparent behavior will be exactly like that of lru_cache - except that the cache is stored on each instance, so values in one - instance will not flush values from another, and when an instance is - deleted, so are the cached values for that instance. - - >>> b = MyClass() - >>> for x in range(35): - ... res = b.method(x) - >>> b.calls - 35 - >>> a.method(0) - 0 - >>> a.calls - 75 - - Note that if method had been decorated with ``functools.lru_cache()``, - a.calls would have been 76 (due to the cached value of 0 having been - flushed by the 'b' instance). - - Clear the cache with ``.cache_clear()`` - - >>> a.method.cache_clear() - - Same for a method that hasn't yet been called. - - >>> c = MyClass() - >>> c.method.cache_clear() - - Another cache wrapper may be supplied: - - >>> cache = functools.lru_cache(maxsize=2) - >>> MyClass.method2 = method_cache(lambda self: 3, cache_wrapper=cache) - >>> a = MyClass() - >>> a.method2() - 3 - - Caution - do not subsequently wrap the method with another decorator, such - as ``@property``, which changes the semantics of the function. - - See also - http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/ - for another implementation and additional justification. - """ - cache_wrapper = cache_wrapper or functools.lru_cache() - - def wrapper(self, *args, **kwargs): - # it's the first call, replace the method with a cached, bound method - bound_method = types.MethodType(method, self) - cached_method = cache_wrapper(bound_method) - setattr(self, method.__name__, cached_method) - return cached_method(*args, **kwargs) - - # Support cache clear even before cache has been created. - wrapper.cache_clear = lambda: None - - return wrapper - - -# From jaraco.functools 3.3 -def pass_none(func): - """ - Wrap func so it's not called if its first param is None - - >>> print_text = pass_none(print) - >>> print_text('text') - text - >>> print_text(None) - """ - - @functools.wraps(func) - def wrapper(param, *args, **kwargs): - if param is not None: - return func(param, *args, **kwargs) - - return wrapper diff --git a/vendor/importlib_metadata/importlib_metadata/_itertools.py b/vendor/importlib_metadata/importlib_metadata/_itertools.py deleted file mode 100644 index d4ca9b9..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_itertools.py +++ /dev/null @@ -1,73 +0,0 @@ -from itertools import filterfalse - - -def unique_everseen(iterable, key=None): - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - # unique_everseen('ABBCcAD', str.lower) --> A B C D - seen = set() - seen_add = seen.add - if key is None: - for element in filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element - - -# copied from more_itertools 8.8 -def always_iterable(obj, base_type=(str, bytes)): - """If *obj* is iterable, return an iterator over its items:: - - >>> obj = (1, 2, 3) - >>> list(always_iterable(obj)) - [1, 2, 3] - - If *obj* is not iterable, return a one-item iterable containing *obj*:: - - >>> obj = 1 - >>> list(always_iterable(obj)) - [1] - - If *obj* is ``None``, return an empty iterable: - - >>> obj = None - >>> list(always_iterable(None)) - [] - - By default, binary and text strings are not considered iterable:: - - >>> obj = 'foo' - >>> list(always_iterable(obj)) - ['foo'] - - If *base_type* is set, objects for which ``isinstance(obj, base_type)`` - returns ``True`` won't be considered iterable. - - >>> obj = {'a': 1} - >>> list(always_iterable(obj)) # Iterate over the dict's keys - ['a'] - >>> list(always_iterable(obj, base_type=dict)) # Treat dicts as a unit - [{'a': 1}] - - Set *base_type* to ``None`` to avoid any special handling and treat objects - Python considers iterable as iterable: - - >>> obj = 'foo' - >>> list(always_iterable(obj, base_type=None)) - ['f', 'o', 'o'] - """ - if obj is None: - return iter(()) - - if (base_type is not None) and isinstance(obj, base_type): - return iter((obj,)) - - try: - return iter(obj) - except TypeError: - return iter((obj,)) diff --git a/vendor/importlib_metadata/importlib_metadata/_meta.py b/vendor/importlib_metadata/importlib_metadata/_meta.py deleted file mode 100644 index 37ee43e..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_meta.py +++ /dev/null @@ -1,48 +0,0 @@ -from ._compat import Protocol -from typing import Any, Dict, Iterator, List, TypeVar, Union - - -_T = TypeVar("_T") - - -class PackageMetadata(Protocol): - def __len__(self) -> int: - ... # pragma: no cover - - def __contains__(self, item: str) -> bool: - ... # pragma: no cover - - def __getitem__(self, key: str) -> str: - ... # pragma: no cover - - def __iter__(self) -> Iterator[str]: - ... # pragma: no cover - - def get_all(self, name: str, failobj: _T = ...) -> Union[List[Any], _T]: - """ - Return all values associated with a possibly multi-valued key. - """ - - @property - def json(self) -> Dict[str, Union[str, List[str]]]: - """ - A JSON-compatible form of the metadata. - """ - - -class SimplePath(Protocol): - """ - A minimal subset of pathlib.Path required by PathDistribution. - """ - - def joinpath(self) -> 'SimplePath': - ... # pragma: no cover - - def __truediv__(self) -> 'SimplePath': - ... # pragma: no cover - - def parent(self) -> 'SimplePath': - ... # pragma: no cover - - def read_text(self) -> str: - ... # pragma: no cover diff --git a/vendor/importlib_metadata/importlib_metadata/_py39compat.py b/vendor/importlib_metadata/importlib_metadata/_py39compat.py deleted file mode 100644 index cf9cc12..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_py39compat.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -Compatibility layer with Python 3.8/3.9 -""" -from typing import TYPE_CHECKING, Any, Optional, Tuple - -if TYPE_CHECKING: # pragma: no cover - # Prevent circular imports on runtime. - from . import Distribution, EntryPoint -else: - Distribution = EntryPoint = Any - - -def normalized_name(dist: Distribution) -> Optional[str]: - """ - Honor name normalization for distributions that don't provide ``_normalized_name``. - """ - try: - return dist._normalized_name - except AttributeError: - from . import Prepared # -> delay to prevent circular imports. - - return Prepared.normalize(getattr(dist, "name", None) or dist.metadata['Name']) - - -def ep_matches(ep: EntryPoint, **params) -> Tuple[EntryPoint, bool]: - """ - Workaround for ``EntryPoint`` objects without the ``matches`` method. - For the sake of convenience, a tuple is returned containing not only the - boolean value corresponding to the predicate evalutation, but also a compatible - ``EntryPoint`` object that can be safely used at a later stage. - - For example, the following sequences of expressions should be compatible: - - # Sequence 1: using the compatibility layer - candidates = (_py39compat.ep_matches(ep, **params) for ep in entry_points) - [ep for ep, predicate in candidates if predicate] - - # Sequence 2: using Python 3.9+ - [ep for ep in entry_points if ep.matches(**params)] - """ - try: - return ep, ep.matches(**params) - except AttributeError: - from . import EntryPoint # -> delay to prevent circular imports. - - # Reconstruct the EntryPoint object to make sure it is compatible. - _ep = EntryPoint(ep.name, ep.value, ep.group) - return _ep, _ep.matches(**params) diff --git a/vendor/importlib_metadata/importlib_metadata/_text.py b/vendor/importlib_metadata/importlib_metadata/_text.py deleted file mode 100644 index c88cfbb..0000000 --- a/vendor/importlib_metadata/importlib_metadata/_text.py +++ /dev/null @@ -1,99 +0,0 @@ -import re - -from ._functools import method_cache - - -# from jaraco.text 3.5 -class FoldedCase(str): - """ - A case insensitive string class; behaves just like str - except compares equal when the only variation is case. - - >>> s = FoldedCase('hello world') - - >>> s == 'Hello World' - True - - >>> 'Hello World' == s - True - - >>> s != 'Hello World' - False - - >>> s.index('O') - 4 - - >>> s.split('O') - ['hell', ' w', 'rld'] - - >>> sorted(map(FoldedCase, ['GAMMA', 'alpha', 'Beta'])) - ['alpha', 'Beta', 'GAMMA'] - - Sequence membership is straightforward. - - >>> "Hello World" in [s] - True - >>> s in ["Hello World"] - True - - You may test for set inclusion, but candidate and elements - must both be folded. - - >>> FoldedCase("Hello World") in {s} - True - >>> s in {FoldedCase("Hello World")} - True - - String inclusion works as long as the FoldedCase object - is on the right. - - >>> "hello" in FoldedCase("Hello World") - True - - But not if the FoldedCase object is on the left: - - >>> FoldedCase('hello') in 'Hello World' - False - - In that case, use in_: - - >>> FoldedCase('hello').in_('Hello World') - True - - >>> FoldedCase('hello') > FoldedCase('Hello') - False - """ - - def __lt__(self, other): - return self.lower() < other.lower() - - def __gt__(self, other): - return self.lower() > other.lower() - - def __eq__(self, other): - return self.lower() == other.lower() - - def __ne__(self, other): - return self.lower() != other.lower() - - def __hash__(self): - return hash(self.lower()) - - def __contains__(self, other): - return super().lower().__contains__(other.lower()) - - def in_(self, other): - "Does self appear in other?" - return self in FoldedCase(other) - - # cache lower since it's likely to be called frequently. - @method_cache - def lower(self): - return super().lower() - - def index(self, sub): - return self.lower().index(sub.lower()) - - def split(self, splitter=' ', maxsplit=0): - pattern = re.compile(re.escape(splitter), re.I) - return pattern.split(self, maxsplit) diff --git a/vendor/importlib_metadata/importlib_metadata/py.typed b/vendor/importlib_metadata/importlib_metadata/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/zipp/BUILD.bazel b/vendor/zipp/BUILD.bazel deleted file mode 100644 index 48226d9..0000000 --- a/vendor/zipp/BUILD.bazel +++ /dev/null @@ -1,7 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -py_library( - name = "zipp", - srcs = glob(["**/*.py"]), - imports = ["."], -) diff --git a/vendor/zipp/CHANGES.rst b/vendor/zipp/CHANGES.rst deleted file mode 100644 index 3ec5467..0000000 --- a/vendor/zipp/CHANGES.rst +++ /dev/null @@ -1,224 +0,0 @@ -v3.9.0 -====== - -* #81: ``Path`` objects are now pickleable if they've been - constructed from pickleable objects. Any restored objects - will re-construct the zip file with the original arguments. - -v3.8.1 -====== - -Refreshed packaging. - -Enrolled with Tidelift. - -v3.8.0 -====== - -Removed compatibility code. - -v3.7.0 -====== - -Require Python 3.7 or later. - -v3.6.0 -====== - -#78: Only ``Path`` is exposed in the public API. - -v3.5.1 -====== - -#77: Remove news file intended only for CPython. - -v3.5.0 -====== - -#74 and bpo-44095: Added ``.suffix``, ``.suffixes``, -and ``.stem`` properties. - -v3.4.2 -====== - -Refresh package metadata. - -v3.4.1 -====== - -Refresh packaging. - -v3.4.0 -====== - -#68 and bpo-42090: ``Path.joinpath`` now takes arbitrary -positional arguments and no longer accepts ``add`` as a -keyword argument. - -v3.3.2 -====== - -Updated project metadata including badges. - -v3.3.1 -====== - -bpo-42043: Add tests capturing subclassing requirements. - -v3.3.0 -====== - -#9: ``Path`` objects now expose a ``.filename`` attribute -and rely on that to resolve ``.name`` and ``.parent`` when -the ``Path`` object is at the root of the zipfile. - -v3.2.0 -====== - -#57 and bpo-40564: Mutate the passed ZipFile object -type instead of making a copy. Prevents issues when -both the local copy and the caller's copy attempt to -close the same file handle. - -#56 and bpo-41035: ``Path._next`` now honors -subclasses. - -#55: ``Path.is_file()`` now returns False for non-existent names. - -v3.1.0 -====== - -#47: ``.open`` now raises ``FileNotFoundError`` and -``IsADirectoryError`` when appropriate. - -v3.0.0 -====== - -#44: Merge with v1.2.0. - -v1.2.0 -====== - -#44: ``zipp.Path.open()`` now supports a compatible signature -as ``pathlib.Path.open()``, accepting text (default) or binary -modes and soliciting keyword parameters passed through to -``io.TextIOWrapper`` (encoding, newline, etc). The stream is -opened in text-mode by default now. ``open`` no -longer accepts ``pwd`` as a positional argument and does not -accept the ``force_zip64`` parameter at all. This change is -a backward-incompatible change for that single function. - -v2.2.1 -====== - -#43: Merge with v1.1.1. - -v1.1.1 -====== - -#43: Restored performance of implicit dir computation. - -v2.2.0 -====== - -#36: Rebuild package with minimum Python version declared both -in package metadata and in the python tag. - -v2.1.0 -====== - -#32: Merge with v1.1.0. - -v1.1.0 -====== - -#32: For read-only zip files, complexity of ``.exists`` and -``joinpath`` is now constant time instead of ``O(n)``, preventing -quadratic time in common use-cases and rendering large -zip files unusable for Path. Big thanks to Benjy Weinberger -for the bug report and contributed fix (#33). - -v2.0.1 -====== - -#30: Corrected version inference (from jaraco/skeleton#12). - -v2.0.0 -====== - -Require Python 3.6 or later. - -v1.0.0 -====== - -Re-release of 0.6 to correspond with release as found in -Python 3.8. - -v0.6.0 -====== - -#12: When adding implicit dirs, ensure that ancestral directories -are added and that duplicates are excluded. - -The library now relies on -`more_itertools `_. - -v0.5.2 -====== - -#7: Parent of a directory now actually returns the parent. - -v0.5.1 -====== - -Declared package as backport. - -v0.5.0 -====== - -Add ``.joinpath()`` method and ``.parent`` property. - -Now a backport release of the ``zipfile.Path`` class. - -v0.4.0 -====== - -#4: Add support for zip files with implied directories. - -v0.3.3 -====== - -#3: Fix issue where ``.name`` on a directory was empty. - -v0.3.2 -====== - -#2: Fix TypeError on Python 2.7 when classic division is used. - -v0.3.1 -====== - -#1: Fix TypeError on Python 3.5 when joining to a path-like object. - -v0.3.0 -====== - -Add support for constructing a ``zipp.Path`` from any path-like -object. - -``zipp.Path`` is now a new-style class on Python 2.7. - -v0.2.1 -====== - -Fix issue with ``__str__``. - -v0.2.0 -====== - -Drop reliance on future-fstrings. - -v0.1.0 -====== - -Initial release with basic functionality. diff --git a/vendor/zipp/LICENSE b/vendor/zipp/LICENSE deleted file mode 100644 index 353924b..0000000 --- a/vendor/zipp/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright Jason R. Coombs - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/vendor/zipp/README.rst b/vendor/zipp/README.rst deleted file mode 100644 index 4a4c394..0000000 --- a/vendor/zipp/README.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. image:: https://img.shields.io/pypi/v/zipp.svg - :target: `PyPI link`_ - -.. image:: https://img.shields.io/pypi/pyversions/zipp.svg - :target: `PyPI link`_ - -.. _PyPI link: https://pypi.org/project/zipp - -.. image:: https://github.com/jaraco/zipp/workflows/tests/badge.svg - :target: https://github.com/jaraco/zipp/actions?query=workflow%3A%22tests%22 - :alt: tests - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: Black - -.. .. image:: https://readthedocs.org/projects/skeleton/badge/?version=latest -.. :target: https://skeleton.readthedocs.io/en/latest/?badge=latest - -.. image:: https://img.shields.io/badge/skeleton-2022-informational - :target: https://blog.jaraco.com/skeleton - -.. image:: https://tidelift.com/badges/package/pypi/zipp - :target: https://tidelift.com/subscription/pkg/pypi-zipp?utm_source=pypi-zipp&utm_medium=readme - - -A pathlib-compatible Zipfile object wrapper. Official backport of the standard library -`Path object `_. - - -Compatibility -============= - -New features are introduced in this third-party library and later merged -into CPython. The following table indicates which versions of this library -were contributed to different versions in the standard library: - -.. list-table:: - :header-rows: 1 - - * - zipp - - stdlib - * - 3.5 - - 3.11 - * - 3.3 - - 3.9 - * - 1.0 - - 3.8 - - -Usage -===== - -Use ``zipp.Path`` in place of ``zipfile.Path`` on any Python. - -For Enterprise -============== - -Available as part of the Tidelift Subscription. - -This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. - -`Learn more `_. - -Security Contact -================ - -To report a security vulnerability, please use the -`Tidelift security contact `_. -Tidelift will coordinate the fix and disclosure. diff --git a/vendor/zipp/zipp.py b/vendor/zipp/zipp.py deleted file mode 100644 index be1bdb0..0000000 --- a/vendor/zipp/zipp.py +++ /dev/null @@ -1,330 +0,0 @@ -import io -import posixpath -import zipfile -import itertools -import contextlib -import pathlib - - -__all__ = ['Path'] - - -def _parents(path): - """ - Given a path with elements separated by - posixpath.sep, generate all parents of that path. - - >>> list(_parents('b/d')) - ['b'] - >>> list(_parents('/b/d/')) - ['/b'] - >>> list(_parents('b/d/f/')) - ['b/d', 'b'] - >>> list(_parents('b')) - [] - >>> list(_parents('')) - [] - """ - return itertools.islice(_ancestry(path), 1, None) - - -def _ancestry(path): - """ - Given a path with elements separated by - posixpath.sep, generate all elements of that path - - >>> list(_ancestry('b/d')) - ['b/d', 'b'] - >>> list(_ancestry('/b/d/')) - ['/b/d', '/b'] - >>> list(_ancestry('b/d/f/')) - ['b/d/f', 'b/d', 'b'] - >>> list(_ancestry('b')) - ['b'] - >>> list(_ancestry('')) - [] - """ - path = path.rstrip(posixpath.sep) - while path and path != posixpath.sep: - yield path - path, tail = posixpath.split(path) - - -_dedupe = dict.fromkeys -"""Deduplicate an iterable in original order""" - - -def _difference(minuend, subtrahend): - """ - Return items in minuend not in subtrahend, retaining order - with O(1) lookup. - """ - return itertools.filterfalse(set(subtrahend).__contains__, minuend) - - -class InitializedState: - """ - Mix-in to save the initialization state for pickling. - """ - - def __init__(self, *args, **kwargs): - self.__args = args - self.__kwargs = kwargs - super().__init__(*args, **kwargs) - - def __getstate__(self): - return self.__args, self.__kwargs - - def __setstate__(self, state): - args, kwargs = state - super().__init__(*args, **kwargs) - - -class CompleteDirs(InitializedState, zipfile.ZipFile): - """ - A ZipFile subclass that ensures that implied directories - are always included in the namelist. - """ - - @staticmethod - def _implied_dirs(names): - parents = itertools.chain.from_iterable(map(_parents, names)) - as_dirs = (p + posixpath.sep for p in parents) - return _dedupe(_difference(as_dirs, names)) - - def namelist(self): - names = super(CompleteDirs, self).namelist() - return names + list(self._implied_dirs(names)) - - def _name_set(self): - return set(self.namelist()) - - def resolve_dir(self, name): - """ - If the name represents a directory, return that name - as a directory (with the trailing slash). - """ - names = self._name_set() - dirname = name + '/' - dir_match = name not in names and dirname in names - return dirname if dir_match else name - - @classmethod - def make(cls, source): - """ - Given a source (filename or zipfile), return an - appropriate CompleteDirs subclass. - """ - if isinstance(source, CompleteDirs): - return source - - if not isinstance(source, zipfile.ZipFile): - return cls(source) - - # Only allow for FastLookup when supplied zipfile is read-only - if 'r' not in source.mode: - cls = CompleteDirs - - source.__class__ = cls - return source - - -class FastLookup(CompleteDirs): - """ - ZipFile subclass to ensure implicit - dirs exist and are resolved rapidly. - """ - - def namelist(self): - with contextlib.suppress(AttributeError): - return self.__names - self.__names = super(FastLookup, self).namelist() - return self.__names - - def _name_set(self): - with contextlib.suppress(AttributeError): - return self.__lookup - self.__lookup = super(FastLookup, self)._name_set() - return self.__lookup - - -class Path: - """ - A pathlib-compatible interface for zip files. - - Consider a zip file with this structure:: - - . - ├── a.txt - └── b - ├── c.txt - └── d - └── e.txt - - >>> data = io.BytesIO() - >>> zf = zipfile.ZipFile(data, 'w') - >>> zf.writestr('a.txt', 'content of a') - >>> zf.writestr('b/c.txt', 'content of c') - >>> zf.writestr('b/d/e.txt', 'content of e') - >>> zf.filename = 'mem/abcde.zip' - - Path accepts the zipfile object itself or a filename - - >>> root = Path(zf) - - From there, several path operations are available. - - Directory iteration (including the zip file itself): - - >>> a, b = root.iterdir() - >>> a - Path('mem/abcde.zip', 'a.txt') - >>> b - Path('mem/abcde.zip', 'b/') - - name property: - - >>> b.name - 'b' - - join with divide operator: - - >>> c = b / 'c.txt' - >>> c - Path('mem/abcde.zip', 'b/c.txt') - >>> c.name - 'c.txt' - - Read text: - - >>> c.read_text() - 'content of c' - - existence: - - >>> c.exists() - True - >>> (b / 'missing.txt').exists() - False - - Coercion to string: - - >>> import os - >>> str(c).replace(os.sep, posixpath.sep) - 'mem/abcde.zip/b/c.txt' - - At the root, ``name``, ``filename``, and ``parent`` - resolve to the zipfile. Note these attributes are not - valid and will raise a ``ValueError`` if the zipfile - has no filename. - - >>> root.name - 'abcde.zip' - >>> str(root.filename).replace(os.sep, posixpath.sep) - 'mem/abcde.zip' - >>> str(root.parent) - 'mem' - """ - - __repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})" - - def __init__(self, root, at=""): - """ - Construct a Path from a ZipFile or filename. - - Note: When the source is an existing ZipFile object, - its type (__class__) will be mutated to a - specialized type. If the caller wishes to retain the - original type, the caller should either create a - separate ZipFile object or pass a filename. - """ - self.root = FastLookup.make(root) - self.at = at - - def open(self, mode='r', *args, pwd=None, **kwargs): - """ - Open this entry as text or binary following the semantics - of ``pathlib.Path.open()`` by passing arguments through - to io.TextIOWrapper(). - """ - if self.is_dir(): - raise IsADirectoryError(self) - zip_mode = mode[0] - if not self.exists() and zip_mode == 'r': - raise FileNotFoundError(self) - stream = self.root.open(self.at, zip_mode, pwd=pwd) - if 'b' in mode: - if args or kwargs: - raise ValueError("encoding args invalid for binary operation") - return stream - return io.TextIOWrapper(stream, *args, **kwargs) - - @property - def name(self): - return pathlib.Path(self.at).name or self.filename.name - - @property - def suffix(self): - return pathlib.Path(self.at).suffix or self.filename.suffix - - @property - def suffixes(self): - return pathlib.Path(self.at).suffixes or self.filename.suffixes - - @property - def stem(self): - return pathlib.Path(self.at).stem or self.filename.stem - - @property - def filename(self): - return pathlib.Path(self.root.filename).joinpath(self.at) - - def read_text(self, *args, **kwargs): - with self.open('r', *args, **kwargs) as strm: - return strm.read() - - def read_bytes(self): - with self.open('rb') as strm: - return strm.read() - - def _is_child(self, path): - return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/") - - def _next(self, at): - return self.__class__(self.root, at) - - def is_dir(self): - return not self.at or self.at.endswith("/") - - def is_file(self): - return self.exists() and not self.is_dir() - - def exists(self): - return self.at in self.root._name_set() - - def iterdir(self): - if not self.is_dir(): - raise ValueError("Can't listdir a file") - subs = map(self._next, self.root.namelist()) - return filter(self._is_child, subs) - - def __str__(self): - return posixpath.join(self.root.filename, self.at) - - def __repr__(self): - return self.__repr.format(self=self) - - def joinpath(self, *other): - next = posixpath.join(self.at, *other) - return self._next(self.root.resolve_dir(next)) - - __truediv__ = joinpath - - @property - def parent(self): - if not self.at: - return self.filename.parent - parent_at = posixpath.dirname(self.at.rstrip('/')) - if parent_at: - parent_at += '/' - return self._next(parent_at) diff --git a/venv.bzl b/venv.bzl.tmpl similarity index 93% rename from venv.bzl rename to venv.bzl.tmpl index 0ae293d..b1ce100 100644 --- a/venv.bzl +++ b/venv.bzl.tmpl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_python//python:defs.bzl", "py_binary") +load("@rules_python//python:defs.bzl", _py_binary = "py_binary") PYTHON_TOOLCHAIN_TYPE = "@bazel_tools//tools/python:toolchain_type" @@ -61,7 +61,7 @@ _py_venv_deps = rule( toolchains = [PYTHON_TOOLCHAIN_TYPE], ) -def py_venv(name, deps = None, extra_pip_commands = None, always_link = False, venv_location = None, **kwargs): +def py_venv(name, deps = None, extra_pip_commands = None, always_link = False, venv_location = None, py_binary = _py_binary, **kwargs): deps = deps or [] extra_pip_commands = extra_pip_commands or [] @@ -74,7 +74,6 @@ def py_venv(name, deps = None, extra_pip_commands = None, always_link = False, v commands = extra_pip_commands, always_link = always_link, output = out_name, - **kwargs, ) env = { @@ -87,9 +86,9 @@ def py_venv(name, deps = None, extra_pip_commands = None, always_link = False, v py_binary( name = name, srcs = ["@rules_pyvenv//:build_env.py"], - deps = ["@rules_pyvenv//vendor/importlib_metadata"], + deps = ["@%%NAME%%//importlib_metadata"], data = [out_label] + deps, main = "@rules_pyvenv//:build_env.py", env = env, - **kwargs, + **kwargs )