Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/INSTALLER +1 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/LICENSE.txt +20 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/METADATA +92 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/RECORD +407 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/REQUESTED +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/WHEEL +5 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/entry_points.txt +5 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/top_level.txt +1 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/pkg_resources/__init__.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/pkg_resources/py31compat.py +23 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/__init__.py +26 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/compat/__init__.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py +6 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/providers.py +124 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/reporters.py +37 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/resolvers.py +473 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/structs.py +165 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py +51 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py +24 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py +160 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/__init__.py +242 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_deprecation_warning.py +7 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_imp.py +82 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/__init__.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/more_itertools/__init__.py +4 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/more_itertools/more.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/more_itertools/recipes.py +620 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/ordered_set.py +488 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/__about__.py +27 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/__init__.py +26 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_compat.py +38 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_structures.py +86 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_typing.py +48 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/markers.py +328 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/requirements.py +145 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/specifiers.py +863 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/tags.py +751 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/utils.py +65 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/version.py +535 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/pyparsing.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/archive_util.py +205 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/build_meta.py +281 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/cli-32.exe +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/cli-64.exe +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/cli.exe +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/alias.py +78 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/bdist_egg.py +456 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/build_ext.py +328 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/easy_install.py +2290 -0
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright (c) 2008-2021 The pip developers (see AUTHORS.txt file)
|
| 2 |
+
|
| 3 |
+
Permission is hereby granted, free of charge, to any person obtaining
|
| 4 |
+
a copy of this software and associated documentation files (the
|
| 5 |
+
"Software"), to deal in the Software without restriction, including
|
| 6 |
+
without limitation the rights to use, copy, modify, merge, publish,
|
| 7 |
+
distribute, sublicense, and/or sell copies of the Software, and to
|
| 8 |
+
permit persons to whom the Software is furnished to do so, subject to
|
| 9 |
+
the following conditions:
|
| 10 |
+
|
| 11 |
+
The above copyright notice and this permission notice shall be
|
| 12 |
+
included in all copies or substantial portions of the Software.
|
| 13 |
+
|
| 14 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
| 15 |
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
| 16 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
| 17 |
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
| 18 |
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
| 19 |
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
| 20 |
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/METADATA
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.1
|
| 2 |
+
Name: pip
|
| 3 |
+
Version: 21.2.4
|
| 4 |
+
Summary: The PyPA recommended tool for installing Python packages.
|
| 5 |
+
Home-page: https://pip.pypa.io/
|
| 6 |
+
Author: The pip developers
|
| 7 |
+
Author-email: distutils-sig@python.org
|
| 8 |
+
License: MIT
|
| 9 |
+
Project-URL: Documentation, https://pip.pypa.io
|
| 10 |
+
Project-URL: Source, https://github.com/pypa/pip
|
| 11 |
+
Project-URL: Changelog, https://pip.pypa.io/en/stable/news/
|
| 12 |
+
Platform: UNKNOWN
|
| 13 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 14 |
+
Classifier: Intended Audience :: Developers
|
| 15 |
+
Classifier: License :: OSI Approved :: MIT License
|
| 16 |
+
Classifier: Topic :: Software Development :: Build Tools
|
| 17 |
+
Classifier: Programming Language :: Python
|
| 18 |
+
Classifier: Programming Language :: Python :: 3
|
| 19 |
+
Classifier: Programming Language :: Python :: 3 :: Only
|
| 20 |
+
Classifier: Programming Language :: Python :: 3.6
|
| 21 |
+
Classifier: Programming Language :: Python :: 3.7
|
| 22 |
+
Classifier: Programming Language :: Python :: 3.8
|
| 23 |
+
Classifier: Programming Language :: Python :: 3.9
|
| 24 |
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
| 25 |
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
| 26 |
+
Requires-Python: >=3.6
|
| 27 |
+
License-File: LICENSE.txt
|
| 28 |
+
|
| 29 |
+
pip - The Python Package Installer
|
| 30 |
+
==================================
|
| 31 |
+
|
| 32 |
+
.. image:: https://img.shields.io/pypi/v/pip.svg
|
| 33 |
+
:target: https://pypi.org/project/pip/
|
| 34 |
+
|
| 35 |
+
.. image:: https://readthedocs.org/projects/pip/badge/?version=latest
|
| 36 |
+
:target: https://pip.pypa.io/en/latest
|
| 37 |
+
|
| 38 |
+
pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.
|
| 39 |
+
|
| 40 |
+
Please take a look at our documentation for how to install and use pip:
|
| 41 |
+
|
| 42 |
+
* `Installation`_
|
| 43 |
+
* `Usage`_
|
| 44 |
+
|
| 45 |
+
We release updates regularly, with a new version every 3 months. Find more details in our documentation:
|
| 46 |
+
|
| 47 |
+
* `Release notes`_
|
| 48 |
+
* `Release process`_
|
| 49 |
+
|
| 50 |
+
In pip 20.3, we've `made a big improvement to the heart of pip`_; `learn more`_. We want your input, so `sign up for our user experience research studies`_ to help us do it right.
|
| 51 |
+
|
| 52 |
+
**Note**: pip 21.0, in January 2021, removed Python 2 support, per pip's `Python 2 support policy`_. Please migrate to Python 3.
|
| 53 |
+
|
| 54 |
+
If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:
|
| 55 |
+
|
| 56 |
+
* `Issue tracking`_
|
| 57 |
+
* `Discourse channel`_
|
| 58 |
+
* `User IRC`_
|
| 59 |
+
|
| 60 |
+
If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:
|
| 61 |
+
|
| 62 |
+
* `GitHub page`_
|
| 63 |
+
* `Development documentation`_
|
| 64 |
+
* `Development mailing list`_
|
| 65 |
+
* `Development IRC`_
|
| 66 |
+
|
| 67 |
+
Code of Conduct
|
| 68 |
+
---------------
|
| 69 |
+
|
| 70 |
+
Everyone interacting in the pip project's codebases, issue trackers, chat
|
| 71 |
+
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
|
| 72 |
+
|
| 73 |
+
.. _package installer: https://packaging.python.org/guides/tool-recommendations/
|
| 74 |
+
.. _Python Package Index: https://pypi.org
|
| 75 |
+
.. _Installation: https://pip.pypa.io/en/stable/installation/
|
| 76 |
+
.. _Usage: https://pip.pypa.io/en/stable/
|
| 77 |
+
.. _Release notes: https://pip.pypa.io/en/stable/news.html
|
| 78 |
+
.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
|
| 79 |
+
.. _GitHub page: https://github.com/pypa/pip
|
| 80 |
+
.. _Development documentation: https://pip.pypa.io/en/latest/development
|
| 81 |
+
.. _made a big improvement to the heart of pip: https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html
|
| 82 |
+
.. _learn more: https://pip.pypa.io/en/latest/user_guide/#changes-to-the-pip-dependency-resolver-in-20-3-2020
|
| 83 |
+
.. _sign up for our user experience research studies: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html
|
| 84 |
+
.. _Python 2 support policy: https://pip.pypa.io/en/latest/development/release-process/#python-2-support
|
| 85 |
+
.. _Issue tracking: https://github.com/pypa/pip/issues
|
| 86 |
+
.. _Discourse channel: https://discuss.python.org/c/packaging
|
| 87 |
+
.. _Development mailing list: https://mail.python.org/mailman3/lists/distutils-sig.python.org/
|
| 88 |
+
.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
|
| 89 |
+
.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
|
| 90 |
+
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
|
| 91 |
+
|
| 92 |
+
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/RECORD
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
../../../bin/pip,sha256=tzObN17Wbm7g14pPEhnDImT6UTGg53jn4T9cDgS2jjA,272
|
| 2 |
+
../../../bin/pip3,sha256=tzObN17Wbm7g14pPEhnDImT6UTGg53jn4T9cDgS2jjA,272
|
| 3 |
+
../../../bin/pip3.9,sha256=tzObN17Wbm7g14pPEhnDImT6UTGg53jn4T9cDgS2jjA,272
|
| 4 |
+
pip-21.2.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 5 |
+
pip-21.2.4.dist-info/LICENSE.txt,sha256=I6c2HCsVgQKLxiO52ivSSZeryqR4Gs5q1ESjeUT42uE,1090
|
| 6 |
+
pip-21.2.4.dist-info/METADATA,sha256=PGCimuD-VsKv664Ne_9navMt6I9Ym_rm5p_u6Ykgfd4,4165
|
| 7 |
+
pip-21.2.4.dist-info/RECORD,,
|
| 8 |
+
pip-21.2.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 9 |
+
pip-21.2.4.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
|
| 10 |
+
pip-21.2.4.dist-info/entry_points.txt,sha256=5ExSa1s54zSPNA_1epJn5SX06786S8k5YHwskMvVYzw,125
|
| 11 |
+
pip-21.2.4.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
| 12 |
+
pip/__init__.py,sha256=EkjFYKiNdO5r1TZT1K-GxPs3Bl2IdRXw75e7IVsKrmc,357
|
| 13 |
+
pip/__main__.py,sha256=mXwWDftNLMKfwVqKFWGE_uuBZvGSIiUELhLkeysIuZc,1198
|
| 14 |
+
pip/_internal/__init__.py,sha256=nnFCuxrPMgALrIDxSoy-H6Zj4W4UY60D-uL1aJyq0pc,573
|
| 15 |
+
pip/_internal/build_env.py,sha256=uqtt1F0185ctzme5UX43I6bFHVeORY7q-dyhpkk5NDE,10121
|
| 16 |
+
pip/_internal/cache.py,sha256=6VONtoReGZbBd7sqY1n6hwkdWC4iz3tmXwXwZjpjZKw,9958
|
| 17 |
+
pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132
|
| 18 |
+
pip/_internal/cli/autocompletion.py,sha256=NK5yqe49SgExZOCFVEUT5Bf0QV2CuITGK27WSo2MWg8,6399
|
| 19 |
+
pip/_internal/cli/base_command.py,sha256=Dq5oXBXYd24GaHs1vPt6CfYgCl22V_4tLEJqfQyBrdE,7596
|
| 20 |
+
pip/_internal/cli/cmdoptions.py,sha256=xOqvgDNfpkMXVjy0mH3hI0HyczVD6wMuP8K44qsvbew,28283
|
| 21 |
+
pip/_internal/cli/command_context.py,sha256=a1pBBvvGLDiZ1Kw64_4tT6HmRTwYDoYy8JFgG5Czn7s,760
|
| 22 |
+
pip/_internal/cli/main.py,sha256=ioJ8IVlb2K1qLOxR-tXkee9lURhYV89CDM71MKag7YY,2472
|
| 23 |
+
pip/_internal/cli/main_parser.py,sha256=Q9TnytfuC5Z2JSjBFWVGtEdYLFy7rukNIb04movHdAo,2614
|
| 24 |
+
pip/_internal/cli/parser.py,sha256=CDXTuFr2UD8ozOlZYf1KDziQdo9-X_IaYOiUcyJQwrA,10788
|
| 25 |
+
pip/_internal/cli/progress_bars.py,sha256=ha8wowclY8_PaoM0cz4G6qK37zjnzuxQ-ydOtzx4EMI,8300
|
| 26 |
+
pip/_internal/cli/req_command.py,sha256=ZlxKFS9LtEbE1IRB6JyeUeYMe7lvKxVIzpdvag-BHok,16548
|
| 27 |
+
pip/_internal/cli/spinners.py,sha256=TFhjxtOnLeNJ5YmRvQm4eKPgPbJNkZiqO8jOXuxRaYU,5076
|
| 28 |
+
pip/_internal/cli/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116
|
| 29 |
+
pip/_internal/commands/__init__.py,sha256=3f1ZVidEDfgmzAH7aypZLKOZUvUy7qxv4X1CiIZEN30,3776
|
| 30 |
+
pip/_internal/commands/cache.py,sha256=O1grQjTg6IRFs_8DxMH00583tmCR0ujqTMv_gZ0h0uU,7237
|
| 31 |
+
pip/_internal/commands/check.py,sha256=gPC6GTp7S9aK73IeZAW7Z6yxlMnWdMyDTq9er9nXpIY,1570
|
| 32 |
+
pip/_internal/commands/completion.py,sha256=4Uh_cg04qDmtmgLji-J4VJKZ8BaIBZy2_uTWLi8tiVk,2914
|
| 33 |
+
pip/_internal/commands/configuration.py,sha256=TK9VTXNJ5haVH0Dc_ylhqo6A9Q_GcNoNsAOMJff4MYY,8962
|
| 34 |
+
pip/_internal/commands/debug.py,sha256=f943fbrAUufQ7flAR2zHfI0oi_uqhJEEW7Fj_EiwB1Y,6647
|
| 35 |
+
pip/_internal/commands/download.py,sha256=VGyQ6TDLiqJqJXfJwr_D6ZuHnYfhmzZPQk1mRSQp3tQ,4949
|
| 36 |
+
pip/_internal/commands/freeze.py,sha256=x0-ia-MFrVvfYqe5p6yAWqzaK5AIi3SqqcXBJNvxXkg,2785
|
| 37 |
+
pip/_internal/commands/hash.py,sha256=Y5FQ_WgbuEFnJxyLZdNYP928BGWNyNm9ljIUr90R6tI,1664
|
| 38 |
+
pip/_internal/commands/help.py,sha256=F_IJkERv9gGfGC6YpBNYm_qs8xmBphUCfOuguNRSqLs,1132
|
| 39 |
+
pip/_internal/commands/index.py,sha256=xA5LSVy1kv-IAvsjIX6Wnk5ZHA0Y_m6AP9T5ZoUGs9o,4781
|
| 40 |
+
pip/_internal/commands/install.py,sha256=FV-qBbQ56TUEmLDtuWTMeNpD4aQtOpjBEi7ePqlEtSM,27493
|
| 41 |
+
pip/_internal/commands/list.py,sha256=fpG6_KYqtAEBV8uSlt_lfF7o1GTuS4UdobsZjVqZspQ,11753
|
| 42 |
+
pip/_internal/commands/search.py,sha256=P8GY077JmUwy7FiOgYJ1CPDsBPgmo7it-b14luquJN4,5543
|
| 43 |
+
pip/_internal/commands/show.py,sha256=2TxWaJ2saCDSVUVBoRYueijLiueid2DNOhZuM-jhGf0,7974
|
| 44 |
+
pip/_internal/commands/uninstall.py,sha256=0VQQMfPBTGSlWJn1RRgvYtJhSj7tQFYc3H1kOjrstRE,3480
|
| 45 |
+
pip/_internal/commands/wheel.py,sha256=UiH15NXfrJ9piFNg3oHm4n2Jyk9Ojv5q0MvrWbHB3Ac,6189
|
| 46 |
+
pip/_internal/configuration.py,sha256=QBLfhv-sbP-oR08NFxSYnv_mLB-SgtNOsWXAF9tDEcM,13725
|
| 47 |
+
pip/_internal/distributions/__init__.py,sha256=Hq6kt6gXBgjNit5hTTWLAzeCNOKoB-N0pGYSqehrli8,858
|
| 48 |
+
pip/_internal/distributions/base.py,sha256=GynlnVE3QLvNu4JvnxPO6D8IQSs_GAlFUabA6U-G-eU,1206
|
| 49 |
+
pip/_internal/distributions/installed.py,sha256=gT20WSniecOvKGMA-nCyq-4DcJlrIjv8jT-JEWyEOnA,645
|
| 50 |
+
pip/_internal/distributions/sdist.py,sha256=VBme1UNlCuH_wIoUHTZq9ngo2NpFWQXmJqnwUb3ZpTk,3862
|
| 51 |
+
pip/_internal/distributions/wheel.py,sha256=J7DNQvKS50pXfwXtetKZtLNgYzkEc8SAbaKQ5v6JHtA,1183
|
| 52 |
+
pip/_internal/exceptions.py,sha256=2JQJSS68oggR_ZIOA-h1U2DRADURbkQn9Nf4EZWZ834,13170
|
| 53 |
+
pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30
|
| 54 |
+
pip/_internal/index/collector.py,sha256=oH4XlYHvGMXePbjNhKZPpLI-NLBTXxpHRRZgQ85meNk,17645
|
| 55 |
+
pip/_internal/index/package_finder.py,sha256=Zzto_P1YPeTlBjJTlPgU8wjocQDJnLYZxUSR8JxVf1E,36138
|
| 56 |
+
pip/_internal/index/sources.py,sha256=SVyPitv08-Qalh2_Bk5diAJ9GAA_d-a93koouQodAG0,6557
|
| 57 |
+
pip/_internal/locations/__init__.py,sha256=8HvAnPCRi2Ln5yimpHRq8NVtsImh1KEvqsPhi4H56y0,13292
|
| 58 |
+
pip/_internal/locations/_distutils.py,sha256=Sk7tw8ZP1DWMYJ8MibABsa8IME2Ejv1PKeGlYQCBTZc,5871
|
| 59 |
+
pip/_internal/locations/_sysconfig.py,sha256=LQNKTJKyjVqxXaPntlBwdUqTG1xwYf6GVCKMbyRJx5M,7918
|
| 60 |
+
pip/_internal/locations/base.py,sha256=x5D1ONktmPJd8nnUTh-ELsAJ7fiXA-k-0a_vhfi2_Us,1579
|
| 61 |
+
pip/_internal/main.py,sha256=BZ0vkdqgpoteTo1A1Q8ovFe8EzgKFJWOUjPmIUQfGCY,351
|
| 62 |
+
pip/_internal/metadata/__init__.py,sha256=0XQDTWweYOV7kcMuzwoiCggu3wJearBNcK8JV9LXA6Y,1576
|
| 63 |
+
pip/_internal/metadata/base.py,sha256=oRj58fKGutZKZCslfQlKfrzuXI_0M4w1xVOluT3-6TQ,7928
|
| 64 |
+
pip/_internal/metadata/pkg_resources.py,sha256=xOYt6IluIDvVMgYX-QoZA3SFbToJlZDOVPRHVPJ2Uk4,5200
|
| 65 |
+
pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63
|
| 66 |
+
pip/_internal/models/candidate.py,sha256=b2aiufhD5jZEI0zhEaMn_o1VRldVE2J-MPsqPpcY2Ds,946
|
| 67 |
+
pip/_internal/models/direct_url.py,sha256=x2-kAnrP18XAdOftYBStDNt3Zfd8sipef5h0h_efGvY,6262
|
| 68 |
+
pip/_internal/models/format_control.py,sha256=t5nmFD43huIFj0VchV6FuvlaRHfaMTotbBOTOPBsKeY,2557
|
| 69 |
+
pip/_internal/models/index.py,sha256=_U2imEWggevvcI7rhQCFZK0djsE-It13BJmvW9Ejmig,1058
|
| 70 |
+
pip/_internal/models/link.py,sha256=chRRuGqeE5w1XqidCrw6j-j8O-eeCmw-HUdYCR18HmQ,9809
|
| 71 |
+
pip/_internal/models/scheme.py,sha256=i2QGt5J96gMKC_Wm7xO587kibhhChUQoULhAFgPRxkE,738
|
| 72 |
+
pip/_internal/models/search_scope.py,sha256=mykEee0wDNCx9xZmQBtkgVaDiQVcDNqbjAZGqI1nm78,4474
|
| 73 |
+
pip/_internal/models/selection_prefs.py,sha256=OEoiP83Wpm7cUwjH7fnbRo7TzHl5D4y23W0JnZLXk_4,1877
|
| 74 |
+
pip/_internal/models/target_python.py,sha256=7iT4lbRtoNRkwsmLndysJ4Ic7Iwp_YyIII3doXeLD8c,3870
|
| 75 |
+
pip/_internal/models/wheel.py,sha256=Ec8fvPoSYeBX9cvBvffLM7gNRx23CrVud1dN3zJmBjc,3541
|
| 76 |
+
pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50
|
| 77 |
+
pip/_internal/network/auth.py,sha256=zq-fu-eK_EwiqjT0SVmMxuzyvhBlCdBGJi_fnOmcar8,11645
|
| 78 |
+
pip/_internal/network/cache.py,sha256=HoprMCecwd4IS2wDZowc9B_OpaBlFjJYJl4xOxvtuwU,2100
|
| 79 |
+
pip/_internal/network/download.py,sha256=VmiR-KKIBugShZS4JlD7N8mq3hErx-0fK-D8aTYU3Og,6016
|
| 80 |
+
pip/_internal/network/lazy_wheel.py,sha256=4szChUW2I9quggvjEoIhALezmiVVteescGh6TDUslaQ,7615
|
| 81 |
+
pip/_internal/network/session.py,sha256=3tJHNQCooM7bjLK1WP-q6tiJ84jtqkyrIdrYY84WR1A,16582
|
| 82 |
+
pip/_internal/network/utils.py,sha256=igLlTu_-q0LmL8FdJKq-Uj7AT_owrQ-T9FfyarkhK5U,4059
|
| 83 |
+
pip/_internal/network/xmlrpc.py,sha256=AzQgG4GgS152_cqmGr_Oz2MIXsCal-xfsis7fA7nmU0,1791
|
| 84 |
+
pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 85 |
+
pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 86 |
+
pip/_internal/operations/build/metadata.py,sha256=jJp05Rrp0AMsQb7izDXbNGC1LtPNwOhHQj7cRM5324c,1165
|
| 87 |
+
pip/_internal/operations/build/metadata_legacy.py,sha256=ECMBhLEPEQv6PUUCpPCXW-wN9QRXdY45PNXJv7BZKTU,1917
|
| 88 |
+
pip/_internal/operations/build/wheel.py,sha256=WYLMxuxqN3ahJTQk2MI9hdmZKBpFyxHeNpUdO0PybxU,1106
|
| 89 |
+
pip/_internal/operations/build/wheel_legacy.py,sha256=NOJhTYMYljdbizFo_WjkaKGWG1SEZ6aByrBdCrrsZB8,3227
|
| 90 |
+
pip/_internal/operations/check.py,sha256=zEIdxyRL3vc7CQ1p8qkLFG-mjs-LjnaJDxOr1WI5Yp0,5295
|
| 91 |
+
pip/_internal/operations/freeze.py,sha256=TyLvXT4ZqpIi8x8X_TTsgBJ76IG54CidJlxGIHBbmBM,10556
|
| 92 |
+
pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51
|
| 93 |
+
pip/_internal/operations/install/editable_legacy.py,sha256=bjBObfE6sz3UmGI7y4-GCgKa2WmTgnWlFFU7b-i0sQs,1396
|
| 94 |
+
pip/_internal/operations/install/legacy.py,sha256=Wk_46sR7zDsh7vp4j63Hka4NTevQ617WdqJKt8_TuUQ,4405
|
| 95 |
+
pip/_internal/operations/install/wheel.py,sha256=4Y6rtOpPnjlvGkzYXP8HXzqJu1KHEuA6ExgHBdZnD6s,29466
|
| 96 |
+
pip/_internal/operations/prepare.py,sha256=jgnH7CIdoAhwnYOSpkESvhrJ1yr5TL2ZY5ojjSzRMZo,24848
|
| 97 |
+
pip/_internal/pyproject.py,sha256=Sl1dOQYazG9AsrE0TXWK2zVcDR_FROshCTwjKBRQsPE,7063
|
| 98 |
+
pip/_internal/req/__init__.py,sha256=lz4GFfzm5gsm0e8H98Wi6IPI14R2JdDMBc61-4F-0CY,2831
|
| 99 |
+
pip/_internal/req/constructors.py,sha256=35LRb-iaL01AlKBOO_2vrbKil6KI5Tl450NJwUvUnhk,15826
|
| 100 |
+
pip/_internal/req/req_file.py,sha256=TsBSr0LMVIYF7AqkwslyJxHPLstN0SMqKeVxciI2In4,17408
|
| 101 |
+
pip/_internal/req/req_install.py,sha256=jPfSPt-s3RoRCj6tYqvvHaxxIW1yr8KbiPRGbAyF3pU,31671
|
| 102 |
+
pip/_internal/req/req_set.py,sha256=NoPQztL1Z5HZEB3n2Wtst6KV51hMDAPe9AfdAUWmJLs,7572
|
| 103 |
+
pip/_internal/req/req_tracker.py,sha256=dJ3ql2C3VyaKUQN9kwbFvOPMxAvbTdblB0hKQ2f6Lns,4182
|
| 104 |
+
pip/_internal/req/req_uninstall.py,sha256=wBcGKaweIyi5RGPPpBqrrn62t8uP3frZmrUJ-qDeO0Y,23821
|
| 105 |
+
pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 106 |
+
pip/_internal/resolution/base.py,sha256=yATwIW1VbJkwkFJIgG3JQafndFDSZ50smc-Ao9-SoxI,557
|
| 107 |
+
pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 108 |
+
pip/_internal/resolution/legacy/resolver.py,sha256=TZnGUay9WM2Uk0W3D48OA70U9cLYYGHxles1h9ELqSg,17552
|
| 109 |
+
pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 110 |
+
pip/_internal/resolution/resolvelib/base.py,sha256=Yvgb2jf0l6S4C2rXAbjbpURYF6yjUgCdwDSrnpiZA8U,5290
|
| 111 |
+
pip/_internal/resolution/resolvelib/candidates.py,sha256=RgCvLf1meDecmw9lfhG_AU5tN9ufaC0EDrcVOR2hgiA,18842
|
| 112 |
+
pip/_internal/resolution/resolvelib/factory.py,sha256=N9telNB1arFV-4TqdGdh9KML8zfAWdMbqUSNip6HeEc,26859
|
| 113 |
+
pip/_internal/resolution/resolvelib/found_candidates.py,sha256=ES3PNACh3ONwGAghPip2Vbgyy_e4baKmeEEHVQiq47g,5285
|
| 114 |
+
pip/_internal/resolution/resolvelib/provider.py,sha256=fy139RDxPrsPmNLn6YrrjqhBOmeLY0aHEEdzZqS35aU,8420
|
| 115 |
+
pip/_internal/resolution/resolvelib/reporter.py,sha256=Z06Xa4d9dTWbHNvXIBtBxDn4DHeQmlyW9MJAojkC_iU,2600
|
| 116 |
+
pip/_internal/resolution/resolvelib/requirements.py,sha256=pcsnwz7txyDNZUEOWJOZEfivy3COWHPf_DIU7fwZ-Kk,5455
|
| 117 |
+
pip/_internal/resolution/resolvelib/resolver.py,sha256=Rry36d0uCKobfBnSPYMw8WStyNYtjAEFz3j6ZtBsbGQ,10523
|
| 118 |
+
pip/_internal/self_outdated_check.py,sha256=ivoUYaGuq-Ra_DvlZvPtHhgbY97NKHYuPGzrgN2G1A8,6484
|
| 119 |
+
pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 120 |
+
pip/_internal/utils/_log.py,sha256=-jHLOE_THaZz5BFcCnoSL9EYAtJ0nXem49s9of4jvKw,1015
|
| 121 |
+
pip/_internal/utils/appdirs.py,sha256=CyH0arjhfR4kaeybXs5B1hxe66KeeCfssJhiRFxpFJk,1185
|
| 122 |
+
pip/_internal/utils/compat.py,sha256=ACyBfLgj3_XG-iA5omEDrXqDM0cQKzi8h8HRBInzG6Q,1884
|
| 123 |
+
pip/_internal/utils/compatibility_tags.py,sha256=h2P4U0ZCkWHwPYveBzFZA79it6agElRhm6yci7S8MCo,5454
|
| 124 |
+
pip/_internal/utils/datetime.py,sha256=m21Y3wAtQc-ji6Veb6k_M5g6A0ZyFI4egchTdnwh-pQ,242
|
| 125 |
+
pip/_internal/utils/deprecation.py,sha256=0bdiuvnAcAZMp1dDrwxK7uDgmJQDHVfb1790_ypO9U4,3200
|
| 126 |
+
pip/_internal/utils/direct_url_helpers.py,sha256=5ffB9GHoqalUvSU6C53lEFdUgYcWAbXJGfyCwGyIlrY,2994
|
| 127 |
+
pip/_internal/utils/distutils_args.py,sha256=mcAscyp80vTt3xAGTipnpgc83V-_wCvydNELVXLq7JI,1249
|
| 128 |
+
pip/_internal/utils/encoding.py,sha256=bdZ3YgUpaOEBI5MP4-DEXiQarCW3V0rxw1kRz-TaU1Q,1169
|
| 129 |
+
pip/_internal/utils/entrypoints.py,sha256=aPvCnQVi9Hdk35Kloww_D5ibjUpqxgqcJP8O9VuMZek,1055
|
| 130 |
+
pip/_internal/utils/filesystem.py,sha256=rrl-rY1w8TYyKYndUyZlE9ffkQyA4-jI9x_59zXkn5s,5893
|
| 131 |
+
pip/_internal/utils/filetypes.py,sha256=weviVbapHWVQ_8-K-PTQ_TnYL66kZi4SrVBTmRYZXLc,761
|
| 132 |
+
pip/_internal/utils/glibc.py,sha256=GM1Y2hWkOf_tumySGFg-iNbc7oilBQQrjczb_705CF8,3170
|
| 133 |
+
pip/_internal/utils/hashes.py,sha256=o1qQEkqe2AqsRm_JhLoM4hkxmVtewH0ZZpQ6EBObHuU,5167
|
| 134 |
+
pip/_internal/utils/inject_securetransport.py,sha256=tGl9Bgyt2IHKtB3b0B-6r3W2yYF3Og-PBe0647S3lZs,810
|
| 135 |
+
pip/_internal/utils/logging.py,sha256=E5VE1n-pqgdd5DajPQPKpmu7VpJVd7dAhhdjPZNsYjE,12344
|
| 136 |
+
pip/_internal/utils/misc.py,sha256=WhWMKbtoBWvGrqVMaPekKML-orsLnD2e0N83arjpYQw,23644
|
| 137 |
+
pip/_internal/utils/models.py,sha256=qCgYyUw2mIH1pombsJ3YQsMtONZgyJ4BGwO5MJnSC4c,1329
|
| 138 |
+
pip/_internal/utils/packaging.py,sha256=I1938AB7FprcVJJd6C0vSiMuCVajmrxZF55vX5j0bMo,2900
|
| 139 |
+
pip/_internal/utils/parallel.py,sha256=RZF4JddPEWVbkkPCknfvpqaLfm3Pmqd_ABoCHmV4lXs,3224
|
| 140 |
+
pip/_internal/utils/pkg_resources.py,sha256=jwH5JViPe-JlXLvLC0-ASfTTCRYvm0u9CwQGcWjxStI,1106
|
| 141 |
+
pip/_internal/utils/setuptools_build.py,sha256=xk9sRBjUyNTHs_TvEWebVWs1GfLPN208MzpSXr9Ok_A,5047
|
| 142 |
+
pip/_internal/utils/subprocess.py,sha256=7QOQPJj6ezIVsypJJrcyyq4-mJM9qUsOdOLq0_wUiAA,10043
|
| 143 |
+
pip/_internal/utils/temp_dir.py,sha256=9gs3N9GQeVXRVWjJIalSpH1uj8yQXPTzarb5n1_HMVo,7950
|
| 144 |
+
pip/_internal/utils/unpacking.py,sha256=_qYZgmq8b0rRAN2swXsf9VfPogrjShlsTvhRI2heBYI,9050
|
| 145 |
+
pip/_internal/utils/urls.py,sha256=O5f4VeKJ9cWt_CKqqKmiDTW48uOzo0UNb1QWPQ0n2TI,1798
|
| 146 |
+
pip/_internal/utils/virtualenv.py,sha256=iRTK-sD6bWpHqXcZ0ECfdpFLWatMOHFUVCIRa0L6Gu0,3564
|
| 147 |
+
pip/_internal/utils/wheel.py,sha256=DOIVZaXN7bMOAeMEqzIOZHGl4OFO-KGrEqBUB848DPo,6290
|
| 148 |
+
pip/_internal/vcs/__init__.py,sha256=UAqvzpbi0VbZo3Ub6skEeZAw-ooIZR-zX_WpCbxyCoU,596
|
| 149 |
+
pip/_internal/vcs/bazaar.py,sha256=Ay_vN-87vYSEzBqXT3RVwl40vlk56j3jy_AfQbMj4uo,2962
|
| 150 |
+
pip/_internal/vcs/git.py,sha256=VDSzQlkh1390xw6PMh6fneJAZyc1s9qHZgum3wO3DOU,17347
|
| 151 |
+
pip/_internal/vcs/mercurial.py,sha256=WwoTWZQdQN9FcUTINvIeb0Vt46UJ_lLdf2BAdea9Tic,5076
|
| 152 |
+
pip/_internal/vcs/subversion.py,sha256=FRMYx7q-b6skWuv6IU7tJyC8Jm8PPblMnH7WN_ucXWU,11866
|
| 153 |
+
pip/_internal/vcs/versioncontrol.py,sha256=jMKitwE4bQ45jOKKomBxgBypm2TcuDGWWdTUmPa-MUQ,23276
|
| 154 |
+
pip/_internal/wheel_builder.py,sha256=hW63ZmABr65rOiSRBHXu1jBUdEZw5LZiw0LaQBbz0lI,11740
|
| 155 |
+
pip/_vendor/__init__.py,sha256=eE_yoHELq6Kw--WqhAEcKkvHLKbmTR1-JX_Th1wcNZc,4703
|
| 156 |
+
pip/_vendor/appdirs.py,sha256=M6IYRJtdZgmSPCXCSMBRB0VT3P8MdFbWCDbSLrB2Ebg,25907
|
| 157 |
+
pip/_vendor/cachecontrol/__init__.py,sha256=pJtAaUxOsMPnytI1A3juAJkXYDr8krdSnsg4Yg3OBEg,302
|
| 158 |
+
pip/_vendor/cachecontrol/_cmd.py,sha256=URGE0KrA87QekCG3SGPatlSPT571dZTDjNa-ZXX3pDc,1295
|
| 159 |
+
pip/_vendor/cachecontrol/adapter.py,sha256=sSwaSYd93IIfCFU4tOMgSo6b2LCt_gBSaQUj8ktJFOA,4882
|
| 160 |
+
pip/_vendor/cachecontrol/cache.py,sha256=1fc4wJP8HYt1ycnJXeEw5pCpeBL2Cqxx6g9Fb0AYDWQ,805
|
| 161 |
+
pip/_vendor/cachecontrol/caches/__init__.py,sha256=-gHNKYvaeD0kOk5M74eOrsSgIKUtC6i6GfbmugGweEo,86
|
| 162 |
+
pip/_vendor/cachecontrol/caches/file_cache.py,sha256=nYVKsJtXh6gJXvdn1iWyrhxvkwpQrK-eKoMRzuiwkKk,4153
|
| 163 |
+
pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=HxelMpNCo-dYr2fiJDwM3hhhRmxUYtB5tXm1GpAAT4Y,856
|
| 164 |
+
pip/_vendor/cachecontrol/compat.py,sha256=kHNvMRdt6s_Xwqq_9qJmr9ou3wYMOMUMxPPcwNxT8Mc,695
|
| 165 |
+
pip/_vendor/cachecontrol/controller.py,sha256=CWEX3pedIM9s60suf4zZPtm_JvVgnvogMGK_OiBG5F8,14149
|
| 166 |
+
pip/_vendor/cachecontrol/filewrapper.py,sha256=vACKO8Llzu_ZWyjV1Fxn1MA4TGU60N5N3GSrAFdAY2Q,2533
|
| 167 |
+
pip/_vendor/cachecontrol/heuristics.py,sha256=BFGHJ3yQcxvZizfo90LLZ04T_Z5XSCXvFotrp7Us0sc,4070
|
| 168 |
+
pip/_vendor/cachecontrol/serialize.py,sha256=vIa4jvq4x_KSOLdEIedoknX2aXYHQujLDFV4-F21Dno,7091
|
| 169 |
+
pip/_vendor/cachecontrol/wrapper.py,sha256=5LX0uJwkNQUtYSEw3aGmGu9WY8wGipd81mJ8lG0d0M4,690
|
| 170 |
+
pip/_vendor/certifi/__init__.py,sha256=-b78tXibbl0qtgCzv9tc9v6ozwcNX915lT9Tf4a9lds,62
|
| 171 |
+
pip/_vendor/certifi/__main__.py,sha256=1k3Cr95vCxxGRGDljrW3wMdpZdL3Nhf0u1n-k2qdsCY,255
|
| 172 |
+
pip/_vendor/certifi/cacert.pem,sha256=3i-hfE2K5o3CBKG2tYt6ehJWk2fP64o6Th83fHPoPp4,259465
|
| 173 |
+
pip/_vendor/certifi/core.py,sha256=gOFd0zHYlx4krrLEn982esOtmz3djiG0BFSDhgjlvcI,2840
|
| 174 |
+
pip/_vendor/chardet/__init__.py,sha256=mWZaWmvZkhwfBEAT9O1Y6nRTfKzhT7FHhQTTAujbqUA,3271
|
| 175 |
+
pip/_vendor/chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254
|
| 176 |
+
pip/_vendor/chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757
|
| 177 |
+
pip/_vendor/chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411
|
| 178 |
+
pip/_vendor/chardet/charsetgroupprober.py,sha256=GZLReHP6FRRn43hvSOoGCxYamErKzyp6RgOQxVeC3kg,3839
|
| 179 |
+
pip/_vendor/chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110
|
| 180 |
+
pip/_vendor/chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
| 181 |
+
pip/_vendor/chardet/cli/chardetect.py,sha256=XK5zqjUG2a4-y6eLHZ8ThYcp6WWUrdlmELxNypcc2SE,2747
|
| 182 |
+
pip/_vendor/chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590
|
| 183 |
+
pip/_vendor/chardet/compat.py,sha256=40zr6wICZwknxyuLGGcIOPyve8DTebBCbbvttvnmp5Q,1200
|
| 184 |
+
pip/_vendor/chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855
|
| 185 |
+
pip/_vendor/chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661
|
| 186 |
+
pip/_vendor/chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950
|
| 187 |
+
pip/_vendor/chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510
|
| 188 |
+
pip/_vendor/chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749
|
| 189 |
+
pip/_vendor/chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546
|
| 190 |
+
pip/_vendor/chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748
|
| 191 |
+
pip/_vendor/chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621
|
| 192 |
+
pip/_vendor/chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747
|
| 193 |
+
pip/_vendor/chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715
|
| 194 |
+
pip/_vendor/chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754
|
| 195 |
+
pip/_vendor/chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838
|
| 196 |
+
pip/_vendor/chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777
|
| 197 |
+
pip/_vendor/chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643
|
| 198 |
+
pip/_vendor/chardet/langbulgarianmodel.py,sha256=rk9CJpuxO0bObboJcv6gNgWuosYZmd8qEEds5y7DS_Y,105697
|
| 199 |
+
pip/_vendor/chardet/langgreekmodel.py,sha256=S-uNQ1ihC75yhBvSux24gLFZv3QyctMwC6OxLJdX-bw,99571
|
| 200 |
+
pip/_vendor/chardet/langhebrewmodel.py,sha256=DzPP6TPGG_-PV7tqspu_d8duueqm7uN-5eQ0aHUw1Gg,98776
|
| 201 |
+
pip/_vendor/chardet/langhungarianmodel.py,sha256=RtJH7DZdsmaHqyK46Kkmnk5wQHiJwJPPJSqqIlpeZRc,102498
|
| 202 |
+
pip/_vendor/chardet/langrussianmodel.py,sha256=THqJOhSxiTQcHboDNSc5yofc2koXXQFHFyjtyuntUfM,131180
|
| 203 |
+
pip/_vendor/chardet/langthaimodel.py,sha256=R1wXHnUMtejpw0JnH_JO8XdYasME6wjVqp1zP7TKLgg,103312
|
| 204 |
+
pip/_vendor/chardet/langturkishmodel.py,sha256=rfwanTptTwSycE4-P-QasPmzd-XVYgevytzjlEzBBu8,95946
|
| 205 |
+
pip/_vendor/chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370
|
| 206 |
+
pip/_vendor/chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413
|
| 207 |
+
pip/_vendor/chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012
|
| 208 |
+
pip/_vendor/chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481
|
| 209 |
+
pip/_vendor/chardet/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 210 |
+
pip/_vendor/chardet/metadata/languages.py,sha256=41tLq3eLSrBEbEVVQpVGFq9K7o1ln9b1HpY1l0hCUQo,19474
|
| 211 |
+
pip/_vendor/chardet/sbcharsetprober.py,sha256=nmyMyuxzG87DN6K3Rk2MUzJLMLR69MrWpdnHzOwVUwQ,6136
|
| 212 |
+
pip/_vendor/chardet/sbcsgroupprober.py,sha256=hqefQuXmiFyDBArOjujH6hd6WFXlOD1kWCsxDhjx5Vc,4309
|
| 213 |
+
pip/_vendor/chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774
|
| 214 |
+
pip/_vendor/chardet/universaldetector.py,sha256=DpZTXCX0nUHXxkQ9sr4GZxGB_hveZ6hWt3uM94cgWKs,12503
|
| 215 |
+
pip/_vendor/chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766
|
| 216 |
+
pip/_vendor/chardet/version.py,sha256=A4CILFAd8MRVG1HoXPp45iK9RLlWyV73a1EtwE8Tvn8,242
|
| 217 |
+
pip/_vendor/colorama/__init__.py,sha256=pCdErryzLSzDW5P-rRPBlPLqbBtIRNJB6cMgoeJns5k,239
|
| 218 |
+
pip/_vendor/colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522
|
| 219 |
+
pip/_vendor/colorama/ansitowin32.py,sha256=yV7CEmCb19MjnJKODZEEvMH_fnbJhwnpzo4sxZuGXmA,10517
|
| 220 |
+
pip/_vendor/colorama/initialise.py,sha256=PprovDNxMTrvoNHFcL2NZjpH2XzDc8BLxLxiErfUl4k,1915
|
| 221 |
+
pip/_vendor/colorama/win32.py,sha256=bJ8Il9jwaBN5BJ8bmN6FoYZ1QYuMKv2j8fGrXh7TJjw,5404
|
| 222 |
+
pip/_vendor/colorama/winterm.py,sha256=2y_2b7Zsv34feAsP67mLOVc-Bgq51mdYGo571VprlrM,6438
|
| 223 |
+
pip/_vendor/distlib/__init__.py,sha256=bHNWOvZsLE4ES9S4FEA8CyP-rDYzatVgp9GHbpTnb2I,581
|
| 224 |
+
pip/_vendor/distlib/_backport/__init__.py,sha256=bqS_dTOH6uW9iGgd0uzfpPjo6vZ4xpPZ7kyfZJ2vNaw,274
|
| 225 |
+
pip/_vendor/distlib/_backport/misc.py,sha256=KWecINdbFNOxSOP1fGF680CJnaC6S4fBRgEtaYTw0ig,971
|
| 226 |
+
pip/_vendor/distlib/_backport/shutil.py,sha256=IX_G2NPqwecJibkIDje04bqu0xpHkfSQ2GaGdEVqM5Y,25707
|
| 227 |
+
pip/_vendor/distlib/_backport/sysconfig.cfg,sha256=swZKxq9RY5e9r3PXCrlvQPMsvOdiWZBTHLEbqS8LJLU,2617
|
| 228 |
+
pip/_vendor/distlib/_backport/sysconfig.py,sha256=BQHFlb6pubCl_dvT1NjtzIthylofjKisox239stDg0U,26854
|
| 229 |
+
pip/_vendor/distlib/_backport/tarfile.py,sha256=Ihp7rXRcjbIKw8COm9wSePV9ARGXbSF9gGXAMn2Q-KU,92628
|
| 230 |
+
pip/_vendor/distlib/compat.py,sha256=ADA56xiAxar3mU6qemlBhNbsrFPosXRhO44RzsbJPqk,41408
|
| 231 |
+
pip/_vendor/distlib/database.py,sha256=Kl0YvPQKc4OcpVi7k5cFziydM1xOK8iqdxLGXgbZHV4,51059
|
| 232 |
+
pip/_vendor/distlib/index.py,sha256=UfcimNW19AB7IKWam4VaJbXuCBvArKfSxhV16EwavzE,20739
|
| 233 |
+
pip/_vendor/distlib/locators.py,sha256=AKlB3oZvfOTg4E0CtfwOzujFL19X5V4XUA4eHdKOu44,51965
|
| 234 |
+
pip/_vendor/distlib/manifest.py,sha256=nQEhYmgoreaBZzyFzwYsXxJARu3fo4EkunU163U16iE,14811
|
| 235 |
+
pip/_vendor/distlib/markers.py,sha256=OunMSH1SIbvLLt4z2VEERCll4WNlz2tDrg1mSXCNUj4,4344
|
| 236 |
+
pip/_vendor/distlib/metadata.py,sha256=vatoxFdmBr6ie-sTVXVNPOPG3uwMDWJTnEECnm7xDCw,39109
|
| 237 |
+
pip/_vendor/distlib/resources.py,sha256=LwbPksc0A1JMbi6XnuPdMBUn83X7BPuFNWqPGEKI698,10820
|
| 238 |
+
pip/_vendor/distlib/scripts.py,sha256=YD5_kioPD-qybYwQ4Gxyu-FR4ffxczy2gdBuU4II9qA,17248
|
| 239 |
+
pip/_vendor/distlib/t32.exe,sha256=NS3xBCVAld35JVFNmb-1QRyVtThukMrwZVeXn4LhaEQ,96768
|
| 240 |
+
pip/_vendor/distlib/t64.exe,sha256=oAqHes78rUWVM0OtVqIhUvequl_PKhAhXYQWnUf7zR0,105984
|
| 241 |
+
pip/_vendor/distlib/util.py,sha256=eIKKJ5Mp4unHMOVzixRIRxGq4ty5-h_PoFmZ_lpvkkM,67558
|
| 242 |
+
pip/_vendor/distlib/version.py,sha256=_geOv-cHoV-G8dQzKI8g6z8F0XeFeUqdJ_1G1K6iyrQ,23508
|
| 243 |
+
pip/_vendor/distlib/w32.exe,sha256=lJtnZdeUxTZWya_EW5DZos_K5rswRECGspIl8ZJCIXs,90112
|
| 244 |
+
pip/_vendor/distlib/w64.exe,sha256=0aRzoN2BO9NWW4ENy4_4vHkHR4qZTFZNVSAJJYlODTI,99840
|
| 245 |
+
pip/_vendor/distlib/wheel.py,sha256=W6aQQo2Si0CzWiCaqlS-Nu8CoHnDbmcGMqRxCHJmg_Q,43062
|
| 246 |
+
pip/_vendor/distro.py,sha256=xxMIh2a3KmippeWEHzynTdHT3_jZM0o-pos0dAWJROM,43628
|
| 247 |
+
pip/_vendor/html5lib/__init__.py,sha256=BYzcKCqeEii52xDrqBFruhnmtmkiuHXFyFh-cglQ8mk,1160
|
| 248 |
+
pip/_vendor/html5lib/_ihatexml.py,sha256=ifOwF7pXqmyThIXc3boWc96s4MDezqRrRVp7FwDYUFs,16728
|
| 249 |
+
pip/_vendor/html5lib/_inputstream.py,sha256=jErNASMlkgs7MpOM9Ve_VdLDJyFFweAjLuhVutZz33U,32353
|
| 250 |
+
pip/_vendor/html5lib/_tokenizer.py,sha256=04mgA2sNTniutl2fxFv-ei5bns4iRaPxVXXHh_HrV_4,77040
|
| 251 |
+
pip/_vendor/html5lib/_trie/__init__.py,sha256=nqfgO910329BEVJ5T4psVwQtjd2iJyEXQ2-X8c1YxwU,109
|
| 252 |
+
pip/_vendor/html5lib/_trie/_base.py,sha256=CaybYyMro8uERQYjby2tTeSUatnWDfWroUN9N7ety5w,1013
|
| 253 |
+
pip/_vendor/html5lib/_trie/py.py,sha256=wXmQLrZRf4MyWNyg0m3h81m9InhLR7GJ002mIIZh-8o,1775
|
| 254 |
+
pip/_vendor/html5lib/_utils.py,sha256=Dx9AKntksRjFT1veBj7I362pf5OgIaT0zglwq43RnfU,4931
|
| 255 |
+
pip/_vendor/html5lib/constants.py,sha256=Ll-yzLU_jcjyAI_h57zkqZ7aQWE5t5xA4y_jQgoUUhw,83464
|
| 256 |
+
pip/_vendor/html5lib/filters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 257 |
+
pip/_vendor/html5lib/filters/alphabeticalattributes.py,sha256=lViZc2JMCclXi_5gduvmdzrRxtO5Xo9ONnbHBVCsykU,919
|
| 258 |
+
pip/_vendor/html5lib/filters/base.py,sha256=z-IU9ZAYjpsVsqmVt7kuWC63jR11hDMr6CVrvuao8W0,286
|
| 259 |
+
pip/_vendor/html5lib/filters/inject_meta_charset.py,sha256=egDXUEHXmAG9504xz0K6ALDgYkvUrC2q15YUVeNlVQg,2945
|
| 260 |
+
pip/_vendor/html5lib/filters/lint.py,sha256=jk6q56xY0ojiYfvpdP-OZSm9eTqcAdRqhCoPItemPYA,3643
|
| 261 |
+
pip/_vendor/html5lib/filters/optionaltags.py,sha256=8lWT75J0aBOHmPgfmqTHSfPpPMp01T84NKu0CRedxcE,10588
|
| 262 |
+
pip/_vendor/html5lib/filters/sanitizer.py,sha256=m6oGmkBhkGAnn2nV6D4hE78SCZ6WEnK9rKdZB3uXBIc,26897
|
| 263 |
+
pip/_vendor/html5lib/filters/whitespace.py,sha256=8eWqZxd4UC4zlFGW6iyY6f-2uuT8pOCSALc3IZt7_t4,1214
|
| 264 |
+
pip/_vendor/html5lib/html5parser.py,sha256=anr-aXre_ImfrkQ35c_rftKXxC80vJCREKe06Tq15HA,117186
|
| 265 |
+
pip/_vendor/html5lib/serializer.py,sha256=_PpvcZF07cwE7xr9uKkZqh5f4UEaI8ltCU2xPJzaTpk,15759
|
| 266 |
+
pip/_vendor/html5lib/treeadapters/__init__.py,sha256=A0rY5gXIe4bJOiSGRO_j_tFhngRBO8QZPzPtPw5dFzo,679
|
| 267 |
+
pip/_vendor/html5lib/treeadapters/genshi.py,sha256=CH27pAsDKmu4ZGkAUrwty7u0KauGLCZRLPMzaO3M5vo,1715
|
| 268 |
+
pip/_vendor/html5lib/treeadapters/sax.py,sha256=BKS8woQTnKiqeffHsxChUqL4q2ZR_wb5fc9MJ3zQC8s,1776
|
| 269 |
+
pip/_vendor/html5lib/treebuilders/__init__.py,sha256=AysSJyvPfikCMMsTVvaxwkgDieELD5dfR8FJIAuq7hY,3592
|
| 270 |
+
pip/_vendor/html5lib/treebuilders/base.py,sha256=z-o51vt9r_l2IDG5IioTOKGzZne4Fy3_Fc-7ztrOh4I,14565
|
| 271 |
+
pip/_vendor/html5lib/treebuilders/dom.py,sha256=22whb0C71zXIsai5mamg6qzBEiigcBIvaDy4Asw3at0,8925
|
| 272 |
+
pip/_vendor/html5lib/treebuilders/etree.py,sha256=w5ZFpKk6bAxnrwD2_BrF5EVC7vzz0L3LMi9Sxrbc_8w,12836
|
| 273 |
+
pip/_vendor/html5lib/treebuilders/etree_lxml.py,sha256=9gqDjs-IxsPhBYa5cpvv2FZ1KZlG83Giusy2lFmvIkE,14766
|
| 274 |
+
pip/_vendor/html5lib/treewalkers/__init__.py,sha256=OBPtc1TU5mGyy18QDMxKEyYEz0wxFUUNj5v0-XgmYhY,5719
|
| 275 |
+
pip/_vendor/html5lib/treewalkers/base.py,sha256=ouiOsuSzvI0KgzdWP8PlxIaSNs9falhbiinAEc_UIJY,7476
|
| 276 |
+
pip/_vendor/html5lib/treewalkers/dom.py,sha256=EHyFR8D8lYNnyDU9lx_IKigVJRyecUGua0mOi7HBukc,1413
|
| 277 |
+
pip/_vendor/html5lib/treewalkers/etree.py,sha256=xo1L5m9VtkfpFJK0pFmkLVajhqYYVisVZn3k9kYpPkI,4551
|
| 278 |
+
pip/_vendor/html5lib/treewalkers/etree_lxml.py,sha256=_b0LAVWLcVu9WaU_-w3D8f0IRSpCbjf667V-3NRdhTw,6357
|
| 279 |
+
pip/_vendor/html5lib/treewalkers/genshi.py,sha256=4D2PECZ5n3ZN3qu3jMl9yY7B81jnQApBQSVlfaIuYbA,2309
|
| 280 |
+
pip/_vendor/idna/__init__.py,sha256=KJQN1eQBr8iIK5SKrJ47lXvxG0BJ7Lm38W4zT0v_8lk,849
|
| 281 |
+
pip/_vendor/idna/codec.py,sha256=QsPFD3Je8gN17rfs14e7zTGRWlnL7bNf2ZqcHTRVYHs,3453
|
| 282 |
+
pip/_vendor/idna/compat.py,sha256=5A9xR04puRHCsyjBNewZlVSiarth7K1bZqyEOeob1fA,360
|
| 283 |
+
pip/_vendor/idna/core.py,sha256=icq2P13S6JMjoXgKhhd6ihhby7QsnZlNfniH6fLyf6U,12826
|
| 284 |
+
pip/_vendor/idna/idnadata.py,sha256=cl4x9RLdw1ZMtEEbvKwAsX-Id3AdIjO5U3HaoKM6VGs,42350
|
| 285 |
+
pip/_vendor/idna/intranges.py,sha256=EqgXwyATAn-CTACInqH9tYsYAitGB2VcQ50RZt_Cpjs,1933
|
| 286 |
+
pip/_vendor/idna/package_data.py,sha256=_028B4fvadRIaXMwMYjhuQPP3AxTIt1IRE7X6RDR4Mk,21
|
| 287 |
+
pip/_vendor/idna/uts46data.py,sha256=DGzwDQv8JijY17I_7ondo3stjFjNnjvVAbA-z0k1XOE,201849
|
| 288 |
+
pip/_vendor/msgpack/__init__.py,sha256=2gJwcsTIaAtCM0GMi2rU-_Y6kILeeQuqRkrQ22jSANc,1118
|
| 289 |
+
pip/_vendor/msgpack/_version.py,sha256=dFR03oACnj4lsKd1RnwD7BPMiVI_FMygdOL1TOBEw_U,20
|
| 290 |
+
pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081
|
| 291 |
+
pip/_vendor/msgpack/ext.py,sha256=4l356Y4sVEcvCla2dh_cL57vh4GMhZfa3kuWHFHYz6A,6088
|
| 292 |
+
pip/_vendor/msgpack/fallback.py,sha256=Rpv1Ldey8f8ueRnQznD4ARKBn9dxM2PywVNkXI8IEeE,38026
|
| 293 |
+
pip/_vendor/packaging/__about__.py,sha256=p_OQloqH2saadcbUQmWEsWK857dI6_ff5E3aSiCqGFA,661
|
| 294 |
+
pip/_vendor/packaging/__init__.py,sha256=b9Kk5MF7KxhhLgcDmiUWukN-LatWFxPdNug0joPhHSk,497
|
| 295 |
+
pip/_vendor/packaging/_manylinux.py,sha256=XcbiXB-qcjv3bcohp6N98TMpOP4_j3m-iOA8ptK2GWY,11488
|
| 296 |
+
pip/_vendor/packaging/_musllinux.py,sha256=z5yeG1ygOPx4uUyLdqj-p8Dk5UBb5H_b0NIjW9yo8oA,4378
|
| 297 |
+
pip/_vendor/packaging/_structures.py,sha256=TMiAgFbdUOPmIfDIfiHc3KFhSJ8kMjof2QS5I-2NyQ8,1629
|
| 298 |
+
pip/_vendor/packaging/markers.py,sha256=AJBOcY8Oq0kYc570KuuPTkvuqjAlhufaE2c9sCUbm64,8487
|
| 299 |
+
pip/_vendor/packaging/requirements.py,sha256=NtDlPBtojpn1IUC85iMjPNsUmufjpSlwnNA-Xb4m5NA,4676
|
| 300 |
+
pip/_vendor/packaging/specifiers.py,sha256=MZ-fYcNL3u7pNrt-6g2EQO7AbRXkjc-SPEYwXMQbLmc,30964
|
| 301 |
+
pip/_vendor/packaging/tags.py,sha256=akIerYw8W0sz4OW9HHozgawWnbt2GGOPm3sviW0jowY,15714
|
| 302 |
+
pip/_vendor/packaging/utils.py,sha256=dJjeat3BS-TYn1RrUFVwufUMasbtzLfYRoy_HXENeFQ,4200
|
| 303 |
+
pip/_vendor/packaging/version.py,sha256=_fLRNrFrxYcHVfyo8vk9j8s6JM8N_xsSxVFr6RJyco8,14665
|
| 304 |
+
pip/_vendor/pep517/__init__.py,sha256=qDgVbDWpBYpTvtxA2tilifXlxwzOzRqIodLZdbyahyQ,130
|
| 305 |
+
pip/_vendor/pep517/build.py,sha256=MqN_W6o5a9oauTC0u6W5cILGFjf9x2BV9BdMLeY60hc,3469
|
| 306 |
+
pip/_vendor/pep517/check.py,sha256=AYG2yvpzmtsL810c75Z5-nhaXa7SxgK8APyw-_x53Ok,6096
|
| 307 |
+
pip/_vendor/pep517/colorlog.py,sha256=Tk9AuYm_cLF3BKTBoSTJt9bRryn0aFojIQOwbfVUTxQ,4098
|
| 308 |
+
pip/_vendor/pep517/compat.py,sha256=fw2Py6lqLwJLfp6MKmXvt1m4sbbgoU1D-_gcScvz8OU,1071
|
| 309 |
+
pip/_vendor/pep517/dirtools.py,sha256=2mkAkAL0mRz_elYFjRKuekTJVipH1zTn4tbf1EDev84,1129
|
| 310 |
+
pip/_vendor/pep517/envbuild.py,sha256=LcST0MASmcQNLOFqDPxDoS1kjkglx8F6eEhoBJ-DWkg,6112
|
| 311 |
+
pip/_vendor/pep517/in_process/__init__.py,sha256=MyWoAi8JHdcBv7yXuWpUSVADbx6LSB9rZh7kTIgdA8Y,563
|
| 312 |
+
pip/_vendor/pep517/in_process/_in_process.py,sha256=YJJf-qaL7BBVdgCHuMhTpx-LtwG1EIGVfly4rtusdiI,10833
|
| 313 |
+
pip/_vendor/pep517/meta.py,sha256=8mnM5lDnT4zXQpBTliJbRGfesH7iioHwozbDxALPS9Y,2463
|
| 314 |
+
pip/_vendor/pep517/wrappers.py,sha256=qCWfEUnbE5387PyQl7cT8xv4dDca4uNgro_0bnAO4Rk,13258
|
| 315 |
+
pip/_vendor/pkg_resources/__init__.py,sha256=XpGBfvS9fafA6bm5rx7vnxdxs7yqyoc_NnpzKApkJ64,108277
|
| 316 |
+
pip/_vendor/pkg_resources/py31compat.py,sha256=CRk8fkiPRDLsbi5pZcKsHI__Pbmh_94L8mr9Qy9Ab2U,562
|
| 317 |
+
pip/_vendor/progress/__init__.py,sha256=fcbQQXo5np2CoQyhSH5XprkicwLZNLePR3uIahznSO0,4857
|
| 318 |
+
pip/_vendor/progress/bar.py,sha256=QuDuVNcmXgpxtNtxO0Fq72xKigxABaVmxYGBw4J3Z_E,2854
|
| 319 |
+
pip/_vendor/progress/counter.py,sha256=MznyBrvPWrOlGe4MZAlGUb9q3aODe6_aNYeAE_VNoYA,1372
|
| 320 |
+
pip/_vendor/progress/spinner.py,sha256=k8JbDW94T0-WXuXfxZIFhdoNPYp3jfnpXqBnfRv5fGs,1380
|
| 321 |
+
pip/_vendor/pyparsing.py,sha256=J1b4z3S_KwyJW7hKGnoN-hXW9pgMIzIP6QThyY5yJq4,273394
|
| 322 |
+
pip/_vendor/requests/__init__.py,sha256=g4Bh1QYh6JKjMS4YLobx0uOLq-41sINaXjvbhX2VI8g,5113
|
| 323 |
+
pip/_vendor/requests/__version__.py,sha256=PZEyPTSIN_jRIAIB51wV7pw81m3qAw0InSR7OrKZUnE,441
|
| 324 |
+
pip/_vendor/requests/_internal_utils.py,sha256=Zx3PnEUccyfsB-ie11nZVAW8qClJy0gx1qNME7rgT18,1096
|
| 325 |
+
pip/_vendor/requests/adapters.py,sha256=e-bmKEApNVqFdylxuMJJfiaHdlmS_zhWhIMEzlHvGuc,21548
|
| 326 |
+
pip/_vendor/requests/api.py,sha256=hjuoP79IAEmX6Dysrw8t032cLfwLHxbI_wM4gC5G9t0,6402
|
| 327 |
+
pip/_vendor/requests/auth.py,sha256=OMoJIVKyRLy9THr91y8rxysZuclwPB-K1Xg1zBomUhQ,10207
|
| 328 |
+
pip/_vendor/requests/certs.py,sha256=nXRVq9DtGmv_1AYbwjTu9UrgAcdJv05ZvkNeaoLOZxY,465
|
| 329 |
+
pip/_vendor/requests/compat.py,sha256=LQWuCR4qXk6w7-qQopXyz0WNHUdAD40k0mKnaAEf1-g,2045
|
| 330 |
+
pip/_vendor/requests/cookies.py,sha256=Y-bKX6TvW3FnYlE6Au0SXtVVWcaNdFvuAwQxw-G0iTI,18430
|
| 331 |
+
pip/_vendor/requests/exceptions.py,sha256=dwIi512RCDqXJ2T81nLC88mqPNhUFnOI_CgKKDXhTO8,3250
|
| 332 |
+
pip/_vendor/requests/help.py,sha256=dyhe3lcmHXnFCzDiZVjcGmVvvO_jtsfAm-AC542ndw8,3972
|
| 333 |
+
pip/_vendor/requests/hooks.py,sha256=QReGyy0bRcr5rkwCuObNakbYsc7EkiKeBwG4qHekr2Q,757
|
| 334 |
+
pip/_vendor/requests/models.py,sha256=9_LS_t1t6HbbaWFE3ZkxGmmHN2V8BgxziiOU84rrQ50,34924
|
| 335 |
+
pip/_vendor/requests/packages.py,sha256=njJmVifY4aSctuW3PP5EFRCxjEwMRDO6J_feG2dKWsI,695
|
| 336 |
+
pip/_vendor/requests/sessions.py,sha256=57O4ud9yRL6eLYh-dtFbqC1kO4d_EwZcCgYXEkujlfs,30168
|
| 337 |
+
pip/_vendor/requests/status_codes.py,sha256=gT79Pbs_cQjBgp-fvrUgg1dn2DQO32bDj4TInjnMPSc,4188
|
| 338 |
+
pip/_vendor/requests/structures.py,sha256=msAtr9mq1JxHd-JRyiILfdFlpbJwvvFuP3rfUQT_QxE,3005
|
| 339 |
+
pip/_vendor/requests/utils.py,sha256=U_-i6WxLw-67KEij43xHbcvL0DdeQ5Jbd4hfifWJzQY,31394
|
| 340 |
+
pip/_vendor/resolvelib/__init__.py,sha256=uoW0dgWCDwApX59mRffoPISkZGGk_UZ1It_PY4o_PaE,537
|
| 341 |
+
pip/_vendor/resolvelib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 342 |
+
pip/_vendor/resolvelib/compat/collections_abc.py,sha256=uy8xUZ-NDEw916tugUXm8HgwCGiMO0f-RcdnpkfXfOs,156
|
| 343 |
+
pip/_vendor/resolvelib/providers.py,sha256=bfzFDZd7UqkkAS7lUM_HeYbA-HzjKfDlle_pn_79vio,5638
|
| 344 |
+
pip/_vendor/resolvelib/reporters.py,sha256=hQvvXuuEBOyEWO8KDfLsWKVjX55UFMAUwO0YZMNpzAw,1364
|
| 345 |
+
pip/_vendor/resolvelib/resolvers.py,sha256=wT83PHiBWRCklL-nLJ1-8sk2B3yBI06Rse1H11crOsI,17225
|
| 346 |
+
pip/_vendor/resolvelib/structs.py,sha256=IVIYof6sA_N4ZEiE1C1UhzTX495brCNnyCdgq6CYq28,4794
|
| 347 |
+
pip/_vendor/six.py,sha256=TOOfQi7nFGfMrIvtdr6wX4wyHH8M7aknmuLfo2cBBrM,34549
|
| 348 |
+
pip/_vendor/tenacity/__init__.py,sha256=GLLsTFD4Bd5VDgTR6mU_FxyOsrxc48qONorVaRebeD4,18257
|
| 349 |
+
pip/_vendor/tenacity/_asyncio.py,sha256=HEb0BVJEeBJE9P-m9XBxh1KcaF96BwoeqkJCL5sbVcQ,3314
|
| 350 |
+
pip/_vendor/tenacity/_utils.py,sha256=-y68scDcyoqvTJuJJ0GTfjdSCljEYlbCYvgk7nM4NdM,1944
|
| 351 |
+
pip/_vendor/tenacity/after.py,sha256=dlmyxxFy2uqpLXDr838DiEd7jgv2AGthsWHGYcGYsaI,1496
|
| 352 |
+
pip/_vendor/tenacity/before.py,sha256=7XtvRmO0dRWUp8SVn24OvIiGFj8-4OP5muQRUiWgLh0,1376
|
| 353 |
+
pip/_vendor/tenacity/before_sleep.py,sha256=ThyDvqKU5yle_IvYQz_b6Tp6UjUS0PhVp6zgqYl9U6Y,1908
|
| 354 |
+
pip/_vendor/tenacity/nap.py,sha256=fRWvnz1aIzbIq9Ap3gAkAZgDH6oo5zxMrU6ZOVByq0I,1383
|
| 355 |
+
pip/_vendor/tenacity/retry.py,sha256=62R71W59bQjuNyFKsDM7hE2aEkEPtwNBRA0tnsEvgSk,6645
|
| 356 |
+
pip/_vendor/tenacity/stop.py,sha256=sKHmHaoSaW6sKu3dTxUVKr1-stVkY7lw4Y9yjZU30zQ,2790
|
| 357 |
+
pip/_vendor/tenacity/tornadoweb.py,sha256=E8lWO2nwe6dJgoB-N2HhQprYLDLB_UdSgFnv-EN6wKE,2145
|
| 358 |
+
pip/_vendor/tenacity/wait.py,sha256=e_Saa6I2tsNLpCL1t9897wN2fGb0XQMQlE4bU2t9V2w,6691
|
| 359 |
+
pip/_vendor/tomli/__init__.py,sha256=z1Elt0nLAqU5Y0DOn9p__8QnLWavlEOpRyQikdYgKro,230
|
| 360 |
+
pip/_vendor/tomli/_parser.py,sha256=50BD4o9YbzFAGAYyZLqZC8F81DQ7iWWyJnrHNwBKa6A,22415
|
| 361 |
+
pip/_vendor/tomli/_re.py,sha256=5GPfgXKteg7wRFCF-DzlkAPI2ilHbkMK2-JC49F-AJQ,2681
|
| 362 |
+
pip/_vendor/urllib3/__init__.py,sha256=j3yzHIbmW7CS-IKQJ9-PPQf_YKO8EOAey_rMW0UR7us,2763
|
| 363 |
+
pip/_vendor/urllib3/_collections.py,sha256=Rp1mVyBgc_UlAcp6M3at1skJBXR5J43NawRTvW2g_XY,10811
|
| 364 |
+
pip/_vendor/urllib3/_version.py,sha256=6fJAIPnJkT0m9wzVjHrFcq5wYt65dStDpaRcjj5ugoo,63
|
| 365 |
+
pip/_vendor/urllib3/connection.py,sha256=kAlubwsW33FUSUroPSVHMF_Zzv-uzX_BwUFMXX9Pt8c,18754
|
| 366 |
+
pip/_vendor/urllib3/connectionpool.py,sha256=jXNmm4y3LJWYgteNeGcYJx8-0k7bzKRU__AVTXzaIak,37131
|
| 367 |
+
pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 368 |
+
pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957
|
| 369 |
+
pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 370 |
+
pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=eRy1Mj-wpg7sR6-OSvnSV4jUbjMT464dLN_CWxbIRVw,17649
|
| 371 |
+
pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=lgIdsSycqfB0Xm5BiJzXGeIKT7ybCQMFPJAgkcwPa1s,13908
|
| 372 |
+
pip/_vendor/urllib3/contrib/appengine.py,sha256=lfzpHFmJiO82shClLEm3QB62SYgHWnjpZOH_2JhU5Tc,11034
|
| 373 |
+
pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=ej9gGvfAb2Gt00lafFp45SIoRz-QwrQ4WChm6gQmAlM,4538
|
| 374 |
+
pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=lYIxGFWTosqbfLnkZXOBg7igY71iRvM3NUOaD0stUQ8,16891
|
| 375 |
+
pip/_vendor/urllib3/contrib/securetransport.py,sha256=TN5q9dKZ0Sd5_vW9baRzEAEItdJ-4VlHWmAUrlcJNfo,34434
|
| 376 |
+
pip/_vendor/urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097
|
| 377 |
+
pip/_vendor/urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217
|
| 378 |
+
pip/_vendor/urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579
|
| 379 |
+
pip/_vendor/urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440
|
| 380 |
+
pip/_vendor/urllib3/packages/__init__.py,sha256=h4BLhD4tLaBx1adaDtKXfupsgqY0wWLXb_f1_yVlV6A,108
|
| 381 |
+
pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
| 382 |
+
pip/_vendor/urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417
|
| 383 |
+
pip/_vendor/urllib3/packages/six.py,sha256=1LVW7ljqRirFlfExjwl-v1B7vSAUNTmzGMs-qays2zg,34666
|
| 384 |
+
pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py,sha256=ZVMwCkHx-py8ERsxxM3Il-MiREZktV-8iLBmCfRRHI4,927
|
| 385 |
+
pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py,sha256=6dZ-q074g7XhsJ27MFCgkct8iVNZB3sMZvKhf-KUVy0,5679
|
| 386 |
+
pip/_vendor/urllib3/poolmanager.py,sha256=whzlX6UTEgODMOCy0ZDMUONRBCz5wyIM8Z9opXAY-Lk,19763
|
| 387 |
+
pip/_vendor/urllib3/request.py,sha256=ZFSIqX0C6WizixecChZ3_okyu7BEv0lZu1VT0s6h4SM,5985
|
| 388 |
+
pip/_vendor/urllib3/response.py,sha256=hGhGBh7TkEkh_IQg5C1W_xuPNrgIKv5BUXPyE-q0LuE,28203
|
| 389 |
+
pip/_vendor/urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155
|
| 390 |
+
pip/_vendor/urllib3/util/connection.py,sha256=KykjNIXzUZEzeKEOpl5xvKs6IsESXP9o9eTrjE0W_Ys,4920
|
| 391 |
+
pip/_vendor/urllib3/util/proxy.py,sha256=FGipAEnvZteyldXNjce4DEB7YzwU-a5lep8y5S0qHQg,1604
|
| 392 |
+
pip/_vendor/urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498
|
| 393 |
+
pip/_vendor/urllib3/util/request.py,sha256=NnzaEKQ1Pauw5MFMV6HmgEMHITf0Aua9fQuzi2uZzGc,4123
|
| 394 |
+
pip/_vendor/urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510
|
| 395 |
+
pip/_vendor/urllib3/util/retry.py,sha256=tOWfZpLsuc7Vbk5nWpMwkHdMoXCp90IAvH4xtjSDRqQ,21391
|
| 396 |
+
pip/_vendor/urllib3/util/ssl_.py,sha256=X4-AqW91aYPhPx6-xbf66yHFQKbqqfC_5Zt4WkLX1Hc,17177
|
| 397 |
+
pip/_vendor/urllib3/util/ssltransport.py,sha256=F_UncOXGcc-MgeWFTA1H4QCt_RRNQXRbF6onje3SyHY,6931
|
| 398 |
+
pip/_vendor/urllib3/util/timeout.py,sha256=QSbBUNOB9yh6AnDn61SrLQ0hg5oz0I9-uXEG91AJuIg,10003
|
| 399 |
+
pip/_vendor/urllib3/util/url.py,sha256=QVEzcbHipbXyCWwH6R4K4TR-N8T4LM55WEMwNUTBmLE,14047
|
| 400 |
+
pip/_vendor/urllib3/util/wait.py,sha256=3MUKRSAUJDB2tgco7qRUskW0zXGAWYvRRE4Q1_6xlLs,5404
|
| 401 |
+
pip/_vendor/vendor.txt,sha256=GuFhR0DHZazrSYZyoY7j3X3T_mGJh-ky2opcZ-A7ezo,364
|
| 402 |
+
pip/_vendor/webencodings/__init__.py,sha256=qOBJIuPy_4ByYH6W_bNgJF-qYQ2DoU-dKsDu5yRWCXg,10579
|
| 403 |
+
pip/_vendor/webencodings/labels.py,sha256=4AO_KxTddqGtrL9ns7kAPjb0CcN6xsCIxbK37HY9r3E,8979
|
| 404 |
+
pip/_vendor/webencodings/mklabels.py,sha256=GYIeywnpaLnP0GSic8LFWgd0UVvO_l1Nc6YoF-87R_4,1305
|
| 405 |
+
pip/_vendor/webencodings/tests.py,sha256=OtGLyjhNY1fvkW1GvLJ_FV9ZoqC9Anyjr7q3kxTbzNs,6563
|
| 406 |
+
pip/_vendor/webencodings/x_user_defined.py,sha256=yOqWSdmpytGfUgh_Z6JYgDNhoc-BAHyyeeT15Fr42tM,4307
|
| 407 |
+
pip/py.typed,sha256=EBVvvPRTn_eIpz5e5QztSCdrMX7Qwd7VP93RSoIlZ2I,286
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/REQUESTED
ADDED
|
File without changes
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: bdist_wheel (0.36.2)
|
| 3 |
+
Root-Is-Purelib: true
|
| 4 |
+
Tag: py3-none-any
|
| 5 |
+
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/entry_points.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[console_scripts]
|
| 2 |
+
pip = pip._internal.cli.main:main
|
| 3 |
+
pip3 = pip._internal.cli.main:main
|
| 4 |
+
pip3.9 = pip._internal.cli.main:main
|
| 5 |
+
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip-21.2.4.dist-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/pkg_resources/__init__.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/pkg_resources/py31compat.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import errno
|
| 3 |
+
import sys
|
| 4 |
+
|
| 5 |
+
from pip._vendor import six
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def _makedirs_31(path, exist_ok=False):
|
| 9 |
+
try:
|
| 10 |
+
os.makedirs(path)
|
| 11 |
+
except OSError as exc:
|
| 12 |
+
if not exist_ok or exc.errno != errno.EEXIST:
|
| 13 |
+
raise
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# rely on compatibility behavior until mode considerations
|
| 17 |
+
# and exists_ok considerations are disentangled.
|
| 18 |
+
# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663
|
| 19 |
+
needs_makedirs = (
|
| 20 |
+
six.PY2 or
|
| 21 |
+
(3, 4) <= sys.version_info < (3, 4, 1)
|
| 22 |
+
)
|
| 23 |
+
makedirs = _makedirs_31 if needs_makedirs else os.makedirs
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__all__ = [
|
| 2 |
+
"__version__",
|
| 3 |
+
"AbstractProvider",
|
| 4 |
+
"AbstractResolver",
|
| 5 |
+
"BaseReporter",
|
| 6 |
+
"InconsistentCandidate",
|
| 7 |
+
"Resolver",
|
| 8 |
+
"RequirementsConflicted",
|
| 9 |
+
"ResolutionError",
|
| 10 |
+
"ResolutionImpossible",
|
| 11 |
+
"ResolutionTooDeep",
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
__version__ = "0.7.1"
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
from .providers import AbstractProvider, AbstractResolver
|
| 18 |
+
from .reporters import BaseReporter
|
| 19 |
+
from .resolvers import (
|
| 20 |
+
InconsistentCandidate,
|
| 21 |
+
RequirementsConflicted,
|
| 22 |
+
Resolver,
|
| 23 |
+
ResolutionError,
|
| 24 |
+
ResolutionImpossible,
|
| 25 |
+
ResolutionTooDeep,
|
| 26 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/compat/__init__.py
ADDED
|
File without changes
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__all__ = ["Mapping", "Sequence"]
|
| 2 |
+
|
| 3 |
+
try:
|
| 4 |
+
from collections.abc import Mapping, Sequence
|
| 5 |
+
except ImportError:
|
| 6 |
+
from collections import Mapping, Sequence
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/providers.py
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class AbstractProvider(object):
|
| 2 |
+
"""Delegate class to provide requirement interface for the resolver."""
|
| 3 |
+
|
| 4 |
+
def identify(self, requirement_or_candidate):
|
| 5 |
+
"""Given a requirement, return an identifier for it.
|
| 6 |
+
|
| 7 |
+
This is used to identify a requirement, e.g. whether two requirements
|
| 8 |
+
should have their specifier parts merged.
|
| 9 |
+
"""
|
| 10 |
+
raise NotImplementedError
|
| 11 |
+
|
| 12 |
+
def get_preference(self, identifier, resolutions, candidates, information):
|
| 13 |
+
"""Produce a sort key for given requirement based on preference.
|
| 14 |
+
|
| 15 |
+
The preference is defined as "I think this requirement should be
|
| 16 |
+
resolved first". The lower the return value is, the more preferred
|
| 17 |
+
this group of arguments is.
|
| 18 |
+
|
| 19 |
+
:param identifier: An identifier as returned by ``identify()``. This
|
| 20 |
+
identifies the dependency matches of which should be returned.
|
| 21 |
+
:param resolutions: Mapping of candidates currently pinned by the
|
| 22 |
+
resolver. Each key is an identifier, and the value a candidate.
|
| 23 |
+
The candidate may conflict with requirements from ``information``.
|
| 24 |
+
:param candidates: Mapping of each dependency's possible candidates.
|
| 25 |
+
Each value is an iterator of candidates.
|
| 26 |
+
:param information: Mapping of requirement information of each package.
|
| 27 |
+
Each value is an iterator of *requirement information*.
|
| 28 |
+
|
| 29 |
+
A *requirement information* instance is a named tuple with two members:
|
| 30 |
+
|
| 31 |
+
* ``requirement`` specifies a requirement contributing to the current
|
| 32 |
+
list of candidates.
|
| 33 |
+
* ``parent`` specifies the candidate that provides (dependend on) the
|
| 34 |
+
requirement, or ``None`` to indicate a root requirement.
|
| 35 |
+
|
| 36 |
+
The preference could depend on a various of issues, including (not
|
| 37 |
+
necessarily in this order):
|
| 38 |
+
|
| 39 |
+
* Is this package pinned in the current resolution result?
|
| 40 |
+
* How relaxed is the requirement? Stricter ones should probably be
|
| 41 |
+
worked on first? (I don't know, actually.)
|
| 42 |
+
* How many possibilities are there to satisfy this requirement? Those
|
| 43 |
+
with few left should likely be worked on first, I guess?
|
| 44 |
+
* Are there any known conflicts for this requirement? We should
|
| 45 |
+
probably work on those with the most known conflicts.
|
| 46 |
+
|
| 47 |
+
A sortable value should be returned (this will be used as the ``key``
|
| 48 |
+
parameter of the built-in sorting function). The smaller the value is,
|
| 49 |
+
the more preferred this requirement is (i.e. the sorting function
|
| 50 |
+
is called with ``reverse=False``).
|
| 51 |
+
"""
|
| 52 |
+
raise NotImplementedError
|
| 53 |
+
|
| 54 |
+
def find_matches(self, identifier, requirements, incompatibilities):
|
| 55 |
+
"""Find all possible candidates that satisfy given constraints.
|
| 56 |
+
|
| 57 |
+
:param identifier: An identifier as returned by ``identify()``. This
|
| 58 |
+
identifies the dependency matches of which should be returned.
|
| 59 |
+
:param requirements: A mapping of requirements that all returned
|
| 60 |
+
candidates must satisfy. Each key is an identifier, and the value
|
| 61 |
+
an iterator of requirements for that dependency.
|
| 62 |
+
:param incompatibilities: A mapping of known incompatibilities of
|
| 63 |
+
each dependency. Each key is an identifier, and the value an
|
| 64 |
+
iterator of incompatibilities known to the resolver. All
|
| 65 |
+
incompatibilities *must* be excluded from the return value.
|
| 66 |
+
|
| 67 |
+
This should try to get candidates based on the requirements' types.
|
| 68 |
+
For VCS, local, and archive requirements, the one-and-only match is
|
| 69 |
+
returned, and for a "named" requirement, the index(es) should be
|
| 70 |
+
consulted to find concrete candidates for this requirement.
|
| 71 |
+
|
| 72 |
+
The return value should produce candidates ordered by preference; the
|
| 73 |
+
most preferred candidate should come first. The return type may be one
|
| 74 |
+
of the following:
|
| 75 |
+
|
| 76 |
+
* A callable that returns an iterator that yields candidates.
|
| 77 |
+
* An collection of candidates.
|
| 78 |
+
* An iterable of candidates. This will be consumed immediately into a
|
| 79 |
+
list of candidates.
|
| 80 |
+
"""
|
| 81 |
+
raise NotImplementedError
|
| 82 |
+
|
| 83 |
+
def is_satisfied_by(self, requirement, candidate):
|
| 84 |
+
"""Whether the given requirement can be satisfied by a candidate.
|
| 85 |
+
|
| 86 |
+
The candidate is guarenteed to have been generated from the
|
| 87 |
+
requirement.
|
| 88 |
+
|
| 89 |
+
A boolean should be returned to indicate whether ``candidate`` is a
|
| 90 |
+
viable solution to the requirement.
|
| 91 |
+
"""
|
| 92 |
+
raise NotImplementedError
|
| 93 |
+
|
| 94 |
+
def get_dependencies(self, candidate):
|
| 95 |
+
"""Get dependencies of a candidate.
|
| 96 |
+
|
| 97 |
+
This should return a collection of requirements that `candidate`
|
| 98 |
+
specifies as its dependencies.
|
| 99 |
+
"""
|
| 100 |
+
raise NotImplementedError
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
class AbstractResolver(object):
|
| 104 |
+
"""The thing that performs the actual resolution work."""
|
| 105 |
+
|
| 106 |
+
base_exception = Exception
|
| 107 |
+
|
| 108 |
+
def __init__(self, provider, reporter):
|
| 109 |
+
self.provider = provider
|
| 110 |
+
self.reporter = reporter
|
| 111 |
+
|
| 112 |
+
def resolve(self, requirements, **kwargs):
|
| 113 |
+
"""Take a collection of constraints, spit out the resolution result.
|
| 114 |
+
|
| 115 |
+
This returns a representation of the final resolution state, with one
|
| 116 |
+
guarenteed attribute ``mapping`` that contains resolved candidates as
|
| 117 |
+
values. The keys are their respective identifiers.
|
| 118 |
+
|
| 119 |
+
:param requirements: A collection of constraints.
|
| 120 |
+
:param kwargs: Additional keyword arguments that subclasses may accept.
|
| 121 |
+
|
| 122 |
+
:raises: ``self.base_exception`` or its subclass.
|
| 123 |
+
"""
|
| 124 |
+
raise NotImplementedError
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/reporters.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class BaseReporter(object):
|
| 2 |
+
"""Delegate class to provider progress reporting for the resolver."""
|
| 3 |
+
|
| 4 |
+
def starting(self):
|
| 5 |
+
"""Called before the resolution actually starts."""
|
| 6 |
+
|
| 7 |
+
def starting_round(self, index):
|
| 8 |
+
"""Called before each round of resolution starts.
|
| 9 |
+
|
| 10 |
+
The index is zero-based.
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
def ending_round(self, index, state):
|
| 14 |
+
"""Called before each round of resolution ends.
|
| 15 |
+
|
| 16 |
+
This is NOT called if the resolution ends at this round. Use `ending`
|
| 17 |
+
if you want to report finalization. The index is zero-based.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
def ending(self, state):
|
| 21 |
+
"""Called before the resolution ends successfully."""
|
| 22 |
+
|
| 23 |
+
def adding_requirement(self, requirement, parent):
|
| 24 |
+
"""Called when adding a new requirement into the resolve criteria.
|
| 25 |
+
|
| 26 |
+
:param requirement: The additional requirement to be applied to filter
|
| 27 |
+
the available candidaites.
|
| 28 |
+
:param parent: The candidate that requires ``requirement`` as a
|
| 29 |
+
dependency, or None if ``requirement`` is one of the root
|
| 30 |
+
requirements passed in from ``Resolver.resolve()``.
|
| 31 |
+
"""
|
| 32 |
+
|
| 33 |
+
def backtracking(self, candidate):
|
| 34 |
+
"""Called when rejecting a candidate during backtracking."""
|
| 35 |
+
|
| 36 |
+
def pinning(self, candidate):
|
| 37 |
+
"""Called when adding a candidate to the potential solution."""
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/resolvers.py
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import collections
|
| 2 |
+
import operator
|
| 3 |
+
|
| 4 |
+
from .providers import AbstractResolver
|
| 5 |
+
from .structs import DirectedGraph, IteratorMapping, build_iter_view
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
RequirementInformation = collections.namedtuple(
|
| 9 |
+
"RequirementInformation", ["requirement", "parent"]
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class ResolverException(Exception):
|
| 14 |
+
"""A base class for all exceptions raised by this module.
|
| 15 |
+
|
| 16 |
+
Exceptions derived by this class should all be handled in this module. Any
|
| 17 |
+
bubbling pass the resolver should be treated as a bug.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class RequirementsConflicted(ResolverException):
|
| 22 |
+
def __init__(self, criterion):
|
| 23 |
+
super(RequirementsConflicted, self).__init__(criterion)
|
| 24 |
+
self.criterion = criterion
|
| 25 |
+
|
| 26 |
+
def __str__(self):
|
| 27 |
+
return "Requirements conflict: {}".format(
|
| 28 |
+
", ".join(repr(r) for r in self.criterion.iter_requirement()),
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class InconsistentCandidate(ResolverException):
|
| 33 |
+
def __init__(self, candidate, criterion):
|
| 34 |
+
super(InconsistentCandidate, self).__init__(candidate, criterion)
|
| 35 |
+
self.candidate = candidate
|
| 36 |
+
self.criterion = criterion
|
| 37 |
+
|
| 38 |
+
def __str__(self):
|
| 39 |
+
return "Provided candidate {!r} does not satisfy {}".format(
|
| 40 |
+
self.candidate,
|
| 41 |
+
", ".join(repr(r) for r in self.criterion.iter_requirement()),
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class Criterion(object):
|
| 46 |
+
"""Representation of possible resolution results of a package.
|
| 47 |
+
|
| 48 |
+
This holds three attributes:
|
| 49 |
+
|
| 50 |
+
* `information` is a collection of `RequirementInformation` pairs.
|
| 51 |
+
Each pair is a requirement contributing to this criterion, and the
|
| 52 |
+
candidate that provides the requirement.
|
| 53 |
+
* `incompatibilities` is a collection of all known not-to-work candidates
|
| 54 |
+
to exclude from consideration.
|
| 55 |
+
* `candidates` is a collection containing all possible candidates deducted
|
| 56 |
+
from the union of contributing requirements and known incompatibilities.
|
| 57 |
+
It should never be empty, except when the criterion is an attribute of a
|
| 58 |
+
raised `RequirementsConflicted` (in which case it is always empty).
|
| 59 |
+
|
| 60 |
+
.. note::
|
| 61 |
+
This class is intended to be externally immutable. **Do not** mutate
|
| 62 |
+
any of its attribute containers.
|
| 63 |
+
"""
|
| 64 |
+
|
| 65 |
+
def __init__(self, candidates, information, incompatibilities):
|
| 66 |
+
self.candidates = candidates
|
| 67 |
+
self.information = information
|
| 68 |
+
self.incompatibilities = incompatibilities
|
| 69 |
+
|
| 70 |
+
def __repr__(self):
|
| 71 |
+
requirements = ", ".join(
|
| 72 |
+
"({!r}, via={!r})".format(req, parent)
|
| 73 |
+
for req, parent in self.information
|
| 74 |
+
)
|
| 75 |
+
return "Criterion({})".format(requirements)
|
| 76 |
+
|
| 77 |
+
def iter_requirement(self):
|
| 78 |
+
return (i.requirement for i in self.information)
|
| 79 |
+
|
| 80 |
+
def iter_parent(self):
|
| 81 |
+
return (i.parent for i in self.information)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class ResolutionError(ResolverException):
|
| 85 |
+
pass
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class ResolutionImpossible(ResolutionError):
|
| 89 |
+
def __init__(self, causes):
|
| 90 |
+
super(ResolutionImpossible, self).__init__(causes)
|
| 91 |
+
# causes is a list of RequirementInformation objects
|
| 92 |
+
self.causes = causes
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class ResolutionTooDeep(ResolutionError):
|
| 96 |
+
def __init__(self, round_count):
|
| 97 |
+
super(ResolutionTooDeep, self).__init__(round_count)
|
| 98 |
+
self.round_count = round_count
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# Resolution state in a round.
|
| 102 |
+
State = collections.namedtuple("State", "mapping criteria")
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class Resolution(object):
|
| 106 |
+
"""Stateful resolution object.
|
| 107 |
+
|
| 108 |
+
This is designed as a one-off object that holds information to kick start
|
| 109 |
+
the resolution process, and holds the results afterwards.
|
| 110 |
+
"""
|
| 111 |
+
|
| 112 |
+
def __init__(self, provider, reporter):
|
| 113 |
+
self._p = provider
|
| 114 |
+
self._r = reporter
|
| 115 |
+
self._states = []
|
| 116 |
+
|
| 117 |
+
@property
|
| 118 |
+
def state(self):
|
| 119 |
+
try:
|
| 120 |
+
return self._states[-1]
|
| 121 |
+
except IndexError:
|
| 122 |
+
raise AttributeError("state")
|
| 123 |
+
|
| 124 |
+
def _push_new_state(self):
|
| 125 |
+
"""Push a new state into history.
|
| 126 |
+
|
| 127 |
+
This new state will be used to hold resolution results of the next
|
| 128 |
+
coming round.
|
| 129 |
+
"""
|
| 130 |
+
base = self._states[-1]
|
| 131 |
+
state = State(
|
| 132 |
+
mapping=base.mapping.copy(),
|
| 133 |
+
criteria=base.criteria.copy(),
|
| 134 |
+
)
|
| 135 |
+
self._states.append(state)
|
| 136 |
+
|
| 137 |
+
def _add_to_criteria(self, criteria, requirement, parent):
|
| 138 |
+
self._r.adding_requirement(requirement=requirement, parent=parent)
|
| 139 |
+
|
| 140 |
+
identifier = self._p.identify(requirement_or_candidate=requirement)
|
| 141 |
+
criterion = criteria.get(identifier)
|
| 142 |
+
if criterion:
|
| 143 |
+
incompatibilities = list(criterion.incompatibilities)
|
| 144 |
+
else:
|
| 145 |
+
incompatibilities = []
|
| 146 |
+
|
| 147 |
+
matches = self._p.find_matches(
|
| 148 |
+
identifier=identifier,
|
| 149 |
+
requirements=IteratorMapping(
|
| 150 |
+
criteria,
|
| 151 |
+
operator.methodcaller("iter_requirement"),
|
| 152 |
+
{identifier: [requirement]},
|
| 153 |
+
),
|
| 154 |
+
incompatibilities=IteratorMapping(
|
| 155 |
+
criteria,
|
| 156 |
+
operator.attrgetter("incompatibilities"),
|
| 157 |
+
{identifier: incompatibilities},
|
| 158 |
+
),
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
if criterion:
|
| 162 |
+
information = list(criterion.information)
|
| 163 |
+
information.append(RequirementInformation(requirement, parent))
|
| 164 |
+
else:
|
| 165 |
+
information = [RequirementInformation(requirement, parent)]
|
| 166 |
+
|
| 167 |
+
criterion = Criterion(
|
| 168 |
+
candidates=build_iter_view(matches),
|
| 169 |
+
information=information,
|
| 170 |
+
incompatibilities=incompatibilities,
|
| 171 |
+
)
|
| 172 |
+
if not criterion.candidates:
|
| 173 |
+
raise RequirementsConflicted(criterion)
|
| 174 |
+
criteria[identifier] = criterion
|
| 175 |
+
|
| 176 |
+
def _get_preference(self, name):
|
| 177 |
+
return self._p.get_preference(
|
| 178 |
+
identifier=name,
|
| 179 |
+
resolutions=self.state.mapping,
|
| 180 |
+
candidates=IteratorMapping(
|
| 181 |
+
self.state.criteria,
|
| 182 |
+
operator.attrgetter("candidates"),
|
| 183 |
+
),
|
| 184 |
+
information=IteratorMapping(
|
| 185 |
+
self.state.criteria,
|
| 186 |
+
operator.attrgetter("information"),
|
| 187 |
+
),
|
| 188 |
+
)
|
| 189 |
+
|
| 190 |
+
def _is_current_pin_satisfying(self, name, criterion):
|
| 191 |
+
try:
|
| 192 |
+
current_pin = self.state.mapping[name]
|
| 193 |
+
except KeyError:
|
| 194 |
+
return False
|
| 195 |
+
return all(
|
| 196 |
+
self._p.is_satisfied_by(requirement=r, candidate=current_pin)
|
| 197 |
+
for r in criterion.iter_requirement()
|
| 198 |
+
)
|
| 199 |
+
|
| 200 |
+
def _get_updated_criteria(self, candidate):
|
| 201 |
+
criteria = self.state.criteria.copy()
|
| 202 |
+
for requirement in self._p.get_dependencies(candidate=candidate):
|
| 203 |
+
self._add_to_criteria(criteria, requirement, parent=candidate)
|
| 204 |
+
return criteria
|
| 205 |
+
|
| 206 |
+
def _attempt_to_pin_criterion(self, name):
|
| 207 |
+
criterion = self.state.criteria[name]
|
| 208 |
+
|
| 209 |
+
causes = []
|
| 210 |
+
for candidate in criterion.candidates:
|
| 211 |
+
try:
|
| 212 |
+
criteria = self._get_updated_criteria(candidate)
|
| 213 |
+
except RequirementsConflicted as e:
|
| 214 |
+
causes.append(e.criterion)
|
| 215 |
+
continue
|
| 216 |
+
|
| 217 |
+
# Check the newly-pinned candidate actually works. This should
|
| 218 |
+
# always pass under normal circumstances, but in the case of a
|
| 219 |
+
# faulty provider, we will raise an error to notify the implementer
|
| 220 |
+
# to fix find_matches() and/or is_satisfied_by().
|
| 221 |
+
satisfied = all(
|
| 222 |
+
self._p.is_satisfied_by(requirement=r, candidate=candidate)
|
| 223 |
+
for r in criterion.iter_requirement()
|
| 224 |
+
)
|
| 225 |
+
if not satisfied:
|
| 226 |
+
raise InconsistentCandidate(candidate, criterion)
|
| 227 |
+
|
| 228 |
+
self._r.pinning(candidate=candidate)
|
| 229 |
+
self.state.criteria.update(criteria)
|
| 230 |
+
|
| 231 |
+
# Put newly-pinned candidate at the end. This is essential because
|
| 232 |
+
# backtracking looks at this mapping to get the last pin.
|
| 233 |
+
self.state.mapping.pop(name, None)
|
| 234 |
+
self.state.mapping[name] = candidate
|
| 235 |
+
|
| 236 |
+
return []
|
| 237 |
+
|
| 238 |
+
# All candidates tried, nothing works. This criterion is a dead
|
| 239 |
+
# end, signal for backtracking.
|
| 240 |
+
return causes
|
| 241 |
+
|
| 242 |
+
def _backtrack(self):
|
| 243 |
+
"""Perform backtracking.
|
| 244 |
+
|
| 245 |
+
When we enter here, the stack is like this::
|
| 246 |
+
|
| 247 |
+
[ state Z ]
|
| 248 |
+
[ state Y ]
|
| 249 |
+
[ state X ]
|
| 250 |
+
.... earlier states are irrelevant.
|
| 251 |
+
|
| 252 |
+
1. No pins worked for Z, so it does not have a pin.
|
| 253 |
+
2. We want to reset state Y to unpinned, and pin another candidate.
|
| 254 |
+
3. State X holds what state Y was before the pin, but does not
|
| 255 |
+
have the incompatibility information gathered in state Y.
|
| 256 |
+
|
| 257 |
+
Each iteration of the loop will:
|
| 258 |
+
|
| 259 |
+
1. Discard Z.
|
| 260 |
+
2. Discard Y but remember its incompatibility information gathered
|
| 261 |
+
previously, and the failure we're dealing with right now.
|
| 262 |
+
3. Push a new state Y' based on X, and apply the incompatibility
|
| 263 |
+
information from Y to Y'.
|
| 264 |
+
4a. If this causes Y' to conflict, we need to backtrack again. Make Y'
|
| 265 |
+
the new Z and go back to step 2.
|
| 266 |
+
4b. If the incompatibilities apply cleanly, end backtracking.
|
| 267 |
+
"""
|
| 268 |
+
while len(self._states) >= 3:
|
| 269 |
+
# Remove the state that triggered backtracking.
|
| 270 |
+
del self._states[-1]
|
| 271 |
+
|
| 272 |
+
# Retrieve the last candidate pin and known incompatibilities.
|
| 273 |
+
broken_state = self._states.pop()
|
| 274 |
+
name, candidate = broken_state.mapping.popitem()
|
| 275 |
+
incompatibilities_from_broken = [
|
| 276 |
+
(k, list(v.incompatibilities))
|
| 277 |
+
for k, v in broken_state.criteria.items()
|
| 278 |
+
]
|
| 279 |
+
|
| 280 |
+
# Also mark the newly known incompatibility.
|
| 281 |
+
incompatibilities_from_broken.append((name, [candidate]))
|
| 282 |
+
|
| 283 |
+
self._r.backtracking(candidate=candidate)
|
| 284 |
+
|
| 285 |
+
# Create a new state from the last known-to-work one, and apply
|
| 286 |
+
# the previously gathered incompatibility information.
|
| 287 |
+
def _patch_criteria():
|
| 288 |
+
for k, incompatibilities in incompatibilities_from_broken:
|
| 289 |
+
if not incompatibilities:
|
| 290 |
+
continue
|
| 291 |
+
try:
|
| 292 |
+
criterion = self.state.criteria[k]
|
| 293 |
+
except KeyError:
|
| 294 |
+
continue
|
| 295 |
+
matches = self._p.find_matches(
|
| 296 |
+
identifier=k,
|
| 297 |
+
requirements=IteratorMapping(
|
| 298 |
+
self.state.criteria,
|
| 299 |
+
operator.methodcaller("iter_requirement"),
|
| 300 |
+
),
|
| 301 |
+
incompatibilities=IteratorMapping(
|
| 302 |
+
self.state.criteria,
|
| 303 |
+
operator.attrgetter("incompatibilities"),
|
| 304 |
+
{k: incompatibilities},
|
| 305 |
+
),
|
| 306 |
+
)
|
| 307 |
+
candidates = build_iter_view(matches)
|
| 308 |
+
if not candidates:
|
| 309 |
+
return False
|
| 310 |
+
incompatibilities.extend(criterion.incompatibilities)
|
| 311 |
+
self.state.criteria[k] = Criterion(
|
| 312 |
+
candidates=candidates,
|
| 313 |
+
information=list(criterion.information),
|
| 314 |
+
incompatibilities=incompatibilities,
|
| 315 |
+
)
|
| 316 |
+
return True
|
| 317 |
+
|
| 318 |
+
self._push_new_state()
|
| 319 |
+
success = _patch_criteria()
|
| 320 |
+
|
| 321 |
+
# It works! Let's work on this new state.
|
| 322 |
+
if success:
|
| 323 |
+
return True
|
| 324 |
+
|
| 325 |
+
# State does not work after applying known incompatibilities.
|
| 326 |
+
# Try the still previous state.
|
| 327 |
+
|
| 328 |
+
# No way to backtrack anymore.
|
| 329 |
+
return False
|
| 330 |
+
|
| 331 |
+
def resolve(self, requirements, max_rounds):
|
| 332 |
+
if self._states:
|
| 333 |
+
raise RuntimeError("already resolved")
|
| 334 |
+
|
| 335 |
+
self._r.starting()
|
| 336 |
+
|
| 337 |
+
# Initialize the root state.
|
| 338 |
+
self._states = [State(mapping=collections.OrderedDict(), criteria={})]
|
| 339 |
+
for r in requirements:
|
| 340 |
+
try:
|
| 341 |
+
self._add_to_criteria(self.state.criteria, r, parent=None)
|
| 342 |
+
except RequirementsConflicted as e:
|
| 343 |
+
raise ResolutionImpossible(e.criterion.information)
|
| 344 |
+
|
| 345 |
+
# The root state is saved as a sentinel so the first ever pin can have
|
| 346 |
+
# something to backtrack to if it fails. The root state is basically
|
| 347 |
+
# pinning the virtual "root" package in the graph.
|
| 348 |
+
self._push_new_state()
|
| 349 |
+
|
| 350 |
+
for round_index in range(max_rounds):
|
| 351 |
+
self._r.starting_round(index=round_index)
|
| 352 |
+
|
| 353 |
+
unsatisfied_names = [
|
| 354 |
+
key
|
| 355 |
+
for key, criterion in self.state.criteria.items()
|
| 356 |
+
if not self._is_current_pin_satisfying(key, criterion)
|
| 357 |
+
]
|
| 358 |
+
|
| 359 |
+
# All criteria are accounted for. Nothing more to pin, we are done!
|
| 360 |
+
if not unsatisfied_names:
|
| 361 |
+
self._r.ending(state=self.state)
|
| 362 |
+
return self.state
|
| 363 |
+
|
| 364 |
+
# Choose the most preferred unpinned criterion to try.
|
| 365 |
+
name = min(unsatisfied_names, key=self._get_preference)
|
| 366 |
+
failure_causes = self._attempt_to_pin_criterion(name)
|
| 367 |
+
|
| 368 |
+
if failure_causes:
|
| 369 |
+
# Backtrack if pinning fails. The backtrack process puts us in
|
| 370 |
+
# an unpinned state, so we can work on it in the next round.
|
| 371 |
+
success = self._backtrack()
|
| 372 |
+
|
| 373 |
+
# Dead ends everywhere. Give up.
|
| 374 |
+
if not success:
|
| 375 |
+
causes = [i for c in failure_causes for i in c.information]
|
| 376 |
+
raise ResolutionImpossible(causes)
|
| 377 |
+
else:
|
| 378 |
+
# Pinning was successful. Push a new state to do another pin.
|
| 379 |
+
self._push_new_state()
|
| 380 |
+
|
| 381 |
+
self._r.ending_round(index=round_index, state=self.state)
|
| 382 |
+
|
| 383 |
+
raise ResolutionTooDeep(max_rounds)
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
def _has_route_to_root(criteria, key, all_keys, connected):
|
| 387 |
+
if key in connected:
|
| 388 |
+
return True
|
| 389 |
+
if key not in criteria:
|
| 390 |
+
return False
|
| 391 |
+
for p in criteria[key].iter_parent():
|
| 392 |
+
try:
|
| 393 |
+
pkey = all_keys[id(p)]
|
| 394 |
+
except KeyError:
|
| 395 |
+
continue
|
| 396 |
+
if pkey in connected:
|
| 397 |
+
connected.add(key)
|
| 398 |
+
return True
|
| 399 |
+
if _has_route_to_root(criteria, pkey, all_keys, connected):
|
| 400 |
+
connected.add(key)
|
| 401 |
+
return True
|
| 402 |
+
return False
|
| 403 |
+
|
| 404 |
+
|
| 405 |
+
Result = collections.namedtuple("Result", "mapping graph criteria")
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
def _build_result(state):
|
| 409 |
+
mapping = state.mapping
|
| 410 |
+
all_keys = {id(v): k for k, v in mapping.items()}
|
| 411 |
+
all_keys[id(None)] = None
|
| 412 |
+
|
| 413 |
+
graph = DirectedGraph()
|
| 414 |
+
graph.add(None) # Sentinel as root dependencies' parent.
|
| 415 |
+
|
| 416 |
+
connected = {None}
|
| 417 |
+
for key, criterion in state.criteria.items():
|
| 418 |
+
if not _has_route_to_root(state.criteria, key, all_keys, connected):
|
| 419 |
+
continue
|
| 420 |
+
if key not in graph:
|
| 421 |
+
graph.add(key)
|
| 422 |
+
for p in criterion.iter_parent():
|
| 423 |
+
try:
|
| 424 |
+
pkey = all_keys[id(p)]
|
| 425 |
+
except KeyError:
|
| 426 |
+
continue
|
| 427 |
+
if pkey not in graph:
|
| 428 |
+
graph.add(pkey)
|
| 429 |
+
graph.connect(pkey, key)
|
| 430 |
+
|
| 431 |
+
return Result(
|
| 432 |
+
mapping={k: v for k, v in mapping.items() if k in connected},
|
| 433 |
+
graph=graph,
|
| 434 |
+
criteria=state.criteria,
|
| 435 |
+
)
|
| 436 |
+
|
| 437 |
+
|
| 438 |
+
class Resolver(AbstractResolver):
|
| 439 |
+
"""The thing that performs the actual resolution work."""
|
| 440 |
+
|
| 441 |
+
base_exception = ResolverException
|
| 442 |
+
|
| 443 |
+
def resolve(self, requirements, max_rounds=100):
|
| 444 |
+
"""Take a collection of constraints, spit out the resolution result.
|
| 445 |
+
|
| 446 |
+
The return value is a representation to the final resolution result. It
|
| 447 |
+
is a tuple subclass with three public members:
|
| 448 |
+
|
| 449 |
+
* `mapping`: A dict of resolved candidates. Each key is an identifier
|
| 450 |
+
of a requirement (as returned by the provider's `identify` method),
|
| 451 |
+
and the value is the resolved candidate.
|
| 452 |
+
* `graph`: A `DirectedGraph` instance representing the dependency tree.
|
| 453 |
+
The vertices are keys of `mapping`, and each edge represents *why*
|
| 454 |
+
a particular package is included. A special vertex `None` is
|
| 455 |
+
included to represent parents of user-supplied requirements.
|
| 456 |
+
* `criteria`: A dict of "criteria" that hold detailed information on
|
| 457 |
+
how edges in the graph are derived. Each key is an identifier of a
|
| 458 |
+
requirement, and the value is a `Criterion` instance.
|
| 459 |
+
|
| 460 |
+
The following exceptions may be raised if a resolution cannot be found:
|
| 461 |
+
|
| 462 |
+
* `ResolutionImpossible`: A resolution cannot be found for the given
|
| 463 |
+
combination of requirements. The `causes` attribute of the
|
| 464 |
+
exception is a list of (requirement, parent), giving the
|
| 465 |
+
requirements that could not be satisfied.
|
| 466 |
+
* `ResolutionTooDeep`: The dependency tree is too deeply nested and
|
| 467 |
+
the resolver gave up. This is usually caused by a circular
|
| 468 |
+
dependency, but you can try to resolve this by increasing the
|
| 469 |
+
`max_rounds` argument.
|
| 470 |
+
"""
|
| 471 |
+
resolution = Resolution(self.provider, self.reporter)
|
| 472 |
+
state = resolution.resolve(requirements, max_rounds=max_rounds)
|
| 473 |
+
return _build_result(state)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/resolvelib/structs.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import itertools
|
| 2 |
+
|
| 3 |
+
from .compat import collections_abc
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class DirectedGraph(object):
|
| 7 |
+
"""A graph structure with directed edges."""
|
| 8 |
+
|
| 9 |
+
def __init__(self):
|
| 10 |
+
self._vertices = set()
|
| 11 |
+
self._forwards = {} # <key> -> Set[<key>]
|
| 12 |
+
self._backwards = {} # <key> -> Set[<key>]
|
| 13 |
+
|
| 14 |
+
def __iter__(self):
|
| 15 |
+
return iter(self._vertices)
|
| 16 |
+
|
| 17 |
+
def __len__(self):
|
| 18 |
+
return len(self._vertices)
|
| 19 |
+
|
| 20 |
+
def __contains__(self, key):
|
| 21 |
+
return key in self._vertices
|
| 22 |
+
|
| 23 |
+
def copy(self):
|
| 24 |
+
"""Return a shallow copy of this graph."""
|
| 25 |
+
other = DirectedGraph()
|
| 26 |
+
other._vertices = set(self._vertices)
|
| 27 |
+
other._forwards = {k: set(v) for k, v in self._forwards.items()}
|
| 28 |
+
other._backwards = {k: set(v) for k, v in self._backwards.items()}
|
| 29 |
+
return other
|
| 30 |
+
|
| 31 |
+
def add(self, key):
|
| 32 |
+
"""Add a new vertex to the graph."""
|
| 33 |
+
if key in self._vertices:
|
| 34 |
+
raise ValueError("vertex exists")
|
| 35 |
+
self._vertices.add(key)
|
| 36 |
+
self._forwards[key] = set()
|
| 37 |
+
self._backwards[key] = set()
|
| 38 |
+
|
| 39 |
+
def remove(self, key):
|
| 40 |
+
"""Remove a vertex from the graph, disconnecting all edges from/to it."""
|
| 41 |
+
self._vertices.remove(key)
|
| 42 |
+
for f in self._forwards.pop(key):
|
| 43 |
+
self._backwards[f].remove(key)
|
| 44 |
+
for t in self._backwards.pop(key):
|
| 45 |
+
self._forwards[t].remove(key)
|
| 46 |
+
|
| 47 |
+
def connected(self, f, t):
|
| 48 |
+
return f in self._backwards[t] and t in self._forwards[f]
|
| 49 |
+
|
| 50 |
+
def connect(self, f, t):
|
| 51 |
+
"""Connect two existing vertices.
|
| 52 |
+
|
| 53 |
+
Nothing happens if the vertices are already connected.
|
| 54 |
+
"""
|
| 55 |
+
if t not in self._vertices:
|
| 56 |
+
raise KeyError(t)
|
| 57 |
+
self._forwards[f].add(t)
|
| 58 |
+
self._backwards[t].add(f)
|
| 59 |
+
|
| 60 |
+
def iter_edges(self):
|
| 61 |
+
for f, children in self._forwards.items():
|
| 62 |
+
for t in children:
|
| 63 |
+
yield f, t
|
| 64 |
+
|
| 65 |
+
def iter_children(self, key):
|
| 66 |
+
return iter(self._forwards[key])
|
| 67 |
+
|
| 68 |
+
def iter_parents(self, key):
|
| 69 |
+
return iter(self._backwards[key])
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
class IteratorMapping(collections_abc.Mapping):
|
| 73 |
+
def __init__(self, mapping, accessor, appends=None):
|
| 74 |
+
self._mapping = mapping
|
| 75 |
+
self._accessor = accessor
|
| 76 |
+
self._appends = appends or {}
|
| 77 |
+
|
| 78 |
+
def __repr__(self):
|
| 79 |
+
return "IteratorMapping({!r}, {!r}, {!r})".format(
|
| 80 |
+
self._mapping,
|
| 81 |
+
self._accessor,
|
| 82 |
+
self._appends,
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
def __bool__(self):
|
| 86 |
+
return bool(self._mapping or self._appends)
|
| 87 |
+
|
| 88 |
+
__nonzero__ = __bool__ # XXX: Python 2.
|
| 89 |
+
|
| 90 |
+
def __contains__(self, key):
|
| 91 |
+
return key in self._mapping or key in self._appends
|
| 92 |
+
|
| 93 |
+
def __getitem__(self, k):
|
| 94 |
+
try:
|
| 95 |
+
v = self._mapping[k]
|
| 96 |
+
except KeyError:
|
| 97 |
+
return iter(self._appends[k])
|
| 98 |
+
return itertools.chain(self._accessor(v), self._appends.get(k, ()))
|
| 99 |
+
|
| 100 |
+
def __iter__(self):
|
| 101 |
+
more = (k for k in self._appends if k not in self._mapping)
|
| 102 |
+
return itertools.chain(self._mapping, more)
|
| 103 |
+
|
| 104 |
+
def __len__(self):
|
| 105 |
+
more = sum(1 for k in self._appends if k not in self._mapping)
|
| 106 |
+
return len(self._mapping) + more
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
class _FactoryIterableView(object):
|
| 110 |
+
"""Wrap an iterator factory returned by `find_matches()`.
|
| 111 |
+
|
| 112 |
+
Calling `iter()` on this class would invoke the underlying iterator
|
| 113 |
+
factory, making it a "collection with ordering" that can be iterated
|
| 114 |
+
through multiple times, but lacks random access methods presented in
|
| 115 |
+
built-in Python sequence types.
|
| 116 |
+
"""
|
| 117 |
+
|
| 118 |
+
def __init__(self, factory):
|
| 119 |
+
self._factory = factory
|
| 120 |
+
|
| 121 |
+
def __repr__(self):
|
| 122 |
+
return "{}({})".format(type(self).__name__, list(self._factory()))
|
| 123 |
+
|
| 124 |
+
def __bool__(self):
|
| 125 |
+
try:
|
| 126 |
+
next(self._factory())
|
| 127 |
+
except StopIteration:
|
| 128 |
+
return False
|
| 129 |
+
return True
|
| 130 |
+
|
| 131 |
+
__nonzero__ = __bool__ # XXX: Python 2.
|
| 132 |
+
|
| 133 |
+
def __iter__(self):
|
| 134 |
+
return self._factory()
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
class _SequenceIterableView(object):
|
| 138 |
+
"""Wrap an iterable returned by find_matches().
|
| 139 |
+
|
| 140 |
+
This is essentially just a proxy to the underlying sequence that provides
|
| 141 |
+
the same interface as `_FactoryIterableView`.
|
| 142 |
+
"""
|
| 143 |
+
|
| 144 |
+
def __init__(self, sequence):
|
| 145 |
+
self._sequence = sequence
|
| 146 |
+
|
| 147 |
+
def __repr__(self):
|
| 148 |
+
return "{}({})".format(type(self).__name__, self._sequence)
|
| 149 |
+
|
| 150 |
+
def __bool__(self):
|
| 151 |
+
return bool(self._sequence)
|
| 152 |
+
|
| 153 |
+
__nonzero__ = __bool__ # XXX: Python 2.
|
| 154 |
+
|
| 155 |
+
def __iter__(self):
|
| 156 |
+
return iter(self._sequence)
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
def build_iter_view(matches):
|
| 160 |
+
"""Build an iterable view from the value returned by `find_matches()`."""
|
| 161 |
+
if callable(matches):
|
| 162 |
+
return _FactoryIterableView(matches)
|
| 163 |
+
if not isinstance(matches, collections_abc.Sequence):
|
| 164 |
+
matches = list(matches)
|
| 165 |
+
return _SequenceIterableView(matches)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py
ADDED
|
File without changes
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
backports.makefile
|
| 4 |
+
~~~~~~~~~~~~~~~~~~
|
| 5 |
+
|
| 6 |
+
Backports the Python 3 ``socket.makefile`` method for use with anything that
|
| 7 |
+
wants to create a "fake" socket object.
|
| 8 |
+
"""
|
| 9 |
+
import io
|
| 10 |
+
from socket import SocketIO
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def backport_makefile(
|
| 14 |
+
self, mode="r", buffering=None, encoding=None, errors=None, newline=None
|
| 15 |
+
):
|
| 16 |
+
"""
|
| 17 |
+
Backport of ``socket.makefile`` from Python 3.5.
|
| 18 |
+
"""
|
| 19 |
+
if not set(mode) <= {"r", "w", "b"}:
|
| 20 |
+
raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
|
| 21 |
+
writing = "w" in mode
|
| 22 |
+
reading = "r" in mode or not writing
|
| 23 |
+
assert reading or writing
|
| 24 |
+
binary = "b" in mode
|
| 25 |
+
rawmode = ""
|
| 26 |
+
if reading:
|
| 27 |
+
rawmode += "r"
|
| 28 |
+
if writing:
|
| 29 |
+
rawmode += "w"
|
| 30 |
+
raw = SocketIO(self, rawmode)
|
| 31 |
+
self._makefile_refs += 1
|
| 32 |
+
if buffering is None:
|
| 33 |
+
buffering = -1
|
| 34 |
+
if buffering < 0:
|
| 35 |
+
buffering = io.DEFAULT_BUFFER_SIZE
|
| 36 |
+
if buffering == 0:
|
| 37 |
+
if not binary:
|
| 38 |
+
raise ValueError("unbuffered streams must be binary")
|
| 39 |
+
return raw
|
| 40 |
+
if reading and writing:
|
| 41 |
+
buffer = io.BufferedRWPair(raw, raw, buffering)
|
| 42 |
+
elif reading:
|
| 43 |
+
buffer = io.BufferedReader(raw, buffering)
|
| 44 |
+
else:
|
| 45 |
+
assert writing
|
| 46 |
+
buffer = io.BufferedWriter(raw, buffering)
|
| 47 |
+
if binary:
|
| 48 |
+
return buffer
|
| 49 |
+
text = io.TextIOWrapper(buffer, encoding, errors, newline)
|
| 50 |
+
text.mode = mode
|
| 51 |
+
return text
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
|
| 3 |
+
try:
|
| 4 |
+
# Our match_hostname function is the same as 3.10's, so we only want to
|
| 5 |
+
# import the match_hostname function if it's at least that good.
|
| 6 |
+
# We also fallback on Python 3.10+ because our code doesn't emit
|
| 7 |
+
# deprecation warnings and is the same as Python 3.10 otherwise.
|
| 8 |
+
if sys.version_info < (3, 5) or sys.version_info >= (3, 10):
|
| 9 |
+
raise ImportError("Fallback to vendored code")
|
| 10 |
+
|
| 11 |
+
from ssl import CertificateError, match_hostname
|
| 12 |
+
except ImportError:
|
| 13 |
+
try:
|
| 14 |
+
# Backport of the function from a pypi module
|
| 15 |
+
from backports.ssl_match_hostname import ( # type: ignore
|
| 16 |
+
CertificateError,
|
| 17 |
+
match_hostname,
|
| 18 |
+
)
|
| 19 |
+
except ImportError:
|
| 20 |
+
# Our vendored copy
|
| 21 |
+
from ._implementation import CertificateError, match_hostname # type: ignore
|
| 22 |
+
|
| 23 |
+
# Not needed, but documenting what we provide.
|
| 24 |
+
__all__ = ("CertificateError", "match_hostname")
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""The match_hostname() function from Python 3.3.3, essential when using SSL."""
|
| 2 |
+
|
| 3 |
+
# Note: This file is under the PSF license as the code comes from the python
|
| 4 |
+
# stdlib. http://docs.python.org/3/license.html
|
| 5 |
+
|
| 6 |
+
import re
|
| 7 |
+
import sys
|
| 8 |
+
|
| 9 |
+
# ipaddress has been backported to 2.6+ in pypi. If it is installed on the
|
| 10 |
+
# system, use it to handle IPAddress ServerAltnames (this was added in
|
| 11 |
+
# python-3.5) otherwise only do DNS matching. This allows
|
| 12 |
+
# backports.ssl_match_hostname to continue to be used in Python 2.7.
|
| 13 |
+
try:
|
| 14 |
+
import ipaddress
|
| 15 |
+
except ImportError:
|
| 16 |
+
ipaddress = None
|
| 17 |
+
|
| 18 |
+
__version__ = "3.5.0.1"
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class CertificateError(ValueError):
|
| 22 |
+
pass
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def _dnsname_match(dn, hostname, max_wildcards=1):
|
| 26 |
+
"""Matching according to RFC 6125, section 6.4.3
|
| 27 |
+
|
| 28 |
+
http://tools.ietf.org/html/rfc6125#section-6.4.3
|
| 29 |
+
"""
|
| 30 |
+
pats = []
|
| 31 |
+
if not dn:
|
| 32 |
+
return False
|
| 33 |
+
|
| 34 |
+
# Ported from python3-syntax:
|
| 35 |
+
# leftmost, *remainder = dn.split(r'.')
|
| 36 |
+
parts = dn.split(r".")
|
| 37 |
+
leftmost = parts[0]
|
| 38 |
+
remainder = parts[1:]
|
| 39 |
+
|
| 40 |
+
wildcards = leftmost.count("*")
|
| 41 |
+
if wildcards > max_wildcards:
|
| 42 |
+
# Issue #17980: avoid denials of service by refusing more
|
| 43 |
+
# than one wildcard per fragment. A survey of established
|
| 44 |
+
# policy among SSL implementations showed it to be a
|
| 45 |
+
# reasonable choice.
|
| 46 |
+
raise CertificateError(
|
| 47 |
+
"too many wildcards in certificate DNS name: " + repr(dn)
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
# speed up common case w/o wildcards
|
| 51 |
+
if not wildcards:
|
| 52 |
+
return dn.lower() == hostname.lower()
|
| 53 |
+
|
| 54 |
+
# RFC 6125, section 6.4.3, subitem 1.
|
| 55 |
+
# The client SHOULD NOT attempt to match a presented identifier in which
|
| 56 |
+
# the wildcard character comprises a label other than the left-most label.
|
| 57 |
+
if leftmost == "*":
|
| 58 |
+
# When '*' is a fragment by itself, it matches a non-empty dotless
|
| 59 |
+
# fragment.
|
| 60 |
+
pats.append("[^.]+")
|
| 61 |
+
elif leftmost.startswith("xn--") or hostname.startswith("xn--"):
|
| 62 |
+
# RFC 6125, section 6.4.3, subitem 3.
|
| 63 |
+
# The client SHOULD NOT attempt to match a presented identifier
|
| 64 |
+
# where the wildcard character is embedded within an A-label or
|
| 65 |
+
# U-label of an internationalized domain name.
|
| 66 |
+
pats.append(re.escape(leftmost))
|
| 67 |
+
else:
|
| 68 |
+
# Otherwise, '*' matches any dotless string, e.g. www*
|
| 69 |
+
pats.append(re.escape(leftmost).replace(r"\*", "[^.]*"))
|
| 70 |
+
|
| 71 |
+
# add the remaining fragments, ignore any wildcards
|
| 72 |
+
for frag in remainder:
|
| 73 |
+
pats.append(re.escape(frag))
|
| 74 |
+
|
| 75 |
+
pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE)
|
| 76 |
+
return pat.match(hostname)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def _to_unicode(obj):
|
| 80 |
+
if isinstance(obj, str) and sys.version_info < (3,):
|
| 81 |
+
obj = unicode(obj, encoding="ascii", errors="strict")
|
| 82 |
+
return obj
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _ipaddress_match(ipname, host_ip):
|
| 86 |
+
"""Exact matching of IP addresses.
|
| 87 |
+
|
| 88 |
+
RFC 6125 explicitly doesn't define an algorithm for this
|
| 89 |
+
(section 1.7.2 - "Out of Scope").
|
| 90 |
+
"""
|
| 91 |
+
# OpenSSL may add a trailing newline to a subjectAltName's IP address
|
| 92 |
+
# Divergence from upstream: ipaddress can't handle byte str
|
| 93 |
+
ip = ipaddress.ip_address(_to_unicode(ipname).rstrip())
|
| 94 |
+
return ip == host_ip
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def match_hostname(cert, hostname):
|
| 98 |
+
"""Verify that *cert* (in decoded format as returned by
|
| 99 |
+
SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125
|
| 100 |
+
rules are followed, but IP addresses are not accepted for *hostname*.
|
| 101 |
+
|
| 102 |
+
CertificateError is raised on failure. On success, the function
|
| 103 |
+
returns nothing.
|
| 104 |
+
"""
|
| 105 |
+
if not cert:
|
| 106 |
+
raise ValueError(
|
| 107 |
+
"empty or no certificate, match_hostname needs a "
|
| 108 |
+
"SSL socket or SSL context with either "
|
| 109 |
+
"CERT_OPTIONAL or CERT_REQUIRED"
|
| 110 |
+
)
|
| 111 |
+
try:
|
| 112 |
+
# Divergence from upstream: ipaddress can't handle byte str
|
| 113 |
+
host_ip = ipaddress.ip_address(_to_unicode(hostname))
|
| 114 |
+
except ValueError:
|
| 115 |
+
# Not an IP address (common case)
|
| 116 |
+
host_ip = None
|
| 117 |
+
except UnicodeError:
|
| 118 |
+
# Divergence from upstream: Have to deal with ipaddress not taking
|
| 119 |
+
# byte strings. addresses should be all ascii, so we consider it not
|
| 120 |
+
# an ipaddress in this case
|
| 121 |
+
host_ip = None
|
| 122 |
+
except AttributeError:
|
| 123 |
+
# Divergence from upstream: Make ipaddress library optional
|
| 124 |
+
if ipaddress is None:
|
| 125 |
+
host_ip = None
|
| 126 |
+
else:
|
| 127 |
+
raise
|
| 128 |
+
dnsnames = []
|
| 129 |
+
san = cert.get("subjectAltName", ())
|
| 130 |
+
for key, value in san:
|
| 131 |
+
if key == "DNS":
|
| 132 |
+
if host_ip is None and _dnsname_match(value, hostname):
|
| 133 |
+
return
|
| 134 |
+
dnsnames.append(value)
|
| 135 |
+
elif key == "IP Address":
|
| 136 |
+
if host_ip is not None and _ipaddress_match(value, host_ip):
|
| 137 |
+
return
|
| 138 |
+
dnsnames.append(value)
|
| 139 |
+
if not dnsnames:
|
| 140 |
+
# The subject is only checked when there is no dNSName entry
|
| 141 |
+
# in subjectAltName
|
| 142 |
+
for sub in cert.get("subject", ()):
|
| 143 |
+
for key, value in sub:
|
| 144 |
+
# XXX according to RFC 2818, the most specific Common Name
|
| 145 |
+
# must be used.
|
| 146 |
+
if key == "commonName":
|
| 147 |
+
if _dnsname_match(value, hostname):
|
| 148 |
+
return
|
| 149 |
+
dnsnames.append(value)
|
| 150 |
+
if len(dnsnames) > 1:
|
| 151 |
+
raise CertificateError(
|
| 152 |
+
"hostname %r "
|
| 153 |
+
"doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames)))
|
| 154 |
+
)
|
| 155 |
+
elif len(dnsnames) == 1:
|
| 156 |
+
raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0]))
|
| 157 |
+
else:
|
| 158 |
+
raise CertificateError(
|
| 159 |
+
"no appropriate commonName or subjectAltName fields were found"
|
| 160 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/__init__.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Extensions to the 'distutils' for large or complex distributions"""
|
| 2 |
+
|
| 3 |
+
from fnmatch import fnmatchcase
|
| 4 |
+
import functools
|
| 5 |
+
import os
|
| 6 |
+
import re
|
| 7 |
+
|
| 8 |
+
import _distutils_hack.override # noqa: F401
|
| 9 |
+
|
| 10 |
+
import distutils.core
|
| 11 |
+
from distutils.errors import DistutilsOptionError
|
| 12 |
+
from distutils.util import convert_path
|
| 13 |
+
|
| 14 |
+
from ._deprecation_warning import SetuptoolsDeprecationWarning
|
| 15 |
+
|
| 16 |
+
import setuptools.version
|
| 17 |
+
from setuptools.extension import Extension
|
| 18 |
+
from setuptools.dist import Distribution
|
| 19 |
+
from setuptools.depends import Require
|
| 20 |
+
from . import monkey
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
__all__ = [
|
| 24 |
+
'setup',
|
| 25 |
+
'Distribution',
|
| 26 |
+
'Command',
|
| 27 |
+
'Extension',
|
| 28 |
+
'Require',
|
| 29 |
+
'SetuptoolsDeprecationWarning',
|
| 30 |
+
'find_packages',
|
| 31 |
+
'find_namespace_packages',
|
| 32 |
+
]
|
| 33 |
+
|
| 34 |
+
__version__ = setuptools.version.__version__
|
| 35 |
+
|
| 36 |
+
bootstrap_install_from = None
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class PackageFinder:
|
| 40 |
+
"""
|
| 41 |
+
Generate a list of all Python packages found within a directory
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
@classmethod
|
| 45 |
+
def find(cls, where='.', exclude=(), include=('*',)):
|
| 46 |
+
"""Return a list all Python packages found within directory 'where'
|
| 47 |
+
|
| 48 |
+
'where' is the root directory which will be searched for packages. It
|
| 49 |
+
should be supplied as a "cross-platform" (i.e. URL-style) path; it will
|
| 50 |
+
be converted to the appropriate local path syntax.
|
| 51 |
+
|
| 52 |
+
'exclude' is a sequence of package names to exclude; '*' can be used
|
| 53 |
+
as a wildcard in the names, such that 'foo.*' will exclude all
|
| 54 |
+
subpackages of 'foo' (but not 'foo' itself).
|
| 55 |
+
|
| 56 |
+
'include' is a sequence of package names to include. If it's
|
| 57 |
+
specified, only the named packages will be included. If it's not
|
| 58 |
+
specified, all found packages will be included. 'include' can contain
|
| 59 |
+
shell style wildcard patterns just like 'exclude'.
|
| 60 |
+
"""
|
| 61 |
+
|
| 62 |
+
return list(
|
| 63 |
+
cls._find_packages_iter(
|
| 64 |
+
convert_path(where),
|
| 65 |
+
cls._build_filter('ez_setup', '*__pycache__', *exclude),
|
| 66 |
+
cls._build_filter(*include),
|
| 67 |
+
)
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
@classmethod
|
| 71 |
+
def _find_packages_iter(cls, where, exclude, include):
|
| 72 |
+
"""
|
| 73 |
+
All the packages found in 'where' that pass the 'include' filter, but
|
| 74 |
+
not the 'exclude' filter.
|
| 75 |
+
"""
|
| 76 |
+
for root, dirs, files in os.walk(where, followlinks=True):
|
| 77 |
+
# Copy dirs to iterate over it, then empty dirs.
|
| 78 |
+
all_dirs = dirs[:]
|
| 79 |
+
dirs[:] = []
|
| 80 |
+
|
| 81 |
+
for dir in all_dirs:
|
| 82 |
+
full_path = os.path.join(root, dir)
|
| 83 |
+
rel_path = os.path.relpath(full_path, where)
|
| 84 |
+
package = rel_path.replace(os.path.sep, '.')
|
| 85 |
+
|
| 86 |
+
# Skip directory trees that are not valid packages
|
| 87 |
+
if '.' in dir or not cls._looks_like_package(full_path):
|
| 88 |
+
continue
|
| 89 |
+
|
| 90 |
+
# Should this package be included?
|
| 91 |
+
if include(package) and not exclude(package):
|
| 92 |
+
yield package
|
| 93 |
+
|
| 94 |
+
# Keep searching subdirectories, as there may be more packages
|
| 95 |
+
# down there, even if the parent was excluded.
|
| 96 |
+
dirs.append(dir)
|
| 97 |
+
|
| 98 |
+
@staticmethod
|
| 99 |
+
def _looks_like_package(path):
|
| 100 |
+
"""Does a directory look like a package?"""
|
| 101 |
+
return os.path.isfile(os.path.join(path, '__init__.py'))
|
| 102 |
+
|
| 103 |
+
@staticmethod
|
| 104 |
+
def _build_filter(*patterns):
|
| 105 |
+
"""
|
| 106 |
+
Given a list of patterns, return a callable that will be true only if
|
| 107 |
+
the input matches at least one of the patterns.
|
| 108 |
+
"""
|
| 109 |
+
return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
class PEP420PackageFinder(PackageFinder):
|
| 113 |
+
@staticmethod
|
| 114 |
+
def _looks_like_package(path):
|
| 115 |
+
return True
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
find_packages = PackageFinder.find
|
| 119 |
+
find_namespace_packages = PEP420PackageFinder.find
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def _install_setup_requires(attrs):
|
| 123 |
+
# Note: do not use `setuptools.Distribution` directly, as
|
| 124 |
+
# our PEP 517 backend patch `distutils.core.Distribution`.
|
| 125 |
+
class MinimalDistribution(distutils.core.Distribution):
|
| 126 |
+
"""
|
| 127 |
+
A minimal version of a distribution for supporting the
|
| 128 |
+
fetch_build_eggs interface.
|
| 129 |
+
"""
|
| 130 |
+
|
| 131 |
+
def __init__(self, attrs):
|
| 132 |
+
_incl = 'dependency_links', 'setup_requires'
|
| 133 |
+
filtered = {k: attrs[k] for k in set(_incl) & set(attrs)}
|
| 134 |
+
distutils.core.Distribution.__init__(self, filtered)
|
| 135 |
+
|
| 136 |
+
def finalize_options(self):
|
| 137 |
+
"""
|
| 138 |
+
Disable finalize_options to avoid building the working set.
|
| 139 |
+
Ref #2158.
|
| 140 |
+
"""
|
| 141 |
+
|
| 142 |
+
dist = MinimalDistribution(attrs)
|
| 143 |
+
|
| 144 |
+
# Honor setup.cfg's options.
|
| 145 |
+
dist.parse_config_files(ignore_option_errors=True)
|
| 146 |
+
if dist.setup_requires:
|
| 147 |
+
dist.fetch_build_eggs(dist.setup_requires)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def setup(**attrs):
|
| 151 |
+
# Make sure we have any requirements needed to interpret 'attrs'.
|
| 152 |
+
_install_setup_requires(attrs)
|
| 153 |
+
return distutils.core.setup(**attrs)
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
setup.__doc__ = distutils.core.setup.__doc__
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
_Command = monkey.get_unpatched(distutils.core.Command)
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
class Command(_Command):
|
| 163 |
+
__doc__ = _Command.__doc__
|
| 164 |
+
|
| 165 |
+
command_consumes_arguments = False
|
| 166 |
+
|
| 167 |
+
def __init__(self, dist, **kw):
|
| 168 |
+
"""
|
| 169 |
+
Construct the command for dist, updating
|
| 170 |
+
vars(self) with any keyword parameters.
|
| 171 |
+
"""
|
| 172 |
+
_Command.__init__(self, dist)
|
| 173 |
+
vars(self).update(kw)
|
| 174 |
+
|
| 175 |
+
def _ensure_stringlike(self, option, what, default=None):
|
| 176 |
+
val = getattr(self, option)
|
| 177 |
+
if val is None:
|
| 178 |
+
setattr(self, option, default)
|
| 179 |
+
return default
|
| 180 |
+
elif not isinstance(val, str):
|
| 181 |
+
raise DistutilsOptionError(
|
| 182 |
+
"'%s' must be a %s (got `%s`)" % (option, what, val)
|
| 183 |
+
)
|
| 184 |
+
return val
|
| 185 |
+
|
| 186 |
+
def ensure_string_list(self, option):
|
| 187 |
+
r"""Ensure that 'option' is a list of strings. If 'option' is
|
| 188 |
+
currently a string, we split it either on /,\s*/ or /\s+/, so
|
| 189 |
+
"foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
|
| 190 |
+
["foo", "bar", "baz"].
|
| 191 |
+
"""
|
| 192 |
+
val = getattr(self, option)
|
| 193 |
+
if val is None:
|
| 194 |
+
return
|
| 195 |
+
elif isinstance(val, str):
|
| 196 |
+
setattr(self, option, re.split(r',\s*|\s+', val))
|
| 197 |
+
else:
|
| 198 |
+
if isinstance(val, list):
|
| 199 |
+
ok = all(isinstance(v, str) for v in val)
|
| 200 |
+
else:
|
| 201 |
+
ok = False
|
| 202 |
+
if not ok:
|
| 203 |
+
raise DistutilsOptionError(
|
| 204 |
+
"'%s' must be a list of strings (got %r)" % (option, val)
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
def reinitialize_command(self, command, reinit_subcommands=0, **kw):
|
| 208 |
+
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
|
| 209 |
+
vars(cmd).update(kw)
|
| 210 |
+
return cmd
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def _find_all_simple(path):
|
| 214 |
+
"""
|
| 215 |
+
Find all files under 'path'
|
| 216 |
+
"""
|
| 217 |
+
results = (
|
| 218 |
+
os.path.join(base, file)
|
| 219 |
+
for base, dirs, files in os.walk(path, followlinks=True)
|
| 220 |
+
for file in files
|
| 221 |
+
)
|
| 222 |
+
return filter(os.path.isfile, results)
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def findall(dir=os.curdir):
|
| 226 |
+
"""
|
| 227 |
+
Find all files under 'dir' and return the list of full filenames.
|
| 228 |
+
Unless dir is '.', return full filenames with dir prepended.
|
| 229 |
+
"""
|
| 230 |
+
files = _find_all_simple(dir)
|
| 231 |
+
if dir == os.curdir:
|
| 232 |
+
make_rel = functools.partial(os.path.relpath, start=dir)
|
| 233 |
+
files = map(make_rel, files)
|
| 234 |
+
return list(files)
|
| 235 |
+
|
| 236 |
+
|
| 237 |
+
class sic(str):
|
| 238 |
+
"""Treat this string as-is (https://en.wikipedia.org/wiki/Sic)"""
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
# Apply monkey patches
|
| 242 |
+
monkey.patch_all()
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_deprecation_warning.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
class SetuptoolsDeprecationWarning(Warning):
|
| 2 |
+
"""
|
| 3 |
+
Base class for warning deprecations in ``setuptools``
|
| 4 |
+
|
| 5 |
+
This class is not derived from ``DeprecationWarning``, and as such is
|
| 6 |
+
visible by default.
|
| 7 |
+
"""
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_imp.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Re-implementation of find_module and get_frozen_object
|
| 3 |
+
from the deprecated imp module.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import os
|
| 7 |
+
import importlib.util
|
| 8 |
+
import importlib.machinery
|
| 9 |
+
|
| 10 |
+
from .py34compat import module_from_spec
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
PY_SOURCE = 1
|
| 14 |
+
PY_COMPILED = 2
|
| 15 |
+
C_EXTENSION = 3
|
| 16 |
+
C_BUILTIN = 6
|
| 17 |
+
PY_FROZEN = 7
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def find_spec(module, paths):
|
| 21 |
+
finder = (
|
| 22 |
+
importlib.machinery.PathFinder().find_spec
|
| 23 |
+
if isinstance(paths, list) else
|
| 24 |
+
importlib.util.find_spec
|
| 25 |
+
)
|
| 26 |
+
return finder(module, paths)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def find_module(module, paths=None):
|
| 30 |
+
"""Just like 'imp.find_module()', but with package support"""
|
| 31 |
+
spec = find_spec(module, paths)
|
| 32 |
+
if spec is None:
|
| 33 |
+
raise ImportError("Can't find %s" % module)
|
| 34 |
+
if not spec.has_location and hasattr(spec, 'submodule_search_locations'):
|
| 35 |
+
spec = importlib.util.spec_from_loader('__init__.py', spec.loader)
|
| 36 |
+
|
| 37 |
+
kind = -1
|
| 38 |
+
file = None
|
| 39 |
+
static = isinstance(spec.loader, type)
|
| 40 |
+
if spec.origin == 'frozen' or static and issubclass(
|
| 41 |
+
spec.loader, importlib.machinery.FrozenImporter):
|
| 42 |
+
kind = PY_FROZEN
|
| 43 |
+
path = None # imp compabilty
|
| 44 |
+
suffix = mode = '' # imp compatibility
|
| 45 |
+
elif spec.origin == 'built-in' or static and issubclass(
|
| 46 |
+
spec.loader, importlib.machinery.BuiltinImporter):
|
| 47 |
+
kind = C_BUILTIN
|
| 48 |
+
path = None # imp compabilty
|
| 49 |
+
suffix = mode = '' # imp compatibility
|
| 50 |
+
elif spec.has_location:
|
| 51 |
+
path = spec.origin
|
| 52 |
+
suffix = os.path.splitext(path)[1]
|
| 53 |
+
mode = 'r' if suffix in importlib.machinery.SOURCE_SUFFIXES else 'rb'
|
| 54 |
+
|
| 55 |
+
if suffix in importlib.machinery.SOURCE_SUFFIXES:
|
| 56 |
+
kind = PY_SOURCE
|
| 57 |
+
elif suffix in importlib.machinery.BYTECODE_SUFFIXES:
|
| 58 |
+
kind = PY_COMPILED
|
| 59 |
+
elif suffix in importlib.machinery.EXTENSION_SUFFIXES:
|
| 60 |
+
kind = C_EXTENSION
|
| 61 |
+
|
| 62 |
+
if kind in {PY_SOURCE, PY_COMPILED}:
|
| 63 |
+
file = open(path, mode)
|
| 64 |
+
else:
|
| 65 |
+
path = None
|
| 66 |
+
suffix = mode = ''
|
| 67 |
+
|
| 68 |
+
return file, path, (suffix, mode, kind)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def get_frozen_object(module, paths=None):
|
| 72 |
+
spec = find_spec(module, paths)
|
| 73 |
+
if not spec:
|
| 74 |
+
raise ImportError("Can't find %s" % module)
|
| 75 |
+
return spec.loader.get_code(module)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def get_module(module, paths, info):
|
| 79 |
+
spec = find_spec(module, paths)
|
| 80 |
+
if not spec:
|
| 81 |
+
raise ImportError("Can't find %s" % module)
|
| 82 |
+
return module_from_spec(spec)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/__init__.py
ADDED
|
File without changes
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/more_itertools/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .more import * # noqa
|
| 2 |
+
from .recipes import * # noqa
|
| 3 |
+
|
| 4 |
+
__version__ = '8.8.0'
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/more_itertools/more.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/more_itertools/recipes.py
ADDED
|
@@ -0,0 +1,620 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Imported from the recipes section of the itertools documentation.
|
| 2 |
+
|
| 3 |
+
All functions taken from the recipes section of the itertools library docs
|
| 4 |
+
[1]_.
|
| 5 |
+
Some backward-compatible usability improvements have been made.
|
| 6 |
+
|
| 7 |
+
.. [1] http://docs.python.org/library/itertools.html#recipes
|
| 8 |
+
|
| 9 |
+
"""
|
| 10 |
+
import warnings
|
| 11 |
+
from collections import deque
|
| 12 |
+
from itertools import (
|
| 13 |
+
chain,
|
| 14 |
+
combinations,
|
| 15 |
+
count,
|
| 16 |
+
cycle,
|
| 17 |
+
groupby,
|
| 18 |
+
islice,
|
| 19 |
+
repeat,
|
| 20 |
+
starmap,
|
| 21 |
+
tee,
|
| 22 |
+
zip_longest,
|
| 23 |
+
)
|
| 24 |
+
import operator
|
| 25 |
+
from random import randrange, sample, choice
|
| 26 |
+
|
| 27 |
+
__all__ = [
|
| 28 |
+
'all_equal',
|
| 29 |
+
'consume',
|
| 30 |
+
'convolve',
|
| 31 |
+
'dotproduct',
|
| 32 |
+
'first_true',
|
| 33 |
+
'flatten',
|
| 34 |
+
'grouper',
|
| 35 |
+
'iter_except',
|
| 36 |
+
'ncycles',
|
| 37 |
+
'nth',
|
| 38 |
+
'nth_combination',
|
| 39 |
+
'padnone',
|
| 40 |
+
'pad_none',
|
| 41 |
+
'pairwise',
|
| 42 |
+
'partition',
|
| 43 |
+
'powerset',
|
| 44 |
+
'prepend',
|
| 45 |
+
'quantify',
|
| 46 |
+
'random_combination_with_replacement',
|
| 47 |
+
'random_combination',
|
| 48 |
+
'random_permutation',
|
| 49 |
+
'random_product',
|
| 50 |
+
'repeatfunc',
|
| 51 |
+
'roundrobin',
|
| 52 |
+
'tabulate',
|
| 53 |
+
'tail',
|
| 54 |
+
'take',
|
| 55 |
+
'unique_everseen',
|
| 56 |
+
'unique_justseen',
|
| 57 |
+
]
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def take(n, iterable):
|
| 61 |
+
"""Return first *n* items of the iterable as a list.
|
| 62 |
+
|
| 63 |
+
>>> take(3, range(10))
|
| 64 |
+
[0, 1, 2]
|
| 65 |
+
|
| 66 |
+
If there are fewer than *n* items in the iterable, all of them are
|
| 67 |
+
returned.
|
| 68 |
+
|
| 69 |
+
>>> take(10, range(3))
|
| 70 |
+
[0, 1, 2]
|
| 71 |
+
|
| 72 |
+
"""
|
| 73 |
+
return list(islice(iterable, n))
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def tabulate(function, start=0):
|
| 77 |
+
"""Return an iterator over the results of ``func(start)``,
|
| 78 |
+
``func(start + 1)``, ``func(start + 2)``...
|
| 79 |
+
|
| 80 |
+
*func* should be a function that accepts one integer argument.
|
| 81 |
+
|
| 82 |
+
If *start* is not specified it defaults to 0. It will be incremented each
|
| 83 |
+
time the iterator is advanced.
|
| 84 |
+
|
| 85 |
+
>>> square = lambda x: x ** 2
|
| 86 |
+
>>> iterator = tabulate(square, -3)
|
| 87 |
+
>>> take(4, iterator)
|
| 88 |
+
[9, 4, 1, 0]
|
| 89 |
+
|
| 90 |
+
"""
|
| 91 |
+
return map(function, count(start))
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def tail(n, iterable):
|
| 95 |
+
"""Return an iterator over the last *n* items of *iterable*.
|
| 96 |
+
|
| 97 |
+
>>> t = tail(3, 'ABCDEFG')
|
| 98 |
+
>>> list(t)
|
| 99 |
+
['E', 'F', 'G']
|
| 100 |
+
|
| 101 |
+
"""
|
| 102 |
+
return iter(deque(iterable, maxlen=n))
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def consume(iterator, n=None):
|
| 106 |
+
"""Advance *iterable* by *n* steps. If *n* is ``None``, consume it
|
| 107 |
+
entirely.
|
| 108 |
+
|
| 109 |
+
Efficiently exhausts an iterator without returning values. Defaults to
|
| 110 |
+
consuming the whole iterator, but an optional second argument may be
|
| 111 |
+
provided to limit consumption.
|
| 112 |
+
|
| 113 |
+
>>> i = (x for x in range(10))
|
| 114 |
+
>>> next(i)
|
| 115 |
+
0
|
| 116 |
+
>>> consume(i, 3)
|
| 117 |
+
>>> next(i)
|
| 118 |
+
4
|
| 119 |
+
>>> consume(i)
|
| 120 |
+
>>> next(i)
|
| 121 |
+
Traceback (most recent call last):
|
| 122 |
+
File "<stdin>", line 1, in <module>
|
| 123 |
+
StopIteration
|
| 124 |
+
|
| 125 |
+
If the iterator has fewer items remaining than the provided limit, the
|
| 126 |
+
whole iterator will be consumed.
|
| 127 |
+
|
| 128 |
+
>>> i = (x for x in range(3))
|
| 129 |
+
>>> consume(i, 5)
|
| 130 |
+
>>> next(i)
|
| 131 |
+
Traceback (most recent call last):
|
| 132 |
+
File "<stdin>", line 1, in <module>
|
| 133 |
+
StopIteration
|
| 134 |
+
|
| 135 |
+
"""
|
| 136 |
+
# Use functions that consume iterators at C speed.
|
| 137 |
+
if n is None:
|
| 138 |
+
# feed the entire iterator into a zero-length deque
|
| 139 |
+
deque(iterator, maxlen=0)
|
| 140 |
+
else:
|
| 141 |
+
# advance to the empty slice starting at position n
|
| 142 |
+
next(islice(iterator, n, n), None)
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def nth(iterable, n, default=None):
|
| 146 |
+
"""Returns the nth item or a default value.
|
| 147 |
+
|
| 148 |
+
>>> l = range(10)
|
| 149 |
+
>>> nth(l, 3)
|
| 150 |
+
3
|
| 151 |
+
>>> nth(l, 20, "zebra")
|
| 152 |
+
'zebra'
|
| 153 |
+
|
| 154 |
+
"""
|
| 155 |
+
return next(islice(iterable, n, None), default)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def all_equal(iterable):
|
| 159 |
+
"""
|
| 160 |
+
Returns ``True`` if all the elements are equal to each other.
|
| 161 |
+
|
| 162 |
+
>>> all_equal('aaaa')
|
| 163 |
+
True
|
| 164 |
+
>>> all_equal('aaab')
|
| 165 |
+
False
|
| 166 |
+
|
| 167 |
+
"""
|
| 168 |
+
g = groupby(iterable)
|
| 169 |
+
return next(g, True) and not next(g, False)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def quantify(iterable, pred=bool):
|
| 173 |
+
"""Return the how many times the predicate is true.
|
| 174 |
+
|
| 175 |
+
>>> quantify([True, False, True])
|
| 176 |
+
2
|
| 177 |
+
|
| 178 |
+
"""
|
| 179 |
+
return sum(map(pred, iterable))
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
def pad_none(iterable):
|
| 183 |
+
"""Returns the sequence of elements and then returns ``None`` indefinitely.
|
| 184 |
+
|
| 185 |
+
>>> take(5, pad_none(range(3)))
|
| 186 |
+
[0, 1, 2, None, None]
|
| 187 |
+
|
| 188 |
+
Useful for emulating the behavior of the built-in :func:`map` function.
|
| 189 |
+
|
| 190 |
+
See also :func:`padded`.
|
| 191 |
+
|
| 192 |
+
"""
|
| 193 |
+
return chain(iterable, repeat(None))
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
padnone = pad_none
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def ncycles(iterable, n):
|
| 200 |
+
"""Returns the sequence elements *n* times
|
| 201 |
+
|
| 202 |
+
>>> list(ncycles(["a", "b"], 3))
|
| 203 |
+
['a', 'b', 'a', 'b', 'a', 'b']
|
| 204 |
+
|
| 205 |
+
"""
|
| 206 |
+
return chain.from_iterable(repeat(tuple(iterable), n))
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def dotproduct(vec1, vec2):
|
| 210 |
+
"""Returns the dot product of the two iterables.
|
| 211 |
+
|
| 212 |
+
>>> dotproduct([10, 10], [20, 20])
|
| 213 |
+
400
|
| 214 |
+
|
| 215 |
+
"""
|
| 216 |
+
return sum(map(operator.mul, vec1, vec2))
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
def flatten(listOfLists):
|
| 220 |
+
"""Return an iterator flattening one level of nesting in a list of lists.
|
| 221 |
+
|
| 222 |
+
>>> list(flatten([[0, 1], [2, 3]]))
|
| 223 |
+
[0, 1, 2, 3]
|
| 224 |
+
|
| 225 |
+
See also :func:`collapse`, which can flatten multiple levels of nesting.
|
| 226 |
+
|
| 227 |
+
"""
|
| 228 |
+
return chain.from_iterable(listOfLists)
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def repeatfunc(func, times=None, *args):
|
| 232 |
+
"""Call *func* with *args* repeatedly, returning an iterable over the
|
| 233 |
+
results.
|
| 234 |
+
|
| 235 |
+
If *times* is specified, the iterable will terminate after that many
|
| 236 |
+
repetitions:
|
| 237 |
+
|
| 238 |
+
>>> from operator import add
|
| 239 |
+
>>> times = 4
|
| 240 |
+
>>> args = 3, 5
|
| 241 |
+
>>> list(repeatfunc(add, times, *args))
|
| 242 |
+
[8, 8, 8, 8]
|
| 243 |
+
|
| 244 |
+
If *times* is ``None`` the iterable will not terminate:
|
| 245 |
+
|
| 246 |
+
>>> from random import randrange
|
| 247 |
+
>>> times = None
|
| 248 |
+
>>> args = 1, 11
|
| 249 |
+
>>> take(6, repeatfunc(randrange, times, *args)) # doctest:+SKIP
|
| 250 |
+
[2, 4, 8, 1, 8, 4]
|
| 251 |
+
|
| 252 |
+
"""
|
| 253 |
+
if times is None:
|
| 254 |
+
return starmap(func, repeat(args))
|
| 255 |
+
return starmap(func, repeat(args, times))
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def _pairwise(iterable):
|
| 259 |
+
"""Returns an iterator of paired items, overlapping, from the original
|
| 260 |
+
|
| 261 |
+
>>> take(4, pairwise(count()))
|
| 262 |
+
[(0, 1), (1, 2), (2, 3), (3, 4)]
|
| 263 |
+
|
| 264 |
+
On Python 3.10 and above, this is an alias for :func:`itertools.pairwise`.
|
| 265 |
+
|
| 266 |
+
"""
|
| 267 |
+
a, b = tee(iterable)
|
| 268 |
+
next(b, None)
|
| 269 |
+
yield from zip(a, b)
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
try:
|
| 273 |
+
from itertools import pairwise as itertools_pairwise
|
| 274 |
+
except ImportError:
|
| 275 |
+
pairwise = _pairwise
|
| 276 |
+
else:
|
| 277 |
+
|
| 278 |
+
def pairwise(iterable):
|
| 279 |
+
yield from itertools_pairwise(iterable)
|
| 280 |
+
|
| 281 |
+
pairwise.__doc__ = _pairwise.__doc__
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
def grouper(iterable, n, fillvalue=None):
|
| 285 |
+
"""Collect data into fixed-length chunks or blocks.
|
| 286 |
+
|
| 287 |
+
>>> list(grouper('ABCDEFG', 3, 'x'))
|
| 288 |
+
[('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
|
| 289 |
+
|
| 290 |
+
"""
|
| 291 |
+
if isinstance(iterable, int):
|
| 292 |
+
warnings.warn(
|
| 293 |
+
"grouper expects iterable as first parameter", DeprecationWarning
|
| 294 |
+
)
|
| 295 |
+
n, iterable = iterable, n
|
| 296 |
+
args = [iter(iterable)] * n
|
| 297 |
+
return zip_longest(fillvalue=fillvalue, *args)
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
def roundrobin(*iterables):
|
| 301 |
+
"""Yields an item from each iterable, alternating between them.
|
| 302 |
+
|
| 303 |
+
>>> list(roundrobin('ABC', 'D', 'EF'))
|
| 304 |
+
['A', 'D', 'E', 'B', 'F', 'C']
|
| 305 |
+
|
| 306 |
+
This function produces the same output as :func:`interleave_longest`, but
|
| 307 |
+
may perform better for some inputs (in particular when the number of
|
| 308 |
+
iterables is small).
|
| 309 |
+
|
| 310 |
+
"""
|
| 311 |
+
# Recipe credited to George Sakkis
|
| 312 |
+
pending = len(iterables)
|
| 313 |
+
nexts = cycle(iter(it).__next__ for it in iterables)
|
| 314 |
+
while pending:
|
| 315 |
+
try:
|
| 316 |
+
for next in nexts:
|
| 317 |
+
yield next()
|
| 318 |
+
except StopIteration:
|
| 319 |
+
pending -= 1
|
| 320 |
+
nexts = cycle(islice(nexts, pending))
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
def partition(pred, iterable):
|
| 324 |
+
"""
|
| 325 |
+
Returns a 2-tuple of iterables derived from the input iterable.
|
| 326 |
+
The first yields the items that have ``pred(item) == False``.
|
| 327 |
+
The second yields the items that have ``pred(item) == True``.
|
| 328 |
+
|
| 329 |
+
>>> is_odd = lambda x: x % 2 != 0
|
| 330 |
+
>>> iterable = range(10)
|
| 331 |
+
>>> even_items, odd_items = partition(is_odd, iterable)
|
| 332 |
+
>>> list(even_items), list(odd_items)
|
| 333 |
+
([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
|
| 334 |
+
|
| 335 |
+
If *pred* is None, :func:`bool` is used.
|
| 336 |
+
|
| 337 |
+
>>> iterable = [0, 1, False, True, '', ' ']
|
| 338 |
+
>>> false_items, true_items = partition(None, iterable)
|
| 339 |
+
>>> list(false_items), list(true_items)
|
| 340 |
+
([0, False, ''], [1, True, ' '])
|
| 341 |
+
|
| 342 |
+
"""
|
| 343 |
+
if pred is None:
|
| 344 |
+
pred = bool
|
| 345 |
+
|
| 346 |
+
evaluations = ((pred(x), x) for x in iterable)
|
| 347 |
+
t1, t2 = tee(evaluations)
|
| 348 |
+
return (
|
| 349 |
+
(x for (cond, x) in t1 if not cond),
|
| 350 |
+
(x for (cond, x) in t2 if cond),
|
| 351 |
+
)
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
def powerset(iterable):
|
| 355 |
+
"""Yields all possible subsets of the iterable.
|
| 356 |
+
|
| 357 |
+
>>> list(powerset([1, 2, 3]))
|
| 358 |
+
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
|
| 359 |
+
|
| 360 |
+
:func:`powerset` will operate on iterables that aren't :class:`set`
|
| 361 |
+
instances, so repeated elements in the input will produce repeated elements
|
| 362 |
+
in the output. Use :func:`unique_everseen` on the input to avoid generating
|
| 363 |
+
duplicates:
|
| 364 |
+
|
| 365 |
+
>>> seq = [1, 1, 0]
|
| 366 |
+
>>> list(powerset(seq))
|
| 367 |
+
[(), (1,), (1,), (0,), (1, 1), (1, 0), (1, 0), (1, 1, 0)]
|
| 368 |
+
>>> from more_itertools import unique_everseen
|
| 369 |
+
>>> list(powerset(unique_everseen(seq)))
|
| 370 |
+
[(), (1,), (0,), (1, 0)]
|
| 371 |
+
|
| 372 |
+
"""
|
| 373 |
+
s = list(iterable)
|
| 374 |
+
return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def unique_everseen(iterable, key=None):
|
| 378 |
+
"""
|
| 379 |
+
Yield unique elements, preserving order.
|
| 380 |
+
|
| 381 |
+
>>> list(unique_everseen('AAAABBBCCDAABBB'))
|
| 382 |
+
['A', 'B', 'C', 'D']
|
| 383 |
+
>>> list(unique_everseen('ABBCcAD', str.lower))
|
| 384 |
+
['A', 'B', 'C', 'D']
|
| 385 |
+
|
| 386 |
+
Sequences with a mix of hashable and unhashable items can be used.
|
| 387 |
+
The function will be slower (i.e., `O(n^2)`) for unhashable items.
|
| 388 |
+
|
| 389 |
+
Remember that ``list`` objects are unhashable - you can use the *key*
|
| 390 |
+
parameter to transform the list to a tuple (which is hashable) to
|
| 391 |
+
avoid a slowdown.
|
| 392 |
+
|
| 393 |
+
>>> iterable = ([1, 2], [2, 3], [1, 2])
|
| 394 |
+
>>> list(unique_everseen(iterable)) # Slow
|
| 395 |
+
[[1, 2], [2, 3]]
|
| 396 |
+
>>> list(unique_everseen(iterable, key=tuple)) # Faster
|
| 397 |
+
[[1, 2], [2, 3]]
|
| 398 |
+
|
| 399 |
+
Similary, you may want to convert unhashable ``set`` objects with
|
| 400 |
+
``key=frozenset``. For ``dict`` objects,
|
| 401 |
+
``key=lambda x: frozenset(x.items())`` can be used.
|
| 402 |
+
|
| 403 |
+
"""
|
| 404 |
+
seenset = set()
|
| 405 |
+
seenset_add = seenset.add
|
| 406 |
+
seenlist = []
|
| 407 |
+
seenlist_add = seenlist.append
|
| 408 |
+
use_key = key is not None
|
| 409 |
+
|
| 410 |
+
for element in iterable:
|
| 411 |
+
k = key(element) if use_key else element
|
| 412 |
+
try:
|
| 413 |
+
if k not in seenset:
|
| 414 |
+
seenset_add(k)
|
| 415 |
+
yield element
|
| 416 |
+
except TypeError:
|
| 417 |
+
if k not in seenlist:
|
| 418 |
+
seenlist_add(k)
|
| 419 |
+
yield element
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
def unique_justseen(iterable, key=None):
|
| 423 |
+
"""Yields elements in order, ignoring serial duplicates
|
| 424 |
+
|
| 425 |
+
>>> list(unique_justseen('AAAABBBCCDAABBB'))
|
| 426 |
+
['A', 'B', 'C', 'D', 'A', 'B']
|
| 427 |
+
>>> list(unique_justseen('ABBCcAD', str.lower))
|
| 428 |
+
['A', 'B', 'C', 'A', 'D']
|
| 429 |
+
|
| 430 |
+
"""
|
| 431 |
+
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
def iter_except(func, exception, first=None):
|
| 435 |
+
"""Yields results from a function repeatedly until an exception is raised.
|
| 436 |
+
|
| 437 |
+
Converts a call-until-exception interface to an iterator interface.
|
| 438 |
+
Like ``iter(func, sentinel)``, but uses an exception instead of a sentinel
|
| 439 |
+
to end the loop.
|
| 440 |
+
|
| 441 |
+
>>> l = [0, 1, 2]
|
| 442 |
+
>>> list(iter_except(l.pop, IndexError))
|
| 443 |
+
[2, 1, 0]
|
| 444 |
+
|
| 445 |
+
"""
|
| 446 |
+
try:
|
| 447 |
+
if first is not None:
|
| 448 |
+
yield first()
|
| 449 |
+
while 1:
|
| 450 |
+
yield func()
|
| 451 |
+
except exception:
|
| 452 |
+
pass
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
def first_true(iterable, default=None, pred=None):
|
| 456 |
+
"""
|
| 457 |
+
Returns the first true value in the iterable.
|
| 458 |
+
|
| 459 |
+
If no true value is found, returns *default*
|
| 460 |
+
|
| 461 |
+
If *pred* is not None, returns the first item for which
|
| 462 |
+
``pred(item) == True`` .
|
| 463 |
+
|
| 464 |
+
>>> first_true(range(10))
|
| 465 |
+
1
|
| 466 |
+
>>> first_true(range(10), pred=lambda x: x > 5)
|
| 467 |
+
6
|
| 468 |
+
>>> first_true(range(10), default='missing', pred=lambda x: x > 9)
|
| 469 |
+
'missing'
|
| 470 |
+
|
| 471 |
+
"""
|
| 472 |
+
return next(filter(pred, iterable), default)
|
| 473 |
+
|
| 474 |
+
|
| 475 |
+
def random_product(*args, repeat=1):
|
| 476 |
+
"""Draw an item at random from each of the input iterables.
|
| 477 |
+
|
| 478 |
+
>>> random_product('abc', range(4), 'XYZ') # doctest:+SKIP
|
| 479 |
+
('c', 3, 'Z')
|
| 480 |
+
|
| 481 |
+
If *repeat* is provided as a keyword argument, that many items will be
|
| 482 |
+
drawn from each iterable.
|
| 483 |
+
|
| 484 |
+
>>> random_product('abcd', range(4), repeat=2) # doctest:+SKIP
|
| 485 |
+
('a', 2, 'd', 3)
|
| 486 |
+
|
| 487 |
+
This equivalent to taking a random selection from
|
| 488 |
+
``itertools.product(*args, **kwarg)``.
|
| 489 |
+
|
| 490 |
+
"""
|
| 491 |
+
pools = [tuple(pool) for pool in args] * repeat
|
| 492 |
+
return tuple(choice(pool) for pool in pools)
|
| 493 |
+
|
| 494 |
+
|
| 495 |
+
def random_permutation(iterable, r=None):
|
| 496 |
+
"""Return a random *r* length permutation of the elements in *iterable*.
|
| 497 |
+
|
| 498 |
+
If *r* is not specified or is ``None``, then *r* defaults to the length of
|
| 499 |
+
*iterable*.
|
| 500 |
+
|
| 501 |
+
>>> random_permutation(range(5)) # doctest:+SKIP
|
| 502 |
+
(3, 4, 0, 1, 2)
|
| 503 |
+
|
| 504 |
+
This equivalent to taking a random selection from
|
| 505 |
+
``itertools.permutations(iterable, r)``.
|
| 506 |
+
|
| 507 |
+
"""
|
| 508 |
+
pool = tuple(iterable)
|
| 509 |
+
r = len(pool) if r is None else r
|
| 510 |
+
return tuple(sample(pool, r))
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
def random_combination(iterable, r):
|
| 514 |
+
"""Return a random *r* length subsequence of the elements in *iterable*.
|
| 515 |
+
|
| 516 |
+
>>> random_combination(range(5), 3) # doctest:+SKIP
|
| 517 |
+
(2, 3, 4)
|
| 518 |
+
|
| 519 |
+
This equivalent to taking a random selection from
|
| 520 |
+
``itertools.combinations(iterable, r)``.
|
| 521 |
+
|
| 522 |
+
"""
|
| 523 |
+
pool = tuple(iterable)
|
| 524 |
+
n = len(pool)
|
| 525 |
+
indices = sorted(sample(range(n), r))
|
| 526 |
+
return tuple(pool[i] for i in indices)
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
def random_combination_with_replacement(iterable, r):
|
| 530 |
+
"""Return a random *r* length subsequence of elements in *iterable*,
|
| 531 |
+
allowing individual elements to be repeated.
|
| 532 |
+
|
| 533 |
+
>>> random_combination_with_replacement(range(3), 5) # doctest:+SKIP
|
| 534 |
+
(0, 0, 1, 2, 2)
|
| 535 |
+
|
| 536 |
+
This equivalent to taking a random selection from
|
| 537 |
+
``itertools.combinations_with_replacement(iterable, r)``.
|
| 538 |
+
|
| 539 |
+
"""
|
| 540 |
+
pool = tuple(iterable)
|
| 541 |
+
n = len(pool)
|
| 542 |
+
indices = sorted(randrange(n) for i in range(r))
|
| 543 |
+
return tuple(pool[i] for i in indices)
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def nth_combination(iterable, r, index):
|
| 547 |
+
"""Equivalent to ``list(combinations(iterable, r))[index]``.
|
| 548 |
+
|
| 549 |
+
The subsequences of *iterable* that are of length *r* can be ordered
|
| 550 |
+
lexicographically. :func:`nth_combination` computes the subsequence at
|
| 551 |
+
sort position *index* directly, without computing the previous
|
| 552 |
+
subsequences.
|
| 553 |
+
|
| 554 |
+
>>> nth_combination(range(5), 3, 5)
|
| 555 |
+
(0, 3, 4)
|
| 556 |
+
|
| 557 |
+
``ValueError`` will be raised If *r* is negative or greater than the length
|
| 558 |
+
of *iterable*.
|
| 559 |
+
``IndexError`` will be raised if the given *index* is invalid.
|
| 560 |
+
"""
|
| 561 |
+
pool = tuple(iterable)
|
| 562 |
+
n = len(pool)
|
| 563 |
+
if (r < 0) or (r > n):
|
| 564 |
+
raise ValueError
|
| 565 |
+
|
| 566 |
+
c = 1
|
| 567 |
+
k = min(r, n - r)
|
| 568 |
+
for i in range(1, k + 1):
|
| 569 |
+
c = c * (n - k + i) // i
|
| 570 |
+
|
| 571 |
+
if index < 0:
|
| 572 |
+
index += c
|
| 573 |
+
|
| 574 |
+
if (index < 0) or (index >= c):
|
| 575 |
+
raise IndexError
|
| 576 |
+
|
| 577 |
+
result = []
|
| 578 |
+
while r:
|
| 579 |
+
c, n, r = c * r // n, n - 1, r - 1
|
| 580 |
+
while index >= c:
|
| 581 |
+
index -= c
|
| 582 |
+
c, n = c * (n - r) // n, n - 1
|
| 583 |
+
result.append(pool[-1 - n])
|
| 584 |
+
|
| 585 |
+
return tuple(result)
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
def prepend(value, iterator):
|
| 589 |
+
"""Yield *value*, followed by the elements in *iterator*.
|
| 590 |
+
|
| 591 |
+
>>> value = '0'
|
| 592 |
+
>>> iterator = ['1', '2', '3']
|
| 593 |
+
>>> list(prepend(value, iterator))
|
| 594 |
+
['0', '1', '2', '3']
|
| 595 |
+
|
| 596 |
+
To prepend multiple values, see :func:`itertools.chain`
|
| 597 |
+
or :func:`value_chain`.
|
| 598 |
+
|
| 599 |
+
"""
|
| 600 |
+
return chain([value], iterator)
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
def convolve(signal, kernel):
|
| 604 |
+
"""Convolve the iterable *signal* with the iterable *kernel*.
|
| 605 |
+
|
| 606 |
+
>>> signal = (1, 2, 3, 4, 5)
|
| 607 |
+
>>> kernel = [3, 2, 1]
|
| 608 |
+
>>> list(convolve(signal, kernel))
|
| 609 |
+
[3, 8, 14, 20, 26, 14, 5]
|
| 610 |
+
|
| 611 |
+
Note: the input arguments are not interchangeable, as the *kernel*
|
| 612 |
+
is immediately consumed and stored.
|
| 613 |
+
|
| 614 |
+
"""
|
| 615 |
+
kernel = tuple(kernel)[::-1]
|
| 616 |
+
n = len(kernel)
|
| 617 |
+
window = deque([0], maxlen=n) * n
|
| 618 |
+
for x in chain(signal, repeat(0, n - 1)):
|
| 619 |
+
window.append(x)
|
| 620 |
+
yield sum(map(operator.mul, kernel, window))
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/ordered_set.py
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
An OrderedSet is a custom MutableSet that remembers its order, so that every
|
| 3 |
+
entry has an index that can be looked up.
|
| 4 |
+
|
| 5 |
+
Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger,
|
| 6 |
+
and released under the MIT license.
|
| 7 |
+
"""
|
| 8 |
+
import itertools as it
|
| 9 |
+
from collections import deque
|
| 10 |
+
|
| 11 |
+
try:
|
| 12 |
+
# Python 3
|
| 13 |
+
from collections.abc import MutableSet, Sequence
|
| 14 |
+
except ImportError:
|
| 15 |
+
# Python 2.7
|
| 16 |
+
from collections import MutableSet, Sequence
|
| 17 |
+
|
| 18 |
+
SLICE_ALL = slice(None)
|
| 19 |
+
__version__ = "3.1"
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def is_iterable(obj):
|
| 23 |
+
"""
|
| 24 |
+
Are we being asked to look up a list of things, instead of a single thing?
|
| 25 |
+
We check for the `__iter__` attribute so that this can cover types that
|
| 26 |
+
don't have to be known by this module, such as NumPy arrays.
|
| 27 |
+
|
| 28 |
+
Strings, however, should be considered as atomic values to look up, not
|
| 29 |
+
iterables. The same goes for tuples, since they are immutable and therefore
|
| 30 |
+
valid entries.
|
| 31 |
+
|
| 32 |
+
We don't need to check for the Python 2 `unicode` type, because it doesn't
|
| 33 |
+
have an `__iter__` attribute anyway.
|
| 34 |
+
"""
|
| 35 |
+
return (
|
| 36 |
+
hasattr(obj, "__iter__")
|
| 37 |
+
and not isinstance(obj, str)
|
| 38 |
+
and not isinstance(obj, tuple)
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class OrderedSet(MutableSet, Sequence):
|
| 43 |
+
"""
|
| 44 |
+
An OrderedSet is a custom MutableSet that remembers its order, so that
|
| 45 |
+
every entry has an index that can be looked up.
|
| 46 |
+
|
| 47 |
+
Example:
|
| 48 |
+
>>> OrderedSet([1, 1, 2, 3, 2])
|
| 49 |
+
OrderedSet([1, 2, 3])
|
| 50 |
+
"""
|
| 51 |
+
|
| 52 |
+
def __init__(self, iterable=None):
|
| 53 |
+
self.items = []
|
| 54 |
+
self.map = {}
|
| 55 |
+
if iterable is not None:
|
| 56 |
+
self |= iterable
|
| 57 |
+
|
| 58 |
+
def __len__(self):
|
| 59 |
+
"""
|
| 60 |
+
Returns the number of unique elements in the ordered set
|
| 61 |
+
|
| 62 |
+
Example:
|
| 63 |
+
>>> len(OrderedSet([]))
|
| 64 |
+
0
|
| 65 |
+
>>> len(OrderedSet([1, 2]))
|
| 66 |
+
2
|
| 67 |
+
"""
|
| 68 |
+
return len(self.items)
|
| 69 |
+
|
| 70 |
+
def __getitem__(self, index):
|
| 71 |
+
"""
|
| 72 |
+
Get the item at a given index.
|
| 73 |
+
|
| 74 |
+
If `index` is a slice, you will get back that slice of items, as a
|
| 75 |
+
new OrderedSet.
|
| 76 |
+
|
| 77 |
+
If `index` is a list or a similar iterable, you'll get a list of
|
| 78 |
+
items corresponding to those indices. This is similar to NumPy's
|
| 79 |
+
"fancy indexing". The result is not an OrderedSet because you may ask
|
| 80 |
+
for duplicate indices, and the number of elements returned should be
|
| 81 |
+
the number of elements asked for.
|
| 82 |
+
|
| 83 |
+
Example:
|
| 84 |
+
>>> oset = OrderedSet([1, 2, 3])
|
| 85 |
+
>>> oset[1]
|
| 86 |
+
2
|
| 87 |
+
"""
|
| 88 |
+
if isinstance(index, slice) and index == SLICE_ALL:
|
| 89 |
+
return self.copy()
|
| 90 |
+
elif is_iterable(index):
|
| 91 |
+
return [self.items[i] for i in index]
|
| 92 |
+
elif hasattr(index, "__index__") or isinstance(index, slice):
|
| 93 |
+
result = self.items[index]
|
| 94 |
+
if isinstance(result, list):
|
| 95 |
+
return self.__class__(result)
|
| 96 |
+
else:
|
| 97 |
+
return result
|
| 98 |
+
else:
|
| 99 |
+
raise TypeError("Don't know how to index an OrderedSet by %r" % index)
|
| 100 |
+
|
| 101 |
+
def copy(self):
|
| 102 |
+
"""
|
| 103 |
+
Return a shallow copy of this object.
|
| 104 |
+
|
| 105 |
+
Example:
|
| 106 |
+
>>> this = OrderedSet([1, 2, 3])
|
| 107 |
+
>>> other = this.copy()
|
| 108 |
+
>>> this == other
|
| 109 |
+
True
|
| 110 |
+
>>> this is other
|
| 111 |
+
False
|
| 112 |
+
"""
|
| 113 |
+
return self.__class__(self)
|
| 114 |
+
|
| 115 |
+
def __getstate__(self):
|
| 116 |
+
if len(self) == 0:
|
| 117 |
+
# The state can't be an empty list.
|
| 118 |
+
# We need to return a truthy value, or else __setstate__ won't be run.
|
| 119 |
+
#
|
| 120 |
+
# This could have been done more gracefully by always putting the state
|
| 121 |
+
# in a tuple, but this way is backwards- and forwards- compatible with
|
| 122 |
+
# previous versions of OrderedSet.
|
| 123 |
+
return (None,)
|
| 124 |
+
else:
|
| 125 |
+
return list(self)
|
| 126 |
+
|
| 127 |
+
def __setstate__(self, state):
|
| 128 |
+
if state == (None,):
|
| 129 |
+
self.__init__([])
|
| 130 |
+
else:
|
| 131 |
+
self.__init__(state)
|
| 132 |
+
|
| 133 |
+
def __contains__(self, key):
|
| 134 |
+
"""
|
| 135 |
+
Test if the item is in this ordered set
|
| 136 |
+
|
| 137 |
+
Example:
|
| 138 |
+
>>> 1 in OrderedSet([1, 3, 2])
|
| 139 |
+
True
|
| 140 |
+
>>> 5 in OrderedSet([1, 3, 2])
|
| 141 |
+
False
|
| 142 |
+
"""
|
| 143 |
+
return key in self.map
|
| 144 |
+
|
| 145 |
+
def add(self, key):
|
| 146 |
+
"""
|
| 147 |
+
Add `key` as an item to this OrderedSet, then return its index.
|
| 148 |
+
|
| 149 |
+
If `key` is already in the OrderedSet, return the index it already
|
| 150 |
+
had.
|
| 151 |
+
|
| 152 |
+
Example:
|
| 153 |
+
>>> oset = OrderedSet()
|
| 154 |
+
>>> oset.append(3)
|
| 155 |
+
0
|
| 156 |
+
>>> print(oset)
|
| 157 |
+
OrderedSet([3])
|
| 158 |
+
"""
|
| 159 |
+
if key not in self.map:
|
| 160 |
+
self.map[key] = len(self.items)
|
| 161 |
+
self.items.append(key)
|
| 162 |
+
return self.map[key]
|
| 163 |
+
|
| 164 |
+
append = add
|
| 165 |
+
|
| 166 |
+
def update(self, sequence):
|
| 167 |
+
"""
|
| 168 |
+
Update the set with the given iterable sequence, then return the index
|
| 169 |
+
of the last element inserted.
|
| 170 |
+
|
| 171 |
+
Example:
|
| 172 |
+
>>> oset = OrderedSet([1, 2, 3])
|
| 173 |
+
>>> oset.update([3, 1, 5, 1, 4])
|
| 174 |
+
4
|
| 175 |
+
>>> print(oset)
|
| 176 |
+
OrderedSet([1, 2, 3, 5, 4])
|
| 177 |
+
"""
|
| 178 |
+
item_index = None
|
| 179 |
+
try:
|
| 180 |
+
for item in sequence:
|
| 181 |
+
item_index = self.add(item)
|
| 182 |
+
except TypeError:
|
| 183 |
+
raise ValueError(
|
| 184 |
+
"Argument needs to be an iterable, got %s" % type(sequence)
|
| 185 |
+
)
|
| 186 |
+
return item_index
|
| 187 |
+
|
| 188 |
+
def index(self, key):
|
| 189 |
+
"""
|
| 190 |
+
Get the index of a given entry, raising an IndexError if it's not
|
| 191 |
+
present.
|
| 192 |
+
|
| 193 |
+
`key` can be an iterable of entries that is not a string, in which case
|
| 194 |
+
this returns a list of indices.
|
| 195 |
+
|
| 196 |
+
Example:
|
| 197 |
+
>>> oset = OrderedSet([1, 2, 3])
|
| 198 |
+
>>> oset.index(2)
|
| 199 |
+
1
|
| 200 |
+
"""
|
| 201 |
+
if is_iterable(key):
|
| 202 |
+
return [self.index(subkey) for subkey in key]
|
| 203 |
+
return self.map[key]
|
| 204 |
+
|
| 205 |
+
# Provide some compatibility with pd.Index
|
| 206 |
+
get_loc = index
|
| 207 |
+
get_indexer = index
|
| 208 |
+
|
| 209 |
+
def pop(self):
|
| 210 |
+
"""
|
| 211 |
+
Remove and return the last element from the set.
|
| 212 |
+
|
| 213 |
+
Raises KeyError if the set is empty.
|
| 214 |
+
|
| 215 |
+
Example:
|
| 216 |
+
>>> oset = OrderedSet([1, 2, 3])
|
| 217 |
+
>>> oset.pop()
|
| 218 |
+
3
|
| 219 |
+
"""
|
| 220 |
+
if not self.items:
|
| 221 |
+
raise KeyError("Set is empty")
|
| 222 |
+
|
| 223 |
+
elem = self.items[-1]
|
| 224 |
+
del self.items[-1]
|
| 225 |
+
del self.map[elem]
|
| 226 |
+
return elem
|
| 227 |
+
|
| 228 |
+
def discard(self, key):
|
| 229 |
+
"""
|
| 230 |
+
Remove an element. Do not raise an exception if absent.
|
| 231 |
+
|
| 232 |
+
The MutableSet mixin uses this to implement the .remove() method, which
|
| 233 |
+
*does* raise an error when asked to remove a non-existent item.
|
| 234 |
+
|
| 235 |
+
Example:
|
| 236 |
+
>>> oset = OrderedSet([1, 2, 3])
|
| 237 |
+
>>> oset.discard(2)
|
| 238 |
+
>>> print(oset)
|
| 239 |
+
OrderedSet([1, 3])
|
| 240 |
+
>>> oset.discard(2)
|
| 241 |
+
>>> print(oset)
|
| 242 |
+
OrderedSet([1, 3])
|
| 243 |
+
"""
|
| 244 |
+
if key in self:
|
| 245 |
+
i = self.map[key]
|
| 246 |
+
del self.items[i]
|
| 247 |
+
del self.map[key]
|
| 248 |
+
for k, v in self.map.items():
|
| 249 |
+
if v >= i:
|
| 250 |
+
self.map[k] = v - 1
|
| 251 |
+
|
| 252 |
+
def clear(self):
|
| 253 |
+
"""
|
| 254 |
+
Remove all items from this OrderedSet.
|
| 255 |
+
"""
|
| 256 |
+
del self.items[:]
|
| 257 |
+
self.map.clear()
|
| 258 |
+
|
| 259 |
+
def __iter__(self):
|
| 260 |
+
"""
|
| 261 |
+
Example:
|
| 262 |
+
>>> list(iter(OrderedSet([1, 2, 3])))
|
| 263 |
+
[1, 2, 3]
|
| 264 |
+
"""
|
| 265 |
+
return iter(self.items)
|
| 266 |
+
|
| 267 |
+
def __reversed__(self):
|
| 268 |
+
"""
|
| 269 |
+
Example:
|
| 270 |
+
>>> list(reversed(OrderedSet([1, 2, 3])))
|
| 271 |
+
[3, 2, 1]
|
| 272 |
+
"""
|
| 273 |
+
return reversed(self.items)
|
| 274 |
+
|
| 275 |
+
def __repr__(self):
|
| 276 |
+
if not self:
|
| 277 |
+
return "%s()" % (self.__class__.__name__,)
|
| 278 |
+
return "%s(%r)" % (self.__class__.__name__, list(self))
|
| 279 |
+
|
| 280 |
+
def __eq__(self, other):
|
| 281 |
+
"""
|
| 282 |
+
Returns true if the containers have the same items. If `other` is a
|
| 283 |
+
Sequence, then order is checked, otherwise it is ignored.
|
| 284 |
+
|
| 285 |
+
Example:
|
| 286 |
+
>>> oset = OrderedSet([1, 3, 2])
|
| 287 |
+
>>> oset == [1, 3, 2]
|
| 288 |
+
True
|
| 289 |
+
>>> oset == [1, 2, 3]
|
| 290 |
+
False
|
| 291 |
+
>>> oset == [2, 3]
|
| 292 |
+
False
|
| 293 |
+
>>> oset == OrderedSet([3, 2, 1])
|
| 294 |
+
False
|
| 295 |
+
"""
|
| 296 |
+
# In Python 2 deque is not a Sequence, so treat it as one for
|
| 297 |
+
# consistent behavior with Python 3.
|
| 298 |
+
if isinstance(other, (Sequence, deque)):
|
| 299 |
+
# Check that this OrderedSet contains the same elements, in the
|
| 300 |
+
# same order, as the other object.
|
| 301 |
+
return list(self) == list(other)
|
| 302 |
+
try:
|
| 303 |
+
other_as_set = set(other)
|
| 304 |
+
except TypeError:
|
| 305 |
+
# If `other` can't be converted into a set, it's not equal.
|
| 306 |
+
return False
|
| 307 |
+
else:
|
| 308 |
+
return set(self) == other_as_set
|
| 309 |
+
|
| 310 |
+
def union(self, *sets):
|
| 311 |
+
"""
|
| 312 |
+
Combines all unique items.
|
| 313 |
+
Each items order is defined by its first appearance.
|
| 314 |
+
|
| 315 |
+
Example:
|
| 316 |
+
>>> oset = OrderedSet.union(OrderedSet([3, 1, 4, 1, 5]), [1, 3], [2, 0])
|
| 317 |
+
>>> print(oset)
|
| 318 |
+
OrderedSet([3, 1, 4, 5, 2, 0])
|
| 319 |
+
>>> oset.union([8, 9])
|
| 320 |
+
OrderedSet([3, 1, 4, 5, 2, 0, 8, 9])
|
| 321 |
+
>>> oset | {10}
|
| 322 |
+
OrderedSet([3, 1, 4, 5, 2, 0, 10])
|
| 323 |
+
"""
|
| 324 |
+
cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet
|
| 325 |
+
containers = map(list, it.chain([self], sets))
|
| 326 |
+
items = it.chain.from_iterable(containers)
|
| 327 |
+
return cls(items)
|
| 328 |
+
|
| 329 |
+
def __and__(self, other):
|
| 330 |
+
# the parent implementation of this is backwards
|
| 331 |
+
return self.intersection(other)
|
| 332 |
+
|
| 333 |
+
def intersection(self, *sets):
|
| 334 |
+
"""
|
| 335 |
+
Returns elements in common between all sets. Order is defined only
|
| 336 |
+
by the first set.
|
| 337 |
+
|
| 338 |
+
Example:
|
| 339 |
+
>>> oset = OrderedSet.intersection(OrderedSet([0, 1, 2, 3]), [1, 2, 3])
|
| 340 |
+
>>> print(oset)
|
| 341 |
+
OrderedSet([1, 2, 3])
|
| 342 |
+
>>> oset.intersection([2, 4, 5], [1, 2, 3, 4])
|
| 343 |
+
OrderedSet([2])
|
| 344 |
+
>>> oset.intersection()
|
| 345 |
+
OrderedSet([1, 2, 3])
|
| 346 |
+
"""
|
| 347 |
+
cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet
|
| 348 |
+
if sets:
|
| 349 |
+
common = set.intersection(*map(set, sets))
|
| 350 |
+
items = (item for item in self if item in common)
|
| 351 |
+
else:
|
| 352 |
+
items = self
|
| 353 |
+
return cls(items)
|
| 354 |
+
|
| 355 |
+
def difference(self, *sets):
|
| 356 |
+
"""
|
| 357 |
+
Returns all elements that are in this set but not the others.
|
| 358 |
+
|
| 359 |
+
Example:
|
| 360 |
+
>>> OrderedSet([1, 2, 3]).difference(OrderedSet([2]))
|
| 361 |
+
OrderedSet([1, 3])
|
| 362 |
+
>>> OrderedSet([1, 2, 3]).difference(OrderedSet([2]), OrderedSet([3]))
|
| 363 |
+
OrderedSet([1])
|
| 364 |
+
>>> OrderedSet([1, 2, 3]) - OrderedSet([2])
|
| 365 |
+
OrderedSet([1, 3])
|
| 366 |
+
>>> OrderedSet([1, 2, 3]).difference()
|
| 367 |
+
OrderedSet([1, 2, 3])
|
| 368 |
+
"""
|
| 369 |
+
cls = self.__class__
|
| 370 |
+
if sets:
|
| 371 |
+
other = set.union(*map(set, sets))
|
| 372 |
+
items = (item for item in self if item not in other)
|
| 373 |
+
else:
|
| 374 |
+
items = self
|
| 375 |
+
return cls(items)
|
| 376 |
+
|
| 377 |
+
def issubset(self, other):
|
| 378 |
+
"""
|
| 379 |
+
Report whether another set contains this set.
|
| 380 |
+
|
| 381 |
+
Example:
|
| 382 |
+
>>> OrderedSet([1, 2, 3]).issubset({1, 2})
|
| 383 |
+
False
|
| 384 |
+
>>> OrderedSet([1, 2, 3]).issubset({1, 2, 3, 4})
|
| 385 |
+
True
|
| 386 |
+
>>> OrderedSet([1, 2, 3]).issubset({1, 4, 3, 5})
|
| 387 |
+
False
|
| 388 |
+
"""
|
| 389 |
+
if len(self) > len(other): # Fast check for obvious cases
|
| 390 |
+
return False
|
| 391 |
+
return all(item in other for item in self)
|
| 392 |
+
|
| 393 |
+
def issuperset(self, other):
|
| 394 |
+
"""
|
| 395 |
+
Report whether this set contains another set.
|
| 396 |
+
|
| 397 |
+
Example:
|
| 398 |
+
>>> OrderedSet([1, 2]).issuperset([1, 2, 3])
|
| 399 |
+
False
|
| 400 |
+
>>> OrderedSet([1, 2, 3, 4]).issuperset({1, 2, 3})
|
| 401 |
+
True
|
| 402 |
+
>>> OrderedSet([1, 4, 3, 5]).issuperset({1, 2, 3})
|
| 403 |
+
False
|
| 404 |
+
"""
|
| 405 |
+
if len(self) < len(other): # Fast check for obvious cases
|
| 406 |
+
return False
|
| 407 |
+
return all(item in self for item in other)
|
| 408 |
+
|
| 409 |
+
def symmetric_difference(self, other):
|
| 410 |
+
"""
|
| 411 |
+
Return the symmetric difference of two OrderedSets as a new set.
|
| 412 |
+
That is, the new set will contain all elements that are in exactly
|
| 413 |
+
one of the sets.
|
| 414 |
+
|
| 415 |
+
Their order will be preserved, with elements from `self` preceding
|
| 416 |
+
elements from `other`.
|
| 417 |
+
|
| 418 |
+
Example:
|
| 419 |
+
>>> this = OrderedSet([1, 4, 3, 5, 7])
|
| 420 |
+
>>> other = OrderedSet([9, 7, 1, 3, 2])
|
| 421 |
+
>>> this.symmetric_difference(other)
|
| 422 |
+
OrderedSet([4, 5, 9, 2])
|
| 423 |
+
"""
|
| 424 |
+
cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet
|
| 425 |
+
diff1 = cls(self).difference(other)
|
| 426 |
+
diff2 = cls(other).difference(self)
|
| 427 |
+
return diff1.union(diff2)
|
| 428 |
+
|
| 429 |
+
def _update_items(self, items):
|
| 430 |
+
"""
|
| 431 |
+
Replace the 'items' list of this OrderedSet with a new one, updating
|
| 432 |
+
self.map accordingly.
|
| 433 |
+
"""
|
| 434 |
+
self.items = items
|
| 435 |
+
self.map = {item: idx for (idx, item) in enumerate(items)}
|
| 436 |
+
|
| 437 |
+
def difference_update(self, *sets):
|
| 438 |
+
"""
|
| 439 |
+
Update this OrderedSet to remove items from one or more other sets.
|
| 440 |
+
|
| 441 |
+
Example:
|
| 442 |
+
>>> this = OrderedSet([1, 2, 3])
|
| 443 |
+
>>> this.difference_update(OrderedSet([2, 4]))
|
| 444 |
+
>>> print(this)
|
| 445 |
+
OrderedSet([1, 3])
|
| 446 |
+
|
| 447 |
+
>>> this = OrderedSet([1, 2, 3, 4, 5])
|
| 448 |
+
>>> this.difference_update(OrderedSet([2, 4]), OrderedSet([1, 4, 6]))
|
| 449 |
+
>>> print(this)
|
| 450 |
+
OrderedSet([3, 5])
|
| 451 |
+
"""
|
| 452 |
+
items_to_remove = set()
|
| 453 |
+
for other in sets:
|
| 454 |
+
items_to_remove |= set(other)
|
| 455 |
+
self._update_items([item for item in self.items if item not in items_to_remove])
|
| 456 |
+
|
| 457 |
+
def intersection_update(self, other):
|
| 458 |
+
"""
|
| 459 |
+
Update this OrderedSet to keep only items in another set, preserving
|
| 460 |
+
their order in this set.
|
| 461 |
+
|
| 462 |
+
Example:
|
| 463 |
+
>>> this = OrderedSet([1, 4, 3, 5, 7])
|
| 464 |
+
>>> other = OrderedSet([9, 7, 1, 3, 2])
|
| 465 |
+
>>> this.intersection_update(other)
|
| 466 |
+
>>> print(this)
|
| 467 |
+
OrderedSet([1, 3, 7])
|
| 468 |
+
"""
|
| 469 |
+
other = set(other)
|
| 470 |
+
self._update_items([item for item in self.items if item in other])
|
| 471 |
+
|
| 472 |
+
def symmetric_difference_update(self, other):
|
| 473 |
+
"""
|
| 474 |
+
Update this OrderedSet to remove items from another set, then
|
| 475 |
+
add items from the other set that were not present in this set.
|
| 476 |
+
|
| 477 |
+
Example:
|
| 478 |
+
>>> this = OrderedSet([1, 4, 3, 5, 7])
|
| 479 |
+
>>> other = OrderedSet([9, 7, 1, 3, 2])
|
| 480 |
+
>>> this.symmetric_difference_update(other)
|
| 481 |
+
>>> print(this)
|
| 482 |
+
OrderedSet([4, 5, 9, 2])
|
| 483 |
+
"""
|
| 484 |
+
items_to_add = [item for item in other if item not in self]
|
| 485 |
+
items_to_remove = set(other)
|
| 486 |
+
self._update_items(
|
| 487 |
+
[item for item in self.items if item not in items_to_remove] + items_to_add
|
| 488 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/__about__.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
__all__ = [
|
| 7 |
+
"__title__",
|
| 8 |
+
"__summary__",
|
| 9 |
+
"__uri__",
|
| 10 |
+
"__version__",
|
| 11 |
+
"__author__",
|
| 12 |
+
"__email__",
|
| 13 |
+
"__license__",
|
| 14 |
+
"__copyright__",
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
__title__ = "packaging"
|
| 18 |
+
__summary__ = "Core utilities for Python packages"
|
| 19 |
+
__uri__ = "https://github.com/pypa/packaging"
|
| 20 |
+
|
| 21 |
+
__version__ = "20.4"
|
| 22 |
+
|
| 23 |
+
__author__ = "Donald Stufft and individual contributors"
|
| 24 |
+
__email__ = "donald@stufft.io"
|
| 25 |
+
|
| 26 |
+
__license__ = "BSD-2-Clause or Apache-2.0"
|
| 27 |
+
__copyright__ = "Copyright 2014-2019 %s" % __author__
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/__init__.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
from .__about__ import (
|
| 7 |
+
__author__,
|
| 8 |
+
__copyright__,
|
| 9 |
+
__email__,
|
| 10 |
+
__license__,
|
| 11 |
+
__summary__,
|
| 12 |
+
__title__,
|
| 13 |
+
__uri__,
|
| 14 |
+
__version__,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
__all__ = [
|
| 18 |
+
"__title__",
|
| 19 |
+
"__summary__",
|
| 20 |
+
"__uri__",
|
| 21 |
+
"__version__",
|
| 22 |
+
"__author__",
|
| 23 |
+
"__email__",
|
| 24 |
+
"__license__",
|
| 25 |
+
"__copyright__",
|
| 26 |
+
]
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_compat.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
from ._typing import TYPE_CHECKING
|
| 9 |
+
|
| 10 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 11 |
+
from typing import Any, Dict, Tuple, Type
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
PY2 = sys.version_info[0] == 2
|
| 15 |
+
PY3 = sys.version_info[0] == 3
|
| 16 |
+
|
| 17 |
+
# flake8: noqa
|
| 18 |
+
|
| 19 |
+
if PY3:
|
| 20 |
+
string_types = (str,)
|
| 21 |
+
else:
|
| 22 |
+
string_types = (basestring,)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def with_metaclass(meta, *bases):
|
| 26 |
+
# type: (Type[Any], Tuple[Type[Any], ...]) -> Any
|
| 27 |
+
"""
|
| 28 |
+
Create a base class with a metaclass.
|
| 29 |
+
"""
|
| 30 |
+
# This requires a bit of explanation: the basic idea is to make a dummy
|
| 31 |
+
# metaclass for one level of class instantiation that replaces itself with
|
| 32 |
+
# the actual metaclass.
|
| 33 |
+
class metaclass(meta): # type: ignore
|
| 34 |
+
def __new__(cls, name, this_bases, d):
|
| 35 |
+
# type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
|
| 36 |
+
return meta(name, bases, d)
|
| 37 |
+
|
| 38 |
+
return type.__new__(metaclass, "temporary_class", (), {})
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_structures.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class InfinityType(object):
|
| 8 |
+
def __repr__(self):
|
| 9 |
+
# type: () -> str
|
| 10 |
+
return "Infinity"
|
| 11 |
+
|
| 12 |
+
def __hash__(self):
|
| 13 |
+
# type: () -> int
|
| 14 |
+
return hash(repr(self))
|
| 15 |
+
|
| 16 |
+
def __lt__(self, other):
|
| 17 |
+
# type: (object) -> bool
|
| 18 |
+
return False
|
| 19 |
+
|
| 20 |
+
def __le__(self, other):
|
| 21 |
+
# type: (object) -> bool
|
| 22 |
+
return False
|
| 23 |
+
|
| 24 |
+
def __eq__(self, other):
|
| 25 |
+
# type: (object) -> bool
|
| 26 |
+
return isinstance(other, self.__class__)
|
| 27 |
+
|
| 28 |
+
def __ne__(self, other):
|
| 29 |
+
# type: (object) -> bool
|
| 30 |
+
return not isinstance(other, self.__class__)
|
| 31 |
+
|
| 32 |
+
def __gt__(self, other):
|
| 33 |
+
# type: (object) -> bool
|
| 34 |
+
return True
|
| 35 |
+
|
| 36 |
+
def __ge__(self, other):
|
| 37 |
+
# type: (object) -> bool
|
| 38 |
+
return True
|
| 39 |
+
|
| 40 |
+
def __neg__(self):
|
| 41 |
+
# type: (object) -> NegativeInfinityType
|
| 42 |
+
return NegativeInfinity
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
Infinity = InfinityType()
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class NegativeInfinityType(object):
|
| 49 |
+
def __repr__(self):
|
| 50 |
+
# type: () -> str
|
| 51 |
+
return "-Infinity"
|
| 52 |
+
|
| 53 |
+
def __hash__(self):
|
| 54 |
+
# type: () -> int
|
| 55 |
+
return hash(repr(self))
|
| 56 |
+
|
| 57 |
+
def __lt__(self, other):
|
| 58 |
+
# type: (object) -> bool
|
| 59 |
+
return True
|
| 60 |
+
|
| 61 |
+
def __le__(self, other):
|
| 62 |
+
# type: (object) -> bool
|
| 63 |
+
return True
|
| 64 |
+
|
| 65 |
+
def __eq__(self, other):
|
| 66 |
+
# type: (object) -> bool
|
| 67 |
+
return isinstance(other, self.__class__)
|
| 68 |
+
|
| 69 |
+
def __ne__(self, other):
|
| 70 |
+
# type: (object) -> bool
|
| 71 |
+
return not isinstance(other, self.__class__)
|
| 72 |
+
|
| 73 |
+
def __gt__(self, other):
|
| 74 |
+
# type: (object) -> bool
|
| 75 |
+
return False
|
| 76 |
+
|
| 77 |
+
def __ge__(self, other):
|
| 78 |
+
# type: (object) -> bool
|
| 79 |
+
return False
|
| 80 |
+
|
| 81 |
+
def __neg__(self):
|
| 82 |
+
# type: (object) -> InfinityType
|
| 83 |
+
return Infinity
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
NegativeInfinity = NegativeInfinityType()
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/_typing.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""For neatly implementing static typing in packaging.
|
| 2 |
+
|
| 3 |
+
`mypy` - the static type analysis tool we use - uses the `typing` module, which
|
| 4 |
+
provides core functionality fundamental to mypy's functioning.
|
| 5 |
+
|
| 6 |
+
Generally, `typing` would be imported at runtime and used in that fashion -
|
| 7 |
+
it acts as a no-op at runtime and does not have any run-time overhead by
|
| 8 |
+
design.
|
| 9 |
+
|
| 10 |
+
As it turns out, `typing` is not vendorable - it uses separate sources for
|
| 11 |
+
Python 2/Python 3. Thus, this codebase can not expect it to be present.
|
| 12 |
+
To work around this, mypy allows the typing import to be behind a False-y
|
| 13 |
+
optional to prevent it from running at runtime and type-comments can be used
|
| 14 |
+
to remove the need for the types to be accessible directly during runtime.
|
| 15 |
+
|
| 16 |
+
This module provides the False-y guard in a nicely named fashion so that a
|
| 17 |
+
curious maintainer can reach here to read this.
|
| 18 |
+
|
| 19 |
+
In packaging, all static-typing related imports should be guarded as follows:
|
| 20 |
+
|
| 21 |
+
from packaging._typing import TYPE_CHECKING
|
| 22 |
+
|
| 23 |
+
if TYPE_CHECKING:
|
| 24 |
+
from typing import ...
|
| 25 |
+
|
| 26 |
+
Ref: https://github.com/python/mypy/issues/3216
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
__all__ = ["TYPE_CHECKING", "cast"]
|
| 30 |
+
|
| 31 |
+
# The TYPE_CHECKING constant defined by the typing module is False at runtime
|
| 32 |
+
# but True while type checking.
|
| 33 |
+
if False: # pragma: no cover
|
| 34 |
+
from typing import TYPE_CHECKING
|
| 35 |
+
else:
|
| 36 |
+
TYPE_CHECKING = False
|
| 37 |
+
|
| 38 |
+
# typing's cast syntax requires calling typing.cast at runtime, but we don't
|
| 39 |
+
# want to import typing at runtime. Here, we inform the type checkers that
|
| 40 |
+
# we're importing `typing.cast` as `cast` and re-implement typing.cast's
|
| 41 |
+
# runtime behavior in a block that is ignored by type checkers.
|
| 42 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 43 |
+
# not executed at runtime
|
| 44 |
+
from typing import cast
|
| 45 |
+
else:
|
| 46 |
+
# executed at runtime
|
| 47 |
+
def cast(type_, value): # noqa
|
| 48 |
+
return value
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/markers.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
import operator
|
| 7 |
+
import os
|
| 8 |
+
import platform
|
| 9 |
+
import sys
|
| 10 |
+
|
| 11 |
+
from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd
|
| 12 |
+
from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString
|
| 13 |
+
from setuptools.extern.pyparsing import Literal as L # noqa
|
| 14 |
+
|
| 15 |
+
from ._compat import string_types
|
| 16 |
+
from ._typing import TYPE_CHECKING
|
| 17 |
+
from .specifiers import Specifier, InvalidSpecifier
|
| 18 |
+
|
| 19 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 20 |
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
| 21 |
+
|
| 22 |
+
Operator = Callable[[str, str], bool]
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
__all__ = [
|
| 26 |
+
"InvalidMarker",
|
| 27 |
+
"UndefinedComparison",
|
| 28 |
+
"UndefinedEnvironmentName",
|
| 29 |
+
"Marker",
|
| 30 |
+
"default_environment",
|
| 31 |
+
]
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class InvalidMarker(ValueError):
|
| 35 |
+
"""
|
| 36 |
+
An invalid marker was found, users should refer to PEP 508.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class UndefinedComparison(ValueError):
|
| 41 |
+
"""
|
| 42 |
+
An invalid operation was attempted on a value that doesn't support it.
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class UndefinedEnvironmentName(ValueError):
|
| 47 |
+
"""
|
| 48 |
+
A name was attempted to be used that does not exist inside of the
|
| 49 |
+
environment.
|
| 50 |
+
"""
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class Node(object):
|
| 54 |
+
def __init__(self, value):
|
| 55 |
+
# type: (Any) -> None
|
| 56 |
+
self.value = value
|
| 57 |
+
|
| 58 |
+
def __str__(self):
|
| 59 |
+
# type: () -> str
|
| 60 |
+
return str(self.value)
|
| 61 |
+
|
| 62 |
+
def __repr__(self):
|
| 63 |
+
# type: () -> str
|
| 64 |
+
return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
|
| 65 |
+
|
| 66 |
+
def serialize(self):
|
| 67 |
+
# type: () -> str
|
| 68 |
+
raise NotImplementedError
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class Variable(Node):
|
| 72 |
+
def serialize(self):
|
| 73 |
+
# type: () -> str
|
| 74 |
+
return str(self)
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class Value(Node):
|
| 78 |
+
def serialize(self):
|
| 79 |
+
# type: () -> str
|
| 80 |
+
return '"{0}"'.format(self)
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class Op(Node):
|
| 84 |
+
def serialize(self):
|
| 85 |
+
# type: () -> str
|
| 86 |
+
return str(self)
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
VARIABLE = (
|
| 90 |
+
L("implementation_version")
|
| 91 |
+
| L("platform_python_implementation")
|
| 92 |
+
| L("implementation_name")
|
| 93 |
+
| L("python_full_version")
|
| 94 |
+
| L("platform_release")
|
| 95 |
+
| L("platform_version")
|
| 96 |
+
| L("platform_machine")
|
| 97 |
+
| L("platform_system")
|
| 98 |
+
| L("python_version")
|
| 99 |
+
| L("sys_platform")
|
| 100 |
+
| L("os_name")
|
| 101 |
+
| L("os.name") # PEP-345
|
| 102 |
+
| L("sys.platform") # PEP-345
|
| 103 |
+
| L("platform.version") # PEP-345
|
| 104 |
+
| L("platform.machine") # PEP-345
|
| 105 |
+
| L("platform.python_implementation") # PEP-345
|
| 106 |
+
| L("python_implementation") # undocumented setuptools legacy
|
| 107 |
+
| L("extra") # PEP-508
|
| 108 |
+
)
|
| 109 |
+
ALIASES = {
|
| 110 |
+
"os.name": "os_name",
|
| 111 |
+
"sys.platform": "sys_platform",
|
| 112 |
+
"platform.version": "platform_version",
|
| 113 |
+
"platform.machine": "platform_machine",
|
| 114 |
+
"platform.python_implementation": "platform_python_implementation",
|
| 115 |
+
"python_implementation": "platform_python_implementation",
|
| 116 |
+
}
|
| 117 |
+
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
|
| 118 |
+
|
| 119 |
+
VERSION_CMP = (
|
| 120 |
+
L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
MARKER_OP = VERSION_CMP | L("not in") | L("in")
|
| 124 |
+
MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
|
| 125 |
+
|
| 126 |
+
MARKER_VALUE = QuotedString("'") | QuotedString('"')
|
| 127 |
+
MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
|
| 128 |
+
|
| 129 |
+
BOOLOP = L("and") | L("or")
|
| 130 |
+
|
| 131 |
+
MARKER_VAR = VARIABLE | MARKER_VALUE
|
| 132 |
+
|
| 133 |
+
MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
|
| 134 |
+
MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
|
| 135 |
+
|
| 136 |
+
LPAREN = L("(").suppress()
|
| 137 |
+
RPAREN = L(")").suppress()
|
| 138 |
+
|
| 139 |
+
MARKER_EXPR = Forward()
|
| 140 |
+
MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
|
| 141 |
+
MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR)
|
| 142 |
+
|
| 143 |
+
MARKER = stringStart + MARKER_EXPR + stringEnd
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def _coerce_parse_result(results):
|
| 147 |
+
# type: (Union[ParseResults, List[Any]]) -> List[Any]
|
| 148 |
+
if isinstance(results, ParseResults):
|
| 149 |
+
return [_coerce_parse_result(i) for i in results]
|
| 150 |
+
else:
|
| 151 |
+
return results
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
def _format_marker(marker, first=True):
|
| 155 |
+
# type: (Union[List[str], Tuple[Node, ...], str], Optional[bool]) -> str
|
| 156 |
+
|
| 157 |
+
assert isinstance(marker, (list, tuple, string_types))
|
| 158 |
+
|
| 159 |
+
# Sometimes we have a structure like [[...]] which is a single item list
|
| 160 |
+
# where the single item is itself it's own list. In that case we want skip
|
| 161 |
+
# the rest of this function so that we don't get extraneous () on the
|
| 162 |
+
# outside.
|
| 163 |
+
if (
|
| 164 |
+
isinstance(marker, list)
|
| 165 |
+
and len(marker) == 1
|
| 166 |
+
and isinstance(marker[0], (list, tuple))
|
| 167 |
+
):
|
| 168 |
+
return _format_marker(marker[0])
|
| 169 |
+
|
| 170 |
+
if isinstance(marker, list):
|
| 171 |
+
inner = (_format_marker(m, first=False) for m in marker)
|
| 172 |
+
if first:
|
| 173 |
+
return " ".join(inner)
|
| 174 |
+
else:
|
| 175 |
+
return "(" + " ".join(inner) + ")"
|
| 176 |
+
elif isinstance(marker, tuple):
|
| 177 |
+
return " ".join([m.serialize() for m in marker])
|
| 178 |
+
else:
|
| 179 |
+
return marker
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
_operators = {
|
| 183 |
+
"in": lambda lhs, rhs: lhs in rhs,
|
| 184 |
+
"not in": lambda lhs, rhs: lhs not in rhs,
|
| 185 |
+
"<": operator.lt,
|
| 186 |
+
"<=": operator.le,
|
| 187 |
+
"==": operator.eq,
|
| 188 |
+
"!=": operator.ne,
|
| 189 |
+
">=": operator.ge,
|
| 190 |
+
">": operator.gt,
|
| 191 |
+
} # type: Dict[str, Operator]
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def _eval_op(lhs, op, rhs):
|
| 195 |
+
# type: (str, Op, str) -> bool
|
| 196 |
+
try:
|
| 197 |
+
spec = Specifier("".join([op.serialize(), rhs]))
|
| 198 |
+
except InvalidSpecifier:
|
| 199 |
+
pass
|
| 200 |
+
else:
|
| 201 |
+
return spec.contains(lhs)
|
| 202 |
+
|
| 203 |
+
oper = _operators.get(op.serialize()) # type: Optional[Operator]
|
| 204 |
+
if oper is None:
|
| 205 |
+
raise UndefinedComparison(
|
| 206 |
+
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
|
| 207 |
+
)
|
| 208 |
+
|
| 209 |
+
return oper(lhs, rhs)
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
class Undefined(object):
|
| 213 |
+
pass
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
_undefined = Undefined()
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
def _get_env(environment, name):
|
| 220 |
+
# type: (Dict[str, str], str) -> str
|
| 221 |
+
value = environment.get(name, _undefined) # type: Union[str, Undefined]
|
| 222 |
+
|
| 223 |
+
if isinstance(value, Undefined):
|
| 224 |
+
raise UndefinedEnvironmentName(
|
| 225 |
+
"{0!r} does not exist in evaluation environment.".format(name)
|
| 226 |
+
)
|
| 227 |
+
|
| 228 |
+
return value
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def _evaluate_markers(markers, environment):
|
| 232 |
+
# type: (List[Any], Dict[str, str]) -> bool
|
| 233 |
+
groups = [[]] # type: List[List[bool]]
|
| 234 |
+
|
| 235 |
+
for marker in markers:
|
| 236 |
+
assert isinstance(marker, (list, tuple, string_types))
|
| 237 |
+
|
| 238 |
+
if isinstance(marker, list):
|
| 239 |
+
groups[-1].append(_evaluate_markers(marker, environment))
|
| 240 |
+
elif isinstance(marker, tuple):
|
| 241 |
+
lhs, op, rhs = marker
|
| 242 |
+
|
| 243 |
+
if isinstance(lhs, Variable):
|
| 244 |
+
lhs_value = _get_env(environment, lhs.value)
|
| 245 |
+
rhs_value = rhs.value
|
| 246 |
+
else:
|
| 247 |
+
lhs_value = lhs.value
|
| 248 |
+
rhs_value = _get_env(environment, rhs.value)
|
| 249 |
+
|
| 250 |
+
groups[-1].append(_eval_op(lhs_value, op, rhs_value))
|
| 251 |
+
else:
|
| 252 |
+
assert marker in ["and", "or"]
|
| 253 |
+
if marker == "or":
|
| 254 |
+
groups.append([])
|
| 255 |
+
|
| 256 |
+
return any(all(item) for item in groups)
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
def format_full_version(info):
|
| 260 |
+
# type: (sys._version_info) -> str
|
| 261 |
+
version = "{0.major}.{0.minor}.{0.micro}".format(info)
|
| 262 |
+
kind = info.releaselevel
|
| 263 |
+
if kind != "final":
|
| 264 |
+
version += kind[0] + str(info.serial)
|
| 265 |
+
return version
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
def default_environment():
|
| 269 |
+
# type: () -> Dict[str, str]
|
| 270 |
+
if hasattr(sys, "implementation"):
|
| 271 |
+
# Ignoring the `sys.implementation` reference for type checking due to
|
| 272 |
+
# mypy not liking that the attribute doesn't exist in Python 2.7 when
|
| 273 |
+
# run with the `--py27` flag.
|
| 274 |
+
iver = format_full_version(sys.implementation.version) # type: ignore
|
| 275 |
+
implementation_name = sys.implementation.name # type: ignore
|
| 276 |
+
else:
|
| 277 |
+
iver = "0"
|
| 278 |
+
implementation_name = ""
|
| 279 |
+
|
| 280 |
+
return {
|
| 281 |
+
"implementation_name": implementation_name,
|
| 282 |
+
"implementation_version": iver,
|
| 283 |
+
"os_name": os.name,
|
| 284 |
+
"platform_machine": platform.machine(),
|
| 285 |
+
"platform_release": platform.release(),
|
| 286 |
+
"platform_system": platform.system(),
|
| 287 |
+
"platform_version": platform.version(),
|
| 288 |
+
"python_full_version": platform.python_version(),
|
| 289 |
+
"platform_python_implementation": platform.python_implementation(),
|
| 290 |
+
"python_version": ".".join(platform.python_version_tuple()[:2]),
|
| 291 |
+
"sys_platform": sys.platform,
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
class Marker(object):
|
| 296 |
+
def __init__(self, marker):
|
| 297 |
+
# type: (str) -> None
|
| 298 |
+
try:
|
| 299 |
+
self._markers = _coerce_parse_result(MARKER.parseString(marker))
|
| 300 |
+
except ParseException as e:
|
| 301 |
+
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
|
| 302 |
+
marker, marker[e.loc : e.loc + 8]
|
| 303 |
+
)
|
| 304 |
+
raise InvalidMarker(err_str)
|
| 305 |
+
|
| 306 |
+
def __str__(self):
|
| 307 |
+
# type: () -> str
|
| 308 |
+
return _format_marker(self._markers)
|
| 309 |
+
|
| 310 |
+
def __repr__(self):
|
| 311 |
+
# type: () -> str
|
| 312 |
+
return "<Marker({0!r})>".format(str(self))
|
| 313 |
+
|
| 314 |
+
def evaluate(self, environment=None):
|
| 315 |
+
# type: (Optional[Dict[str, str]]) -> bool
|
| 316 |
+
"""Evaluate a marker.
|
| 317 |
+
|
| 318 |
+
Return the boolean from evaluating the given marker against the
|
| 319 |
+
environment. environment is an optional argument to override all or
|
| 320 |
+
part of the determined environment.
|
| 321 |
+
|
| 322 |
+
The environment is determined from the current Python process.
|
| 323 |
+
"""
|
| 324 |
+
current_environment = default_environment()
|
| 325 |
+
if environment is not None:
|
| 326 |
+
current_environment.update(environment)
|
| 327 |
+
|
| 328 |
+
return _evaluate_markers(self._markers, current_environment)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/requirements.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
import string
|
| 7 |
+
import re
|
| 8 |
+
|
| 9 |
+
from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
|
| 10 |
+
from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
|
| 11 |
+
from setuptools.extern.pyparsing import Literal as L # noqa
|
| 12 |
+
from urllib import parse as urlparse
|
| 13 |
+
|
| 14 |
+
from ._typing import TYPE_CHECKING
|
| 15 |
+
from .markers import MARKER_EXPR, Marker
|
| 16 |
+
from .specifiers import LegacySpecifier, Specifier, SpecifierSet
|
| 17 |
+
|
| 18 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 19 |
+
from typing import List
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class InvalidRequirement(ValueError):
|
| 23 |
+
"""
|
| 24 |
+
An invalid requirement was found, users should refer to PEP 508.
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
ALPHANUM = Word(string.ascii_letters + string.digits)
|
| 29 |
+
|
| 30 |
+
LBRACKET = L("[").suppress()
|
| 31 |
+
RBRACKET = L("]").suppress()
|
| 32 |
+
LPAREN = L("(").suppress()
|
| 33 |
+
RPAREN = L(")").suppress()
|
| 34 |
+
COMMA = L(",").suppress()
|
| 35 |
+
SEMICOLON = L(";").suppress()
|
| 36 |
+
AT = L("@").suppress()
|
| 37 |
+
|
| 38 |
+
PUNCTUATION = Word("-_.")
|
| 39 |
+
IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM)
|
| 40 |
+
IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
|
| 41 |
+
|
| 42 |
+
NAME = IDENTIFIER("name")
|
| 43 |
+
EXTRA = IDENTIFIER
|
| 44 |
+
|
| 45 |
+
URI = Regex(r"[^ ]+")("url")
|
| 46 |
+
URL = AT + URI
|
| 47 |
+
|
| 48 |
+
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
|
| 49 |
+
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
|
| 50 |
+
|
| 51 |
+
VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
|
| 52 |
+
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
|
| 53 |
+
|
| 54 |
+
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
|
| 55 |
+
VERSION_MANY = Combine(
|
| 56 |
+
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
|
| 57 |
+
)("_raw_spec")
|
| 58 |
+
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
|
| 59 |
+
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
|
| 60 |
+
|
| 61 |
+
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
|
| 62 |
+
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
|
| 63 |
+
|
| 64 |
+
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
|
| 65 |
+
MARKER_EXPR.setParseAction(
|
| 66 |
+
lambda s, l, t: Marker(s[t._original_start : t._original_end])
|
| 67 |
+
)
|
| 68 |
+
MARKER_SEPARATOR = SEMICOLON
|
| 69 |
+
MARKER = MARKER_SEPARATOR + MARKER_EXPR
|
| 70 |
+
|
| 71 |
+
VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
|
| 72 |
+
URL_AND_MARKER = URL + Optional(MARKER)
|
| 73 |
+
|
| 74 |
+
NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
|
| 75 |
+
|
| 76 |
+
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
|
| 77 |
+
# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
|
| 78 |
+
# issue #104
|
| 79 |
+
REQUIREMENT.parseString("x[]")
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class Requirement(object):
|
| 83 |
+
"""Parse a requirement.
|
| 84 |
+
|
| 85 |
+
Parse a given requirement string into its parts, such as name, specifier,
|
| 86 |
+
URL, and extras. Raises InvalidRequirement on a badly-formed requirement
|
| 87 |
+
string.
|
| 88 |
+
"""
|
| 89 |
+
|
| 90 |
+
# TODO: Can we test whether something is contained within a requirement?
|
| 91 |
+
# If so how do we do that? Do we need to test against the _name_ of
|
| 92 |
+
# the thing as well as the version? What about the markers?
|
| 93 |
+
# TODO: Can we normalize the name and extra name?
|
| 94 |
+
|
| 95 |
+
def __init__(self, requirement_string):
|
| 96 |
+
# type: (str) -> None
|
| 97 |
+
try:
|
| 98 |
+
req = REQUIREMENT.parseString(requirement_string)
|
| 99 |
+
except ParseException as e:
|
| 100 |
+
raise InvalidRequirement(
|
| 101 |
+
'Parse error at "{0!r}": {1}'.format(
|
| 102 |
+
requirement_string[e.loc : e.loc + 8], e.msg
|
| 103 |
+
)
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
self.name = req.name
|
| 107 |
+
if req.url:
|
| 108 |
+
parsed_url = urlparse.urlparse(req.url)
|
| 109 |
+
if parsed_url.scheme == "file":
|
| 110 |
+
if urlparse.urlunparse(parsed_url) != req.url:
|
| 111 |
+
raise InvalidRequirement("Invalid URL given")
|
| 112 |
+
elif not (parsed_url.scheme and parsed_url.netloc) or (
|
| 113 |
+
not parsed_url.scheme and not parsed_url.netloc
|
| 114 |
+
):
|
| 115 |
+
raise InvalidRequirement("Invalid URL: {0}".format(req.url))
|
| 116 |
+
self.url = req.url
|
| 117 |
+
else:
|
| 118 |
+
self.url = None
|
| 119 |
+
self.extras = set(req.extras.asList() if req.extras else [])
|
| 120 |
+
self.specifier = SpecifierSet(req.specifier)
|
| 121 |
+
self.marker = req.marker if req.marker else None
|
| 122 |
+
|
| 123 |
+
def __str__(self):
|
| 124 |
+
# type: () -> str
|
| 125 |
+
parts = [self.name] # type: List[str]
|
| 126 |
+
|
| 127 |
+
if self.extras:
|
| 128 |
+
parts.append("[{0}]".format(",".join(sorted(self.extras))))
|
| 129 |
+
|
| 130 |
+
if self.specifier:
|
| 131 |
+
parts.append(str(self.specifier))
|
| 132 |
+
|
| 133 |
+
if self.url:
|
| 134 |
+
parts.append("@ {0}".format(self.url))
|
| 135 |
+
if self.marker:
|
| 136 |
+
parts.append(" ")
|
| 137 |
+
|
| 138 |
+
if self.marker:
|
| 139 |
+
parts.append("; {0}".format(self.marker))
|
| 140 |
+
|
| 141 |
+
return "".join(parts)
|
| 142 |
+
|
| 143 |
+
def __repr__(self):
|
| 144 |
+
# type: () -> str
|
| 145 |
+
return "<Requirement({0!r})>".format(str(self))
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/specifiers.py
ADDED
|
@@ -0,0 +1,863 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
import abc
|
| 7 |
+
import functools
|
| 8 |
+
import itertools
|
| 9 |
+
import re
|
| 10 |
+
|
| 11 |
+
from ._compat import string_types, with_metaclass
|
| 12 |
+
from ._typing import TYPE_CHECKING
|
| 13 |
+
from .utils import canonicalize_version
|
| 14 |
+
from .version import Version, LegacyVersion, parse
|
| 15 |
+
|
| 16 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 17 |
+
from typing import (
|
| 18 |
+
List,
|
| 19 |
+
Dict,
|
| 20 |
+
Union,
|
| 21 |
+
Iterable,
|
| 22 |
+
Iterator,
|
| 23 |
+
Optional,
|
| 24 |
+
Callable,
|
| 25 |
+
Tuple,
|
| 26 |
+
FrozenSet,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
ParsedVersion = Union[Version, LegacyVersion]
|
| 30 |
+
UnparsedVersion = Union[Version, LegacyVersion, str]
|
| 31 |
+
CallableOperator = Callable[[ParsedVersion, str], bool]
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class InvalidSpecifier(ValueError):
|
| 35 |
+
"""
|
| 36 |
+
An invalid specifier was found, users should refer to PEP 440.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): # type: ignore
|
| 41 |
+
@abc.abstractmethod
|
| 42 |
+
def __str__(self):
|
| 43 |
+
# type: () -> str
|
| 44 |
+
"""
|
| 45 |
+
Returns the str representation of this Specifier like object. This
|
| 46 |
+
should be representative of the Specifier itself.
|
| 47 |
+
"""
|
| 48 |
+
|
| 49 |
+
@abc.abstractmethod
|
| 50 |
+
def __hash__(self):
|
| 51 |
+
# type: () -> int
|
| 52 |
+
"""
|
| 53 |
+
Returns a hash value for this Specifier like object.
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
@abc.abstractmethod
|
| 57 |
+
def __eq__(self, other):
|
| 58 |
+
# type: (object) -> bool
|
| 59 |
+
"""
|
| 60 |
+
Returns a boolean representing whether or not the two Specifier like
|
| 61 |
+
objects are equal.
|
| 62 |
+
"""
|
| 63 |
+
|
| 64 |
+
@abc.abstractmethod
|
| 65 |
+
def __ne__(self, other):
|
| 66 |
+
# type: (object) -> bool
|
| 67 |
+
"""
|
| 68 |
+
Returns a boolean representing whether or not the two Specifier like
|
| 69 |
+
objects are not equal.
|
| 70 |
+
"""
|
| 71 |
+
|
| 72 |
+
@abc.abstractproperty
|
| 73 |
+
def prereleases(self):
|
| 74 |
+
# type: () -> Optional[bool]
|
| 75 |
+
"""
|
| 76 |
+
Returns whether or not pre-releases as a whole are allowed by this
|
| 77 |
+
specifier.
|
| 78 |
+
"""
|
| 79 |
+
|
| 80 |
+
@prereleases.setter
|
| 81 |
+
def prereleases(self, value):
|
| 82 |
+
# type: (bool) -> None
|
| 83 |
+
"""
|
| 84 |
+
Sets whether or not pre-releases as a whole are allowed by this
|
| 85 |
+
specifier.
|
| 86 |
+
"""
|
| 87 |
+
|
| 88 |
+
@abc.abstractmethod
|
| 89 |
+
def contains(self, item, prereleases=None):
|
| 90 |
+
# type: (str, Optional[bool]) -> bool
|
| 91 |
+
"""
|
| 92 |
+
Determines if the given item is contained within this specifier.
|
| 93 |
+
"""
|
| 94 |
+
|
| 95 |
+
@abc.abstractmethod
|
| 96 |
+
def filter(self, iterable, prereleases=None):
|
| 97 |
+
# type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion]
|
| 98 |
+
"""
|
| 99 |
+
Takes an iterable of items and filters them so that only items which
|
| 100 |
+
are contained within this specifier are allowed in it.
|
| 101 |
+
"""
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class _IndividualSpecifier(BaseSpecifier):
|
| 105 |
+
|
| 106 |
+
_operators = {} # type: Dict[str, str]
|
| 107 |
+
|
| 108 |
+
def __init__(self, spec="", prereleases=None):
|
| 109 |
+
# type: (str, Optional[bool]) -> None
|
| 110 |
+
match = self._regex.search(spec)
|
| 111 |
+
if not match:
|
| 112 |
+
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
|
| 113 |
+
|
| 114 |
+
self._spec = (
|
| 115 |
+
match.group("operator").strip(),
|
| 116 |
+
match.group("version").strip(),
|
| 117 |
+
) # type: Tuple[str, str]
|
| 118 |
+
|
| 119 |
+
# Store whether or not this Specifier should accept prereleases
|
| 120 |
+
self._prereleases = prereleases
|
| 121 |
+
|
| 122 |
+
def __repr__(self):
|
| 123 |
+
# type: () -> str
|
| 124 |
+
pre = (
|
| 125 |
+
", prereleases={0!r}".format(self.prereleases)
|
| 126 |
+
if self._prereleases is not None
|
| 127 |
+
else ""
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
|
| 131 |
+
|
| 132 |
+
def __str__(self):
|
| 133 |
+
# type: () -> str
|
| 134 |
+
return "{0}{1}".format(*self._spec)
|
| 135 |
+
|
| 136 |
+
@property
|
| 137 |
+
def _canonical_spec(self):
|
| 138 |
+
# type: () -> Tuple[str, Union[Version, str]]
|
| 139 |
+
return self._spec[0], canonicalize_version(self._spec[1])
|
| 140 |
+
|
| 141 |
+
def __hash__(self):
|
| 142 |
+
# type: () -> int
|
| 143 |
+
return hash(self._canonical_spec)
|
| 144 |
+
|
| 145 |
+
def __eq__(self, other):
|
| 146 |
+
# type: (object) -> bool
|
| 147 |
+
if isinstance(other, string_types):
|
| 148 |
+
try:
|
| 149 |
+
other = self.__class__(str(other))
|
| 150 |
+
except InvalidSpecifier:
|
| 151 |
+
return NotImplemented
|
| 152 |
+
elif not isinstance(other, self.__class__):
|
| 153 |
+
return NotImplemented
|
| 154 |
+
|
| 155 |
+
return self._canonical_spec == other._canonical_spec
|
| 156 |
+
|
| 157 |
+
def __ne__(self, other):
|
| 158 |
+
# type: (object) -> bool
|
| 159 |
+
if isinstance(other, string_types):
|
| 160 |
+
try:
|
| 161 |
+
other = self.__class__(str(other))
|
| 162 |
+
except InvalidSpecifier:
|
| 163 |
+
return NotImplemented
|
| 164 |
+
elif not isinstance(other, self.__class__):
|
| 165 |
+
return NotImplemented
|
| 166 |
+
|
| 167 |
+
return self._spec != other._spec
|
| 168 |
+
|
| 169 |
+
def _get_operator(self, op):
|
| 170 |
+
# type: (str) -> CallableOperator
|
| 171 |
+
operator_callable = getattr(
|
| 172 |
+
self, "_compare_{0}".format(self._operators[op])
|
| 173 |
+
) # type: CallableOperator
|
| 174 |
+
return operator_callable
|
| 175 |
+
|
| 176 |
+
def _coerce_version(self, version):
|
| 177 |
+
# type: (UnparsedVersion) -> ParsedVersion
|
| 178 |
+
if not isinstance(version, (LegacyVersion, Version)):
|
| 179 |
+
version = parse(version)
|
| 180 |
+
return version
|
| 181 |
+
|
| 182 |
+
@property
|
| 183 |
+
def operator(self):
|
| 184 |
+
# type: () -> str
|
| 185 |
+
return self._spec[0]
|
| 186 |
+
|
| 187 |
+
@property
|
| 188 |
+
def version(self):
|
| 189 |
+
# type: () -> str
|
| 190 |
+
return self._spec[1]
|
| 191 |
+
|
| 192 |
+
@property
|
| 193 |
+
def prereleases(self):
|
| 194 |
+
# type: () -> Optional[bool]
|
| 195 |
+
return self._prereleases
|
| 196 |
+
|
| 197 |
+
@prereleases.setter
|
| 198 |
+
def prereleases(self, value):
|
| 199 |
+
# type: (bool) -> None
|
| 200 |
+
self._prereleases = value
|
| 201 |
+
|
| 202 |
+
def __contains__(self, item):
|
| 203 |
+
# type: (str) -> bool
|
| 204 |
+
return self.contains(item)
|
| 205 |
+
|
| 206 |
+
def contains(self, item, prereleases=None):
|
| 207 |
+
# type: (UnparsedVersion, Optional[bool]) -> bool
|
| 208 |
+
|
| 209 |
+
# Determine if prereleases are to be allowed or not.
|
| 210 |
+
if prereleases is None:
|
| 211 |
+
prereleases = self.prereleases
|
| 212 |
+
|
| 213 |
+
# Normalize item to a Version or LegacyVersion, this allows us to have
|
| 214 |
+
# a shortcut for ``"2.0" in Specifier(">=2")
|
| 215 |
+
normalized_item = self._coerce_version(item)
|
| 216 |
+
|
| 217 |
+
# Determine if we should be supporting prereleases in this specifier
|
| 218 |
+
# or not, if we do not support prereleases than we can short circuit
|
| 219 |
+
# logic if this version is a prereleases.
|
| 220 |
+
if normalized_item.is_prerelease and not prereleases:
|
| 221 |
+
return False
|
| 222 |
+
|
| 223 |
+
# Actually do the comparison to determine if this item is contained
|
| 224 |
+
# within this Specifier or not.
|
| 225 |
+
operator_callable = self._get_operator(self.operator) # type: CallableOperator
|
| 226 |
+
return operator_callable(normalized_item, self.version)
|
| 227 |
+
|
| 228 |
+
def filter(self, iterable, prereleases=None):
|
| 229 |
+
# type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion]
|
| 230 |
+
|
| 231 |
+
yielded = False
|
| 232 |
+
found_prereleases = []
|
| 233 |
+
|
| 234 |
+
kw = {"prereleases": prereleases if prereleases is not None else True}
|
| 235 |
+
|
| 236 |
+
# Attempt to iterate over all the values in the iterable and if any of
|
| 237 |
+
# them match, yield them.
|
| 238 |
+
for version in iterable:
|
| 239 |
+
parsed_version = self._coerce_version(version)
|
| 240 |
+
|
| 241 |
+
if self.contains(parsed_version, **kw):
|
| 242 |
+
# If our version is a prerelease, and we were not set to allow
|
| 243 |
+
# prereleases, then we'll store it for later incase nothing
|
| 244 |
+
# else matches this specifier.
|
| 245 |
+
if parsed_version.is_prerelease and not (
|
| 246 |
+
prereleases or self.prereleases
|
| 247 |
+
):
|
| 248 |
+
found_prereleases.append(version)
|
| 249 |
+
# Either this is not a prerelease, or we should have been
|
| 250 |
+
# accepting prereleases from the beginning.
|
| 251 |
+
else:
|
| 252 |
+
yielded = True
|
| 253 |
+
yield version
|
| 254 |
+
|
| 255 |
+
# Now that we've iterated over everything, determine if we've yielded
|
| 256 |
+
# any values, and if we have not and we have any prereleases stored up
|
| 257 |
+
# then we will go ahead and yield the prereleases.
|
| 258 |
+
if not yielded and found_prereleases:
|
| 259 |
+
for version in found_prereleases:
|
| 260 |
+
yield version
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
class LegacySpecifier(_IndividualSpecifier):
|
| 264 |
+
|
| 265 |
+
_regex_str = r"""
|
| 266 |
+
(?P<operator>(==|!=|<=|>=|<|>))
|
| 267 |
+
\s*
|
| 268 |
+
(?P<version>
|
| 269 |
+
[^,;\s)]* # Since this is a "legacy" specifier, and the version
|
| 270 |
+
# string can be just about anything, we match everything
|
| 271 |
+
# except for whitespace, a semi-colon for marker support,
|
| 272 |
+
# a closing paren since versions can be enclosed in
|
| 273 |
+
# them, and a comma since it's a version separator.
|
| 274 |
+
)
|
| 275 |
+
"""
|
| 276 |
+
|
| 277 |
+
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
|
| 278 |
+
|
| 279 |
+
_operators = {
|
| 280 |
+
"==": "equal",
|
| 281 |
+
"!=": "not_equal",
|
| 282 |
+
"<=": "less_than_equal",
|
| 283 |
+
">=": "greater_than_equal",
|
| 284 |
+
"<": "less_than",
|
| 285 |
+
">": "greater_than",
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
def _coerce_version(self, version):
|
| 289 |
+
# type: (Union[ParsedVersion, str]) -> LegacyVersion
|
| 290 |
+
if not isinstance(version, LegacyVersion):
|
| 291 |
+
version = LegacyVersion(str(version))
|
| 292 |
+
return version
|
| 293 |
+
|
| 294 |
+
def _compare_equal(self, prospective, spec):
|
| 295 |
+
# type: (LegacyVersion, str) -> bool
|
| 296 |
+
return prospective == self._coerce_version(spec)
|
| 297 |
+
|
| 298 |
+
def _compare_not_equal(self, prospective, spec):
|
| 299 |
+
# type: (LegacyVersion, str) -> bool
|
| 300 |
+
return prospective != self._coerce_version(spec)
|
| 301 |
+
|
| 302 |
+
def _compare_less_than_equal(self, prospective, spec):
|
| 303 |
+
# type: (LegacyVersion, str) -> bool
|
| 304 |
+
return prospective <= self._coerce_version(spec)
|
| 305 |
+
|
| 306 |
+
def _compare_greater_than_equal(self, prospective, spec):
|
| 307 |
+
# type: (LegacyVersion, str) -> bool
|
| 308 |
+
return prospective >= self._coerce_version(spec)
|
| 309 |
+
|
| 310 |
+
def _compare_less_than(self, prospective, spec):
|
| 311 |
+
# type: (LegacyVersion, str) -> bool
|
| 312 |
+
return prospective < self._coerce_version(spec)
|
| 313 |
+
|
| 314 |
+
def _compare_greater_than(self, prospective, spec):
|
| 315 |
+
# type: (LegacyVersion, str) -> bool
|
| 316 |
+
return prospective > self._coerce_version(spec)
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
def _require_version_compare(
|
| 320 |
+
fn # type: (Callable[[Specifier, ParsedVersion, str], bool])
|
| 321 |
+
):
|
| 322 |
+
# type: (...) -> Callable[[Specifier, ParsedVersion, str], bool]
|
| 323 |
+
@functools.wraps(fn)
|
| 324 |
+
def wrapped(self, prospective, spec):
|
| 325 |
+
# type: (Specifier, ParsedVersion, str) -> bool
|
| 326 |
+
if not isinstance(prospective, Version):
|
| 327 |
+
return False
|
| 328 |
+
return fn(self, prospective, spec)
|
| 329 |
+
|
| 330 |
+
return wrapped
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
class Specifier(_IndividualSpecifier):
|
| 334 |
+
|
| 335 |
+
_regex_str = r"""
|
| 336 |
+
(?P<operator>(~=|==|!=|<=|>=|<|>|===))
|
| 337 |
+
(?P<version>
|
| 338 |
+
(?:
|
| 339 |
+
# The identity operators allow for an escape hatch that will
|
| 340 |
+
# do an exact string match of the version you wish to install.
|
| 341 |
+
# This will not be parsed by PEP 440 and we cannot determine
|
| 342 |
+
# any semantic meaning from it. This operator is discouraged
|
| 343 |
+
# but included entirely as an escape hatch.
|
| 344 |
+
(?<====) # Only match for the identity operator
|
| 345 |
+
\s*
|
| 346 |
+
[^\s]* # We just match everything, except for whitespace
|
| 347 |
+
# since we are only testing for strict identity.
|
| 348 |
+
)
|
| 349 |
+
|
|
| 350 |
+
(?:
|
| 351 |
+
# The (non)equality operators allow for wild card and local
|
| 352 |
+
# versions to be specified so we have to define these two
|
| 353 |
+
# operators separately to enable that.
|
| 354 |
+
(?<===|!=) # Only match for equals and not equals
|
| 355 |
+
|
| 356 |
+
\s*
|
| 357 |
+
v?
|
| 358 |
+
(?:[0-9]+!)? # epoch
|
| 359 |
+
[0-9]+(?:\.[0-9]+)* # release
|
| 360 |
+
(?: # pre release
|
| 361 |
+
[-_\.]?
|
| 362 |
+
(a|b|c|rc|alpha|beta|pre|preview)
|
| 363 |
+
[-_\.]?
|
| 364 |
+
[0-9]*
|
| 365 |
+
)?
|
| 366 |
+
(?: # post release
|
| 367 |
+
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
| 368 |
+
)?
|
| 369 |
+
|
| 370 |
+
# You cannot use a wild card and a dev or local version
|
| 371 |
+
# together so group them with a | and make them optional.
|
| 372 |
+
(?:
|
| 373 |
+
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
| 374 |
+
(?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
|
| 375 |
+
|
|
| 376 |
+
\.\* # Wild card syntax of .*
|
| 377 |
+
)?
|
| 378 |
+
)
|
| 379 |
+
|
|
| 380 |
+
(?:
|
| 381 |
+
# The compatible operator requires at least two digits in the
|
| 382 |
+
# release segment.
|
| 383 |
+
(?<=~=) # Only match for the compatible operator
|
| 384 |
+
|
| 385 |
+
\s*
|
| 386 |
+
v?
|
| 387 |
+
(?:[0-9]+!)? # epoch
|
| 388 |
+
[0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *)
|
| 389 |
+
(?: # pre release
|
| 390 |
+
[-_\.]?
|
| 391 |
+
(a|b|c|rc|alpha|beta|pre|preview)
|
| 392 |
+
[-_\.]?
|
| 393 |
+
[0-9]*
|
| 394 |
+
)?
|
| 395 |
+
(?: # post release
|
| 396 |
+
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
| 397 |
+
)?
|
| 398 |
+
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
| 399 |
+
)
|
| 400 |
+
|
|
| 401 |
+
(?:
|
| 402 |
+
# All other operators only allow a sub set of what the
|
| 403 |
+
# (non)equality operators do. Specifically they do not allow
|
| 404 |
+
# local versions to be specified nor do they allow the prefix
|
| 405 |
+
# matching wild cards.
|
| 406 |
+
(?<!==|!=|~=) # We have special cases for these
|
| 407 |
+
# operators so we want to make sure they
|
| 408 |
+
# don't match here.
|
| 409 |
+
|
| 410 |
+
\s*
|
| 411 |
+
v?
|
| 412 |
+
(?:[0-9]+!)? # epoch
|
| 413 |
+
[0-9]+(?:\.[0-9]+)* # release
|
| 414 |
+
(?: # pre release
|
| 415 |
+
[-_\.]?
|
| 416 |
+
(a|b|c|rc|alpha|beta|pre|preview)
|
| 417 |
+
[-_\.]?
|
| 418 |
+
[0-9]*
|
| 419 |
+
)?
|
| 420 |
+
(?: # post release
|
| 421 |
+
(?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
|
| 422 |
+
)?
|
| 423 |
+
(?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release
|
| 424 |
+
)
|
| 425 |
+
)
|
| 426 |
+
"""
|
| 427 |
+
|
| 428 |
+
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
|
| 429 |
+
|
| 430 |
+
_operators = {
|
| 431 |
+
"~=": "compatible",
|
| 432 |
+
"==": "equal",
|
| 433 |
+
"!=": "not_equal",
|
| 434 |
+
"<=": "less_than_equal",
|
| 435 |
+
">=": "greater_than_equal",
|
| 436 |
+
"<": "less_than",
|
| 437 |
+
">": "greater_than",
|
| 438 |
+
"===": "arbitrary",
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
@_require_version_compare
|
| 442 |
+
def _compare_compatible(self, prospective, spec):
|
| 443 |
+
# type: (ParsedVersion, str) -> bool
|
| 444 |
+
|
| 445 |
+
# Compatible releases have an equivalent combination of >= and ==. That
|
| 446 |
+
# is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
|
| 447 |
+
# implement this in terms of the other specifiers instead of
|
| 448 |
+
# implementing it ourselves. The only thing we need to do is construct
|
| 449 |
+
# the other specifiers.
|
| 450 |
+
|
| 451 |
+
# We want everything but the last item in the version, but we want to
|
| 452 |
+
# ignore post and dev releases and we want to treat the pre-release as
|
| 453 |
+
# it's own separate segment.
|
| 454 |
+
prefix = ".".join(
|
| 455 |
+
list(
|
| 456 |
+
itertools.takewhile(
|
| 457 |
+
lambda x: (not x.startswith("post") and not x.startswith("dev")),
|
| 458 |
+
_version_split(spec),
|
| 459 |
+
)
|
| 460 |
+
)[:-1]
|
| 461 |
+
)
|
| 462 |
+
|
| 463 |
+
# Add the prefix notation to the end of our string
|
| 464 |
+
prefix += ".*"
|
| 465 |
+
|
| 466 |
+
return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
|
| 467 |
+
prospective, prefix
|
| 468 |
+
)
|
| 469 |
+
|
| 470 |
+
@_require_version_compare
|
| 471 |
+
def _compare_equal(self, prospective, spec):
|
| 472 |
+
# type: (ParsedVersion, str) -> bool
|
| 473 |
+
|
| 474 |
+
# We need special logic to handle prefix matching
|
| 475 |
+
if spec.endswith(".*"):
|
| 476 |
+
# In the case of prefix matching we want to ignore local segment.
|
| 477 |
+
prospective = Version(prospective.public)
|
| 478 |
+
# Split the spec out by dots, and pretend that there is an implicit
|
| 479 |
+
# dot in between a release segment and a pre-release segment.
|
| 480 |
+
split_spec = _version_split(spec[:-2]) # Remove the trailing .*
|
| 481 |
+
|
| 482 |
+
# Split the prospective version out by dots, and pretend that there
|
| 483 |
+
# is an implicit dot in between a release segment and a pre-release
|
| 484 |
+
# segment.
|
| 485 |
+
split_prospective = _version_split(str(prospective))
|
| 486 |
+
|
| 487 |
+
# Shorten the prospective version to be the same length as the spec
|
| 488 |
+
# so that we can determine if the specifier is a prefix of the
|
| 489 |
+
# prospective version or not.
|
| 490 |
+
shortened_prospective = split_prospective[: len(split_spec)]
|
| 491 |
+
|
| 492 |
+
# Pad out our two sides with zeros so that they both equal the same
|
| 493 |
+
# length.
|
| 494 |
+
padded_spec, padded_prospective = _pad_version(
|
| 495 |
+
split_spec, shortened_prospective
|
| 496 |
+
)
|
| 497 |
+
|
| 498 |
+
return padded_prospective == padded_spec
|
| 499 |
+
else:
|
| 500 |
+
# Convert our spec string into a Version
|
| 501 |
+
spec_version = Version(spec)
|
| 502 |
+
|
| 503 |
+
# If the specifier does not have a local segment, then we want to
|
| 504 |
+
# act as if the prospective version also does not have a local
|
| 505 |
+
# segment.
|
| 506 |
+
if not spec_version.local:
|
| 507 |
+
prospective = Version(prospective.public)
|
| 508 |
+
|
| 509 |
+
return prospective == spec_version
|
| 510 |
+
|
| 511 |
+
@_require_version_compare
|
| 512 |
+
def _compare_not_equal(self, prospective, spec):
|
| 513 |
+
# type: (ParsedVersion, str) -> bool
|
| 514 |
+
return not self._compare_equal(prospective, spec)
|
| 515 |
+
|
| 516 |
+
@_require_version_compare
|
| 517 |
+
def _compare_less_than_equal(self, prospective, spec):
|
| 518 |
+
# type: (ParsedVersion, str) -> bool
|
| 519 |
+
|
| 520 |
+
# NB: Local version identifiers are NOT permitted in the version
|
| 521 |
+
# specifier, so local version labels can be universally removed from
|
| 522 |
+
# the prospective version.
|
| 523 |
+
return Version(prospective.public) <= Version(spec)
|
| 524 |
+
|
| 525 |
+
@_require_version_compare
|
| 526 |
+
def _compare_greater_than_equal(self, prospective, spec):
|
| 527 |
+
# type: (ParsedVersion, str) -> bool
|
| 528 |
+
|
| 529 |
+
# NB: Local version identifiers are NOT permitted in the version
|
| 530 |
+
# specifier, so local version labels can be universally removed from
|
| 531 |
+
# the prospective version.
|
| 532 |
+
return Version(prospective.public) >= Version(spec)
|
| 533 |
+
|
| 534 |
+
@_require_version_compare
|
| 535 |
+
def _compare_less_than(self, prospective, spec_str):
|
| 536 |
+
# type: (ParsedVersion, str) -> bool
|
| 537 |
+
|
| 538 |
+
# Convert our spec to a Version instance, since we'll want to work with
|
| 539 |
+
# it as a version.
|
| 540 |
+
spec = Version(spec_str)
|
| 541 |
+
|
| 542 |
+
# Check to see if the prospective version is less than the spec
|
| 543 |
+
# version. If it's not we can short circuit and just return False now
|
| 544 |
+
# instead of doing extra unneeded work.
|
| 545 |
+
if not prospective < spec:
|
| 546 |
+
return False
|
| 547 |
+
|
| 548 |
+
# This special case is here so that, unless the specifier itself
|
| 549 |
+
# includes is a pre-release version, that we do not accept pre-release
|
| 550 |
+
# versions for the version mentioned in the specifier (e.g. <3.1 should
|
| 551 |
+
# not match 3.1.dev0, but should match 3.0.dev0).
|
| 552 |
+
if not spec.is_prerelease and prospective.is_prerelease:
|
| 553 |
+
if Version(prospective.base_version) == Version(spec.base_version):
|
| 554 |
+
return False
|
| 555 |
+
|
| 556 |
+
# If we've gotten to here, it means that prospective version is both
|
| 557 |
+
# less than the spec version *and* it's not a pre-release of the same
|
| 558 |
+
# version in the spec.
|
| 559 |
+
return True
|
| 560 |
+
|
| 561 |
+
@_require_version_compare
|
| 562 |
+
def _compare_greater_than(self, prospective, spec_str):
|
| 563 |
+
# type: (ParsedVersion, str) -> bool
|
| 564 |
+
|
| 565 |
+
# Convert our spec to a Version instance, since we'll want to work with
|
| 566 |
+
# it as a version.
|
| 567 |
+
spec = Version(spec_str)
|
| 568 |
+
|
| 569 |
+
# Check to see if the prospective version is greater than the spec
|
| 570 |
+
# version. If it's not we can short circuit and just return False now
|
| 571 |
+
# instead of doing extra unneeded work.
|
| 572 |
+
if not prospective > spec:
|
| 573 |
+
return False
|
| 574 |
+
|
| 575 |
+
# This special case is here so that, unless the specifier itself
|
| 576 |
+
# includes is a post-release version, that we do not accept
|
| 577 |
+
# post-release versions for the version mentioned in the specifier
|
| 578 |
+
# (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
|
| 579 |
+
if not spec.is_postrelease and prospective.is_postrelease:
|
| 580 |
+
if Version(prospective.base_version) == Version(spec.base_version):
|
| 581 |
+
return False
|
| 582 |
+
|
| 583 |
+
# Ensure that we do not allow a local version of the version mentioned
|
| 584 |
+
# in the specifier, which is technically greater than, to match.
|
| 585 |
+
if prospective.local is not None:
|
| 586 |
+
if Version(prospective.base_version) == Version(spec.base_version):
|
| 587 |
+
return False
|
| 588 |
+
|
| 589 |
+
# If we've gotten to here, it means that prospective version is both
|
| 590 |
+
# greater than the spec version *and* it's not a pre-release of the
|
| 591 |
+
# same version in the spec.
|
| 592 |
+
return True
|
| 593 |
+
|
| 594 |
+
def _compare_arbitrary(self, prospective, spec):
|
| 595 |
+
# type: (Version, str) -> bool
|
| 596 |
+
return str(prospective).lower() == str(spec).lower()
|
| 597 |
+
|
| 598 |
+
@property
|
| 599 |
+
def prereleases(self):
|
| 600 |
+
# type: () -> bool
|
| 601 |
+
|
| 602 |
+
# If there is an explicit prereleases set for this, then we'll just
|
| 603 |
+
# blindly use that.
|
| 604 |
+
if self._prereleases is not None:
|
| 605 |
+
return self._prereleases
|
| 606 |
+
|
| 607 |
+
# Look at all of our specifiers and determine if they are inclusive
|
| 608 |
+
# operators, and if they are if they are including an explicit
|
| 609 |
+
# prerelease.
|
| 610 |
+
operator, version = self._spec
|
| 611 |
+
if operator in ["==", ">=", "<=", "~=", "==="]:
|
| 612 |
+
# The == specifier can include a trailing .*, if it does we
|
| 613 |
+
# want to remove before parsing.
|
| 614 |
+
if operator == "==" and version.endswith(".*"):
|
| 615 |
+
version = version[:-2]
|
| 616 |
+
|
| 617 |
+
# Parse the version, and if it is a pre-release than this
|
| 618 |
+
# specifier allows pre-releases.
|
| 619 |
+
if parse(version).is_prerelease:
|
| 620 |
+
return True
|
| 621 |
+
|
| 622 |
+
return False
|
| 623 |
+
|
| 624 |
+
@prereleases.setter
|
| 625 |
+
def prereleases(self, value):
|
| 626 |
+
# type: (bool) -> None
|
| 627 |
+
self._prereleases = value
|
| 628 |
+
|
| 629 |
+
|
| 630 |
+
_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
|
| 631 |
+
|
| 632 |
+
|
| 633 |
+
def _version_split(version):
|
| 634 |
+
# type: (str) -> List[str]
|
| 635 |
+
result = [] # type: List[str]
|
| 636 |
+
for item in version.split("."):
|
| 637 |
+
match = _prefix_regex.search(item)
|
| 638 |
+
if match:
|
| 639 |
+
result.extend(match.groups())
|
| 640 |
+
else:
|
| 641 |
+
result.append(item)
|
| 642 |
+
return result
|
| 643 |
+
|
| 644 |
+
|
| 645 |
+
def _pad_version(left, right):
|
| 646 |
+
# type: (List[str], List[str]) -> Tuple[List[str], List[str]]
|
| 647 |
+
left_split, right_split = [], []
|
| 648 |
+
|
| 649 |
+
# Get the release segment of our versions
|
| 650 |
+
left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
|
| 651 |
+
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
|
| 652 |
+
|
| 653 |
+
# Get the rest of our versions
|
| 654 |
+
left_split.append(left[len(left_split[0]) :])
|
| 655 |
+
right_split.append(right[len(right_split[0]) :])
|
| 656 |
+
|
| 657 |
+
# Insert our padding
|
| 658 |
+
left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
|
| 659 |
+
right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
|
| 660 |
+
|
| 661 |
+
return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
|
| 662 |
+
|
| 663 |
+
|
| 664 |
+
class SpecifierSet(BaseSpecifier):
|
| 665 |
+
def __init__(self, specifiers="", prereleases=None):
|
| 666 |
+
# type: (str, Optional[bool]) -> None
|
| 667 |
+
|
| 668 |
+
# Split on , to break each individual specifier into it's own item, and
|
| 669 |
+
# strip each item to remove leading/trailing whitespace.
|
| 670 |
+
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
|
| 671 |
+
|
| 672 |
+
# Parsed each individual specifier, attempting first to make it a
|
| 673 |
+
# Specifier and falling back to a LegacySpecifier.
|
| 674 |
+
parsed = set()
|
| 675 |
+
for specifier in split_specifiers:
|
| 676 |
+
try:
|
| 677 |
+
parsed.add(Specifier(specifier))
|
| 678 |
+
except InvalidSpecifier:
|
| 679 |
+
parsed.add(LegacySpecifier(specifier))
|
| 680 |
+
|
| 681 |
+
# Turn our parsed specifiers into a frozen set and save them for later.
|
| 682 |
+
self._specs = frozenset(parsed)
|
| 683 |
+
|
| 684 |
+
# Store our prereleases value so we can use it later to determine if
|
| 685 |
+
# we accept prereleases or not.
|
| 686 |
+
self._prereleases = prereleases
|
| 687 |
+
|
| 688 |
+
def __repr__(self):
|
| 689 |
+
# type: () -> str
|
| 690 |
+
pre = (
|
| 691 |
+
", prereleases={0!r}".format(self.prereleases)
|
| 692 |
+
if self._prereleases is not None
|
| 693 |
+
else ""
|
| 694 |
+
)
|
| 695 |
+
|
| 696 |
+
return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
|
| 697 |
+
|
| 698 |
+
def __str__(self):
|
| 699 |
+
# type: () -> str
|
| 700 |
+
return ",".join(sorted(str(s) for s in self._specs))
|
| 701 |
+
|
| 702 |
+
def __hash__(self):
|
| 703 |
+
# type: () -> int
|
| 704 |
+
return hash(self._specs)
|
| 705 |
+
|
| 706 |
+
def __and__(self, other):
|
| 707 |
+
# type: (Union[SpecifierSet, str]) -> SpecifierSet
|
| 708 |
+
if isinstance(other, string_types):
|
| 709 |
+
other = SpecifierSet(other)
|
| 710 |
+
elif not isinstance(other, SpecifierSet):
|
| 711 |
+
return NotImplemented
|
| 712 |
+
|
| 713 |
+
specifier = SpecifierSet()
|
| 714 |
+
specifier._specs = frozenset(self._specs | other._specs)
|
| 715 |
+
|
| 716 |
+
if self._prereleases is None and other._prereleases is not None:
|
| 717 |
+
specifier._prereleases = other._prereleases
|
| 718 |
+
elif self._prereleases is not None and other._prereleases is None:
|
| 719 |
+
specifier._prereleases = self._prereleases
|
| 720 |
+
elif self._prereleases == other._prereleases:
|
| 721 |
+
specifier._prereleases = self._prereleases
|
| 722 |
+
else:
|
| 723 |
+
raise ValueError(
|
| 724 |
+
"Cannot combine SpecifierSets with True and False prerelease "
|
| 725 |
+
"overrides."
|
| 726 |
+
)
|
| 727 |
+
|
| 728 |
+
return specifier
|
| 729 |
+
|
| 730 |
+
def __eq__(self, other):
|
| 731 |
+
# type: (object) -> bool
|
| 732 |
+
if isinstance(other, (string_types, _IndividualSpecifier)):
|
| 733 |
+
other = SpecifierSet(str(other))
|
| 734 |
+
elif not isinstance(other, SpecifierSet):
|
| 735 |
+
return NotImplemented
|
| 736 |
+
|
| 737 |
+
return self._specs == other._specs
|
| 738 |
+
|
| 739 |
+
def __ne__(self, other):
|
| 740 |
+
# type: (object) -> bool
|
| 741 |
+
if isinstance(other, (string_types, _IndividualSpecifier)):
|
| 742 |
+
other = SpecifierSet(str(other))
|
| 743 |
+
elif not isinstance(other, SpecifierSet):
|
| 744 |
+
return NotImplemented
|
| 745 |
+
|
| 746 |
+
return self._specs != other._specs
|
| 747 |
+
|
| 748 |
+
def __len__(self):
|
| 749 |
+
# type: () -> int
|
| 750 |
+
return len(self._specs)
|
| 751 |
+
|
| 752 |
+
def __iter__(self):
|
| 753 |
+
# type: () -> Iterator[FrozenSet[_IndividualSpecifier]]
|
| 754 |
+
return iter(self._specs)
|
| 755 |
+
|
| 756 |
+
@property
|
| 757 |
+
def prereleases(self):
|
| 758 |
+
# type: () -> Optional[bool]
|
| 759 |
+
|
| 760 |
+
# If we have been given an explicit prerelease modifier, then we'll
|
| 761 |
+
# pass that through here.
|
| 762 |
+
if self._prereleases is not None:
|
| 763 |
+
return self._prereleases
|
| 764 |
+
|
| 765 |
+
# If we don't have any specifiers, and we don't have a forced value,
|
| 766 |
+
# then we'll just return None since we don't know if this should have
|
| 767 |
+
# pre-releases or not.
|
| 768 |
+
if not self._specs:
|
| 769 |
+
return None
|
| 770 |
+
|
| 771 |
+
# Otherwise we'll see if any of the given specifiers accept
|
| 772 |
+
# prereleases, if any of them do we'll return True, otherwise False.
|
| 773 |
+
return any(s.prereleases for s in self._specs)
|
| 774 |
+
|
| 775 |
+
@prereleases.setter
|
| 776 |
+
def prereleases(self, value):
|
| 777 |
+
# type: (bool) -> None
|
| 778 |
+
self._prereleases = value
|
| 779 |
+
|
| 780 |
+
def __contains__(self, item):
|
| 781 |
+
# type: (Union[ParsedVersion, str]) -> bool
|
| 782 |
+
return self.contains(item)
|
| 783 |
+
|
| 784 |
+
def contains(self, item, prereleases=None):
|
| 785 |
+
# type: (Union[ParsedVersion, str], Optional[bool]) -> bool
|
| 786 |
+
|
| 787 |
+
# Ensure that our item is a Version or LegacyVersion instance.
|
| 788 |
+
if not isinstance(item, (LegacyVersion, Version)):
|
| 789 |
+
item = parse(item)
|
| 790 |
+
|
| 791 |
+
# Determine if we're forcing a prerelease or not, if we're not forcing
|
| 792 |
+
# one for this particular filter call, then we'll use whatever the
|
| 793 |
+
# SpecifierSet thinks for whether or not we should support prereleases.
|
| 794 |
+
if prereleases is None:
|
| 795 |
+
prereleases = self.prereleases
|
| 796 |
+
|
| 797 |
+
# We can determine if we're going to allow pre-releases by looking to
|
| 798 |
+
# see if any of the underlying items supports them. If none of them do
|
| 799 |
+
# and this item is a pre-release then we do not allow it and we can
|
| 800 |
+
# short circuit that here.
|
| 801 |
+
# Note: This means that 1.0.dev1 would not be contained in something
|
| 802 |
+
# like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
|
| 803 |
+
if not prereleases and item.is_prerelease:
|
| 804 |
+
return False
|
| 805 |
+
|
| 806 |
+
# We simply dispatch to the underlying specs here to make sure that the
|
| 807 |
+
# given version is contained within all of them.
|
| 808 |
+
# Note: This use of all() here means that an empty set of specifiers
|
| 809 |
+
# will always return True, this is an explicit design decision.
|
| 810 |
+
return all(s.contains(item, prereleases=prereleases) for s in self._specs)
|
| 811 |
+
|
| 812 |
+
def filter(
|
| 813 |
+
self,
|
| 814 |
+
iterable, # type: Iterable[Union[ParsedVersion, str]]
|
| 815 |
+
prereleases=None, # type: Optional[bool]
|
| 816 |
+
):
|
| 817 |
+
# type: (...) -> Iterable[Union[ParsedVersion, str]]
|
| 818 |
+
|
| 819 |
+
# Determine if we're forcing a prerelease or not, if we're not forcing
|
| 820 |
+
# one for this particular filter call, then we'll use whatever the
|
| 821 |
+
# SpecifierSet thinks for whether or not we should support prereleases.
|
| 822 |
+
if prereleases is None:
|
| 823 |
+
prereleases = self.prereleases
|
| 824 |
+
|
| 825 |
+
# If we have any specifiers, then we want to wrap our iterable in the
|
| 826 |
+
# filter method for each one, this will act as a logical AND amongst
|
| 827 |
+
# each specifier.
|
| 828 |
+
if self._specs:
|
| 829 |
+
for spec in self._specs:
|
| 830 |
+
iterable = spec.filter(iterable, prereleases=bool(prereleases))
|
| 831 |
+
return iterable
|
| 832 |
+
# If we do not have any specifiers, then we need to have a rough filter
|
| 833 |
+
# which will filter out any pre-releases, unless there are no final
|
| 834 |
+
# releases, and which will filter out LegacyVersion in general.
|
| 835 |
+
else:
|
| 836 |
+
filtered = [] # type: List[Union[ParsedVersion, str]]
|
| 837 |
+
found_prereleases = [] # type: List[Union[ParsedVersion, str]]
|
| 838 |
+
|
| 839 |
+
for item in iterable:
|
| 840 |
+
# Ensure that we some kind of Version class for this item.
|
| 841 |
+
if not isinstance(item, (LegacyVersion, Version)):
|
| 842 |
+
parsed_version = parse(item)
|
| 843 |
+
else:
|
| 844 |
+
parsed_version = item
|
| 845 |
+
|
| 846 |
+
# Filter out any item which is parsed as a LegacyVersion
|
| 847 |
+
if isinstance(parsed_version, LegacyVersion):
|
| 848 |
+
continue
|
| 849 |
+
|
| 850 |
+
# Store any item which is a pre-release for later unless we've
|
| 851 |
+
# already found a final version or we are accepting prereleases
|
| 852 |
+
if parsed_version.is_prerelease and not prereleases:
|
| 853 |
+
if not filtered:
|
| 854 |
+
found_prereleases.append(item)
|
| 855 |
+
else:
|
| 856 |
+
filtered.append(item)
|
| 857 |
+
|
| 858 |
+
# If we've found no items except for pre-releases, then we'll go
|
| 859 |
+
# ahead and use the pre-releases
|
| 860 |
+
if not filtered and found_prereleases and prereleases is None:
|
| 861 |
+
return found_prereleases
|
| 862 |
+
|
| 863 |
+
return filtered
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/tags.py
ADDED
|
@@ -0,0 +1,751 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
|
| 5 |
+
from __future__ import absolute_import
|
| 6 |
+
|
| 7 |
+
import distutils.util
|
| 8 |
+
|
| 9 |
+
try:
|
| 10 |
+
from importlib.machinery import EXTENSION_SUFFIXES
|
| 11 |
+
except ImportError: # pragma: no cover
|
| 12 |
+
import imp
|
| 13 |
+
|
| 14 |
+
EXTENSION_SUFFIXES = [x[0] for x in imp.get_suffixes()]
|
| 15 |
+
del imp
|
| 16 |
+
import logging
|
| 17 |
+
import os
|
| 18 |
+
import platform
|
| 19 |
+
import re
|
| 20 |
+
import struct
|
| 21 |
+
import sys
|
| 22 |
+
import sysconfig
|
| 23 |
+
import warnings
|
| 24 |
+
|
| 25 |
+
from ._typing import TYPE_CHECKING, cast
|
| 26 |
+
|
| 27 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 28 |
+
from typing import (
|
| 29 |
+
Dict,
|
| 30 |
+
FrozenSet,
|
| 31 |
+
IO,
|
| 32 |
+
Iterable,
|
| 33 |
+
Iterator,
|
| 34 |
+
List,
|
| 35 |
+
Optional,
|
| 36 |
+
Sequence,
|
| 37 |
+
Tuple,
|
| 38 |
+
Union,
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
PythonVersion = Sequence[int]
|
| 42 |
+
MacVersion = Tuple[int, int]
|
| 43 |
+
GlibcVersion = Tuple[int, int]
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
logger = logging.getLogger(__name__)
|
| 47 |
+
|
| 48 |
+
INTERPRETER_SHORT_NAMES = {
|
| 49 |
+
"python": "py", # Generic.
|
| 50 |
+
"cpython": "cp",
|
| 51 |
+
"pypy": "pp",
|
| 52 |
+
"ironpython": "ip",
|
| 53 |
+
"jython": "jy",
|
| 54 |
+
} # type: Dict[str, str]
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
class Tag(object):
|
| 61 |
+
"""
|
| 62 |
+
A representation of the tag triple for a wheel.
|
| 63 |
+
|
| 64 |
+
Instances are considered immutable and thus are hashable. Equality checking
|
| 65 |
+
is also supported.
|
| 66 |
+
"""
|
| 67 |
+
|
| 68 |
+
__slots__ = ["_interpreter", "_abi", "_platform"]
|
| 69 |
+
|
| 70 |
+
def __init__(self, interpreter, abi, platform):
|
| 71 |
+
# type: (str, str, str) -> None
|
| 72 |
+
self._interpreter = interpreter.lower()
|
| 73 |
+
self._abi = abi.lower()
|
| 74 |
+
self._platform = platform.lower()
|
| 75 |
+
|
| 76 |
+
@property
|
| 77 |
+
def interpreter(self):
|
| 78 |
+
# type: () -> str
|
| 79 |
+
return self._interpreter
|
| 80 |
+
|
| 81 |
+
@property
|
| 82 |
+
def abi(self):
|
| 83 |
+
# type: () -> str
|
| 84 |
+
return self._abi
|
| 85 |
+
|
| 86 |
+
@property
|
| 87 |
+
def platform(self):
|
| 88 |
+
# type: () -> str
|
| 89 |
+
return self._platform
|
| 90 |
+
|
| 91 |
+
def __eq__(self, other):
|
| 92 |
+
# type: (object) -> bool
|
| 93 |
+
if not isinstance(other, Tag):
|
| 94 |
+
return NotImplemented
|
| 95 |
+
|
| 96 |
+
return (
|
| 97 |
+
(self.platform == other.platform)
|
| 98 |
+
and (self.abi == other.abi)
|
| 99 |
+
and (self.interpreter == other.interpreter)
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
def __hash__(self):
|
| 103 |
+
# type: () -> int
|
| 104 |
+
return hash((self._interpreter, self._abi, self._platform))
|
| 105 |
+
|
| 106 |
+
def __str__(self):
|
| 107 |
+
# type: () -> str
|
| 108 |
+
return "{}-{}-{}".format(self._interpreter, self._abi, self._platform)
|
| 109 |
+
|
| 110 |
+
def __repr__(self):
|
| 111 |
+
# type: () -> str
|
| 112 |
+
return "<{self} @ {self_id}>".format(self=self, self_id=id(self))
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def parse_tag(tag):
|
| 116 |
+
# type: (str) -> FrozenSet[Tag]
|
| 117 |
+
"""
|
| 118 |
+
Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances.
|
| 119 |
+
|
| 120 |
+
Returning a set is required due to the possibility that the tag is a
|
| 121 |
+
compressed tag set.
|
| 122 |
+
"""
|
| 123 |
+
tags = set()
|
| 124 |
+
interpreters, abis, platforms = tag.split("-")
|
| 125 |
+
for interpreter in interpreters.split("."):
|
| 126 |
+
for abi in abis.split("."):
|
| 127 |
+
for platform_ in platforms.split("."):
|
| 128 |
+
tags.add(Tag(interpreter, abi, platform_))
|
| 129 |
+
return frozenset(tags)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def _warn_keyword_parameter(func_name, kwargs):
|
| 133 |
+
# type: (str, Dict[str, bool]) -> bool
|
| 134 |
+
"""
|
| 135 |
+
Backwards-compatibility with Python 2.7 to allow treating 'warn' as keyword-only.
|
| 136 |
+
"""
|
| 137 |
+
if not kwargs:
|
| 138 |
+
return False
|
| 139 |
+
elif len(kwargs) > 1 or "warn" not in kwargs:
|
| 140 |
+
kwargs.pop("warn", None)
|
| 141 |
+
arg = next(iter(kwargs.keys()))
|
| 142 |
+
raise TypeError(
|
| 143 |
+
"{}() got an unexpected keyword argument {!r}".format(func_name, arg)
|
| 144 |
+
)
|
| 145 |
+
return kwargs["warn"]
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def _get_config_var(name, warn=False):
|
| 149 |
+
# type: (str, bool) -> Union[int, str, None]
|
| 150 |
+
value = sysconfig.get_config_var(name)
|
| 151 |
+
if value is None and warn:
|
| 152 |
+
logger.debug(
|
| 153 |
+
"Config variable '%s' is unset, Python ABI tag may be incorrect", name
|
| 154 |
+
)
|
| 155 |
+
return value
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def _normalize_string(string):
|
| 159 |
+
# type: (str) -> str
|
| 160 |
+
return string.replace(".", "_").replace("-", "_")
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def _abi3_applies(python_version):
|
| 164 |
+
# type: (PythonVersion) -> bool
|
| 165 |
+
"""
|
| 166 |
+
Determine if the Python version supports abi3.
|
| 167 |
+
|
| 168 |
+
PEP 384 was first implemented in Python 3.2.
|
| 169 |
+
"""
|
| 170 |
+
return len(python_version) > 1 and tuple(python_version) >= (3, 2)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def _cpython_abis(py_version, warn=False):
|
| 174 |
+
# type: (PythonVersion, bool) -> List[str]
|
| 175 |
+
py_version = tuple(py_version) # To allow for version comparison.
|
| 176 |
+
abis = []
|
| 177 |
+
version = _version_nodot(py_version[:2])
|
| 178 |
+
debug = pymalloc = ucs4 = ""
|
| 179 |
+
with_debug = _get_config_var("Py_DEBUG", warn)
|
| 180 |
+
has_refcount = hasattr(sys, "gettotalrefcount")
|
| 181 |
+
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
|
| 182 |
+
# extension modules is the best option.
|
| 183 |
+
# https://github.com/pypa/pip/issues/3383#issuecomment-173267692
|
| 184 |
+
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
|
| 185 |
+
if with_debug or (with_debug is None and (has_refcount or has_ext)):
|
| 186 |
+
debug = "d"
|
| 187 |
+
if py_version < (3, 8):
|
| 188 |
+
with_pymalloc = _get_config_var("WITH_PYMALLOC", warn)
|
| 189 |
+
if with_pymalloc or with_pymalloc is None:
|
| 190 |
+
pymalloc = "m"
|
| 191 |
+
if py_version < (3, 3):
|
| 192 |
+
unicode_size = _get_config_var("Py_UNICODE_SIZE", warn)
|
| 193 |
+
if unicode_size == 4 or (
|
| 194 |
+
unicode_size is None and sys.maxunicode == 0x10FFFF
|
| 195 |
+
):
|
| 196 |
+
ucs4 = "u"
|
| 197 |
+
elif debug:
|
| 198 |
+
# Debug builds can also load "normal" extension modules.
|
| 199 |
+
# We can also assume no UCS-4 or pymalloc requirement.
|
| 200 |
+
abis.append("cp{version}".format(version=version))
|
| 201 |
+
abis.insert(
|
| 202 |
+
0,
|
| 203 |
+
"cp{version}{debug}{pymalloc}{ucs4}".format(
|
| 204 |
+
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4
|
| 205 |
+
),
|
| 206 |
+
)
|
| 207 |
+
return abis
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def cpython_tags(
|
| 211 |
+
python_version=None, # type: Optional[PythonVersion]
|
| 212 |
+
abis=None, # type: Optional[Iterable[str]]
|
| 213 |
+
platforms=None, # type: Optional[Iterable[str]]
|
| 214 |
+
**kwargs # type: bool
|
| 215 |
+
):
|
| 216 |
+
# type: (...) -> Iterator[Tag]
|
| 217 |
+
"""
|
| 218 |
+
Yields the tags for a CPython interpreter.
|
| 219 |
+
|
| 220 |
+
The tags consist of:
|
| 221 |
+
- cp<python_version>-<abi>-<platform>
|
| 222 |
+
- cp<python_version>-abi3-<platform>
|
| 223 |
+
- cp<python_version>-none-<platform>
|
| 224 |
+
- cp<less than python_version>-abi3-<platform> # Older Python versions down to 3.2.
|
| 225 |
+
|
| 226 |
+
If python_version only specifies a major version then user-provided ABIs and
|
| 227 |
+
the 'none' ABItag will be used.
|
| 228 |
+
|
| 229 |
+
If 'abi3' or 'none' are specified in 'abis' then they will be yielded at
|
| 230 |
+
their normal position and not at the beginning.
|
| 231 |
+
"""
|
| 232 |
+
warn = _warn_keyword_parameter("cpython_tags", kwargs)
|
| 233 |
+
if not python_version:
|
| 234 |
+
python_version = sys.version_info[:2]
|
| 235 |
+
|
| 236 |
+
interpreter = "cp{}".format(_version_nodot(python_version[:2]))
|
| 237 |
+
|
| 238 |
+
if abis is None:
|
| 239 |
+
if len(python_version) > 1:
|
| 240 |
+
abis = _cpython_abis(python_version, warn)
|
| 241 |
+
else:
|
| 242 |
+
abis = []
|
| 243 |
+
abis = list(abis)
|
| 244 |
+
# 'abi3' and 'none' are explicitly handled later.
|
| 245 |
+
for explicit_abi in ("abi3", "none"):
|
| 246 |
+
try:
|
| 247 |
+
abis.remove(explicit_abi)
|
| 248 |
+
except ValueError:
|
| 249 |
+
pass
|
| 250 |
+
|
| 251 |
+
platforms = list(platforms or _platform_tags())
|
| 252 |
+
for abi in abis:
|
| 253 |
+
for platform_ in platforms:
|
| 254 |
+
yield Tag(interpreter, abi, platform_)
|
| 255 |
+
if _abi3_applies(python_version):
|
| 256 |
+
for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms):
|
| 257 |
+
yield tag
|
| 258 |
+
for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms):
|
| 259 |
+
yield tag
|
| 260 |
+
|
| 261 |
+
if _abi3_applies(python_version):
|
| 262 |
+
for minor_version in range(python_version[1] - 1, 1, -1):
|
| 263 |
+
for platform_ in platforms:
|
| 264 |
+
interpreter = "cp{version}".format(
|
| 265 |
+
version=_version_nodot((python_version[0], minor_version))
|
| 266 |
+
)
|
| 267 |
+
yield Tag(interpreter, "abi3", platform_)
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def _generic_abi():
|
| 271 |
+
# type: () -> Iterator[str]
|
| 272 |
+
abi = sysconfig.get_config_var("SOABI")
|
| 273 |
+
if abi:
|
| 274 |
+
yield _normalize_string(abi)
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
def generic_tags(
|
| 278 |
+
interpreter=None, # type: Optional[str]
|
| 279 |
+
abis=None, # type: Optional[Iterable[str]]
|
| 280 |
+
platforms=None, # type: Optional[Iterable[str]]
|
| 281 |
+
**kwargs # type: bool
|
| 282 |
+
):
|
| 283 |
+
# type: (...) -> Iterator[Tag]
|
| 284 |
+
"""
|
| 285 |
+
Yields the tags for a generic interpreter.
|
| 286 |
+
|
| 287 |
+
The tags consist of:
|
| 288 |
+
- <interpreter>-<abi>-<platform>
|
| 289 |
+
|
| 290 |
+
The "none" ABI will be added if it was not explicitly provided.
|
| 291 |
+
"""
|
| 292 |
+
warn = _warn_keyword_parameter("generic_tags", kwargs)
|
| 293 |
+
if not interpreter:
|
| 294 |
+
interp_name = interpreter_name()
|
| 295 |
+
interp_version = interpreter_version(warn=warn)
|
| 296 |
+
interpreter = "".join([interp_name, interp_version])
|
| 297 |
+
if abis is None:
|
| 298 |
+
abis = _generic_abi()
|
| 299 |
+
platforms = list(platforms or _platform_tags())
|
| 300 |
+
abis = list(abis)
|
| 301 |
+
if "none" not in abis:
|
| 302 |
+
abis.append("none")
|
| 303 |
+
for abi in abis:
|
| 304 |
+
for platform_ in platforms:
|
| 305 |
+
yield Tag(interpreter, abi, platform_)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def _py_interpreter_range(py_version):
|
| 309 |
+
# type: (PythonVersion) -> Iterator[str]
|
| 310 |
+
"""
|
| 311 |
+
Yields Python versions in descending order.
|
| 312 |
+
|
| 313 |
+
After the latest version, the major-only version will be yielded, and then
|
| 314 |
+
all previous versions of that major version.
|
| 315 |
+
"""
|
| 316 |
+
if len(py_version) > 1:
|
| 317 |
+
yield "py{version}".format(version=_version_nodot(py_version[:2]))
|
| 318 |
+
yield "py{major}".format(major=py_version[0])
|
| 319 |
+
if len(py_version) > 1:
|
| 320 |
+
for minor in range(py_version[1] - 1, -1, -1):
|
| 321 |
+
yield "py{version}".format(version=_version_nodot((py_version[0], minor)))
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
def compatible_tags(
|
| 325 |
+
python_version=None, # type: Optional[PythonVersion]
|
| 326 |
+
interpreter=None, # type: Optional[str]
|
| 327 |
+
platforms=None, # type: Optional[Iterable[str]]
|
| 328 |
+
):
|
| 329 |
+
# type: (...) -> Iterator[Tag]
|
| 330 |
+
"""
|
| 331 |
+
Yields the sequence of tags that are compatible with a specific version of Python.
|
| 332 |
+
|
| 333 |
+
The tags consist of:
|
| 334 |
+
- py*-none-<platform>
|
| 335 |
+
- <interpreter>-none-any # ... if `interpreter` is provided.
|
| 336 |
+
- py*-none-any
|
| 337 |
+
"""
|
| 338 |
+
if not python_version:
|
| 339 |
+
python_version = sys.version_info[:2]
|
| 340 |
+
platforms = list(platforms or _platform_tags())
|
| 341 |
+
for version in _py_interpreter_range(python_version):
|
| 342 |
+
for platform_ in platforms:
|
| 343 |
+
yield Tag(version, "none", platform_)
|
| 344 |
+
if interpreter:
|
| 345 |
+
yield Tag(interpreter, "none", "any")
|
| 346 |
+
for version in _py_interpreter_range(python_version):
|
| 347 |
+
yield Tag(version, "none", "any")
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
|
| 351 |
+
# type: (str, bool) -> str
|
| 352 |
+
if not is_32bit:
|
| 353 |
+
return arch
|
| 354 |
+
|
| 355 |
+
if arch.startswith("ppc"):
|
| 356 |
+
return "ppc"
|
| 357 |
+
|
| 358 |
+
return "i386"
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
def _mac_binary_formats(version, cpu_arch):
|
| 362 |
+
# type: (MacVersion, str) -> List[str]
|
| 363 |
+
formats = [cpu_arch]
|
| 364 |
+
if cpu_arch == "x86_64":
|
| 365 |
+
if version < (10, 4):
|
| 366 |
+
return []
|
| 367 |
+
formats.extend(["intel", "fat64", "fat32"])
|
| 368 |
+
|
| 369 |
+
elif cpu_arch == "i386":
|
| 370 |
+
if version < (10, 4):
|
| 371 |
+
return []
|
| 372 |
+
formats.extend(["intel", "fat32", "fat"])
|
| 373 |
+
|
| 374 |
+
elif cpu_arch == "ppc64":
|
| 375 |
+
# TODO: Need to care about 32-bit PPC for ppc64 through 10.2?
|
| 376 |
+
if version > (10, 5) or version < (10, 4):
|
| 377 |
+
return []
|
| 378 |
+
formats.append("fat64")
|
| 379 |
+
|
| 380 |
+
elif cpu_arch == "ppc":
|
| 381 |
+
if version > (10, 6):
|
| 382 |
+
return []
|
| 383 |
+
formats.extend(["fat32", "fat"])
|
| 384 |
+
|
| 385 |
+
formats.append("universal")
|
| 386 |
+
return formats
|
| 387 |
+
|
| 388 |
+
|
| 389 |
+
def mac_platforms(version=None, arch=None):
|
| 390 |
+
# type: (Optional[MacVersion], Optional[str]) -> Iterator[str]
|
| 391 |
+
"""
|
| 392 |
+
Yields the platform tags for a macOS system.
|
| 393 |
+
|
| 394 |
+
The `version` parameter is a two-item tuple specifying the macOS version to
|
| 395 |
+
generate platform tags for. The `arch` parameter is the CPU architecture to
|
| 396 |
+
generate platform tags for. Both parameters default to the appropriate value
|
| 397 |
+
for the current system.
|
| 398 |
+
"""
|
| 399 |
+
version_str, _, cpu_arch = platform.mac_ver() # type: ignore
|
| 400 |
+
if version is None:
|
| 401 |
+
version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
|
| 402 |
+
else:
|
| 403 |
+
version = version
|
| 404 |
+
if arch is None:
|
| 405 |
+
arch = _mac_arch(cpu_arch)
|
| 406 |
+
else:
|
| 407 |
+
arch = arch
|
| 408 |
+
for minor_version in range(version[1], -1, -1):
|
| 409 |
+
compat_version = version[0], minor_version
|
| 410 |
+
binary_formats = _mac_binary_formats(compat_version, arch)
|
| 411 |
+
for binary_format in binary_formats:
|
| 412 |
+
yield "macosx_{major}_{minor}_{binary_format}".format(
|
| 413 |
+
major=compat_version[0],
|
| 414 |
+
minor=compat_version[1],
|
| 415 |
+
binary_format=binary_format,
|
| 416 |
+
)
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
# From PEP 513.
|
| 420 |
+
def _is_manylinux_compatible(name, glibc_version):
|
| 421 |
+
# type: (str, GlibcVersion) -> bool
|
| 422 |
+
# Check for presence of _manylinux module.
|
| 423 |
+
try:
|
| 424 |
+
import _manylinux # noqa
|
| 425 |
+
|
| 426 |
+
return bool(getattr(_manylinux, name + "_compatible"))
|
| 427 |
+
except (ImportError, AttributeError):
|
| 428 |
+
# Fall through to heuristic check below.
|
| 429 |
+
pass
|
| 430 |
+
|
| 431 |
+
return _have_compatible_glibc(*glibc_version)
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
def _glibc_version_string():
|
| 435 |
+
# type: () -> Optional[str]
|
| 436 |
+
# Returns glibc version string, or None if not using glibc.
|
| 437 |
+
return _glibc_version_string_confstr() or _glibc_version_string_ctypes()
|
| 438 |
+
|
| 439 |
+
|
| 440 |
+
def _glibc_version_string_confstr():
|
| 441 |
+
# type: () -> Optional[str]
|
| 442 |
+
"""
|
| 443 |
+
Primary implementation of glibc_version_string using os.confstr.
|
| 444 |
+
"""
|
| 445 |
+
# os.confstr is quite a bit faster than ctypes.DLL. It's also less likely
|
| 446 |
+
# to be broken or missing. This strategy is used in the standard library
|
| 447 |
+
# platform module.
|
| 448 |
+
# https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183
|
| 449 |
+
try:
|
| 450 |
+
# os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17".
|
| 451 |
+
version_string = os.confstr( # type: ignore[attr-defined] # noqa: F821
|
| 452 |
+
"CS_GNU_LIBC_VERSION"
|
| 453 |
+
)
|
| 454 |
+
assert version_string is not None
|
| 455 |
+
_, version = version_string.split() # type: Tuple[str, str]
|
| 456 |
+
except (AssertionError, AttributeError, OSError, ValueError):
|
| 457 |
+
# os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)...
|
| 458 |
+
return None
|
| 459 |
+
return version
|
| 460 |
+
|
| 461 |
+
|
| 462 |
+
def _glibc_version_string_ctypes():
|
| 463 |
+
# type: () -> Optional[str]
|
| 464 |
+
"""
|
| 465 |
+
Fallback implementation of glibc_version_string using ctypes.
|
| 466 |
+
"""
|
| 467 |
+
try:
|
| 468 |
+
import ctypes
|
| 469 |
+
except ImportError:
|
| 470 |
+
return None
|
| 471 |
+
|
| 472 |
+
# ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
|
| 473 |
+
# manpage says, "If filename is NULL, then the returned handle is for the
|
| 474 |
+
# main program". This way we can let the linker do the work to figure out
|
| 475 |
+
# which libc our process is actually using.
|
| 476 |
+
#
|
| 477 |
+
# Note: typeshed is wrong here so we are ignoring this line.
|
| 478 |
+
process_namespace = ctypes.CDLL(None) # type: ignore
|
| 479 |
+
try:
|
| 480 |
+
gnu_get_libc_version = process_namespace.gnu_get_libc_version
|
| 481 |
+
except AttributeError:
|
| 482 |
+
# Symbol doesn't exist -> therefore, we are not linked to
|
| 483 |
+
# glibc.
|
| 484 |
+
return None
|
| 485 |
+
|
| 486 |
+
# Call gnu_get_libc_version, which returns a string like "2.5"
|
| 487 |
+
gnu_get_libc_version.restype = ctypes.c_char_p
|
| 488 |
+
version_str = gnu_get_libc_version() # type: str
|
| 489 |
+
# py2 / py3 compatibility:
|
| 490 |
+
if not isinstance(version_str, str):
|
| 491 |
+
version_str = version_str.decode("ascii")
|
| 492 |
+
|
| 493 |
+
return version_str
|
| 494 |
+
|
| 495 |
+
|
| 496 |
+
# Separated out from have_compatible_glibc for easier unit testing.
|
| 497 |
+
def _check_glibc_version(version_str, required_major, minimum_minor):
|
| 498 |
+
# type: (str, int, int) -> bool
|
| 499 |
+
# Parse string and check against requested version.
|
| 500 |
+
#
|
| 501 |
+
# We use a regexp instead of str.split because we want to discard any
|
| 502 |
+
# random junk that might come after the minor version -- this might happen
|
| 503 |
+
# in patched/forked versions of glibc (e.g. Linaro's version of glibc
|
| 504 |
+
# uses version strings like "2.20-2014.11"). See gh-3588.
|
| 505 |
+
m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
|
| 506 |
+
if not m:
|
| 507 |
+
warnings.warn(
|
| 508 |
+
"Expected glibc version with 2 components major.minor,"
|
| 509 |
+
" got: %s" % version_str,
|
| 510 |
+
RuntimeWarning,
|
| 511 |
+
)
|
| 512 |
+
return False
|
| 513 |
+
return (
|
| 514 |
+
int(m.group("major")) == required_major
|
| 515 |
+
and int(m.group("minor")) >= minimum_minor
|
| 516 |
+
)
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
def _have_compatible_glibc(required_major, minimum_minor):
|
| 520 |
+
# type: (int, int) -> bool
|
| 521 |
+
version_str = _glibc_version_string()
|
| 522 |
+
if version_str is None:
|
| 523 |
+
return False
|
| 524 |
+
return _check_glibc_version(version_str, required_major, minimum_minor)
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
# Python does not provide platform information at sufficient granularity to
|
| 528 |
+
# identify the architecture of the running executable in some cases, so we
|
| 529 |
+
# determine it dynamically by reading the information from the running
|
| 530 |
+
# process. This only applies on Linux, which uses the ELF format.
|
| 531 |
+
class _ELFFileHeader(object):
|
| 532 |
+
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
|
| 533 |
+
class _InvalidELFFileHeader(ValueError):
|
| 534 |
+
"""
|
| 535 |
+
An invalid ELF file header was found.
|
| 536 |
+
"""
|
| 537 |
+
|
| 538 |
+
ELF_MAGIC_NUMBER = 0x7F454C46
|
| 539 |
+
ELFCLASS32 = 1
|
| 540 |
+
ELFCLASS64 = 2
|
| 541 |
+
ELFDATA2LSB = 1
|
| 542 |
+
ELFDATA2MSB = 2
|
| 543 |
+
EM_386 = 3
|
| 544 |
+
EM_S390 = 22
|
| 545 |
+
EM_ARM = 40
|
| 546 |
+
EM_X86_64 = 62
|
| 547 |
+
EF_ARM_ABIMASK = 0xFF000000
|
| 548 |
+
EF_ARM_ABI_VER5 = 0x05000000
|
| 549 |
+
EF_ARM_ABI_FLOAT_HARD = 0x00000400
|
| 550 |
+
|
| 551 |
+
def __init__(self, file):
|
| 552 |
+
# type: (IO[bytes]) -> None
|
| 553 |
+
def unpack(fmt):
|
| 554 |
+
# type: (str) -> int
|
| 555 |
+
try:
|
| 556 |
+
(result,) = struct.unpack(
|
| 557 |
+
fmt, file.read(struct.calcsize(fmt))
|
| 558 |
+
) # type: (int, )
|
| 559 |
+
except struct.error:
|
| 560 |
+
raise _ELFFileHeader._InvalidELFFileHeader()
|
| 561 |
+
return result
|
| 562 |
+
|
| 563 |
+
self.e_ident_magic = unpack(">I")
|
| 564 |
+
if self.e_ident_magic != self.ELF_MAGIC_NUMBER:
|
| 565 |
+
raise _ELFFileHeader._InvalidELFFileHeader()
|
| 566 |
+
self.e_ident_class = unpack("B")
|
| 567 |
+
if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}:
|
| 568 |
+
raise _ELFFileHeader._InvalidELFFileHeader()
|
| 569 |
+
self.e_ident_data = unpack("B")
|
| 570 |
+
if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}:
|
| 571 |
+
raise _ELFFileHeader._InvalidELFFileHeader()
|
| 572 |
+
self.e_ident_version = unpack("B")
|
| 573 |
+
self.e_ident_osabi = unpack("B")
|
| 574 |
+
self.e_ident_abiversion = unpack("B")
|
| 575 |
+
self.e_ident_pad = file.read(7)
|
| 576 |
+
format_h = "<H" if self.e_ident_data == self.ELFDATA2LSB else ">H"
|
| 577 |
+
format_i = "<I" if self.e_ident_data == self.ELFDATA2LSB else ">I"
|
| 578 |
+
format_q = "<Q" if self.e_ident_data == self.ELFDATA2LSB else ">Q"
|
| 579 |
+
format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q
|
| 580 |
+
self.e_type = unpack(format_h)
|
| 581 |
+
self.e_machine = unpack(format_h)
|
| 582 |
+
self.e_version = unpack(format_i)
|
| 583 |
+
self.e_entry = unpack(format_p)
|
| 584 |
+
self.e_phoff = unpack(format_p)
|
| 585 |
+
self.e_shoff = unpack(format_p)
|
| 586 |
+
self.e_flags = unpack(format_i)
|
| 587 |
+
self.e_ehsize = unpack(format_h)
|
| 588 |
+
self.e_phentsize = unpack(format_h)
|
| 589 |
+
self.e_phnum = unpack(format_h)
|
| 590 |
+
self.e_shentsize = unpack(format_h)
|
| 591 |
+
self.e_shnum = unpack(format_h)
|
| 592 |
+
self.e_shstrndx = unpack(format_h)
|
| 593 |
+
|
| 594 |
+
|
| 595 |
+
def _get_elf_header():
|
| 596 |
+
# type: () -> Optional[_ELFFileHeader]
|
| 597 |
+
try:
|
| 598 |
+
with open(sys.executable, "rb") as f:
|
| 599 |
+
elf_header = _ELFFileHeader(f)
|
| 600 |
+
except (IOError, OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
|
| 601 |
+
return None
|
| 602 |
+
return elf_header
|
| 603 |
+
|
| 604 |
+
|
| 605 |
+
def _is_linux_armhf():
|
| 606 |
+
# type: () -> bool
|
| 607 |
+
# hard-float ABI can be detected from the ELF header of the running
|
| 608 |
+
# process
|
| 609 |
+
# https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
|
| 610 |
+
elf_header = _get_elf_header()
|
| 611 |
+
if elf_header is None:
|
| 612 |
+
return False
|
| 613 |
+
result = elf_header.e_ident_class == elf_header.ELFCLASS32
|
| 614 |
+
result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB
|
| 615 |
+
result &= elf_header.e_machine == elf_header.EM_ARM
|
| 616 |
+
result &= (
|
| 617 |
+
elf_header.e_flags & elf_header.EF_ARM_ABIMASK
|
| 618 |
+
) == elf_header.EF_ARM_ABI_VER5
|
| 619 |
+
result &= (
|
| 620 |
+
elf_header.e_flags & elf_header.EF_ARM_ABI_FLOAT_HARD
|
| 621 |
+
) == elf_header.EF_ARM_ABI_FLOAT_HARD
|
| 622 |
+
return result
|
| 623 |
+
|
| 624 |
+
|
| 625 |
+
def _is_linux_i686():
|
| 626 |
+
# type: () -> bool
|
| 627 |
+
elf_header = _get_elf_header()
|
| 628 |
+
if elf_header is None:
|
| 629 |
+
return False
|
| 630 |
+
result = elf_header.e_ident_class == elf_header.ELFCLASS32
|
| 631 |
+
result &= elf_header.e_ident_data == elf_header.ELFDATA2LSB
|
| 632 |
+
result &= elf_header.e_machine == elf_header.EM_386
|
| 633 |
+
return result
|
| 634 |
+
|
| 635 |
+
|
| 636 |
+
def _have_compatible_manylinux_abi(arch):
|
| 637 |
+
# type: (str) -> bool
|
| 638 |
+
if arch == "armv7l":
|
| 639 |
+
return _is_linux_armhf()
|
| 640 |
+
if arch == "i686":
|
| 641 |
+
return _is_linux_i686()
|
| 642 |
+
return True
|
| 643 |
+
|
| 644 |
+
|
| 645 |
+
def _linux_platforms(is_32bit=_32_BIT_INTERPRETER):
|
| 646 |
+
# type: (bool) -> Iterator[str]
|
| 647 |
+
linux = _normalize_string(distutils.util.get_platform())
|
| 648 |
+
if is_32bit:
|
| 649 |
+
if linux == "linux_x86_64":
|
| 650 |
+
linux = "linux_i686"
|
| 651 |
+
elif linux == "linux_aarch64":
|
| 652 |
+
linux = "linux_armv7l"
|
| 653 |
+
manylinux_support = []
|
| 654 |
+
_, arch = linux.split("_", 1)
|
| 655 |
+
if _have_compatible_manylinux_abi(arch):
|
| 656 |
+
if arch in {"x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"}:
|
| 657 |
+
manylinux_support.append(
|
| 658 |
+
("manylinux2014", (2, 17))
|
| 659 |
+
) # CentOS 7 w/ glibc 2.17 (PEP 599)
|
| 660 |
+
if arch in {"x86_64", "i686"}:
|
| 661 |
+
manylinux_support.append(
|
| 662 |
+
("manylinux2010", (2, 12))
|
| 663 |
+
) # CentOS 6 w/ glibc 2.12 (PEP 571)
|
| 664 |
+
manylinux_support.append(
|
| 665 |
+
("manylinux1", (2, 5))
|
| 666 |
+
) # CentOS 5 w/ glibc 2.5 (PEP 513)
|
| 667 |
+
manylinux_support_iter = iter(manylinux_support)
|
| 668 |
+
for name, glibc_version in manylinux_support_iter:
|
| 669 |
+
if _is_manylinux_compatible(name, glibc_version):
|
| 670 |
+
yield linux.replace("linux", name)
|
| 671 |
+
break
|
| 672 |
+
# Support for a later manylinux implies support for an earlier version.
|
| 673 |
+
for name, _ in manylinux_support_iter:
|
| 674 |
+
yield linux.replace("linux", name)
|
| 675 |
+
yield linux
|
| 676 |
+
|
| 677 |
+
|
| 678 |
+
def _generic_platforms():
|
| 679 |
+
# type: () -> Iterator[str]
|
| 680 |
+
yield _normalize_string(distutils.util.get_platform())
|
| 681 |
+
|
| 682 |
+
|
| 683 |
+
def _platform_tags():
|
| 684 |
+
# type: () -> Iterator[str]
|
| 685 |
+
"""
|
| 686 |
+
Provides the platform tags for this installation.
|
| 687 |
+
"""
|
| 688 |
+
if platform.system() == "Darwin":
|
| 689 |
+
return mac_platforms()
|
| 690 |
+
elif platform.system() == "Linux":
|
| 691 |
+
return _linux_platforms()
|
| 692 |
+
else:
|
| 693 |
+
return _generic_platforms()
|
| 694 |
+
|
| 695 |
+
|
| 696 |
+
def interpreter_name():
|
| 697 |
+
# type: () -> str
|
| 698 |
+
"""
|
| 699 |
+
Returns the name of the running interpreter.
|
| 700 |
+
"""
|
| 701 |
+
try:
|
| 702 |
+
name = sys.implementation.name # type: ignore
|
| 703 |
+
except AttributeError: # pragma: no cover
|
| 704 |
+
# Python 2.7 compatibility.
|
| 705 |
+
name = platform.python_implementation().lower()
|
| 706 |
+
return INTERPRETER_SHORT_NAMES.get(name) or name
|
| 707 |
+
|
| 708 |
+
|
| 709 |
+
def interpreter_version(**kwargs):
|
| 710 |
+
# type: (bool) -> str
|
| 711 |
+
"""
|
| 712 |
+
Returns the version of the running interpreter.
|
| 713 |
+
"""
|
| 714 |
+
warn = _warn_keyword_parameter("interpreter_version", kwargs)
|
| 715 |
+
version = _get_config_var("py_version_nodot", warn=warn)
|
| 716 |
+
if version:
|
| 717 |
+
version = str(version)
|
| 718 |
+
else:
|
| 719 |
+
version = _version_nodot(sys.version_info[:2])
|
| 720 |
+
return version
|
| 721 |
+
|
| 722 |
+
|
| 723 |
+
def _version_nodot(version):
|
| 724 |
+
# type: (PythonVersion) -> str
|
| 725 |
+
if any(v >= 10 for v in version):
|
| 726 |
+
sep = "_"
|
| 727 |
+
else:
|
| 728 |
+
sep = ""
|
| 729 |
+
return sep.join(map(str, version))
|
| 730 |
+
|
| 731 |
+
|
| 732 |
+
def sys_tags(**kwargs):
|
| 733 |
+
# type: (bool) -> Iterator[Tag]
|
| 734 |
+
"""
|
| 735 |
+
Returns the sequence of tag triples for the running interpreter.
|
| 736 |
+
|
| 737 |
+
The order of the sequence corresponds to priority order for the
|
| 738 |
+
interpreter, from most to least important.
|
| 739 |
+
"""
|
| 740 |
+
warn = _warn_keyword_parameter("sys_tags", kwargs)
|
| 741 |
+
|
| 742 |
+
interp_name = interpreter_name()
|
| 743 |
+
if interp_name == "cp":
|
| 744 |
+
for tag in cpython_tags(warn=warn):
|
| 745 |
+
yield tag
|
| 746 |
+
else:
|
| 747 |
+
for tag in generic_tags():
|
| 748 |
+
yield tag
|
| 749 |
+
|
| 750 |
+
for tag in compatible_tags():
|
| 751 |
+
yield tag
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/utils.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
import re
|
| 7 |
+
|
| 8 |
+
from ._typing import TYPE_CHECKING, cast
|
| 9 |
+
from .version import InvalidVersion, Version
|
| 10 |
+
|
| 11 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 12 |
+
from typing import NewType, Union
|
| 13 |
+
|
| 14 |
+
NormalizedName = NewType("NormalizedName", str)
|
| 15 |
+
|
| 16 |
+
_canonicalize_regex = re.compile(r"[-_.]+")
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def canonicalize_name(name):
|
| 20 |
+
# type: (str) -> NormalizedName
|
| 21 |
+
# This is taken from PEP 503.
|
| 22 |
+
value = _canonicalize_regex.sub("-", name).lower()
|
| 23 |
+
return cast("NormalizedName", value)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def canonicalize_version(_version):
|
| 27 |
+
# type: (str) -> Union[Version, str]
|
| 28 |
+
"""
|
| 29 |
+
This is very similar to Version.__str__, but has one subtle difference
|
| 30 |
+
with the way it handles the release segment.
|
| 31 |
+
"""
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
version = Version(_version)
|
| 35 |
+
except InvalidVersion:
|
| 36 |
+
# Legacy versions cannot be normalized
|
| 37 |
+
return _version
|
| 38 |
+
|
| 39 |
+
parts = []
|
| 40 |
+
|
| 41 |
+
# Epoch
|
| 42 |
+
if version.epoch != 0:
|
| 43 |
+
parts.append("{0}!".format(version.epoch))
|
| 44 |
+
|
| 45 |
+
# Release segment
|
| 46 |
+
# NB: This strips trailing '.0's to normalize
|
| 47 |
+
parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
|
| 48 |
+
|
| 49 |
+
# Pre-release
|
| 50 |
+
if version.pre is not None:
|
| 51 |
+
parts.append("".join(str(x) for x in version.pre))
|
| 52 |
+
|
| 53 |
+
# Post-release
|
| 54 |
+
if version.post is not None:
|
| 55 |
+
parts.append(".post{0}".format(version.post))
|
| 56 |
+
|
| 57 |
+
# Development release
|
| 58 |
+
if version.dev is not None:
|
| 59 |
+
parts.append(".dev{0}".format(version.dev))
|
| 60 |
+
|
| 61 |
+
# Local version segment
|
| 62 |
+
if version.local is not None:
|
| 63 |
+
parts.append("+{0}".format(version.local))
|
| 64 |
+
|
| 65 |
+
return "".join(parts)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/packaging/version.py
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is dual licensed under the terms of the Apache License, Version
|
| 2 |
+
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
|
| 3 |
+
# for complete details.
|
| 4 |
+
from __future__ import absolute_import, division, print_function
|
| 5 |
+
|
| 6 |
+
import collections
|
| 7 |
+
import itertools
|
| 8 |
+
import re
|
| 9 |
+
|
| 10 |
+
from ._structures import Infinity, NegativeInfinity
|
| 11 |
+
from ._typing import TYPE_CHECKING
|
| 12 |
+
|
| 13 |
+
if TYPE_CHECKING: # pragma: no cover
|
| 14 |
+
from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union
|
| 15 |
+
|
| 16 |
+
from ._structures import InfinityType, NegativeInfinityType
|
| 17 |
+
|
| 18 |
+
InfiniteTypes = Union[InfinityType, NegativeInfinityType]
|
| 19 |
+
PrePostDevType = Union[InfiniteTypes, Tuple[str, int]]
|
| 20 |
+
SubLocalType = Union[InfiniteTypes, int, str]
|
| 21 |
+
LocalType = Union[
|
| 22 |
+
NegativeInfinityType,
|
| 23 |
+
Tuple[
|
| 24 |
+
Union[
|
| 25 |
+
SubLocalType,
|
| 26 |
+
Tuple[SubLocalType, str],
|
| 27 |
+
Tuple[NegativeInfinityType, SubLocalType],
|
| 28 |
+
],
|
| 29 |
+
...,
|
| 30 |
+
],
|
| 31 |
+
]
|
| 32 |
+
CmpKey = Tuple[
|
| 33 |
+
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType
|
| 34 |
+
]
|
| 35 |
+
LegacyCmpKey = Tuple[int, Tuple[str, ...]]
|
| 36 |
+
VersionComparisonMethod = Callable[
|
| 37 |
+
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
_Version = collections.namedtuple(
|
| 44 |
+
"_Version", ["epoch", "release", "dev", "pre", "post", "local"]
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def parse(version):
|
| 49 |
+
# type: (str) -> Union[LegacyVersion, Version]
|
| 50 |
+
"""
|
| 51 |
+
Parse the given version string and return either a :class:`Version` object
|
| 52 |
+
or a :class:`LegacyVersion` object depending on if the given version is
|
| 53 |
+
a valid PEP 440 version or a legacy version.
|
| 54 |
+
"""
|
| 55 |
+
try:
|
| 56 |
+
return Version(version)
|
| 57 |
+
except InvalidVersion:
|
| 58 |
+
return LegacyVersion(version)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
class InvalidVersion(ValueError):
|
| 62 |
+
"""
|
| 63 |
+
An invalid version was found, users should refer to PEP 440.
|
| 64 |
+
"""
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class _BaseVersion(object):
|
| 68 |
+
_key = None # type: Union[CmpKey, LegacyCmpKey]
|
| 69 |
+
|
| 70 |
+
def __hash__(self):
|
| 71 |
+
# type: () -> int
|
| 72 |
+
return hash(self._key)
|
| 73 |
+
|
| 74 |
+
def __lt__(self, other):
|
| 75 |
+
# type: (_BaseVersion) -> bool
|
| 76 |
+
return self._compare(other, lambda s, o: s < o)
|
| 77 |
+
|
| 78 |
+
def __le__(self, other):
|
| 79 |
+
# type: (_BaseVersion) -> bool
|
| 80 |
+
return self._compare(other, lambda s, o: s <= o)
|
| 81 |
+
|
| 82 |
+
def __eq__(self, other):
|
| 83 |
+
# type: (object) -> bool
|
| 84 |
+
return self._compare(other, lambda s, o: s == o)
|
| 85 |
+
|
| 86 |
+
def __ge__(self, other):
|
| 87 |
+
# type: (_BaseVersion) -> bool
|
| 88 |
+
return self._compare(other, lambda s, o: s >= o)
|
| 89 |
+
|
| 90 |
+
def __gt__(self, other):
|
| 91 |
+
# type: (_BaseVersion) -> bool
|
| 92 |
+
return self._compare(other, lambda s, o: s > o)
|
| 93 |
+
|
| 94 |
+
def __ne__(self, other):
|
| 95 |
+
# type: (object) -> bool
|
| 96 |
+
return self._compare(other, lambda s, o: s != o)
|
| 97 |
+
|
| 98 |
+
def _compare(self, other, method):
|
| 99 |
+
# type: (object, VersionComparisonMethod) -> Union[bool, NotImplemented]
|
| 100 |
+
if not isinstance(other, _BaseVersion):
|
| 101 |
+
return NotImplemented
|
| 102 |
+
|
| 103 |
+
return method(self._key, other._key)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
class LegacyVersion(_BaseVersion):
|
| 107 |
+
def __init__(self, version):
|
| 108 |
+
# type: (str) -> None
|
| 109 |
+
self._version = str(version)
|
| 110 |
+
self._key = _legacy_cmpkey(self._version)
|
| 111 |
+
|
| 112 |
+
def __str__(self):
|
| 113 |
+
# type: () -> str
|
| 114 |
+
return self._version
|
| 115 |
+
|
| 116 |
+
def __repr__(self):
|
| 117 |
+
# type: () -> str
|
| 118 |
+
return "<LegacyVersion({0})>".format(repr(str(self)))
|
| 119 |
+
|
| 120 |
+
@property
|
| 121 |
+
def public(self):
|
| 122 |
+
# type: () -> str
|
| 123 |
+
return self._version
|
| 124 |
+
|
| 125 |
+
@property
|
| 126 |
+
def base_version(self):
|
| 127 |
+
# type: () -> str
|
| 128 |
+
return self._version
|
| 129 |
+
|
| 130 |
+
@property
|
| 131 |
+
def epoch(self):
|
| 132 |
+
# type: () -> int
|
| 133 |
+
return -1
|
| 134 |
+
|
| 135 |
+
@property
|
| 136 |
+
def release(self):
|
| 137 |
+
# type: () -> None
|
| 138 |
+
return None
|
| 139 |
+
|
| 140 |
+
@property
|
| 141 |
+
def pre(self):
|
| 142 |
+
# type: () -> None
|
| 143 |
+
return None
|
| 144 |
+
|
| 145 |
+
@property
|
| 146 |
+
def post(self):
|
| 147 |
+
# type: () -> None
|
| 148 |
+
return None
|
| 149 |
+
|
| 150 |
+
@property
|
| 151 |
+
def dev(self):
|
| 152 |
+
# type: () -> None
|
| 153 |
+
return None
|
| 154 |
+
|
| 155 |
+
@property
|
| 156 |
+
def local(self):
|
| 157 |
+
# type: () -> None
|
| 158 |
+
return None
|
| 159 |
+
|
| 160 |
+
@property
|
| 161 |
+
def is_prerelease(self):
|
| 162 |
+
# type: () -> bool
|
| 163 |
+
return False
|
| 164 |
+
|
| 165 |
+
@property
|
| 166 |
+
def is_postrelease(self):
|
| 167 |
+
# type: () -> bool
|
| 168 |
+
return False
|
| 169 |
+
|
| 170 |
+
@property
|
| 171 |
+
def is_devrelease(self):
|
| 172 |
+
# type: () -> bool
|
| 173 |
+
return False
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
|
| 177 |
+
|
| 178 |
+
_legacy_version_replacement_map = {
|
| 179 |
+
"pre": "c",
|
| 180 |
+
"preview": "c",
|
| 181 |
+
"-": "final-",
|
| 182 |
+
"rc": "c",
|
| 183 |
+
"dev": "@",
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def _parse_version_parts(s):
|
| 188 |
+
# type: (str) -> Iterator[str]
|
| 189 |
+
for part in _legacy_version_component_re.split(s):
|
| 190 |
+
part = _legacy_version_replacement_map.get(part, part)
|
| 191 |
+
|
| 192 |
+
if not part or part == ".":
|
| 193 |
+
continue
|
| 194 |
+
|
| 195 |
+
if part[:1] in "0123456789":
|
| 196 |
+
# pad for numeric comparison
|
| 197 |
+
yield part.zfill(8)
|
| 198 |
+
else:
|
| 199 |
+
yield "*" + part
|
| 200 |
+
|
| 201 |
+
# ensure that alpha/beta/candidate are before final
|
| 202 |
+
yield "*final"
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
def _legacy_cmpkey(version):
|
| 206 |
+
# type: (str) -> LegacyCmpKey
|
| 207 |
+
|
| 208 |
+
# We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
|
| 209 |
+
# greater than or equal to 0. This will effectively put the LegacyVersion,
|
| 210 |
+
# which uses the defacto standard originally implemented by setuptools,
|
| 211 |
+
# as before all PEP 440 versions.
|
| 212 |
+
epoch = -1
|
| 213 |
+
|
| 214 |
+
# This scheme is taken from pkg_resources.parse_version setuptools prior to
|
| 215 |
+
# it's adoption of the packaging library.
|
| 216 |
+
parts = [] # type: List[str]
|
| 217 |
+
for part in _parse_version_parts(version.lower()):
|
| 218 |
+
if part.startswith("*"):
|
| 219 |
+
# remove "-" before a prerelease tag
|
| 220 |
+
if part < "*final":
|
| 221 |
+
while parts and parts[-1] == "*final-":
|
| 222 |
+
parts.pop()
|
| 223 |
+
|
| 224 |
+
# remove trailing zeros from each series of numeric parts
|
| 225 |
+
while parts and parts[-1] == "00000000":
|
| 226 |
+
parts.pop()
|
| 227 |
+
|
| 228 |
+
parts.append(part)
|
| 229 |
+
|
| 230 |
+
return epoch, tuple(parts)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
# Deliberately not anchored to the start and end of the string, to make it
|
| 234 |
+
# easier for 3rd party code to reuse
|
| 235 |
+
VERSION_PATTERN = r"""
|
| 236 |
+
v?
|
| 237 |
+
(?:
|
| 238 |
+
(?:(?P<epoch>[0-9]+)!)? # epoch
|
| 239 |
+
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
|
| 240 |
+
(?P<pre> # pre-release
|
| 241 |
+
[-_\.]?
|
| 242 |
+
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
|
| 243 |
+
[-_\.]?
|
| 244 |
+
(?P<pre_n>[0-9]+)?
|
| 245 |
+
)?
|
| 246 |
+
(?P<post> # post release
|
| 247 |
+
(?:-(?P<post_n1>[0-9]+))
|
| 248 |
+
|
|
| 249 |
+
(?:
|
| 250 |
+
[-_\.]?
|
| 251 |
+
(?P<post_l>post|rev|r)
|
| 252 |
+
[-_\.]?
|
| 253 |
+
(?P<post_n2>[0-9]+)?
|
| 254 |
+
)
|
| 255 |
+
)?
|
| 256 |
+
(?P<dev> # dev release
|
| 257 |
+
[-_\.]?
|
| 258 |
+
(?P<dev_l>dev)
|
| 259 |
+
[-_\.]?
|
| 260 |
+
(?P<dev_n>[0-9]+)?
|
| 261 |
+
)?
|
| 262 |
+
)
|
| 263 |
+
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
|
| 264 |
+
"""
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
class Version(_BaseVersion):
|
| 268 |
+
|
| 269 |
+
_regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
|
| 270 |
+
|
| 271 |
+
def __init__(self, version):
|
| 272 |
+
# type: (str) -> None
|
| 273 |
+
|
| 274 |
+
# Validate the version and parse it into pieces
|
| 275 |
+
match = self._regex.search(version)
|
| 276 |
+
if not match:
|
| 277 |
+
raise InvalidVersion("Invalid version: '{0}'".format(version))
|
| 278 |
+
|
| 279 |
+
# Store the parsed out pieces of the version
|
| 280 |
+
self._version = _Version(
|
| 281 |
+
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
|
| 282 |
+
release=tuple(int(i) for i in match.group("release").split(".")),
|
| 283 |
+
pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
|
| 284 |
+
post=_parse_letter_version(
|
| 285 |
+
match.group("post_l"), match.group("post_n1") or match.group("post_n2")
|
| 286 |
+
),
|
| 287 |
+
dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
|
| 288 |
+
local=_parse_local_version(match.group("local")),
|
| 289 |
+
)
|
| 290 |
+
|
| 291 |
+
# Generate a key which will be used for sorting
|
| 292 |
+
self._key = _cmpkey(
|
| 293 |
+
self._version.epoch,
|
| 294 |
+
self._version.release,
|
| 295 |
+
self._version.pre,
|
| 296 |
+
self._version.post,
|
| 297 |
+
self._version.dev,
|
| 298 |
+
self._version.local,
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
def __repr__(self):
|
| 302 |
+
# type: () -> str
|
| 303 |
+
return "<Version({0})>".format(repr(str(self)))
|
| 304 |
+
|
| 305 |
+
def __str__(self):
|
| 306 |
+
# type: () -> str
|
| 307 |
+
parts = []
|
| 308 |
+
|
| 309 |
+
# Epoch
|
| 310 |
+
if self.epoch != 0:
|
| 311 |
+
parts.append("{0}!".format(self.epoch))
|
| 312 |
+
|
| 313 |
+
# Release segment
|
| 314 |
+
parts.append(".".join(str(x) for x in self.release))
|
| 315 |
+
|
| 316 |
+
# Pre-release
|
| 317 |
+
if self.pre is not None:
|
| 318 |
+
parts.append("".join(str(x) for x in self.pre))
|
| 319 |
+
|
| 320 |
+
# Post-release
|
| 321 |
+
if self.post is not None:
|
| 322 |
+
parts.append(".post{0}".format(self.post))
|
| 323 |
+
|
| 324 |
+
# Development release
|
| 325 |
+
if self.dev is not None:
|
| 326 |
+
parts.append(".dev{0}".format(self.dev))
|
| 327 |
+
|
| 328 |
+
# Local version segment
|
| 329 |
+
if self.local is not None:
|
| 330 |
+
parts.append("+{0}".format(self.local))
|
| 331 |
+
|
| 332 |
+
return "".join(parts)
|
| 333 |
+
|
| 334 |
+
@property
|
| 335 |
+
def epoch(self):
|
| 336 |
+
# type: () -> int
|
| 337 |
+
_epoch = self._version.epoch # type: int
|
| 338 |
+
return _epoch
|
| 339 |
+
|
| 340 |
+
@property
|
| 341 |
+
def release(self):
|
| 342 |
+
# type: () -> Tuple[int, ...]
|
| 343 |
+
_release = self._version.release # type: Tuple[int, ...]
|
| 344 |
+
return _release
|
| 345 |
+
|
| 346 |
+
@property
|
| 347 |
+
def pre(self):
|
| 348 |
+
# type: () -> Optional[Tuple[str, int]]
|
| 349 |
+
_pre = self._version.pre # type: Optional[Tuple[str, int]]
|
| 350 |
+
return _pre
|
| 351 |
+
|
| 352 |
+
@property
|
| 353 |
+
def post(self):
|
| 354 |
+
# type: () -> Optional[Tuple[str, int]]
|
| 355 |
+
return self._version.post[1] if self._version.post else None
|
| 356 |
+
|
| 357 |
+
@property
|
| 358 |
+
def dev(self):
|
| 359 |
+
# type: () -> Optional[Tuple[str, int]]
|
| 360 |
+
return self._version.dev[1] if self._version.dev else None
|
| 361 |
+
|
| 362 |
+
@property
|
| 363 |
+
def local(self):
|
| 364 |
+
# type: () -> Optional[str]
|
| 365 |
+
if self._version.local:
|
| 366 |
+
return ".".join(str(x) for x in self._version.local)
|
| 367 |
+
else:
|
| 368 |
+
return None
|
| 369 |
+
|
| 370 |
+
@property
|
| 371 |
+
def public(self):
|
| 372 |
+
# type: () -> str
|
| 373 |
+
return str(self).split("+", 1)[0]
|
| 374 |
+
|
| 375 |
+
@property
|
| 376 |
+
def base_version(self):
|
| 377 |
+
# type: () -> str
|
| 378 |
+
parts = []
|
| 379 |
+
|
| 380 |
+
# Epoch
|
| 381 |
+
if self.epoch != 0:
|
| 382 |
+
parts.append("{0}!".format(self.epoch))
|
| 383 |
+
|
| 384 |
+
# Release segment
|
| 385 |
+
parts.append(".".join(str(x) for x in self.release))
|
| 386 |
+
|
| 387 |
+
return "".join(parts)
|
| 388 |
+
|
| 389 |
+
@property
|
| 390 |
+
def is_prerelease(self):
|
| 391 |
+
# type: () -> bool
|
| 392 |
+
return self.dev is not None or self.pre is not None
|
| 393 |
+
|
| 394 |
+
@property
|
| 395 |
+
def is_postrelease(self):
|
| 396 |
+
# type: () -> bool
|
| 397 |
+
return self.post is not None
|
| 398 |
+
|
| 399 |
+
@property
|
| 400 |
+
def is_devrelease(self):
|
| 401 |
+
# type: () -> bool
|
| 402 |
+
return self.dev is not None
|
| 403 |
+
|
| 404 |
+
@property
|
| 405 |
+
def major(self):
|
| 406 |
+
# type: () -> int
|
| 407 |
+
return self.release[0] if len(self.release) >= 1 else 0
|
| 408 |
+
|
| 409 |
+
@property
|
| 410 |
+
def minor(self):
|
| 411 |
+
# type: () -> int
|
| 412 |
+
return self.release[1] if len(self.release) >= 2 else 0
|
| 413 |
+
|
| 414 |
+
@property
|
| 415 |
+
def micro(self):
|
| 416 |
+
# type: () -> int
|
| 417 |
+
return self.release[2] if len(self.release) >= 3 else 0
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
def _parse_letter_version(
|
| 421 |
+
letter, # type: str
|
| 422 |
+
number, # type: Union[str, bytes, SupportsInt]
|
| 423 |
+
):
|
| 424 |
+
# type: (...) -> Optional[Tuple[str, int]]
|
| 425 |
+
|
| 426 |
+
if letter:
|
| 427 |
+
# We consider there to be an implicit 0 in a pre-release if there is
|
| 428 |
+
# not a numeral associated with it.
|
| 429 |
+
if number is None:
|
| 430 |
+
number = 0
|
| 431 |
+
|
| 432 |
+
# We normalize any letters to their lower case form
|
| 433 |
+
letter = letter.lower()
|
| 434 |
+
|
| 435 |
+
# We consider some words to be alternate spellings of other words and
|
| 436 |
+
# in those cases we want to normalize the spellings to our preferred
|
| 437 |
+
# spelling.
|
| 438 |
+
if letter == "alpha":
|
| 439 |
+
letter = "a"
|
| 440 |
+
elif letter == "beta":
|
| 441 |
+
letter = "b"
|
| 442 |
+
elif letter in ["c", "pre", "preview"]:
|
| 443 |
+
letter = "rc"
|
| 444 |
+
elif letter in ["rev", "r"]:
|
| 445 |
+
letter = "post"
|
| 446 |
+
|
| 447 |
+
return letter, int(number)
|
| 448 |
+
if not letter and number:
|
| 449 |
+
# We assume if we are given a number, but we are not given a letter
|
| 450 |
+
# then this is using the implicit post release syntax (e.g. 1.0-1)
|
| 451 |
+
letter = "post"
|
| 452 |
+
|
| 453 |
+
return letter, int(number)
|
| 454 |
+
|
| 455 |
+
return None
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
_local_version_separators = re.compile(r"[\._-]")
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
def _parse_local_version(local):
|
| 462 |
+
# type: (str) -> Optional[LocalType]
|
| 463 |
+
"""
|
| 464 |
+
Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
|
| 465 |
+
"""
|
| 466 |
+
if local is not None:
|
| 467 |
+
return tuple(
|
| 468 |
+
part.lower() if not part.isdigit() else int(part)
|
| 469 |
+
for part in _local_version_separators.split(local)
|
| 470 |
+
)
|
| 471 |
+
return None
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def _cmpkey(
|
| 475 |
+
epoch, # type: int
|
| 476 |
+
release, # type: Tuple[int, ...]
|
| 477 |
+
pre, # type: Optional[Tuple[str, int]]
|
| 478 |
+
post, # type: Optional[Tuple[str, int]]
|
| 479 |
+
dev, # type: Optional[Tuple[str, int]]
|
| 480 |
+
local, # type: Optional[Tuple[SubLocalType]]
|
| 481 |
+
):
|
| 482 |
+
# type: (...) -> CmpKey
|
| 483 |
+
|
| 484 |
+
# When we compare a release version, we want to compare it with all of the
|
| 485 |
+
# trailing zeros removed. So we'll use a reverse the list, drop all the now
|
| 486 |
+
# leading zeros until we come to something non zero, then take the rest
|
| 487 |
+
# re-reverse it back into the correct order and make it a tuple and use
|
| 488 |
+
# that for our sorting key.
|
| 489 |
+
_release = tuple(
|
| 490 |
+
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
|
| 491 |
+
)
|
| 492 |
+
|
| 493 |
+
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
|
| 494 |
+
# We'll do this by abusing the pre segment, but we _only_ want to do this
|
| 495 |
+
# if there is not a pre or a post segment. If we have one of those then
|
| 496 |
+
# the normal sorting rules will handle this case correctly.
|
| 497 |
+
if pre is None and post is None and dev is not None:
|
| 498 |
+
_pre = NegativeInfinity # type: PrePostDevType
|
| 499 |
+
# Versions without a pre-release (except as noted above) should sort after
|
| 500 |
+
# those with one.
|
| 501 |
+
elif pre is None:
|
| 502 |
+
_pre = Infinity
|
| 503 |
+
else:
|
| 504 |
+
_pre = pre
|
| 505 |
+
|
| 506 |
+
# Versions without a post segment should sort before those with one.
|
| 507 |
+
if post is None:
|
| 508 |
+
_post = NegativeInfinity # type: PrePostDevType
|
| 509 |
+
|
| 510 |
+
else:
|
| 511 |
+
_post = post
|
| 512 |
+
|
| 513 |
+
# Versions without a development segment should sort after those with one.
|
| 514 |
+
if dev is None:
|
| 515 |
+
_dev = Infinity # type: PrePostDevType
|
| 516 |
+
|
| 517 |
+
else:
|
| 518 |
+
_dev = dev
|
| 519 |
+
|
| 520 |
+
if local is None:
|
| 521 |
+
# Versions without a local segment should sort before those with one.
|
| 522 |
+
_local = NegativeInfinity # type: LocalType
|
| 523 |
+
else:
|
| 524 |
+
# Versions with a local segment need that segment parsed to implement
|
| 525 |
+
# the sorting rules in PEP440.
|
| 526 |
+
# - Alpha numeric segments sort before numeric segments
|
| 527 |
+
# - Alpha numeric segments sort lexicographically
|
| 528 |
+
# - Numeric segments sort numerically
|
| 529 |
+
# - Shorter versions sort before longer versions when the prefixes
|
| 530 |
+
# match exactly
|
| 531 |
+
_local = tuple(
|
| 532 |
+
(i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
|
| 533 |
+
)
|
| 534 |
+
|
| 535 |
+
return epoch, _release, _pre, _post, _dev, _local
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/_vendor/pyparsing.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/archive_util.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Utilities for extracting common archive formats"""
|
| 2 |
+
|
| 3 |
+
import zipfile
|
| 4 |
+
import tarfile
|
| 5 |
+
import os
|
| 6 |
+
import shutil
|
| 7 |
+
import posixpath
|
| 8 |
+
import contextlib
|
| 9 |
+
from distutils.errors import DistutilsError
|
| 10 |
+
|
| 11 |
+
from pkg_resources import ensure_directory
|
| 12 |
+
|
| 13 |
+
__all__ = [
|
| 14 |
+
"unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
|
| 15 |
+
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
|
| 16 |
+
]
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class UnrecognizedFormat(DistutilsError):
|
| 20 |
+
"""Couldn't recognize the archive type"""
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def default_filter(src, dst):
|
| 24 |
+
"""The default progress/filter callback; returns True for all files"""
|
| 25 |
+
return dst
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def unpack_archive(
|
| 29 |
+
filename, extract_dir, progress_filter=default_filter,
|
| 30 |
+
drivers=None):
|
| 31 |
+
"""Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
|
| 32 |
+
|
| 33 |
+
`progress_filter` is a function taking two arguments: a source path
|
| 34 |
+
internal to the archive ('/'-separated), and a filesystem path where it
|
| 35 |
+
will be extracted. The callback must return the desired extract path
|
| 36 |
+
(which may be the same as the one passed in), or else ``None`` to skip
|
| 37 |
+
that file or directory. The callback can thus be used to report on the
|
| 38 |
+
progress of the extraction, as well as to filter the items extracted or
|
| 39 |
+
alter their extraction paths.
|
| 40 |
+
|
| 41 |
+
`drivers`, if supplied, must be a non-empty sequence of functions with the
|
| 42 |
+
same signature as this function (minus the `drivers` argument), that raise
|
| 43 |
+
``UnrecognizedFormat`` if they do not support extracting the designated
|
| 44 |
+
archive type. The `drivers` are tried in sequence until one is found that
|
| 45 |
+
does not raise an error, or until all are exhausted (in which case
|
| 46 |
+
``UnrecognizedFormat`` is raised). If you do not supply a sequence of
|
| 47 |
+
drivers, the module's ``extraction_drivers`` constant will be used, which
|
| 48 |
+
means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that
|
| 49 |
+
order.
|
| 50 |
+
"""
|
| 51 |
+
for driver in drivers or extraction_drivers:
|
| 52 |
+
try:
|
| 53 |
+
driver(filename, extract_dir, progress_filter)
|
| 54 |
+
except UnrecognizedFormat:
|
| 55 |
+
continue
|
| 56 |
+
else:
|
| 57 |
+
return
|
| 58 |
+
else:
|
| 59 |
+
raise UnrecognizedFormat(
|
| 60 |
+
"Not a recognized archive type: %s" % filename
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def unpack_directory(filename, extract_dir, progress_filter=default_filter):
|
| 65 |
+
""""Unpack" a directory, using the same interface as for archives
|
| 66 |
+
|
| 67 |
+
Raises ``UnrecognizedFormat`` if `filename` is not a directory
|
| 68 |
+
"""
|
| 69 |
+
if not os.path.isdir(filename):
|
| 70 |
+
raise UnrecognizedFormat("%s is not a directory" % filename)
|
| 71 |
+
|
| 72 |
+
paths = {
|
| 73 |
+
filename: ('', extract_dir),
|
| 74 |
+
}
|
| 75 |
+
for base, dirs, files in os.walk(filename):
|
| 76 |
+
src, dst = paths[base]
|
| 77 |
+
for d in dirs:
|
| 78 |
+
paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d)
|
| 79 |
+
for f in files:
|
| 80 |
+
target = os.path.join(dst, f)
|
| 81 |
+
target = progress_filter(src + f, target)
|
| 82 |
+
if not target:
|
| 83 |
+
# skip non-files
|
| 84 |
+
continue
|
| 85 |
+
ensure_directory(target)
|
| 86 |
+
f = os.path.join(base, f)
|
| 87 |
+
shutil.copyfile(f, target)
|
| 88 |
+
shutil.copystat(f, target)
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
|
| 92 |
+
"""Unpack zip `filename` to `extract_dir`
|
| 93 |
+
|
| 94 |
+
Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined
|
| 95 |
+
by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation
|
| 96 |
+
of the `progress_filter` argument.
|
| 97 |
+
"""
|
| 98 |
+
|
| 99 |
+
if not zipfile.is_zipfile(filename):
|
| 100 |
+
raise UnrecognizedFormat("%s is not a zip file" % (filename,))
|
| 101 |
+
|
| 102 |
+
with zipfile.ZipFile(filename) as z:
|
| 103 |
+
for info in z.infolist():
|
| 104 |
+
name = info.filename
|
| 105 |
+
|
| 106 |
+
# don't extract absolute paths or ones with .. in them
|
| 107 |
+
if name.startswith('/') or '..' in name.split('/'):
|
| 108 |
+
continue
|
| 109 |
+
|
| 110 |
+
target = os.path.join(extract_dir, *name.split('/'))
|
| 111 |
+
target = progress_filter(name, target)
|
| 112 |
+
if not target:
|
| 113 |
+
continue
|
| 114 |
+
if name.endswith('/'):
|
| 115 |
+
# directory
|
| 116 |
+
ensure_directory(target)
|
| 117 |
+
else:
|
| 118 |
+
# file
|
| 119 |
+
ensure_directory(target)
|
| 120 |
+
data = z.read(info.filename)
|
| 121 |
+
with open(target, 'wb') as f:
|
| 122 |
+
f.write(data)
|
| 123 |
+
unix_attributes = info.external_attr >> 16
|
| 124 |
+
if unix_attributes:
|
| 125 |
+
os.chmod(target, unix_attributes)
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
def _resolve_tar_file_or_dir(tar_obj, tar_member_obj):
|
| 129 |
+
"""Resolve any links and extract link targets as normal files."""
|
| 130 |
+
while tar_member_obj is not None and (
|
| 131 |
+
tar_member_obj.islnk() or tar_member_obj.issym()):
|
| 132 |
+
linkpath = tar_member_obj.linkname
|
| 133 |
+
if tar_member_obj.issym():
|
| 134 |
+
base = posixpath.dirname(tar_member_obj.name)
|
| 135 |
+
linkpath = posixpath.join(base, linkpath)
|
| 136 |
+
linkpath = posixpath.normpath(linkpath)
|
| 137 |
+
tar_member_obj = tar_obj._getmember(linkpath)
|
| 138 |
+
|
| 139 |
+
is_file_or_dir = (
|
| 140 |
+
tar_member_obj is not None and
|
| 141 |
+
(tar_member_obj.isfile() or tar_member_obj.isdir())
|
| 142 |
+
)
|
| 143 |
+
if is_file_or_dir:
|
| 144 |
+
return tar_member_obj
|
| 145 |
+
|
| 146 |
+
raise LookupError('Got unknown file type')
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
def _iter_open_tar(tar_obj, extract_dir, progress_filter):
|
| 150 |
+
"""Emit member-destination pairs from a tar archive."""
|
| 151 |
+
# don't do any chowning!
|
| 152 |
+
tar_obj.chown = lambda *args: None
|
| 153 |
+
|
| 154 |
+
with contextlib.closing(tar_obj):
|
| 155 |
+
for member in tar_obj:
|
| 156 |
+
name = member.name
|
| 157 |
+
# don't extract absolute paths or ones with .. in them
|
| 158 |
+
if name.startswith('/') or '..' in name.split('/'):
|
| 159 |
+
continue
|
| 160 |
+
|
| 161 |
+
prelim_dst = os.path.join(extract_dir, *name.split('/'))
|
| 162 |
+
|
| 163 |
+
try:
|
| 164 |
+
member = _resolve_tar_file_or_dir(tar_obj, member)
|
| 165 |
+
except LookupError:
|
| 166 |
+
continue
|
| 167 |
+
|
| 168 |
+
final_dst = progress_filter(name, prelim_dst)
|
| 169 |
+
if not final_dst:
|
| 170 |
+
continue
|
| 171 |
+
|
| 172 |
+
if final_dst.endswith(os.sep):
|
| 173 |
+
final_dst = final_dst[:-1]
|
| 174 |
+
|
| 175 |
+
yield member, final_dst
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
| 179 |
+
"""Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir`
|
| 180 |
+
|
| 181 |
+
Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined
|
| 182 |
+
by ``tarfile.open()``). See ``unpack_archive()`` for an explanation
|
| 183 |
+
of the `progress_filter` argument.
|
| 184 |
+
"""
|
| 185 |
+
try:
|
| 186 |
+
tarobj = tarfile.open(filename)
|
| 187 |
+
except tarfile.TarError as e:
|
| 188 |
+
raise UnrecognizedFormat(
|
| 189 |
+
"%s is not a compressed or uncompressed tar file" % (filename,)
|
| 190 |
+
) from e
|
| 191 |
+
|
| 192 |
+
for member, final_dst in _iter_open_tar(
|
| 193 |
+
tarobj, extract_dir, progress_filter,
|
| 194 |
+
):
|
| 195 |
+
try:
|
| 196 |
+
# XXX Ugh
|
| 197 |
+
tarobj._extract_member(member, final_dst)
|
| 198 |
+
except tarfile.ExtractError:
|
| 199 |
+
# chown/chmod/mkfifo/mknode/makedev failed
|
| 200 |
+
pass
|
| 201 |
+
|
| 202 |
+
return True
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/build_meta.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""A PEP 517 interface to setuptools
|
| 2 |
+
|
| 3 |
+
Previously, when a user or a command line tool (let's call it a "frontend")
|
| 4 |
+
needed to make a request of setuptools to take a certain action, for
|
| 5 |
+
example, generating a list of installation requirements, the frontend would
|
| 6 |
+
would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line.
|
| 7 |
+
|
| 8 |
+
PEP 517 defines a different method of interfacing with setuptools. Rather
|
| 9 |
+
than calling "setup.py" directly, the frontend should:
|
| 10 |
+
|
| 11 |
+
1. Set the current directory to the directory with a setup.py file
|
| 12 |
+
2. Import this module into a safe python interpreter (one in which
|
| 13 |
+
setuptools can potentially set global variables or crash hard).
|
| 14 |
+
3. Call one of the functions defined in PEP 517.
|
| 15 |
+
|
| 16 |
+
What each function does is defined in PEP 517. However, here is a "casual"
|
| 17 |
+
definition of the functions (this definition should not be relied on for
|
| 18 |
+
bug reports or API stability):
|
| 19 |
+
|
| 20 |
+
- `build_wheel`: build a wheel in the folder and return the basename
|
| 21 |
+
- `get_requires_for_build_wheel`: get the `setup_requires` to build
|
| 22 |
+
- `prepare_metadata_for_build_wheel`: get the `install_requires`
|
| 23 |
+
- `build_sdist`: build an sdist in the folder and return the basename
|
| 24 |
+
- `get_requires_for_build_sdist`: get the `setup_requires` to build
|
| 25 |
+
|
| 26 |
+
Again, this is not a formal definition! Just a "taste" of the module.
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
import io
|
| 30 |
+
import os
|
| 31 |
+
import sys
|
| 32 |
+
import tokenize
|
| 33 |
+
import shutil
|
| 34 |
+
import contextlib
|
| 35 |
+
import tempfile
|
| 36 |
+
|
| 37 |
+
import setuptools
|
| 38 |
+
import distutils
|
| 39 |
+
|
| 40 |
+
from pkg_resources import parse_requirements
|
| 41 |
+
|
| 42 |
+
__all__ = ['get_requires_for_build_sdist',
|
| 43 |
+
'get_requires_for_build_wheel',
|
| 44 |
+
'prepare_metadata_for_build_wheel',
|
| 45 |
+
'build_wheel',
|
| 46 |
+
'build_sdist',
|
| 47 |
+
'__legacy__',
|
| 48 |
+
'SetupRequirementsError']
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
class SetupRequirementsError(BaseException):
|
| 52 |
+
def __init__(self, specifiers):
|
| 53 |
+
self.specifiers = specifiers
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
class Distribution(setuptools.dist.Distribution):
|
| 57 |
+
def fetch_build_eggs(self, specifiers):
|
| 58 |
+
specifier_list = list(map(str, parse_requirements(specifiers)))
|
| 59 |
+
|
| 60 |
+
raise SetupRequirementsError(specifier_list)
|
| 61 |
+
|
| 62 |
+
@classmethod
|
| 63 |
+
@contextlib.contextmanager
|
| 64 |
+
def patch(cls):
|
| 65 |
+
"""
|
| 66 |
+
Replace
|
| 67 |
+
distutils.dist.Distribution with this class
|
| 68 |
+
for the duration of this context.
|
| 69 |
+
"""
|
| 70 |
+
orig = distutils.core.Distribution
|
| 71 |
+
distutils.core.Distribution = cls
|
| 72 |
+
try:
|
| 73 |
+
yield
|
| 74 |
+
finally:
|
| 75 |
+
distutils.core.Distribution = orig
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
@contextlib.contextmanager
|
| 79 |
+
def no_install_setup_requires():
|
| 80 |
+
"""Temporarily disable installing setup_requires
|
| 81 |
+
|
| 82 |
+
Under PEP 517, the backend reports build dependencies to the frontend,
|
| 83 |
+
and the frontend is responsible for ensuring they're installed.
|
| 84 |
+
So setuptools (acting as a backend) should not try to install them.
|
| 85 |
+
"""
|
| 86 |
+
orig = setuptools._install_setup_requires
|
| 87 |
+
setuptools._install_setup_requires = lambda attrs: None
|
| 88 |
+
try:
|
| 89 |
+
yield
|
| 90 |
+
finally:
|
| 91 |
+
setuptools._install_setup_requires = orig
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _get_immediate_subdirectories(a_dir):
|
| 95 |
+
return [name for name in os.listdir(a_dir)
|
| 96 |
+
if os.path.isdir(os.path.join(a_dir, name))]
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def _file_with_extension(directory, extension):
|
| 100 |
+
matching = (
|
| 101 |
+
f for f in os.listdir(directory)
|
| 102 |
+
if f.endswith(extension)
|
| 103 |
+
)
|
| 104 |
+
try:
|
| 105 |
+
file, = matching
|
| 106 |
+
except ValueError:
|
| 107 |
+
raise ValueError(
|
| 108 |
+
'No distribution was found. Ensure that `setup.py` '
|
| 109 |
+
'is not empty and that it calls `setup()`.')
|
| 110 |
+
return file
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def _open_setup_script(setup_script):
|
| 114 |
+
if not os.path.exists(setup_script):
|
| 115 |
+
# Supply a default setup.py
|
| 116 |
+
return io.StringIO(u"from setuptools import setup; setup()")
|
| 117 |
+
|
| 118 |
+
return getattr(tokenize, 'open', open)(setup_script)
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
class _BuildMetaBackend(object):
|
| 122 |
+
|
| 123 |
+
def _fix_config(self, config_settings):
|
| 124 |
+
config_settings = config_settings or {}
|
| 125 |
+
config_settings.setdefault('--global-option', [])
|
| 126 |
+
return config_settings
|
| 127 |
+
|
| 128 |
+
def _get_build_requires(self, config_settings, requirements):
|
| 129 |
+
config_settings = self._fix_config(config_settings)
|
| 130 |
+
|
| 131 |
+
sys.argv = sys.argv[:1] + ['egg_info'] + \
|
| 132 |
+
config_settings["--global-option"]
|
| 133 |
+
try:
|
| 134 |
+
with Distribution.patch():
|
| 135 |
+
self.run_setup()
|
| 136 |
+
except SetupRequirementsError as e:
|
| 137 |
+
requirements += e.specifiers
|
| 138 |
+
|
| 139 |
+
return requirements
|
| 140 |
+
|
| 141 |
+
def run_setup(self, setup_script='setup.py'):
|
| 142 |
+
# Note that we can reuse our build directory between calls
|
| 143 |
+
# Correctness comes first, then optimization later
|
| 144 |
+
__file__ = setup_script
|
| 145 |
+
__name__ = '__main__'
|
| 146 |
+
|
| 147 |
+
with _open_setup_script(__file__) as f:
|
| 148 |
+
code = f.read().replace(r'\r\n', r'\n')
|
| 149 |
+
|
| 150 |
+
exec(compile(code, __file__, 'exec'), locals())
|
| 151 |
+
|
| 152 |
+
def get_requires_for_build_wheel(self, config_settings=None):
|
| 153 |
+
config_settings = self._fix_config(config_settings)
|
| 154 |
+
return self._get_build_requires(
|
| 155 |
+
config_settings, requirements=['wheel'])
|
| 156 |
+
|
| 157 |
+
def get_requires_for_build_sdist(self, config_settings=None):
|
| 158 |
+
config_settings = self._fix_config(config_settings)
|
| 159 |
+
return self._get_build_requires(config_settings, requirements=[])
|
| 160 |
+
|
| 161 |
+
def prepare_metadata_for_build_wheel(self, metadata_directory,
|
| 162 |
+
config_settings=None):
|
| 163 |
+
sys.argv = sys.argv[:1] + [
|
| 164 |
+
'dist_info', '--egg-base', metadata_directory]
|
| 165 |
+
with no_install_setup_requires():
|
| 166 |
+
self.run_setup()
|
| 167 |
+
|
| 168 |
+
dist_info_directory = metadata_directory
|
| 169 |
+
while True:
|
| 170 |
+
dist_infos = [f for f in os.listdir(dist_info_directory)
|
| 171 |
+
if f.endswith('.dist-info')]
|
| 172 |
+
|
| 173 |
+
if (
|
| 174 |
+
len(dist_infos) == 0 and
|
| 175 |
+
len(_get_immediate_subdirectories(dist_info_directory)) == 1
|
| 176 |
+
):
|
| 177 |
+
|
| 178 |
+
dist_info_directory = os.path.join(
|
| 179 |
+
dist_info_directory, os.listdir(dist_info_directory)[0])
|
| 180 |
+
continue
|
| 181 |
+
|
| 182 |
+
assert len(dist_infos) == 1
|
| 183 |
+
break
|
| 184 |
+
|
| 185 |
+
# PEP 517 requires that the .dist-info directory be placed in the
|
| 186 |
+
# metadata_directory. To comply, we MUST copy the directory to the root
|
| 187 |
+
if dist_info_directory != metadata_directory:
|
| 188 |
+
shutil.move(
|
| 189 |
+
os.path.join(dist_info_directory, dist_infos[0]),
|
| 190 |
+
metadata_directory)
|
| 191 |
+
shutil.rmtree(dist_info_directory, ignore_errors=True)
|
| 192 |
+
|
| 193 |
+
return dist_infos[0]
|
| 194 |
+
|
| 195 |
+
def _build_with_temp_dir(self, setup_command, result_extension,
|
| 196 |
+
result_directory, config_settings):
|
| 197 |
+
config_settings = self._fix_config(config_settings)
|
| 198 |
+
result_directory = os.path.abspath(result_directory)
|
| 199 |
+
|
| 200 |
+
# Build in a temporary directory, then copy to the target.
|
| 201 |
+
os.makedirs(result_directory, exist_ok=True)
|
| 202 |
+
with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir:
|
| 203 |
+
sys.argv = (sys.argv[:1] + setup_command +
|
| 204 |
+
['--dist-dir', tmp_dist_dir] +
|
| 205 |
+
config_settings["--global-option"])
|
| 206 |
+
with no_install_setup_requires():
|
| 207 |
+
self.run_setup()
|
| 208 |
+
|
| 209 |
+
result_basename = _file_with_extension(
|
| 210 |
+
tmp_dist_dir, result_extension)
|
| 211 |
+
result_path = os.path.join(result_directory, result_basename)
|
| 212 |
+
if os.path.exists(result_path):
|
| 213 |
+
# os.rename will fail overwriting on non-Unix.
|
| 214 |
+
os.remove(result_path)
|
| 215 |
+
os.rename(os.path.join(tmp_dist_dir, result_basename), result_path)
|
| 216 |
+
|
| 217 |
+
return result_basename
|
| 218 |
+
|
| 219 |
+
def build_wheel(self, wheel_directory, config_settings=None,
|
| 220 |
+
metadata_directory=None):
|
| 221 |
+
return self._build_with_temp_dir(['bdist_wheel'], '.whl',
|
| 222 |
+
wheel_directory, config_settings)
|
| 223 |
+
|
| 224 |
+
def build_sdist(self, sdist_directory, config_settings=None):
|
| 225 |
+
return self._build_with_temp_dir(['sdist', '--formats', 'gztar'],
|
| 226 |
+
'.tar.gz', sdist_directory,
|
| 227 |
+
config_settings)
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
class _BuildMetaLegacyBackend(_BuildMetaBackend):
|
| 231 |
+
"""Compatibility backend for setuptools
|
| 232 |
+
|
| 233 |
+
This is a version of setuptools.build_meta that endeavors
|
| 234 |
+
to maintain backwards
|
| 235 |
+
compatibility with pre-PEP 517 modes of invocation. It
|
| 236 |
+
exists as a temporary
|
| 237 |
+
bridge between the old packaging mechanism and the new
|
| 238 |
+
packaging mechanism,
|
| 239 |
+
and will eventually be removed.
|
| 240 |
+
"""
|
| 241 |
+
def run_setup(self, setup_script='setup.py'):
|
| 242 |
+
# In order to maintain compatibility with scripts assuming that
|
| 243 |
+
# the setup.py script is in a directory on the PYTHONPATH, inject
|
| 244 |
+
# '' into sys.path. (pypa/setuptools#1642)
|
| 245 |
+
sys_path = list(sys.path) # Save the original path
|
| 246 |
+
|
| 247 |
+
script_dir = os.path.dirname(os.path.abspath(setup_script))
|
| 248 |
+
if script_dir not in sys.path:
|
| 249 |
+
sys.path.insert(0, script_dir)
|
| 250 |
+
|
| 251 |
+
# Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to
|
| 252 |
+
# get the directory of the source code. They expect it to refer to the
|
| 253 |
+
# setup.py script.
|
| 254 |
+
sys_argv_0 = sys.argv[0]
|
| 255 |
+
sys.argv[0] = setup_script
|
| 256 |
+
|
| 257 |
+
try:
|
| 258 |
+
super(_BuildMetaLegacyBackend,
|
| 259 |
+
self).run_setup(setup_script=setup_script)
|
| 260 |
+
finally:
|
| 261 |
+
# While PEP 517 frontends should be calling each hook in a fresh
|
| 262 |
+
# subprocess according to the standard (and thus it should not be
|
| 263 |
+
# strictly necessary to restore the old sys.path), we'll restore
|
| 264 |
+
# the original path so that the path manipulation does not persist
|
| 265 |
+
# within the hook after run_setup is called.
|
| 266 |
+
sys.path[:] = sys_path
|
| 267 |
+
sys.argv[0] = sys_argv_0
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
# The primary backend
|
| 271 |
+
_BACKEND = _BuildMetaBackend()
|
| 272 |
+
|
| 273 |
+
get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel
|
| 274 |
+
get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist
|
| 275 |
+
prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel
|
| 276 |
+
build_wheel = _BACKEND.build_wheel
|
| 277 |
+
build_sdist = _BACKEND.build_sdist
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
# The legacy backend
|
| 281 |
+
__legacy__ = _BuildMetaLegacyBackend()
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/cli-32.exe
ADDED
|
Binary file (65.5 kB). View file
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/cli-64.exe
ADDED
|
Binary file (74.8 kB). View file
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/cli.exe
ADDED
|
Binary file (65.5 kB). View file
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/alias.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from distutils.errors import DistutilsOptionError
|
| 2 |
+
|
| 3 |
+
from setuptools.command.setopt import edit_config, option_base, config_file
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def shquote(arg):
|
| 7 |
+
"""Quote an argument for later parsing by shlex.split()"""
|
| 8 |
+
for c in '"', "'", "\\", "#":
|
| 9 |
+
if c in arg:
|
| 10 |
+
return repr(arg)
|
| 11 |
+
if arg.split() != [arg]:
|
| 12 |
+
return repr(arg)
|
| 13 |
+
return arg
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class alias(option_base):
|
| 17 |
+
"""Define a shortcut that invokes one or more commands"""
|
| 18 |
+
|
| 19 |
+
description = "define a shortcut to invoke one or more commands"
|
| 20 |
+
command_consumes_arguments = True
|
| 21 |
+
|
| 22 |
+
user_options = [
|
| 23 |
+
('remove', 'r', 'remove (unset) the alias'),
|
| 24 |
+
] + option_base.user_options
|
| 25 |
+
|
| 26 |
+
boolean_options = option_base.boolean_options + ['remove']
|
| 27 |
+
|
| 28 |
+
def initialize_options(self):
|
| 29 |
+
option_base.initialize_options(self)
|
| 30 |
+
self.args = None
|
| 31 |
+
self.remove = None
|
| 32 |
+
|
| 33 |
+
def finalize_options(self):
|
| 34 |
+
option_base.finalize_options(self)
|
| 35 |
+
if self.remove and len(self.args) != 1:
|
| 36 |
+
raise DistutilsOptionError(
|
| 37 |
+
"Must specify exactly one argument (the alias name) when "
|
| 38 |
+
"using --remove"
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
def run(self):
|
| 42 |
+
aliases = self.distribution.get_option_dict('aliases')
|
| 43 |
+
|
| 44 |
+
if not self.args:
|
| 45 |
+
print("Command Aliases")
|
| 46 |
+
print("---------------")
|
| 47 |
+
for alias in aliases:
|
| 48 |
+
print("setup.py alias", format_alias(alias, aliases))
|
| 49 |
+
return
|
| 50 |
+
|
| 51 |
+
elif len(self.args) == 1:
|
| 52 |
+
alias, = self.args
|
| 53 |
+
if self.remove:
|
| 54 |
+
command = None
|
| 55 |
+
elif alias in aliases:
|
| 56 |
+
print("setup.py alias", format_alias(alias, aliases))
|
| 57 |
+
return
|
| 58 |
+
else:
|
| 59 |
+
print("No alias definition found for %r" % alias)
|
| 60 |
+
return
|
| 61 |
+
else:
|
| 62 |
+
alias = self.args[0]
|
| 63 |
+
command = ' '.join(map(shquote, self.args[1:]))
|
| 64 |
+
|
| 65 |
+
edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def format_alias(name, aliases):
|
| 69 |
+
source, command = aliases[name]
|
| 70 |
+
if source == config_file('global'):
|
| 71 |
+
source = '--global-config '
|
| 72 |
+
elif source == config_file('user'):
|
| 73 |
+
source = '--user-config '
|
| 74 |
+
elif source == config_file('local'):
|
| 75 |
+
source = ''
|
| 76 |
+
else:
|
| 77 |
+
source = '--filename=%r' % source
|
| 78 |
+
return source + name + ' ' + command
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/bdist_egg.py
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""setuptools.command.bdist_egg
|
| 2 |
+
|
| 3 |
+
Build .egg distributions"""
|
| 4 |
+
|
| 5 |
+
from distutils.dir_util import remove_tree, mkpath
|
| 6 |
+
from distutils import log
|
| 7 |
+
from types import CodeType
|
| 8 |
+
import sys
|
| 9 |
+
import os
|
| 10 |
+
import re
|
| 11 |
+
import textwrap
|
| 12 |
+
import marshal
|
| 13 |
+
|
| 14 |
+
from pkg_resources import get_build_platform, Distribution, ensure_directory
|
| 15 |
+
from setuptools.extension import Library
|
| 16 |
+
from setuptools import Command
|
| 17 |
+
|
| 18 |
+
from sysconfig import get_path, get_python_version
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def _get_purelib():
|
| 22 |
+
return get_path("purelib")
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def strip_module(filename):
|
| 26 |
+
if '.' in filename:
|
| 27 |
+
filename = os.path.splitext(filename)[0]
|
| 28 |
+
if filename.endswith('module'):
|
| 29 |
+
filename = filename[:-6]
|
| 30 |
+
return filename
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def sorted_walk(dir):
|
| 34 |
+
"""Do os.walk in a reproducible way,
|
| 35 |
+
independent of indeterministic filesystem readdir order
|
| 36 |
+
"""
|
| 37 |
+
for base, dirs, files in os.walk(dir):
|
| 38 |
+
dirs.sort()
|
| 39 |
+
files.sort()
|
| 40 |
+
yield base, dirs, files
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def write_stub(resource, pyfile):
|
| 44 |
+
_stub_template = textwrap.dedent("""
|
| 45 |
+
def __bootstrap__():
|
| 46 |
+
global __bootstrap__, __loader__, __file__
|
| 47 |
+
import sys, pkg_resources, importlib.util
|
| 48 |
+
__file__ = pkg_resources.resource_filename(__name__, %r)
|
| 49 |
+
__loader__ = None; del __bootstrap__, __loader__
|
| 50 |
+
spec = importlib.util.spec_from_file_location(__name__,__file__)
|
| 51 |
+
mod = importlib.util.module_from_spec(spec)
|
| 52 |
+
spec.loader.exec_module(mod)
|
| 53 |
+
__bootstrap__()
|
| 54 |
+
""").lstrip()
|
| 55 |
+
with open(pyfile, 'w') as f:
|
| 56 |
+
f.write(_stub_template % resource)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class bdist_egg(Command):
|
| 60 |
+
description = "create an \"egg\" distribution"
|
| 61 |
+
|
| 62 |
+
user_options = [
|
| 63 |
+
('bdist-dir=', 'b',
|
| 64 |
+
"temporary directory for creating the distribution"),
|
| 65 |
+
('plat-name=', 'p', "platform name to embed in generated filenames "
|
| 66 |
+
"(default: %s)" % get_build_platform()),
|
| 67 |
+
('exclude-source-files', None,
|
| 68 |
+
"remove all .py files from the generated egg"),
|
| 69 |
+
('keep-temp', 'k',
|
| 70 |
+
"keep the pseudo-installation tree around after " +
|
| 71 |
+
"creating the distribution archive"),
|
| 72 |
+
('dist-dir=', 'd',
|
| 73 |
+
"directory to put final built distributions in"),
|
| 74 |
+
('skip-build', None,
|
| 75 |
+
"skip rebuilding everything (for testing/debugging)"),
|
| 76 |
+
]
|
| 77 |
+
|
| 78 |
+
boolean_options = [
|
| 79 |
+
'keep-temp', 'skip-build', 'exclude-source-files'
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
def initialize_options(self):
|
| 83 |
+
self.bdist_dir = None
|
| 84 |
+
self.plat_name = None
|
| 85 |
+
self.keep_temp = 0
|
| 86 |
+
self.dist_dir = None
|
| 87 |
+
self.skip_build = 0
|
| 88 |
+
self.egg_output = None
|
| 89 |
+
self.exclude_source_files = None
|
| 90 |
+
|
| 91 |
+
def finalize_options(self):
|
| 92 |
+
ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
|
| 93 |
+
self.egg_info = ei_cmd.egg_info
|
| 94 |
+
|
| 95 |
+
if self.bdist_dir is None:
|
| 96 |
+
bdist_base = self.get_finalized_command('bdist').bdist_base
|
| 97 |
+
self.bdist_dir = os.path.join(bdist_base, 'egg')
|
| 98 |
+
|
| 99 |
+
if self.plat_name is None:
|
| 100 |
+
self.plat_name = get_build_platform()
|
| 101 |
+
|
| 102 |
+
self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
|
| 103 |
+
|
| 104 |
+
if self.egg_output is None:
|
| 105 |
+
|
| 106 |
+
# Compute filename of the output egg
|
| 107 |
+
basename = Distribution(
|
| 108 |
+
None, None, ei_cmd.egg_name, ei_cmd.egg_version,
|
| 109 |
+
get_python_version(),
|
| 110 |
+
self.distribution.has_ext_modules() and self.plat_name
|
| 111 |
+
).egg_name()
|
| 112 |
+
|
| 113 |
+
self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
|
| 114 |
+
|
| 115 |
+
def do_install_data(self):
|
| 116 |
+
# Hack for packages that install data to install's --install-lib
|
| 117 |
+
self.get_finalized_command('install').install_lib = self.bdist_dir
|
| 118 |
+
|
| 119 |
+
site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
|
| 120 |
+
old, self.distribution.data_files = self.distribution.data_files, []
|
| 121 |
+
|
| 122 |
+
for item in old:
|
| 123 |
+
if isinstance(item, tuple) and len(item) == 2:
|
| 124 |
+
if os.path.isabs(item[0]):
|
| 125 |
+
realpath = os.path.realpath(item[0])
|
| 126 |
+
normalized = os.path.normcase(realpath)
|
| 127 |
+
if normalized == site_packages or normalized.startswith(
|
| 128 |
+
site_packages + os.sep
|
| 129 |
+
):
|
| 130 |
+
item = realpath[len(site_packages) + 1:], item[1]
|
| 131 |
+
# XXX else: raise ???
|
| 132 |
+
self.distribution.data_files.append(item)
|
| 133 |
+
|
| 134 |
+
try:
|
| 135 |
+
log.info("installing package data to %s", self.bdist_dir)
|
| 136 |
+
self.call_command('install_data', force=0, root=None)
|
| 137 |
+
finally:
|
| 138 |
+
self.distribution.data_files = old
|
| 139 |
+
|
| 140 |
+
def get_outputs(self):
|
| 141 |
+
return [self.egg_output]
|
| 142 |
+
|
| 143 |
+
def call_command(self, cmdname, **kw):
|
| 144 |
+
"""Invoke reinitialized command `cmdname` with keyword args"""
|
| 145 |
+
for dirname in INSTALL_DIRECTORY_ATTRS:
|
| 146 |
+
kw.setdefault(dirname, self.bdist_dir)
|
| 147 |
+
kw.setdefault('skip_build', self.skip_build)
|
| 148 |
+
kw.setdefault('dry_run', self.dry_run)
|
| 149 |
+
cmd = self.reinitialize_command(cmdname, **kw)
|
| 150 |
+
self.run_command(cmdname)
|
| 151 |
+
return cmd
|
| 152 |
+
|
| 153 |
+
def run(self): # noqa: C901 # is too complex (14) # FIXME
|
| 154 |
+
# Generate metadata first
|
| 155 |
+
self.run_command("egg_info")
|
| 156 |
+
# We run install_lib before install_data, because some data hacks
|
| 157 |
+
# pull their data path from the install_lib command.
|
| 158 |
+
log.info("installing library code to %s", self.bdist_dir)
|
| 159 |
+
instcmd = self.get_finalized_command('install')
|
| 160 |
+
old_root = instcmd.root
|
| 161 |
+
instcmd.root = None
|
| 162 |
+
if self.distribution.has_c_libraries() and not self.skip_build:
|
| 163 |
+
self.run_command('build_clib')
|
| 164 |
+
cmd = self.call_command('install_lib', warn_dir=0)
|
| 165 |
+
instcmd.root = old_root
|
| 166 |
+
|
| 167 |
+
all_outputs, ext_outputs = self.get_ext_outputs()
|
| 168 |
+
self.stubs = []
|
| 169 |
+
to_compile = []
|
| 170 |
+
for (p, ext_name) in enumerate(ext_outputs):
|
| 171 |
+
filename, ext = os.path.splitext(ext_name)
|
| 172 |
+
pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
|
| 173 |
+
'.py')
|
| 174 |
+
self.stubs.append(pyfile)
|
| 175 |
+
log.info("creating stub loader for %s", ext_name)
|
| 176 |
+
if not self.dry_run:
|
| 177 |
+
write_stub(os.path.basename(ext_name), pyfile)
|
| 178 |
+
to_compile.append(pyfile)
|
| 179 |
+
ext_outputs[p] = ext_name.replace(os.sep, '/')
|
| 180 |
+
|
| 181 |
+
if to_compile:
|
| 182 |
+
cmd.byte_compile(to_compile)
|
| 183 |
+
if self.distribution.data_files:
|
| 184 |
+
self.do_install_data()
|
| 185 |
+
|
| 186 |
+
# Make the EGG-INFO directory
|
| 187 |
+
archive_root = self.bdist_dir
|
| 188 |
+
egg_info = os.path.join(archive_root, 'EGG-INFO')
|
| 189 |
+
self.mkpath(egg_info)
|
| 190 |
+
if self.distribution.scripts:
|
| 191 |
+
script_dir = os.path.join(egg_info, 'scripts')
|
| 192 |
+
log.info("installing scripts to %s", script_dir)
|
| 193 |
+
self.call_command('install_scripts', install_dir=script_dir,
|
| 194 |
+
no_ep=1)
|
| 195 |
+
|
| 196 |
+
self.copy_metadata_to(egg_info)
|
| 197 |
+
native_libs = os.path.join(egg_info, "native_libs.txt")
|
| 198 |
+
if all_outputs:
|
| 199 |
+
log.info("writing %s", native_libs)
|
| 200 |
+
if not self.dry_run:
|
| 201 |
+
ensure_directory(native_libs)
|
| 202 |
+
libs_file = open(native_libs, 'wt')
|
| 203 |
+
libs_file.write('\n'.join(all_outputs))
|
| 204 |
+
libs_file.write('\n')
|
| 205 |
+
libs_file.close()
|
| 206 |
+
elif os.path.isfile(native_libs):
|
| 207 |
+
log.info("removing %s", native_libs)
|
| 208 |
+
if not self.dry_run:
|
| 209 |
+
os.unlink(native_libs)
|
| 210 |
+
|
| 211 |
+
write_safety_flag(
|
| 212 |
+
os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
|
| 216 |
+
log.warn(
|
| 217 |
+
"WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
|
| 218 |
+
"Use the install_requires/extras_require setup() args instead."
|
| 219 |
+
)
|
| 220 |
+
|
| 221 |
+
if self.exclude_source_files:
|
| 222 |
+
self.zap_pyfiles()
|
| 223 |
+
|
| 224 |
+
# Make the archive
|
| 225 |
+
make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
|
| 226 |
+
dry_run=self.dry_run, mode=self.gen_header())
|
| 227 |
+
if not self.keep_temp:
|
| 228 |
+
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
| 229 |
+
|
| 230 |
+
# Add to 'Distribution.dist_files' so that the "upload" command works
|
| 231 |
+
getattr(self.distribution, 'dist_files', []).append(
|
| 232 |
+
('bdist_egg', get_python_version(), self.egg_output))
|
| 233 |
+
|
| 234 |
+
def zap_pyfiles(self):
|
| 235 |
+
log.info("Removing .py files from temporary directory")
|
| 236 |
+
for base, dirs, files in walk_egg(self.bdist_dir):
|
| 237 |
+
for name in files:
|
| 238 |
+
path = os.path.join(base, name)
|
| 239 |
+
|
| 240 |
+
if name.endswith('.py'):
|
| 241 |
+
log.debug("Deleting %s", path)
|
| 242 |
+
os.unlink(path)
|
| 243 |
+
|
| 244 |
+
if base.endswith('__pycache__'):
|
| 245 |
+
path_old = path
|
| 246 |
+
|
| 247 |
+
pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc'
|
| 248 |
+
m = re.match(pattern, name)
|
| 249 |
+
path_new = os.path.join(
|
| 250 |
+
base, os.pardir, m.group('name') + '.pyc')
|
| 251 |
+
log.info(
|
| 252 |
+
"Renaming file from [%s] to [%s]"
|
| 253 |
+
% (path_old, path_new))
|
| 254 |
+
try:
|
| 255 |
+
os.remove(path_new)
|
| 256 |
+
except OSError:
|
| 257 |
+
pass
|
| 258 |
+
os.rename(path_old, path_new)
|
| 259 |
+
|
| 260 |
+
def zip_safe(self):
|
| 261 |
+
safe = getattr(self.distribution, 'zip_safe', None)
|
| 262 |
+
if safe is not None:
|
| 263 |
+
return safe
|
| 264 |
+
log.warn("zip_safe flag not set; analyzing archive contents...")
|
| 265 |
+
return analyze_egg(self.bdist_dir, self.stubs)
|
| 266 |
+
|
| 267 |
+
def gen_header(self):
|
| 268 |
+
return 'w'
|
| 269 |
+
|
| 270 |
+
def copy_metadata_to(self, target_dir):
|
| 271 |
+
"Copy metadata (egg info) to the target_dir"
|
| 272 |
+
# normalize the path (so that a forward-slash in egg_info will
|
| 273 |
+
# match using startswith below)
|
| 274 |
+
norm_egg_info = os.path.normpath(self.egg_info)
|
| 275 |
+
prefix = os.path.join(norm_egg_info, '')
|
| 276 |
+
for path in self.ei_cmd.filelist.files:
|
| 277 |
+
if path.startswith(prefix):
|
| 278 |
+
target = os.path.join(target_dir, path[len(prefix):])
|
| 279 |
+
ensure_directory(target)
|
| 280 |
+
self.copy_file(path, target)
|
| 281 |
+
|
| 282 |
+
def get_ext_outputs(self):
|
| 283 |
+
"""Get a list of relative paths to C extensions in the output distro"""
|
| 284 |
+
|
| 285 |
+
all_outputs = []
|
| 286 |
+
ext_outputs = []
|
| 287 |
+
|
| 288 |
+
paths = {self.bdist_dir: ''}
|
| 289 |
+
for base, dirs, files in sorted_walk(self.bdist_dir):
|
| 290 |
+
for filename in files:
|
| 291 |
+
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
|
| 292 |
+
all_outputs.append(paths[base] + filename)
|
| 293 |
+
for filename in dirs:
|
| 294 |
+
paths[os.path.join(base, filename)] = (paths[base] +
|
| 295 |
+
filename + '/')
|
| 296 |
+
|
| 297 |
+
if self.distribution.has_ext_modules():
|
| 298 |
+
build_cmd = self.get_finalized_command('build_ext')
|
| 299 |
+
for ext in build_cmd.extensions:
|
| 300 |
+
if isinstance(ext, Library):
|
| 301 |
+
continue
|
| 302 |
+
fullname = build_cmd.get_ext_fullname(ext.name)
|
| 303 |
+
filename = build_cmd.get_ext_filename(fullname)
|
| 304 |
+
if not os.path.basename(filename).startswith('dl-'):
|
| 305 |
+
if os.path.exists(os.path.join(self.bdist_dir, filename)):
|
| 306 |
+
ext_outputs.append(filename)
|
| 307 |
+
|
| 308 |
+
return all_outputs, ext_outputs
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
def walk_egg(egg_dir):
|
| 315 |
+
"""Walk an unpacked egg's contents, skipping the metadata directory"""
|
| 316 |
+
walker = sorted_walk(egg_dir)
|
| 317 |
+
base, dirs, files = next(walker)
|
| 318 |
+
if 'EGG-INFO' in dirs:
|
| 319 |
+
dirs.remove('EGG-INFO')
|
| 320 |
+
yield base, dirs, files
|
| 321 |
+
for bdf in walker:
|
| 322 |
+
yield bdf
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
def analyze_egg(egg_dir, stubs):
|
| 326 |
+
# check for existing flag in EGG-INFO
|
| 327 |
+
for flag, fn in safety_flags.items():
|
| 328 |
+
if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)):
|
| 329 |
+
return flag
|
| 330 |
+
if not can_scan():
|
| 331 |
+
return False
|
| 332 |
+
safe = True
|
| 333 |
+
for base, dirs, files in walk_egg(egg_dir):
|
| 334 |
+
for name in files:
|
| 335 |
+
if name.endswith('.py') or name.endswith('.pyw'):
|
| 336 |
+
continue
|
| 337 |
+
elif name.endswith('.pyc') or name.endswith('.pyo'):
|
| 338 |
+
# always scan, even if we already know we're not safe
|
| 339 |
+
safe = scan_module(egg_dir, base, name, stubs) and safe
|
| 340 |
+
return safe
|
| 341 |
+
|
| 342 |
+
|
| 343 |
+
def write_safety_flag(egg_dir, safe):
|
| 344 |
+
# Write or remove zip safety flag file(s)
|
| 345 |
+
for flag, fn in safety_flags.items():
|
| 346 |
+
fn = os.path.join(egg_dir, fn)
|
| 347 |
+
if os.path.exists(fn):
|
| 348 |
+
if safe is None or bool(safe) != flag:
|
| 349 |
+
os.unlink(fn)
|
| 350 |
+
elif safe is not None and bool(safe) == flag:
|
| 351 |
+
f = open(fn, 'wt')
|
| 352 |
+
f.write('\n')
|
| 353 |
+
f.close()
|
| 354 |
+
|
| 355 |
+
|
| 356 |
+
safety_flags = {
|
| 357 |
+
True: 'zip-safe',
|
| 358 |
+
False: 'not-zip-safe',
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
def scan_module(egg_dir, base, name, stubs):
|
| 363 |
+
"""Check whether module possibly uses unsafe-for-zipfile stuff"""
|
| 364 |
+
|
| 365 |
+
filename = os.path.join(base, name)
|
| 366 |
+
if filename[:-1] in stubs:
|
| 367 |
+
return True # Extension module
|
| 368 |
+
pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
|
| 369 |
+
module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
|
| 370 |
+
if sys.version_info < (3, 7):
|
| 371 |
+
skip = 12 # skip magic & date & file size
|
| 372 |
+
else:
|
| 373 |
+
skip = 16 # skip magic & reserved? & date & file size
|
| 374 |
+
f = open(filename, 'rb')
|
| 375 |
+
f.read(skip)
|
| 376 |
+
code = marshal.load(f)
|
| 377 |
+
f.close()
|
| 378 |
+
safe = True
|
| 379 |
+
symbols = dict.fromkeys(iter_symbols(code))
|
| 380 |
+
for bad in ['__file__', '__path__']:
|
| 381 |
+
if bad in symbols:
|
| 382 |
+
log.warn("%s: module references %s", module, bad)
|
| 383 |
+
safe = False
|
| 384 |
+
if 'inspect' in symbols:
|
| 385 |
+
for bad in [
|
| 386 |
+
'getsource', 'getabsfile', 'getsourcefile', 'getfile'
|
| 387 |
+
'getsourcelines', 'findsource', 'getcomments', 'getframeinfo',
|
| 388 |
+
'getinnerframes', 'getouterframes', 'stack', 'trace'
|
| 389 |
+
]:
|
| 390 |
+
if bad in symbols:
|
| 391 |
+
log.warn("%s: module MAY be using inspect.%s", module, bad)
|
| 392 |
+
safe = False
|
| 393 |
+
return safe
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
def iter_symbols(code):
|
| 397 |
+
"""Yield names and strings used by `code` and its nested code objects"""
|
| 398 |
+
for name in code.co_names:
|
| 399 |
+
yield name
|
| 400 |
+
for const in code.co_consts:
|
| 401 |
+
if isinstance(const, str):
|
| 402 |
+
yield const
|
| 403 |
+
elif isinstance(const, CodeType):
|
| 404 |
+
for name in iter_symbols(const):
|
| 405 |
+
yield name
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
def can_scan():
|
| 409 |
+
if not sys.platform.startswith('java') and sys.platform != 'cli':
|
| 410 |
+
# CPython, PyPy, etc.
|
| 411 |
+
return True
|
| 412 |
+
log.warn("Unable to analyze compiled code on this platform.")
|
| 413 |
+
log.warn("Please ask the author to include a 'zip_safe'"
|
| 414 |
+
" setting (either True or False) in the package's setup.py")
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
# Attribute names of options for commands that might need to be convinced to
|
| 418 |
+
# install to the egg build directory
|
| 419 |
+
|
| 420 |
+
INSTALL_DIRECTORY_ATTRS = [
|
| 421 |
+
'install_lib', 'install_dir', 'install_data', 'install_base'
|
| 422 |
+
]
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True,
|
| 426 |
+
mode='w'):
|
| 427 |
+
"""Create a zip file from all the files under 'base_dir'. The output
|
| 428 |
+
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
|
| 429 |
+
Python module (if available) or the InfoZIP "zip" utility (if installed
|
| 430 |
+
and found on the default search path). If neither tool is available,
|
| 431 |
+
raises DistutilsExecError. Returns the name of the output zip file.
|
| 432 |
+
"""
|
| 433 |
+
import zipfile
|
| 434 |
+
|
| 435 |
+
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
|
| 436 |
+
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
|
| 437 |
+
|
| 438 |
+
def visit(z, dirname, names):
|
| 439 |
+
for name in names:
|
| 440 |
+
path = os.path.normpath(os.path.join(dirname, name))
|
| 441 |
+
if os.path.isfile(path):
|
| 442 |
+
p = path[len(base_dir) + 1:]
|
| 443 |
+
if not dry_run:
|
| 444 |
+
z.write(path, p)
|
| 445 |
+
log.debug("adding '%s'", p)
|
| 446 |
+
|
| 447 |
+
compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED
|
| 448 |
+
if not dry_run:
|
| 449 |
+
z = zipfile.ZipFile(zip_filename, mode, compression=compression)
|
| 450 |
+
for dirname, dirs, files in sorted_walk(base_dir):
|
| 451 |
+
visit(z, dirname, files)
|
| 452 |
+
z.close()
|
| 453 |
+
else:
|
| 454 |
+
for dirname, dirs, files in sorted_walk(base_dir):
|
| 455 |
+
visit(None, dirname, files)
|
| 456 |
+
return zip_filename
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/build_ext.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import itertools
|
| 4 |
+
from importlib.machinery import EXTENSION_SUFFIXES
|
| 5 |
+
from distutils.command.build_ext import build_ext as _du_build_ext
|
| 6 |
+
from distutils.file_util import copy_file
|
| 7 |
+
from distutils.ccompiler import new_compiler
|
| 8 |
+
from distutils.sysconfig import customize_compiler, get_config_var
|
| 9 |
+
from distutils.errors import DistutilsError
|
| 10 |
+
from distutils import log
|
| 11 |
+
|
| 12 |
+
from setuptools.extension import Library
|
| 13 |
+
|
| 14 |
+
try:
|
| 15 |
+
# Attempt to use Cython for building extensions, if available
|
| 16 |
+
from Cython.Distutils.build_ext import build_ext as _build_ext
|
| 17 |
+
# Additionally, assert that the compiler module will load
|
| 18 |
+
# also. Ref #1229.
|
| 19 |
+
__import__('Cython.Compiler.Main')
|
| 20 |
+
except ImportError:
|
| 21 |
+
_build_ext = _du_build_ext
|
| 22 |
+
|
| 23 |
+
# make sure _config_vars is initialized
|
| 24 |
+
get_config_var("LDSHARED")
|
| 25 |
+
from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def _customize_compiler_for_shlib(compiler):
|
| 29 |
+
if sys.platform == "darwin":
|
| 30 |
+
# building .dylib requires additional compiler flags on OSX; here we
|
| 31 |
+
# temporarily substitute the pyconfig.h variables so that distutils'
|
| 32 |
+
# 'customize_compiler' uses them before we build the shared libraries.
|
| 33 |
+
tmp = _CONFIG_VARS.copy()
|
| 34 |
+
try:
|
| 35 |
+
# XXX Help! I don't have any idea whether these are right...
|
| 36 |
+
_CONFIG_VARS['LDSHARED'] = (
|
| 37 |
+
"gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
|
| 38 |
+
_CONFIG_VARS['CCSHARED'] = " -dynamiclib"
|
| 39 |
+
_CONFIG_VARS['SO'] = ".dylib"
|
| 40 |
+
customize_compiler(compiler)
|
| 41 |
+
finally:
|
| 42 |
+
_CONFIG_VARS.clear()
|
| 43 |
+
_CONFIG_VARS.update(tmp)
|
| 44 |
+
else:
|
| 45 |
+
customize_compiler(compiler)
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
have_rtld = False
|
| 49 |
+
use_stubs = False
|
| 50 |
+
libtype = 'shared'
|
| 51 |
+
|
| 52 |
+
if sys.platform == "darwin":
|
| 53 |
+
use_stubs = True
|
| 54 |
+
elif os.name != 'nt':
|
| 55 |
+
try:
|
| 56 |
+
import dl
|
| 57 |
+
use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW')
|
| 58 |
+
except ImportError:
|
| 59 |
+
pass
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def if_dl(s):
|
| 63 |
+
return s if have_rtld else ''
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def get_abi3_suffix():
|
| 67 |
+
"""Return the file extension for an abi3-compliant Extension()"""
|
| 68 |
+
for suffix in EXTENSION_SUFFIXES:
|
| 69 |
+
if '.abi3' in suffix: # Unix
|
| 70 |
+
return suffix
|
| 71 |
+
elif suffix == '.pyd': # Windows
|
| 72 |
+
return suffix
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class build_ext(_build_ext):
|
| 76 |
+
def run(self):
|
| 77 |
+
"""Build extensions in build directory, then copy if --inplace"""
|
| 78 |
+
old_inplace, self.inplace = self.inplace, 0
|
| 79 |
+
_build_ext.run(self)
|
| 80 |
+
self.inplace = old_inplace
|
| 81 |
+
if old_inplace:
|
| 82 |
+
self.copy_extensions_to_source()
|
| 83 |
+
|
| 84 |
+
def copy_extensions_to_source(self):
|
| 85 |
+
build_py = self.get_finalized_command('build_py')
|
| 86 |
+
for ext in self.extensions:
|
| 87 |
+
fullname = self.get_ext_fullname(ext.name)
|
| 88 |
+
filename = self.get_ext_filename(fullname)
|
| 89 |
+
modpath = fullname.split('.')
|
| 90 |
+
package = '.'.join(modpath[:-1])
|
| 91 |
+
package_dir = build_py.get_package_dir(package)
|
| 92 |
+
dest_filename = os.path.join(package_dir,
|
| 93 |
+
os.path.basename(filename))
|
| 94 |
+
src_filename = os.path.join(self.build_lib, filename)
|
| 95 |
+
|
| 96 |
+
# Always copy, even if source is older than destination, to ensure
|
| 97 |
+
# that the right extensions for the current Python/platform are
|
| 98 |
+
# used.
|
| 99 |
+
copy_file(
|
| 100 |
+
src_filename, dest_filename, verbose=self.verbose,
|
| 101 |
+
dry_run=self.dry_run
|
| 102 |
+
)
|
| 103 |
+
if ext._needs_stub:
|
| 104 |
+
self.write_stub(package_dir or os.curdir, ext, True)
|
| 105 |
+
|
| 106 |
+
def get_ext_filename(self, fullname):
|
| 107 |
+
so_ext = os.getenv('SETUPTOOLS_EXT_SUFFIX')
|
| 108 |
+
if so_ext:
|
| 109 |
+
filename = os.path.join(*fullname.split('.')) + so_ext
|
| 110 |
+
else:
|
| 111 |
+
filename = _build_ext.get_ext_filename(self, fullname)
|
| 112 |
+
so_ext = get_config_var('EXT_SUFFIX')
|
| 113 |
+
|
| 114 |
+
if fullname in self.ext_map:
|
| 115 |
+
ext = self.ext_map[fullname]
|
| 116 |
+
use_abi3 = getattr(ext, 'py_limited_api') and get_abi3_suffix()
|
| 117 |
+
if use_abi3:
|
| 118 |
+
filename = filename[:-len(so_ext)]
|
| 119 |
+
so_ext = get_abi3_suffix()
|
| 120 |
+
filename = filename + so_ext
|
| 121 |
+
if isinstance(ext, Library):
|
| 122 |
+
fn, ext = os.path.splitext(filename)
|
| 123 |
+
return self.shlib_compiler.library_filename(fn, libtype)
|
| 124 |
+
elif use_stubs and ext._links_to_dynamic:
|
| 125 |
+
d, fn = os.path.split(filename)
|
| 126 |
+
return os.path.join(d, 'dl-' + fn)
|
| 127 |
+
return filename
|
| 128 |
+
|
| 129 |
+
def initialize_options(self):
|
| 130 |
+
_build_ext.initialize_options(self)
|
| 131 |
+
self.shlib_compiler = None
|
| 132 |
+
self.shlibs = []
|
| 133 |
+
self.ext_map = {}
|
| 134 |
+
|
| 135 |
+
def finalize_options(self):
|
| 136 |
+
_build_ext.finalize_options(self)
|
| 137 |
+
self.extensions = self.extensions or []
|
| 138 |
+
self.check_extensions_list(self.extensions)
|
| 139 |
+
self.shlibs = [ext for ext in self.extensions
|
| 140 |
+
if isinstance(ext, Library)]
|
| 141 |
+
if self.shlibs:
|
| 142 |
+
self.setup_shlib_compiler()
|
| 143 |
+
for ext in self.extensions:
|
| 144 |
+
ext._full_name = self.get_ext_fullname(ext.name)
|
| 145 |
+
for ext in self.extensions:
|
| 146 |
+
fullname = ext._full_name
|
| 147 |
+
self.ext_map[fullname] = ext
|
| 148 |
+
|
| 149 |
+
# distutils 3.1 will also ask for module names
|
| 150 |
+
# XXX what to do with conflicts?
|
| 151 |
+
self.ext_map[fullname.split('.')[-1]] = ext
|
| 152 |
+
|
| 153 |
+
ltd = self.shlibs and self.links_to_dynamic(ext) or False
|
| 154 |
+
ns = ltd and use_stubs and not isinstance(ext, Library)
|
| 155 |
+
ext._links_to_dynamic = ltd
|
| 156 |
+
ext._needs_stub = ns
|
| 157 |
+
filename = ext._file_name = self.get_ext_filename(fullname)
|
| 158 |
+
libdir = os.path.dirname(os.path.join(self.build_lib, filename))
|
| 159 |
+
if ltd and libdir not in ext.library_dirs:
|
| 160 |
+
ext.library_dirs.append(libdir)
|
| 161 |
+
if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
|
| 162 |
+
ext.runtime_library_dirs.append(os.curdir)
|
| 163 |
+
|
| 164 |
+
def setup_shlib_compiler(self):
|
| 165 |
+
compiler = self.shlib_compiler = new_compiler(
|
| 166 |
+
compiler=self.compiler, dry_run=self.dry_run, force=self.force
|
| 167 |
+
)
|
| 168 |
+
_customize_compiler_for_shlib(compiler)
|
| 169 |
+
|
| 170 |
+
if self.include_dirs is not None:
|
| 171 |
+
compiler.set_include_dirs(self.include_dirs)
|
| 172 |
+
if self.define is not None:
|
| 173 |
+
# 'define' option is a list of (name,value) tuples
|
| 174 |
+
for (name, value) in self.define:
|
| 175 |
+
compiler.define_macro(name, value)
|
| 176 |
+
if self.undef is not None:
|
| 177 |
+
for macro in self.undef:
|
| 178 |
+
compiler.undefine_macro(macro)
|
| 179 |
+
if self.libraries is not None:
|
| 180 |
+
compiler.set_libraries(self.libraries)
|
| 181 |
+
if self.library_dirs is not None:
|
| 182 |
+
compiler.set_library_dirs(self.library_dirs)
|
| 183 |
+
if self.rpath is not None:
|
| 184 |
+
compiler.set_runtime_library_dirs(self.rpath)
|
| 185 |
+
if self.link_objects is not None:
|
| 186 |
+
compiler.set_link_objects(self.link_objects)
|
| 187 |
+
|
| 188 |
+
# hack so distutils' build_extension() builds a library instead
|
| 189 |
+
compiler.link_shared_object = link_shared_object.__get__(compiler)
|
| 190 |
+
|
| 191 |
+
def get_export_symbols(self, ext):
|
| 192 |
+
if isinstance(ext, Library):
|
| 193 |
+
return ext.export_symbols
|
| 194 |
+
return _build_ext.get_export_symbols(self, ext)
|
| 195 |
+
|
| 196 |
+
def build_extension(self, ext):
|
| 197 |
+
ext._convert_pyx_sources_to_lang()
|
| 198 |
+
_compiler = self.compiler
|
| 199 |
+
try:
|
| 200 |
+
if isinstance(ext, Library):
|
| 201 |
+
self.compiler = self.shlib_compiler
|
| 202 |
+
_build_ext.build_extension(self, ext)
|
| 203 |
+
if ext._needs_stub:
|
| 204 |
+
cmd = self.get_finalized_command('build_py').build_lib
|
| 205 |
+
self.write_stub(cmd, ext)
|
| 206 |
+
finally:
|
| 207 |
+
self.compiler = _compiler
|
| 208 |
+
|
| 209 |
+
def links_to_dynamic(self, ext):
|
| 210 |
+
"""Return true if 'ext' links to a dynamic lib in the same package"""
|
| 211 |
+
# XXX this should check to ensure the lib is actually being built
|
| 212 |
+
# XXX as dynamic, and not just using a locally-found version or a
|
| 213 |
+
# XXX static-compiled version
|
| 214 |
+
libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
|
| 215 |
+
pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
|
| 216 |
+
return any(pkg + libname in libnames for libname in ext.libraries)
|
| 217 |
+
|
| 218 |
+
def get_outputs(self):
|
| 219 |
+
return _build_ext.get_outputs(self) + self.__get_stubs_outputs()
|
| 220 |
+
|
| 221 |
+
def __get_stubs_outputs(self):
|
| 222 |
+
# assemble the base name for each extension that needs a stub
|
| 223 |
+
ns_ext_bases = (
|
| 224 |
+
os.path.join(self.build_lib, *ext._full_name.split('.'))
|
| 225 |
+
for ext in self.extensions
|
| 226 |
+
if ext._needs_stub
|
| 227 |
+
)
|
| 228 |
+
# pair each base with the extension
|
| 229 |
+
pairs = itertools.product(ns_ext_bases, self.__get_output_extensions())
|
| 230 |
+
return list(base + fnext for base, fnext in pairs)
|
| 231 |
+
|
| 232 |
+
def __get_output_extensions(self):
|
| 233 |
+
yield '.py'
|
| 234 |
+
yield '.pyc'
|
| 235 |
+
if self.get_finalized_command('build_py').optimize:
|
| 236 |
+
yield '.pyo'
|
| 237 |
+
|
| 238 |
+
def write_stub(self, output_dir, ext, compile=False):
|
| 239 |
+
log.info("writing stub loader for %s to %s", ext._full_name,
|
| 240 |
+
output_dir)
|
| 241 |
+
stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +
|
| 242 |
+
'.py')
|
| 243 |
+
if compile and os.path.exists(stub_file):
|
| 244 |
+
raise DistutilsError(stub_file + " already exists! Please delete.")
|
| 245 |
+
if not self.dry_run:
|
| 246 |
+
f = open(stub_file, 'w')
|
| 247 |
+
f.write(
|
| 248 |
+
'\n'.join([
|
| 249 |
+
"def __bootstrap__():",
|
| 250 |
+
" global __bootstrap__, __file__, __loader__",
|
| 251 |
+
" import sys, os, pkg_resources, importlib.util" +
|
| 252 |
+
if_dl(", dl"),
|
| 253 |
+
" __file__ = pkg_resources.resource_filename"
|
| 254 |
+
"(__name__,%r)"
|
| 255 |
+
% os.path.basename(ext._file_name),
|
| 256 |
+
" del __bootstrap__",
|
| 257 |
+
" if '__loader__' in globals():",
|
| 258 |
+
" del __loader__",
|
| 259 |
+
if_dl(" old_flags = sys.getdlopenflags()"),
|
| 260 |
+
" old_dir = os.getcwd()",
|
| 261 |
+
" try:",
|
| 262 |
+
" os.chdir(os.path.dirname(__file__))",
|
| 263 |
+
if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
|
| 264 |
+
" spec = importlib.util.spec_from_file_location(",
|
| 265 |
+
" __name__, __file__)",
|
| 266 |
+
" mod = importlib.util.module_from_spec(spec)",
|
| 267 |
+
" spec.loader.exec_module(mod)",
|
| 268 |
+
" finally:",
|
| 269 |
+
if_dl(" sys.setdlopenflags(old_flags)"),
|
| 270 |
+
" os.chdir(old_dir)",
|
| 271 |
+
"__bootstrap__()",
|
| 272 |
+
"" # terminal \n
|
| 273 |
+
])
|
| 274 |
+
)
|
| 275 |
+
f.close()
|
| 276 |
+
if compile:
|
| 277 |
+
from distutils.util import byte_compile
|
| 278 |
+
|
| 279 |
+
byte_compile([stub_file], optimize=0,
|
| 280 |
+
force=True, dry_run=self.dry_run)
|
| 281 |
+
optimize = self.get_finalized_command('install_lib').optimize
|
| 282 |
+
if optimize > 0:
|
| 283 |
+
byte_compile([stub_file], optimize=optimize,
|
| 284 |
+
force=True, dry_run=self.dry_run)
|
| 285 |
+
if os.path.exists(stub_file) and not self.dry_run:
|
| 286 |
+
os.unlink(stub_file)
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
if use_stubs or os.name == 'nt':
|
| 290 |
+
# Build shared libraries
|
| 291 |
+
#
|
| 292 |
+
def link_shared_object(
|
| 293 |
+
self, objects, output_libname, output_dir=None, libraries=None,
|
| 294 |
+
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
|
| 295 |
+
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
|
| 296 |
+
target_lang=None):
|
| 297 |
+
self.link(
|
| 298 |
+
self.SHARED_LIBRARY, objects, output_libname,
|
| 299 |
+
output_dir, libraries, library_dirs, runtime_library_dirs,
|
| 300 |
+
export_symbols, debug, extra_preargs, extra_postargs,
|
| 301 |
+
build_temp, target_lang
|
| 302 |
+
)
|
| 303 |
+
else:
|
| 304 |
+
# Build static libraries everywhere else
|
| 305 |
+
libtype = 'static'
|
| 306 |
+
|
| 307 |
+
def link_shared_object(
|
| 308 |
+
self, objects, output_libname, output_dir=None, libraries=None,
|
| 309 |
+
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
|
| 310 |
+
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
|
| 311 |
+
target_lang=None):
|
| 312 |
+
# XXX we need to either disallow these attrs on Library instances,
|
| 313 |
+
# or warn/abort here if set, or something...
|
| 314 |
+
# libraries=None, library_dirs=None, runtime_library_dirs=None,
|
| 315 |
+
# export_symbols=None, extra_preargs=None, extra_postargs=None,
|
| 316 |
+
# build_temp=None
|
| 317 |
+
|
| 318 |
+
assert output_dir is None # distutils build_ext doesn't pass this
|
| 319 |
+
output_dir, filename = os.path.split(output_libname)
|
| 320 |
+
basename, ext = os.path.splitext(filename)
|
| 321 |
+
if self.library_filename("x").startswith('lib'):
|
| 322 |
+
# strip 'lib' prefix; this is kludgy if some platform uses
|
| 323 |
+
# a different prefix
|
| 324 |
+
basename = basename[3:]
|
| 325 |
+
|
| 326 |
+
self.create_static_lib(
|
| 327 |
+
objects, basename, output_dir, debug, target_lang
|
| 328 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/setuptools/command/easy_install.py
ADDED
|
@@ -0,0 +1,2290 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Easy Install
|
| 3 |
+
------------
|
| 4 |
+
|
| 5 |
+
A tool for doing automatic download/extract/build of distutils-based Python
|
| 6 |
+
packages. For detailed documentation, see the accompanying EasyInstall.txt
|
| 7 |
+
file, or visit the `EasyInstall home page`__.
|
| 8 |
+
|
| 9 |
+
__ https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html
|
| 10 |
+
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
from glob import glob
|
| 14 |
+
from distutils.util import get_platform
|
| 15 |
+
from distutils.util import convert_path, subst_vars
|
| 16 |
+
from distutils.errors import (
|
| 17 |
+
DistutilsArgError, DistutilsOptionError,
|
| 18 |
+
DistutilsError, DistutilsPlatformError,
|
| 19 |
+
)
|
| 20 |
+
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
|
| 21 |
+
from distutils import log, dir_util
|
| 22 |
+
from distutils.command.build_scripts import first_line_re
|
| 23 |
+
from distutils.spawn import find_executable
|
| 24 |
+
import sys
|
| 25 |
+
import os
|
| 26 |
+
import zipimport
|
| 27 |
+
import shutil
|
| 28 |
+
import tempfile
|
| 29 |
+
import zipfile
|
| 30 |
+
import re
|
| 31 |
+
import stat
|
| 32 |
+
import random
|
| 33 |
+
import textwrap
|
| 34 |
+
import warnings
|
| 35 |
+
import site
|
| 36 |
+
import struct
|
| 37 |
+
import contextlib
|
| 38 |
+
import subprocess
|
| 39 |
+
import shlex
|
| 40 |
+
import io
|
| 41 |
+
import configparser
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
from sysconfig import get_config_vars, get_path
|
| 45 |
+
|
| 46 |
+
from setuptools import SetuptoolsDeprecationWarning
|
| 47 |
+
|
| 48 |
+
from setuptools import Command
|
| 49 |
+
from setuptools.sandbox import run_setup
|
| 50 |
+
from setuptools.command import setopt
|
| 51 |
+
from setuptools.archive_util import unpack_archive
|
| 52 |
+
from setuptools.package_index import (
|
| 53 |
+
PackageIndex, parse_requirement_arg, URL_SCHEME,
|
| 54 |
+
)
|
| 55 |
+
from setuptools.command import bdist_egg, egg_info
|
| 56 |
+
from setuptools.wheel import Wheel
|
| 57 |
+
from pkg_resources import (
|
| 58 |
+
yield_lines, normalize_path, resource_string, ensure_directory,
|
| 59 |
+
get_distribution, find_distributions, Environment, Requirement,
|
| 60 |
+
Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
|
| 61 |
+
VersionConflict, DEVELOP_DIST,
|
| 62 |
+
)
|
| 63 |
+
import pkg_resources
|
| 64 |
+
|
| 65 |
+
# Turn on PEP440Warnings
|
| 66 |
+
warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
|
| 67 |
+
|
| 68 |
+
__all__ = [
|
| 69 |
+
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
|
| 70 |
+
'get_exe_prefixes',
|
| 71 |
+
]
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def is_64bit():
|
| 75 |
+
return struct.calcsize("P") == 8
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def samefile(p1, p2):
|
| 79 |
+
"""
|
| 80 |
+
Determine if two paths reference the same file.
|
| 81 |
+
|
| 82 |
+
Augments os.path.samefile to work on Windows and
|
| 83 |
+
suppresses errors if the path doesn't exist.
|
| 84 |
+
"""
|
| 85 |
+
both_exist = os.path.exists(p1) and os.path.exists(p2)
|
| 86 |
+
use_samefile = hasattr(os.path, 'samefile') and both_exist
|
| 87 |
+
if use_samefile:
|
| 88 |
+
return os.path.samefile(p1, p2)
|
| 89 |
+
norm_p1 = os.path.normpath(os.path.normcase(p1))
|
| 90 |
+
norm_p2 = os.path.normpath(os.path.normcase(p2))
|
| 91 |
+
return norm_p1 == norm_p2
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def _to_bytes(s):
|
| 95 |
+
return s.encode('utf8')
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def isascii(s):
|
| 99 |
+
try:
|
| 100 |
+
s.encode('ascii')
|
| 101 |
+
return True
|
| 102 |
+
except UnicodeError:
|
| 103 |
+
return False
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def _one_liner(text):
|
| 107 |
+
return textwrap.dedent(text).strip().replace('\n', '; ')
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
class easy_install(Command):
|
| 111 |
+
"""Manage a download/build/install process"""
|
| 112 |
+
description = "Find/get/install Python packages"
|
| 113 |
+
command_consumes_arguments = True
|
| 114 |
+
|
| 115 |
+
user_options = [
|
| 116 |
+
('prefix=', None, "installation prefix"),
|
| 117 |
+
("zip-ok", "z", "install package as a zipfile"),
|
| 118 |
+
("multi-version", "m", "make apps have to require() a version"),
|
| 119 |
+
("upgrade", "U", "force upgrade (searches PyPI for latest versions)"),
|
| 120 |
+
("install-dir=", "d", "install package to DIR"),
|
| 121 |
+
("script-dir=", "s", "install scripts to DIR"),
|
| 122 |
+
("exclude-scripts", "x", "Don't install scripts"),
|
| 123 |
+
("always-copy", "a", "Copy all needed packages to install dir"),
|
| 124 |
+
("index-url=", "i", "base URL of Python Package Index"),
|
| 125 |
+
("find-links=", "f", "additional URL(s) to search for packages"),
|
| 126 |
+
("build-directory=", "b",
|
| 127 |
+
"download/extract/build in DIR; keep the results"),
|
| 128 |
+
('optimize=', 'O',
|
| 129 |
+
"also compile with optimization: -O1 for \"python -O\", "
|
| 130 |
+
"-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
|
| 131 |
+
('record=', None,
|
| 132 |
+
"filename in which to record list of installed files"),
|
| 133 |
+
('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
|
| 134 |
+
('site-dirs=', 'S', "list of directories where .pth files work"),
|
| 135 |
+
('editable', 'e', "Install specified packages in editable form"),
|
| 136 |
+
('no-deps', 'N', "don't install dependencies"),
|
| 137 |
+
('allow-hosts=', 'H', "pattern(s) that hostnames must match"),
|
| 138 |
+
('local-snapshots-ok', 'l',
|
| 139 |
+
"allow building eggs from local checkouts"),
|
| 140 |
+
('version', None, "print version information and exit"),
|
| 141 |
+
('no-find-links', None,
|
| 142 |
+
"Don't load find-links defined in packages being installed"),
|
| 143 |
+
('user', None, "install in user site-package '%s'" % site.USER_SITE)
|
| 144 |
+
]
|
| 145 |
+
boolean_options = [
|
| 146 |
+
'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
|
| 147 |
+
'editable',
|
| 148 |
+
'no-deps', 'local-snapshots-ok', 'version',
|
| 149 |
+
'user'
|
| 150 |
+
]
|
| 151 |
+
|
| 152 |
+
negative_opt = {'always-unzip': 'zip-ok'}
|
| 153 |
+
create_index = PackageIndex
|
| 154 |
+
|
| 155 |
+
def initialize_options(self):
|
| 156 |
+
# the --user option seems to be an opt-in one,
|
| 157 |
+
# so the default should be False.
|
| 158 |
+
self.user = 0
|
| 159 |
+
self.zip_ok = self.local_snapshots_ok = None
|
| 160 |
+
self.install_dir = self.script_dir = self.exclude_scripts = None
|
| 161 |
+
self.index_url = None
|
| 162 |
+
self.find_links = None
|
| 163 |
+
self.build_directory = None
|
| 164 |
+
self.args = None
|
| 165 |
+
self.optimize = self.record = None
|
| 166 |
+
self.upgrade = self.always_copy = self.multi_version = None
|
| 167 |
+
self.editable = self.no_deps = self.allow_hosts = None
|
| 168 |
+
self.root = self.prefix = self.no_report = None
|
| 169 |
+
self.version = None
|
| 170 |
+
self.install_purelib = None # for pure module distributions
|
| 171 |
+
self.install_platlib = None # non-pure (dists w/ extensions)
|
| 172 |
+
self.install_headers = None # for C/C++ headers
|
| 173 |
+
self.install_lib = None # set to either purelib or platlib
|
| 174 |
+
self.install_scripts = None
|
| 175 |
+
self.install_data = None
|
| 176 |
+
self.install_base = None
|
| 177 |
+
self.install_platbase = None
|
| 178 |
+
if site.ENABLE_USER_SITE:
|
| 179 |
+
self.install_userbase = site.USER_BASE
|
| 180 |
+
self.install_usersite = site.USER_SITE
|
| 181 |
+
else:
|
| 182 |
+
self.install_userbase = None
|
| 183 |
+
self.install_usersite = None
|
| 184 |
+
self.no_find_links = None
|
| 185 |
+
|
| 186 |
+
# Options not specifiable via command line
|
| 187 |
+
self.package_index = None
|
| 188 |
+
self.pth_file = self.always_copy_from = None
|
| 189 |
+
self.site_dirs = None
|
| 190 |
+
self.installed_projects = {}
|
| 191 |
+
# Always read easy_install options, even if we are subclassed, or have
|
| 192 |
+
# an independent instance created. This ensures that defaults will
|
| 193 |
+
# always come from the standard configuration file(s)' "easy_install"
|
| 194 |
+
# section, even if this is a "develop" or "install" command, or some
|
| 195 |
+
# other embedding.
|
| 196 |
+
self._dry_run = None
|
| 197 |
+
self.verbose = self.distribution.verbose
|
| 198 |
+
self.distribution._set_command_options(
|
| 199 |
+
self, self.distribution.get_option_dict('easy_install')
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
def delete_blockers(self, blockers):
|
| 203 |
+
extant_blockers = (
|
| 204 |
+
filename for filename in blockers
|
| 205 |
+
if os.path.exists(filename) or os.path.islink(filename)
|
| 206 |
+
)
|
| 207 |
+
list(map(self._delete_path, extant_blockers))
|
| 208 |
+
|
| 209 |
+
def _delete_path(self, path):
|
| 210 |
+
log.info("Deleting %s", path)
|
| 211 |
+
if self.dry_run:
|
| 212 |
+
return
|
| 213 |
+
|
| 214 |
+
is_tree = os.path.isdir(path) and not os.path.islink(path)
|
| 215 |
+
remover = rmtree if is_tree else os.unlink
|
| 216 |
+
remover(path)
|
| 217 |
+
|
| 218 |
+
@staticmethod
|
| 219 |
+
def _render_version():
|
| 220 |
+
"""
|
| 221 |
+
Render the Setuptools version and installation details, then exit.
|
| 222 |
+
"""
|
| 223 |
+
ver = '{}.{}'.format(*sys.version_info)
|
| 224 |
+
dist = get_distribution('setuptools')
|
| 225 |
+
tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})'
|
| 226 |
+
print(tmpl.format(**locals()))
|
| 227 |
+
raise SystemExit()
|
| 228 |
+
|
| 229 |
+
def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME
|
| 230 |
+
self.version and self._render_version()
|
| 231 |
+
|
| 232 |
+
py_version = sys.version.split()[0]
|
| 233 |
+
prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix')
|
| 234 |
+
|
| 235 |
+
self.config_vars = {
|
| 236 |
+
'dist_name': self.distribution.get_name(),
|
| 237 |
+
'dist_version': self.distribution.get_version(),
|
| 238 |
+
'dist_fullname': self.distribution.get_fullname(),
|
| 239 |
+
'py_version': py_version,
|
| 240 |
+
'py_version_short': py_version[0:3],
|
| 241 |
+
'py_version_nodot': py_version[0] + py_version[2],
|
| 242 |
+
'sys_prefix': prefix,
|
| 243 |
+
'prefix': prefix,
|
| 244 |
+
'sys_exec_prefix': exec_prefix,
|
| 245 |
+
'exec_prefix': exec_prefix,
|
| 246 |
+
# Only python 3.2+ has abiflags
|
| 247 |
+
'abiflags': getattr(sys, 'abiflags', ''),
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
if site.ENABLE_USER_SITE:
|
| 251 |
+
self.config_vars['userbase'] = self.install_userbase
|
| 252 |
+
self.config_vars['usersite'] = self.install_usersite
|
| 253 |
+
|
| 254 |
+
elif self.user:
|
| 255 |
+
log.warn("WARNING: The user site-packages directory is disabled.")
|
| 256 |
+
|
| 257 |
+
self._fix_install_dir_for_user_site()
|
| 258 |
+
|
| 259 |
+
self.expand_basedirs()
|
| 260 |
+
self.expand_dirs()
|
| 261 |
+
|
| 262 |
+
self._expand(
|
| 263 |
+
'install_dir', 'script_dir', 'build_directory',
|
| 264 |
+
'site_dirs',
|
| 265 |
+
)
|
| 266 |
+
# If a non-default installation directory was specified, default the
|
| 267 |
+
# script directory to match it.
|
| 268 |
+
if self.script_dir is None:
|
| 269 |
+
self.script_dir = self.install_dir
|
| 270 |
+
|
| 271 |
+
if self.no_find_links is None:
|
| 272 |
+
self.no_find_links = False
|
| 273 |
+
|
| 274 |
+
# Let install_dir get set by install_lib command, which in turn
|
| 275 |
+
# gets its info from the install command, and takes into account
|
| 276 |
+
# --prefix and --home and all that other crud.
|
| 277 |
+
self.set_undefined_options(
|
| 278 |
+
'install_lib', ('install_dir', 'install_dir')
|
| 279 |
+
)
|
| 280 |
+
# Likewise, set default script_dir from 'install_scripts.install_dir'
|
| 281 |
+
self.set_undefined_options(
|
| 282 |
+
'install_scripts', ('install_dir', 'script_dir')
|
| 283 |
+
)
|
| 284 |
+
|
| 285 |
+
if self.user and self.install_purelib:
|
| 286 |
+
self.install_dir = self.install_purelib
|
| 287 |
+
self.script_dir = self.install_scripts
|
| 288 |
+
# default --record from the install command
|
| 289 |
+
self.set_undefined_options('install', ('record', 'record'))
|
| 290 |
+
# Should this be moved to the if statement below? It's not used
|
| 291 |
+
# elsewhere
|
| 292 |
+
normpath = map(normalize_path, sys.path)
|
| 293 |
+
self.all_site_dirs = get_site_dirs()
|
| 294 |
+
if self.site_dirs is not None:
|
| 295 |
+
site_dirs = [
|
| 296 |
+
os.path.expanduser(s.strip()) for s in
|
| 297 |
+
self.site_dirs.split(',')
|
| 298 |
+
]
|
| 299 |
+
for d in site_dirs:
|
| 300 |
+
if not os.path.isdir(d):
|
| 301 |
+
log.warn("%s (in --site-dirs) does not exist", d)
|
| 302 |
+
elif normalize_path(d) not in normpath:
|
| 303 |
+
raise DistutilsOptionError(
|
| 304 |
+
d + " (in --site-dirs) is not on sys.path"
|
| 305 |
+
)
|
| 306 |
+
else:
|
| 307 |
+
self.all_site_dirs.append(normalize_path(d))
|
| 308 |
+
if not self.editable:
|
| 309 |
+
self.check_site_dir()
|
| 310 |
+
self.index_url = self.index_url or "https://pypi.org/simple/"
|
| 311 |
+
self.shadow_path = self.all_site_dirs[:]
|
| 312 |
+
for path_item in self.install_dir, normalize_path(self.script_dir):
|
| 313 |
+
if path_item not in self.shadow_path:
|
| 314 |
+
self.shadow_path.insert(0, path_item)
|
| 315 |
+
|
| 316 |
+
if self.allow_hosts is not None:
|
| 317 |
+
hosts = [s.strip() for s in self.allow_hosts.split(',')]
|
| 318 |
+
else:
|
| 319 |
+
hosts = ['*']
|
| 320 |
+
if self.package_index is None:
|
| 321 |
+
self.package_index = self.create_index(
|
| 322 |
+
self.index_url, search_path=self.shadow_path, hosts=hosts,
|
| 323 |
+
)
|
| 324 |
+
self.local_index = Environment(self.shadow_path + sys.path)
|
| 325 |
+
|
| 326 |
+
if self.find_links is not None:
|
| 327 |
+
if isinstance(self.find_links, str):
|
| 328 |
+
self.find_links = self.find_links.split()
|
| 329 |
+
else:
|
| 330 |
+
self.find_links = []
|
| 331 |
+
if self.local_snapshots_ok:
|
| 332 |
+
self.package_index.scan_egg_links(self.shadow_path + sys.path)
|
| 333 |
+
if not self.no_find_links:
|
| 334 |
+
self.package_index.add_find_links(self.find_links)
|
| 335 |
+
self.set_undefined_options('install_lib', ('optimize', 'optimize'))
|
| 336 |
+
if not isinstance(self.optimize, int):
|
| 337 |
+
try:
|
| 338 |
+
self.optimize = int(self.optimize)
|
| 339 |
+
if not (0 <= self.optimize <= 2):
|
| 340 |
+
raise ValueError
|
| 341 |
+
except ValueError as e:
|
| 342 |
+
raise DistutilsOptionError(
|
| 343 |
+
"--optimize must be 0, 1, or 2"
|
| 344 |
+
) from e
|
| 345 |
+
|
| 346 |
+
if self.editable and not self.build_directory:
|
| 347 |
+
raise DistutilsArgError(
|
| 348 |
+
"Must specify a build directory (-b) when using --editable"
|
| 349 |
+
)
|
| 350 |
+
if not self.args:
|
| 351 |
+
raise DistutilsArgError(
|
| 352 |
+
"No urls, filenames, or requirements specified (see --help)")
|
| 353 |
+
|
| 354 |
+
self.outputs = []
|
| 355 |
+
|
| 356 |
+
def _fix_install_dir_for_user_site(self):
|
| 357 |
+
"""
|
| 358 |
+
Fix the install_dir if "--user" was used.
|
| 359 |
+
"""
|
| 360 |
+
if not self.user or not site.ENABLE_USER_SITE:
|
| 361 |
+
return
|
| 362 |
+
|
| 363 |
+
self.create_home_path()
|
| 364 |
+
if self.install_userbase is None:
|
| 365 |
+
msg = "User base directory is not specified"
|
| 366 |
+
raise DistutilsPlatformError(msg)
|
| 367 |
+
self.install_base = self.install_platbase = self.install_userbase
|
| 368 |
+
scheme_name = os.name.replace('posix', 'unix') + '_user'
|
| 369 |
+
self.select_scheme(scheme_name)
|
| 370 |
+
|
| 371 |
+
def _expand_attrs(self, attrs):
|
| 372 |
+
for attr in attrs:
|
| 373 |
+
val = getattr(self, attr)
|
| 374 |
+
if val is not None:
|
| 375 |
+
if os.name == 'posix' or os.name == 'nt':
|
| 376 |
+
val = os.path.expanduser(val)
|
| 377 |
+
val = subst_vars(val, self.config_vars)
|
| 378 |
+
setattr(self, attr, val)
|
| 379 |
+
|
| 380 |
+
def expand_basedirs(self):
|
| 381 |
+
"""Calls `os.path.expanduser` on install_base, install_platbase and
|
| 382 |
+
root."""
|
| 383 |
+
self._expand_attrs(['install_base', 'install_platbase', 'root'])
|
| 384 |
+
|
| 385 |
+
def expand_dirs(self):
|
| 386 |
+
"""Calls `os.path.expanduser` on install dirs."""
|
| 387 |
+
dirs = [
|
| 388 |
+
'install_purelib',
|
| 389 |
+
'install_platlib',
|
| 390 |
+
'install_lib',
|
| 391 |
+
'install_headers',
|
| 392 |
+
'install_scripts',
|
| 393 |
+
'install_data',
|
| 394 |
+
]
|
| 395 |
+
self._expand_attrs(dirs)
|
| 396 |
+
|
| 397 |
+
def run(self, show_deprecation=True):
|
| 398 |
+
if show_deprecation:
|
| 399 |
+
self.announce(
|
| 400 |
+
"WARNING: The easy_install command is deprecated "
|
| 401 |
+
"and will be removed in a future version.",
|
| 402 |
+
log.WARN,
|
| 403 |
+
)
|
| 404 |
+
if self.verbose != self.distribution.verbose:
|
| 405 |
+
log.set_verbosity(self.verbose)
|
| 406 |
+
try:
|
| 407 |
+
for spec in self.args:
|
| 408 |
+
self.easy_install(spec, not self.no_deps)
|
| 409 |
+
if self.record:
|
| 410 |
+
outputs = self.outputs
|
| 411 |
+
if self.root: # strip any package prefix
|
| 412 |
+
root_len = len(self.root)
|
| 413 |
+
for counter in range(len(outputs)):
|
| 414 |
+
outputs[counter] = outputs[counter][root_len:]
|
| 415 |
+
from distutils import file_util
|
| 416 |
+
|
| 417 |
+
self.execute(
|
| 418 |
+
file_util.write_file, (self.record, outputs),
|
| 419 |
+
"writing list of installed files to '%s'" %
|
| 420 |
+
self.record
|
| 421 |
+
)
|
| 422 |
+
self.warn_deprecated_options()
|
| 423 |
+
finally:
|
| 424 |
+
log.set_verbosity(self.distribution.verbose)
|
| 425 |
+
|
| 426 |
+
def pseudo_tempname(self):
|
| 427 |
+
"""Return a pseudo-tempname base in the install directory.
|
| 428 |
+
This code is intentionally naive; if a malicious party can write to
|
| 429 |
+
the target directory you're already in deep doodoo.
|
| 430 |
+
"""
|
| 431 |
+
try:
|
| 432 |
+
pid = os.getpid()
|
| 433 |
+
except Exception:
|
| 434 |
+
pid = random.randint(0, sys.maxsize)
|
| 435 |
+
return os.path.join(self.install_dir, "test-easy-install-%s" % pid)
|
| 436 |
+
|
| 437 |
+
def warn_deprecated_options(self):
|
| 438 |
+
pass
|
| 439 |
+
|
| 440 |
+
def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME
|
| 441 |
+
"""Verify that self.install_dir is .pth-capable dir, if needed"""
|
| 442 |
+
|
| 443 |
+
instdir = normalize_path(self.install_dir)
|
| 444 |
+
pth_file = os.path.join(instdir, 'easy-install.pth')
|
| 445 |
+
|
| 446 |
+
if not os.path.exists(instdir):
|
| 447 |
+
try:
|
| 448 |
+
os.makedirs(instdir)
|
| 449 |
+
except (OSError, IOError):
|
| 450 |
+
self.cant_write_to_target()
|
| 451 |
+
|
| 452 |
+
# Is it a configured, PYTHONPATH, implicit, or explicit site dir?
|
| 453 |
+
is_site_dir = instdir in self.all_site_dirs
|
| 454 |
+
|
| 455 |
+
if not is_site_dir and not self.multi_version:
|
| 456 |
+
# No? Then directly test whether it does .pth file processing
|
| 457 |
+
is_site_dir = self.check_pth_processing()
|
| 458 |
+
else:
|
| 459 |
+
# make sure we can write to target dir
|
| 460 |
+
testfile = self.pseudo_tempname() + '.write-test'
|
| 461 |
+
test_exists = os.path.exists(testfile)
|
| 462 |
+
try:
|
| 463 |
+
if test_exists:
|
| 464 |
+
os.unlink(testfile)
|
| 465 |
+
open(testfile, 'w').close()
|
| 466 |
+
os.unlink(testfile)
|
| 467 |
+
except (OSError, IOError):
|
| 468 |
+
self.cant_write_to_target()
|
| 469 |
+
|
| 470 |
+
if not is_site_dir and not self.multi_version:
|
| 471 |
+
# Can't install non-multi to non-site dir with easy_install
|
| 472 |
+
pythonpath = os.environ.get('PYTHONPATH', '')
|
| 473 |
+
log.warn(self.__no_default_msg, self.install_dir, pythonpath)
|
| 474 |
+
|
| 475 |
+
if is_site_dir:
|
| 476 |
+
if self.pth_file is None:
|
| 477 |
+
self.pth_file = PthDistributions(pth_file, self.all_site_dirs)
|
| 478 |
+
else:
|
| 479 |
+
self.pth_file = None
|
| 480 |
+
|
| 481 |
+
if self.multi_version and not os.path.exists(pth_file):
|
| 482 |
+
self.pth_file = None # don't create a .pth file
|
| 483 |
+
self.install_dir = instdir
|
| 484 |
+
|
| 485 |
+
__cant_write_msg = textwrap.dedent("""
|
| 486 |
+
can't create or remove files in install directory
|
| 487 |
+
|
| 488 |
+
The following error occurred while trying to add or remove files in the
|
| 489 |
+
installation directory:
|
| 490 |
+
|
| 491 |
+
%s
|
| 492 |
+
|
| 493 |
+
The installation directory you specified (via --install-dir, --prefix, or
|
| 494 |
+
the distutils default setting) was:
|
| 495 |
+
|
| 496 |
+
%s
|
| 497 |
+
""").lstrip() # noqa
|
| 498 |
+
|
| 499 |
+
__not_exists_id = textwrap.dedent("""
|
| 500 |
+
This directory does not currently exist. Please create it and try again, or
|
| 501 |
+
choose a different installation directory (using the -d or --install-dir
|
| 502 |
+
option).
|
| 503 |
+
""").lstrip() # noqa
|
| 504 |
+
|
| 505 |
+
__access_msg = textwrap.dedent("""
|
| 506 |
+
Perhaps your account does not have write access to this directory? If the
|
| 507 |
+
installation directory is a system-owned directory, you may need to sign in
|
| 508 |
+
as the administrator or "root" account. If you do not have administrative
|
| 509 |
+
access to this machine, you may wish to choose a different installation
|
| 510 |
+
directory, preferably one that is listed in your PYTHONPATH environment
|
| 511 |
+
variable.
|
| 512 |
+
|
| 513 |
+
For information on other options, you may wish to consult the
|
| 514 |
+
documentation at:
|
| 515 |
+
|
| 516 |
+
https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html
|
| 517 |
+
|
| 518 |
+
Please make the appropriate changes for your system and try again.
|
| 519 |
+
""").lstrip() # noqa
|
| 520 |
+
|
| 521 |
+
def cant_write_to_target(self):
|
| 522 |
+
msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,)
|
| 523 |
+
|
| 524 |
+
if not os.path.exists(self.install_dir):
|
| 525 |
+
msg += '\n' + self.__not_exists_id
|
| 526 |
+
else:
|
| 527 |
+
msg += '\n' + self.__access_msg
|
| 528 |
+
raise DistutilsError(msg)
|
| 529 |
+
|
| 530 |
+
def check_pth_processing(self):
|
| 531 |
+
"""Empirically verify whether .pth files are supported in inst. dir"""
|
| 532 |
+
instdir = self.install_dir
|
| 533 |
+
log.info("Checking .pth file support in %s", instdir)
|
| 534 |
+
pth_file = self.pseudo_tempname() + ".pth"
|
| 535 |
+
ok_file = pth_file + '.ok'
|
| 536 |
+
ok_exists = os.path.exists(ok_file)
|
| 537 |
+
tmpl = _one_liner("""
|
| 538 |
+
import os
|
| 539 |
+
f = open({ok_file!r}, 'w')
|
| 540 |
+
f.write('OK')
|
| 541 |
+
f.close()
|
| 542 |
+
""") + '\n'
|
| 543 |
+
try:
|
| 544 |
+
if ok_exists:
|
| 545 |
+
os.unlink(ok_file)
|
| 546 |
+
dirname = os.path.dirname(ok_file)
|
| 547 |
+
os.makedirs(dirname, exist_ok=True)
|
| 548 |
+
f = open(pth_file, 'w')
|
| 549 |
+
except (OSError, IOError):
|
| 550 |
+
self.cant_write_to_target()
|
| 551 |
+
else:
|
| 552 |
+
try:
|
| 553 |
+
f.write(tmpl.format(**locals()))
|
| 554 |
+
f.close()
|
| 555 |
+
f = None
|
| 556 |
+
executable = sys.executable
|
| 557 |
+
if os.name == 'nt':
|
| 558 |
+
dirname, basename = os.path.split(executable)
|
| 559 |
+
alt = os.path.join(dirname, 'pythonw.exe')
|
| 560 |
+
use_alt = (
|
| 561 |
+
basename.lower() == 'python.exe' and
|
| 562 |
+
os.path.exists(alt)
|
| 563 |
+
)
|
| 564 |
+
if use_alt:
|
| 565 |
+
# use pythonw.exe to avoid opening a console window
|
| 566 |
+
executable = alt
|
| 567 |
+
|
| 568 |
+
from distutils.spawn import spawn
|
| 569 |
+
|
| 570 |
+
spawn([executable, '-E', '-c', 'pass'], 0)
|
| 571 |
+
|
| 572 |
+
if os.path.exists(ok_file):
|
| 573 |
+
log.info(
|
| 574 |
+
"TEST PASSED: %s appears to support .pth files",
|
| 575 |
+
instdir
|
| 576 |
+
)
|
| 577 |
+
return True
|
| 578 |
+
finally:
|
| 579 |
+
if f:
|
| 580 |
+
f.close()
|
| 581 |
+
if os.path.exists(ok_file):
|
| 582 |
+
os.unlink(ok_file)
|
| 583 |
+
if os.path.exists(pth_file):
|
| 584 |
+
os.unlink(pth_file)
|
| 585 |
+
if not self.multi_version:
|
| 586 |
+
log.warn("TEST FAILED: %s does NOT support .pth files", instdir)
|
| 587 |
+
return False
|
| 588 |
+
|
| 589 |
+
def install_egg_scripts(self, dist):
|
| 590 |
+
"""Write all the scripts for `dist`, unless scripts are excluded"""
|
| 591 |
+
if not self.exclude_scripts and dist.metadata_isdir('scripts'):
|
| 592 |
+
for script_name in dist.metadata_listdir('scripts'):
|
| 593 |
+
if dist.metadata_isdir('scripts/' + script_name):
|
| 594 |
+
# The "script" is a directory, likely a Python 3
|
| 595 |
+
# __pycache__ directory, so skip it.
|
| 596 |
+
continue
|
| 597 |
+
self.install_script(
|
| 598 |
+
dist, script_name,
|
| 599 |
+
dist.get_metadata('scripts/' + script_name)
|
| 600 |
+
)
|
| 601 |
+
self.install_wrapper_scripts(dist)
|
| 602 |
+
|
| 603 |
+
def add_output(self, path):
|
| 604 |
+
if os.path.isdir(path):
|
| 605 |
+
for base, dirs, files in os.walk(path):
|
| 606 |
+
for filename in files:
|
| 607 |
+
self.outputs.append(os.path.join(base, filename))
|
| 608 |
+
else:
|
| 609 |
+
self.outputs.append(path)
|
| 610 |
+
|
| 611 |
+
def not_editable(self, spec):
|
| 612 |
+
if self.editable:
|
| 613 |
+
raise DistutilsArgError(
|
| 614 |
+
"Invalid argument %r: you can't use filenames or URLs "
|
| 615 |
+
"with --editable (except via the --find-links option)."
|
| 616 |
+
% (spec,)
|
| 617 |
+
)
|
| 618 |
+
|
| 619 |
+
def check_editable(self, spec):
|
| 620 |
+
if not self.editable:
|
| 621 |
+
return
|
| 622 |
+
|
| 623 |
+
if os.path.exists(os.path.join(self.build_directory, spec.key)):
|
| 624 |
+
raise DistutilsArgError(
|
| 625 |
+
"%r already exists in %s; can't do a checkout there" %
|
| 626 |
+
(spec.key, self.build_directory)
|
| 627 |
+
)
|
| 628 |
+
|
| 629 |
+
@contextlib.contextmanager
|
| 630 |
+
def _tmpdir(self):
|
| 631 |
+
tmpdir = tempfile.mkdtemp(prefix=u"easy_install-")
|
| 632 |
+
try:
|
| 633 |
+
# cast to str as workaround for #709 and #710 and #712
|
| 634 |
+
yield str(tmpdir)
|
| 635 |
+
finally:
|
| 636 |
+
os.path.exists(tmpdir) and rmtree(tmpdir)
|
| 637 |
+
|
| 638 |
+
def easy_install(self, spec, deps=False):
|
| 639 |
+
with self._tmpdir() as tmpdir:
|
| 640 |
+
if not isinstance(spec, Requirement):
|
| 641 |
+
if URL_SCHEME(spec):
|
| 642 |
+
# It's a url, download it to tmpdir and process
|
| 643 |
+
self.not_editable(spec)
|
| 644 |
+
dl = self.package_index.download(spec, tmpdir)
|
| 645 |
+
return self.install_item(None, dl, tmpdir, deps, True)
|
| 646 |
+
|
| 647 |
+
elif os.path.exists(spec):
|
| 648 |
+
# Existing file or directory, just process it directly
|
| 649 |
+
self.not_editable(spec)
|
| 650 |
+
return self.install_item(None, spec, tmpdir, deps, True)
|
| 651 |
+
else:
|
| 652 |
+
spec = parse_requirement_arg(spec)
|
| 653 |
+
|
| 654 |
+
self.check_editable(spec)
|
| 655 |
+
dist = self.package_index.fetch_distribution(
|
| 656 |
+
spec, tmpdir, self.upgrade, self.editable,
|
| 657 |
+
not self.always_copy, self.local_index
|
| 658 |
+
)
|
| 659 |
+
if dist is None:
|
| 660 |
+
msg = "Could not find suitable distribution for %r" % spec
|
| 661 |
+
if self.always_copy:
|
| 662 |
+
msg += " (--always-copy skips system and development eggs)"
|
| 663 |
+
raise DistutilsError(msg)
|
| 664 |
+
elif dist.precedence == DEVELOP_DIST:
|
| 665 |
+
# .egg-info dists don't need installing, just process deps
|
| 666 |
+
self.process_distribution(spec, dist, deps, "Using")
|
| 667 |
+
return dist
|
| 668 |
+
else:
|
| 669 |
+
return self.install_item(spec, dist.location, tmpdir, deps)
|
| 670 |
+
|
| 671 |
+
def install_item(self, spec, download, tmpdir, deps, install_needed=False):
|
| 672 |
+
|
| 673 |
+
# Installation is also needed if file in tmpdir or is not an egg
|
| 674 |
+
install_needed = install_needed or self.always_copy
|
| 675 |
+
install_needed = install_needed or os.path.dirname(download) == tmpdir
|
| 676 |
+
install_needed = install_needed or not download.endswith('.egg')
|
| 677 |
+
install_needed = install_needed or (
|
| 678 |
+
self.always_copy_from is not None and
|
| 679 |
+
os.path.dirname(normalize_path(download)) ==
|
| 680 |
+
normalize_path(self.always_copy_from)
|
| 681 |
+
)
|
| 682 |
+
|
| 683 |
+
if spec and not install_needed:
|
| 684 |
+
# at this point, we know it's a local .egg, we just don't know if
|
| 685 |
+
# it's already installed.
|
| 686 |
+
for dist in self.local_index[spec.project_name]:
|
| 687 |
+
if dist.location == download:
|
| 688 |
+
break
|
| 689 |
+
else:
|
| 690 |
+
install_needed = True # it's not in the local index
|
| 691 |
+
|
| 692 |
+
log.info("Processing %s", os.path.basename(download))
|
| 693 |
+
|
| 694 |
+
if install_needed:
|
| 695 |
+
dists = self.install_eggs(spec, download, tmpdir)
|
| 696 |
+
for dist in dists:
|
| 697 |
+
self.process_distribution(spec, dist, deps)
|
| 698 |
+
else:
|
| 699 |
+
dists = [self.egg_distribution(download)]
|
| 700 |
+
self.process_distribution(spec, dists[0], deps, "Using")
|
| 701 |
+
|
| 702 |
+
if spec is not None:
|
| 703 |
+
for dist in dists:
|
| 704 |
+
if dist in spec:
|
| 705 |
+
return dist
|
| 706 |
+
|
| 707 |
+
def select_scheme(self, name):
|
| 708 |
+
"""Sets the install directories by applying the install schemes."""
|
| 709 |
+
# it's the caller's problem if they supply a bad name!
|
| 710 |
+
scheme = INSTALL_SCHEMES[name]
|
| 711 |
+
for key in SCHEME_KEYS:
|
| 712 |
+
attrname = 'install_' + key
|
| 713 |
+
if getattr(self, attrname) is None:
|
| 714 |
+
setattr(self, attrname, scheme[key])
|
| 715 |
+
|
| 716 |
+
# FIXME: 'easy_install.process_distribution' is too complex (12)
|
| 717 |
+
def process_distribution( # noqa: C901
|
| 718 |
+
self, requirement, dist, deps=True, *info,
|
| 719 |
+
):
|
| 720 |
+
self.update_pth(dist)
|
| 721 |
+
self.package_index.add(dist)
|
| 722 |
+
if dist in self.local_index[dist.key]:
|
| 723 |
+
self.local_index.remove(dist)
|
| 724 |
+
self.local_index.add(dist)
|
| 725 |
+
self.install_egg_scripts(dist)
|
| 726 |
+
self.installed_projects[dist.key] = dist
|
| 727 |
+
log.info(self.installation_report(requirement, dist, *info))
|
| 728 |
+
if (dist.has_metadata('dependency_links.txt') and
|
| 729 |
+
not self.no_find_links):
|
| 730 |
+
self.package_index.add_find_links(
|
| 731 |
+
dist.get_metadata_lines('dependency_links.txt')
|
| 732 |
+
)
|
| 733 |
+
if not deps and not self.always_copy:
|
| 734 |
+
return
|
| 735 |
+
elif requirement is not None and dist.key != requirement.key:
|
| 736 |
+
log.warn("Skipping dependencies for %s", dist)
|
| 737 |
+
return # XXX this is not the distribution we were looking for
|
| 738 |
+
elif requirement is None or dist not in requirement:
|
| 739 |
+
# if we wound up with a different version, resolve what we've got
|
| 740 |
+
distreq = dist.as_requirement()
|
| 741 |
+
requirement = Requirement(str(distreq))
|
| 742 |
+
log.info("Processing dependencies for %s", requirement)
|
| 743 |
+
try:
|
| 744 |
+
distros = WorkingSet([]).resolve(
|
| 745 |
+
[requirement], self.local_index, self.easy_install
|
| 746 |
+
)
|
| 747 |
+
except DistributionNotFound as e:
|
| 748 |
+
raise DistutilsError(str(e)) from e
|
| 749 |
+
except VersionConflict as e:
|
| 750 |
+
raise DistutilsError(e.report()) from e
|
| 751 |
+
if self.always_copy or self.always_copy_from:
|
| 752 |
+
# Force all the relevant distros to be copied or activated
|
| 753 |
+
for dist in distros:
|
| 754 |
+
if dist.key not in self.installed_projects:
|
| 755 |
+
self.easy_install(dist.as_requirement())
|
| 756 |
+
log.info("Finished processing dependencies for %s", requirement)
|
| 757 |
+
|
| 758 |
+
def should_unzip(self, dist):
|
| 759 |
+
if self.zip_ok is not None:
|
| 760 |
+
return not self.zip_ok
|
| 761 |
+
if dist.has_metadata('not-zip-safe'):
|
| 762 |
+
return True
|
| 763 |
+
if not dist.has_metadata('zip-safe'):
|
| 764 |
+
return True
|
| 765 |
+
return False
|
| 766 |
+
|
| 767 |
+
def maybe_move(self, spec, dist_filename, setup_base):
|
| 768 |
+
dst = os.path.join(self.build_directory, spec.key)
|
| 769 |
+
if os.path.exists(dst):
|
| 770 |
+
msg = (
|
| 771 |
+
"%r already exists in %s; build directory %s will not be kept"
|
| 772 |
+
)
|
| 773 |
+
log.warn(msg, spec.key, self.build_directory, setup_base)
|
| 774 |
+
return setup_base
|
| 775 |
+
if os.path.isdir(dist_filename):
|
| 776 |
+
setup_base = dist_filename
|
| 777 |
+
else:
|
| 778 |
+
if os.path.dirname(dist_filename) == setup_base:
|
| 779 |
+
os.unlink(dist_filename) # get it out of the tmp dir
|
| 780 |
+
contents = os.listdir(setup_base)
|
| 781 |
+
if len(contents) == 1:
|
| 782 |
+
dist_filename = os.path.join(setup_base, contents[0])
|
| 783 |
+
if os.path.isdir(dist_filename):
|
| 784 |
+
# if the only thing there is a directory, move it instead
|
| 785 |
+
setup_base = dist_filename
|
| 786 |
+
ensure_directory(dst)
|
| 787 |
+
shutil.move(setup_base, dst)
|
| 788 |
+
return dst
|
| 789 |
+
|
| 790 |
+
def install_wrapper_scripts(self, dist):
|
| 791 |
+
if self.exclude_scripts:
|
| 792 |
+
return
|
| 793 |
+
for args in ScriptWriter.best().get_args(dist):
|
| 794 |
+
self.write_script(*args)
|
| 795 |
+
|
| 796 |
+
def install_script(self, dist, script_name, script_text, dev_path=None):
|
| 797 |
+
"""Generate a legacy script wrapper and install it"""
|
| 798 |
+
spec = str(dist.as_requirement())
|
| 799 |
+
is_script = is_python_script(script_text, script_name)
|
| 800 |
+
|
| 801 |
+
if is_script:
|
| 802 |
+
body = self._load_template(dev_path) % locals()
|
| 803 |
+
script_text = ScriptWriter.get_header(script_text) + body
|
| 804 |
+
self.write_script(script_name, _to_bytes(script_text), 'b')
|
| 805 |
+
|
| 806 |
+
@staticmethod
|
| 807 |
+
def _load_template(dev_path):
|
| 808 |
+
"""
|
| 809 |
+
There are a couple of template scripts in the package. This
|
| 810 |
+
function loads one of them and prepares it for use.
|
| 811 |
+
"""
|
| 812 |
+
# See https://github.com/pypa/setuptools/issues/134 for info
|
| 813 |
+
# on script file naming and downstream issues with SVR4
|
| 814 |
+
name = 'script.tmpl'
|
| 815 |
+
if dev_path:
|
| 816 |
+
name = name.replace('.tmpl', ' (dev).tmpl')
|
| 817 |
+
|
| 818 |
+
raw_bytes = resource_string('setuptools', name)
|
| 819 |
+
return raw_bytes.decode('utf-8')
|
| 820 |
+
|
| 821 |
+
def write_script(self, script_name, contents, mode="t", blockers=()):
|
| 822 |
+
"""Write an executable file to the scripts directory"""
|
| 823 |
+
self.delete_blockers( # clean up old .py/.pyw w/o a script
|
| 824 |
+
[os.path.join(self.script_dir, x) for x in blockers]
|
| 825 |
+
)
|
| 826 |
+
log.info("Installing %s script to %s", script_name, self.script_dir)
|
| 827 |
+
target = os.path.join(self.script_dir, script_name)
|
| 828 |
+
self.add_output(target)
|
| 829 |
+
|
| 830 |
+
if self.dry_run:
|
| 831 |
+
return
|
| 832 |
+
|
| 833 |
+
mask = current_umask()
|
| 834 |
+
ensure_directory(target)
|
| 835 |
+
if os.path.exists(target):
|
| 836 |
+
os.unlink(target)
|
| 837 |
+
with open(target, "w" + mode) as f:
|
| 838 |
+
f.write(contents)
|
| 839 |
+
chmod(target, 0o777 - mask)
|
| 840 |
+
|
| 841 |
+
def install_eggs(self, spec, dist_filename, tmpdir):
|
| 842 |
+
# .egg dirs or files are already built, so just return them
|
| 843 |
+
installer_map = {
|
| 844 |
+
'.egg': self.install_egg,
|
| 845 |
+
'.exe': self.install_exe,
|
| 846 |
+
'.whl': self.install_wheel,
|
| 847 |
+
}
|
| 848 |
+
try:
|
| 849 |
+
install_dist = installer_map[
|
| 850 |
+
dist_filename.lower()[-4:]
|
| 851 |
+
]
|
| 852 |
+
except KeyError:
|
| 853 |
+
pass
|
| 854 |
+
else:
|
| 855 |
+
return [install_dist(dist_filename, tmpdir)]
|
| 856 |
+
|
| 857 |
+
# Anything else, try to extract and build
|
| 858 |
+
setup_base = tmpdir
|
| 859 |
+
if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'):
|
| 860 |
+
unpack_archive(dist_filename, tmpdir, self.unpack_progress)
|
| 861 |
+
elif os.path.isdir(dist_filename):
|
| 862 |
+
setup_base = os.path.abspath(dist_filename)
|
| 863 |
+
|
| 864 |
+
if (setup_base.startswith(tmpdir) # something we downloaded
|
| 865 |
+
and self.build_directory and spec is not None):
|
| 866 |
+
setup_base = self.maybe_move(spec, dist_filename, setup_base)
|
| 867 |
+
|
| 868 |
+
# Find the setup.py file
|
| 869 |
+
setup_script = os.path.join(setup_base, 'setup.py')
|
| 870 |
+
|
| 871 |
+
if not os.path.exists(setup_script):
|
| 872 |
+
setups = glob(os.path.join(setup_base, '*', 'setup.py'))
|
| 873 |
+
if not setups:
|
| 874 |
+
raise DistutilsError(
|
| 875 |
+
"Couldn't find a setup script in %s" %
|
| 876 |
+
os.path.abspath(dist_filename)
|
| 877 |
+
)
|
| 878 |
+
if len(setups) > 1:
|
| 879 |
+
raise DistutilsError(
|
| 880 |
+
"Multiple setup scripts in %s" %
|
| 881 |
+
os.path.abspath(dist_filename)
|
| 882 |
+
)
|
| 883 |
+
setup_script = setups[0]
|
| 884 |
+
|
| 885 |
+
# Now run it, and return the result
|
| 886 |
+
if self.editable:
|
| 887 |
+
log.info(self.report_editable(spec, setup_script))
|
| 888 |
+
return []
|
| 889 |
+
else:
|
| 890 |
+
return self.build_and_install(setup_script, setup_base)
|
| 891 |
+
|
| 892 |
+
def egg_distribution(self, egg_path):
|
| 893 |
+
if os.path.isdir(egg_path):
|
| 894 |
+
metadata = PathMetadata(egg_path, os.path.join(egg_path,
|
| 895 |
+
'EGG-INFO'))
|
| 896 |
+
else:
|
| 897 |
+
metadata = EggMetadata(zipimport.zipimporter(egg_path))
|
| 898 |
+
return Distribution.from_filename(egg_path, metadata=metadata)
|
| 899 |
+
|
| 900 |
+
# FIXME: 'easy_install.install_egg' is too complex (11)
|
| 901 |
+
def install_egg(self, egg_path, tmpdir): # noqa: C901
|
| 902 |
+
destination = os.path.join(
|
| 903 |
+
self.install_dir,
|
| 904 |
+
os.path.basename(egg_path),
|
| 905 |
+
)
|
| 906 |
+
destination = os.path.abspath(destination)
|
| 907 |
+
if not self.dry_run:
|
| 908 |
+
ensure_directory(destination)
|
| 909 |
+
|
| 910 |
+
dist = self.egg_distribution(egg_path)
|
| 911 |
+
if not samefile(egg_path, destination):
|
| 912 |
+
if os.path.isdir(destination) and not os.path.islink(destination):
|
| 913 |
+
dir_util.remove_tree(destination, dry_run=self.dry_run)
|
| 914 |
+
elif os.path.exists(destination):
|
| 915 |
+
self.execute(
|
| 916 |
+
os.unlink,
|
| 917 |
+
(destination,),
|
| 918 |
+
"Removing " + destination,
|
| 919 |
+
)
|
| 920 |
+
try:
|
| 921 |
+
new_dist_is_zipped = False
|
| 922 |
+
if os.path.isdir(egg_path):
|
| 923 |
+
if egg_path.startswith(tmpdir):
|
| 924 |
+
f, m = shutil.move, "Moving"
|
| 925 |
+
else:
|
| 926 |
+
f, m = shutil.copytree, "Copying"
|
| 927 |
+
elif self.should_unzip(dist):
|
| 928 |
+
self.mkpath(destination)
|
| 929 |
+
f, m = self.unpack_and_compile, "Extracting"
|
| 930 |
+
else:
|
| 931 |
+
new_dist_is_zipped = True
|
| 932 |
+
if egg_path.startswith(tmpdir):
|
| 933 |
+
f, m = shutil.move, "Moving"
|
| 934 |
+
else:
|
| 935 |
+
f, m = shutil.copy2, "Copying"
|
| 936 |
+
self.execute(
|
| 937 |
+
f,
|
| 938 |
+
(egg_path, destination),
|
| 939 |
+
(m + " %s to %s") % (
|
| 940 |
+
os.path.basename(egg_path),
|
| 941 |
+
os.path.dirname(destination)
|
| 942 |
+
),
|
| 943 |
+
)
|
| 944 |
+
update_dist_caches(
|
| 945 |
+
destination,
|
| 946 |
+
fix_zipimporter_caches=new_dist_is_zipped,
|
| 947 |
+
)
|
| 948 |
+
except Exception:
|
| 949 |
+
update_dist_caches(destination, fix_zipimporter_caches=False)
|
| 950 |
+
raise
|
| 951 |
+
|
| 952 |
+
self.add_output(destination)
|
| 953 |
+
return self.egg_distribution(destination)
|
| 954 |
+
|
| 955 |
+
def install_exe(self, dist_filename, tmpdir):
|
| 956 |
+
# See if it's valid, get data
|
| 957 |
+
cfg = extract_wininst_cfg(dist_filename)
|
| 958 |
+
if cfg is None:
|
| 959 |
+
raise DistutilsError(
|
| 960 |
+
"%s is not a valid distutils Windows .exe" % dist_filename
|
| 961 |
+
)
|
| 962 |
+
# Create a dummy distribution object until we build the real distro
|
| 963 |
+
dist = Distribution(
|
| 964 |
+
None,
|
| 965 |
+
project_name=cfg.get('metadata', 'name'),
|
| 966 |
+
version=cfg.get('metadata', 'version'), platform=get_platform(),
|
| 967 |
+
)
|
| 968 |
+
|
| 969 |
+
# Convert the .exe to an unpacked egg
|
| 970 |
+
egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg')
|
| 971 |
+
dist.location = egg_path
|
| 972 |
+
egg_tmp = egg_path + '.tmp'
|
| 973 |
+
_egg_info = os.path.join(egg_tmp, 'EGG-INFO')
|
| 974 |
+
pkg_inf = os.path.join(_egg_info, 'PKG-INFO')
|
| 975 |
+
ensure_directory(pkg_inf) # make sure EGG-INFO dir exists
|
| 976 |
+
dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX
|
| 977 |
+
self.exe_to_egg(dist_filename, egg_tmp)
|
| 978 |
+
|
| 979 |
+
# Write EGG-INFO/PKG-INFO
|
| 980 |
+
if not os.path.exists(pkg_inf):
|
| 981 |
+
f = open(pkg_inf, 'w')
|
| 982 |
+
f.write('Metadata-Version: 1.0\n')
|
| 983 |
+
for k, v in cfg.items('metadata'):
|
| 984 |
+
if k != 'target_version':
|
| 985 |
+
f.write('%s: %s\n' % (k.replace('_', '-').title(), v))
|
| 986 |
+
f.close()
|
| 987 |
+
script_dir = os.path.join(_egg_info, 'scripts')
|
| 988 |
+
# delete entry-point scripts to avoid duping
|
| 989 |
+
self.delete_blockers([
|
| 990 |
+
os.path.join(script_dir, args[0])
|
| 991 |
+
for args in ScriptWriter.get_args(dist)
|
| 992 |
+
])
|
| 993 |
+
# Build .egg file from tmpdir
|
| 994 |
+
bdist_egg.make_zipfile(
|
| 995 |
+
egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run,
|
| 996 |
+
)
|
| 997 |
+
# install the .egg
|
| 998 |
+
return self.install_egg(egg_path, tmpdir)
|
| 999 |
+
|
| 1000 |
+
# FIXME: 'easy_install.exe_to_egg' is too complex (12)
|
| 1001 |
+
def exe_to_egg(self, dist_filename, egg_tmp): # noqa: C901
|
| 1002 |
+
"""Extract a bdist_wininst to the directories an egg would use"""
|
| 1003 |
+
# Check for .pth file and set up prefix translations
|
| 1004 |
+
prefixes = get_exe_prefixes(dist_filename)
|
| 1005 |
+
to_compile = []
|
| 1006 |
+
native_libs = []
|
| 1007 |
+
top_level = {}
|
| 1008 |
+
|
| 1009 |
+
def process(src, dst):
|
| 1010 |
+
s = src.lower()
|
| 1011 |
+
for old, new in prefixes:
|
| 1012 |
+
if s.startswith(old):
|
| 1013 |
+
src = new + src[len(old):]
|
| 1014 |
+
parts = src.split('/')
|
| 1015 |
+
dst = os.path.join(egg_tmp, *parts)
|
| 1016 |
+
dl = dst.lower()
|
| 1017 |
+
if dl.endswith('.pyd') or dl.endswith('.dll'):
|
| 1018 |
+
parts[-1] = bdist_egg.strip_module(parts[-1])
|
| 1019 |
+
top_level[os.path.splitext(parts[0])[0]] = 1
|
| 1020 |
+
native_libs.append(src)
|
| 1021 |
+
elif dl.endswith('.py') and old != 'SCRIPTS/':
|
| 1022 |
+
top_level[os.path.splitext(parts[0])[0]] = 1
|
| 1023 |
+
to_compile.append(dst)
|
| 1024 |
+
return dst
|
| 1025 |
+
if not src.endswith('.pth'):
|
| 1026 |
+
log.warn("WARNING: can't process %s", src)
|
| 1027 |
+
return None
|
| 1028 |
+
|
| 1029 |
+
# extract, tracking .pyd/.dll->native_libs and .py -> to_compile
|
| 1030 |
+
unpack_archive(dist_filename, egg_tmp, process)
|
| 1031 |
+
stubs = []
|
| 1032 |
+
for res in native_libs:
|
| 1033 |
+
if res.lower().endswith('.pyd'): # create stubs for .pyd's
|
| 1034 |
+
parts = res.split('/')
|
| 1035 |
+
resource = parts[-1]
|
| 1036 |
+
parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py'
|
| 1037 |
+
pyfile = os.path.join(egg_tmp, *parts)
|
| 1038 |
+
to_compile.append(pyfile)
|
| 1039 |
+
stubs.append(pyfile)
|
| 1040 |
+
bdist_egg.write_stub(resource, pyfile)
|
| 1041 |
+
self.byte_compile(to_compile) # compile .py's
|
| 1042 |
+
bdist_egg.write_safety_flag(
|
| 1043 |
+
os.path.join(egg_tmp, 'EGG-INFO'),
|
| 1044 |
+
bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag
|
| 1045 |
+
|
| 1046 |
+
for name in 'top_level', 'native_libs':
|
| 1047 |
+
if locals()[name]:
|
| 1048 |
+
txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt')
|
| 1049 |
+
if not os.path.exists(txt):
|
| 1050 |
+
f = open(txt, 'w')
|
| 1051 |
+
f.write('\n'.join(locals()[name]) + '\n')
|
| 1052 |
+
f.close()
|
| 1053 |
+
|
| 1054 |
+
def install_wheel(self, wheel_path, tmpdir):
|
| 1055 |
+
wheel = Wheel(wheel_path)
|
| 1056 |
+
assert wheel.is_compatible()
|
| 1057 |
+
destination = os.path.join(self.install_dir, wheel.egg_name())
|
| 1058 |
+
destination = os.path.abspath(destination)
|
| 1059 |
+
if not self.dry_run:
|
| 1060 |
+
ensure_directory(destination)
|
| 1061 |
+
if os.path.isdir(destination) and not os.path.islink(destination):
|
| 1062 |
+
dir_util.remove_tree(destination, dry_run=self.dry_run)
|
| 1063 |
+
elif os.path.exists(destination):
|
| 1064 |
+
self.execute(
|
| 1065 |
+
os.unlink,
|
| 1066 |
+
(destination,),
|
| 1067 |
+
"Removing " + destination,
|
| 1068 |
+
)
|
| 1069 |
+
try:
|
| 1070 |
+
self.execute(
|
| 1071 |
+
wheel.install_as_egg,
|
| 1072 |
+
(destination,),
|
| 1073 |
+
("Installing %s to %s") % (
|
| 1074 |
+
os.path.basename(wheel_path),
|
| 1075 |
+
os.path.dirname(destination)
|
| 1076 |
+
),
|
| 1077 |
+
)
|
| 1078 |
+
finally:
|
| 1079 |
+
update_dist_caches(destination, fix_zipimporter_caches=False)
|
| 1080 |
+
self.add_output(destination)
|
| 1081 |
+
return self.egg_distribution(destination)
|
| 1082 |
+
|
| 1083 |
+
__mv_warning = textwrap.dedent("""
|
| 1084 |
+
Because this distribution was installed --multi-version, before you can
|
| 1085 |
+
import modules from this package in an application, you will need to
|
| 1086 |
+
'import pkg_resources' and then use a 'require()' call similar to one of
|
| 1087 |
+
these examples, in order to select the desired version:
|
| 1088 |
+
|
| 1089 |
+
pkg_resources.require("%(name)s") # latest installed version
|
| 1090 |
+
pkg_resources.require("%(name)s==%(version)s") # this exact version
|
| 1091 |
+
pkg_resources.require("%(name)s>=%(version)s") # this version or higher
|
| 1092 |
+
""").lstrip() # noqa
|
| 1093 |
+
|
| 1094 |
+
__id_warning = textwrap.dedent("""
|
| 1095 |
+
Note also that the installation directory must be on sys.path at runtime for
|
| 1096 |
+
this to work. (e.g. by being the application's script directory, by being on
|
| 1097 |
+
PYTHONPATH, or by being added to sys.path by your code.)
|
| 1098 |
+
""") # noqa
|
| 1099 |
+
|
| 1100 |
+
def installation_report(self, req, dist, what="Installed"):
|
| 1101 |
+
"""Helpful installation message for display to package users"""
|
| 1102 |
+
msg = "\n%(what)s %(eggloc)s%(extras)s"
|
| 1103 |
+
if self.multi_version and not self.no_report:
|
| 1104 |
+
msg += '\n' + self.__mv_warning
|
| 1105 |
+
if self.install_dir not in map(normalize_path, sys.path):
|
| 1106 |
+
msg += '\n' + self.__id_warning
|
| 1107 |
+
|
| 1108 |
+
eggloc = dist.location
|
| 1109 |
+
name = dist.project_name
|
| 1110 |
+
version = dist.version
|
| 1111 |
+
extras = '' # TODO: self.report_extras(req, dist)
|
| 1112 |
+
return msg % locals()
|
| 1113 |
+
|
| 1114 |
+
__editable_msg = textwrap.dedent("""
|
| 1115 |
+
Extracted editable version of %(spec)s to %(dirname)s
|
| 1116 |
+
|
| 1117 |
+
If it uses setuptools in its setup script, you can activate it in
|
| 1118 |
+
"development" mode by going to that directory and running::
|
| 1119 |
+
|
| 1120 |
+
%(python)s setup.py develop
|
| 1121 |
+
|
| 1122 |
+
See the setuptools documentation for the "develop" command for more info.
|
| 1123 |
+
""").lstrip() # noqa
|
| 1124 |
+
|
| 1125 |
+
def report_editable(self, spec, setup_script):
|
| 1126 |
+
dirname = os.path.dirname(setup_script)
|
| 1127 |
+
python = sys.executable
|
| 1128 |
+
return '\n' + self.__editable_msg % locals()
|
| 1129 |
+
|
| 1130 |
+
def run_setup(self, setup_script, setup_base, args):
|
| 1131 |
+
sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg)
|
| 1132 |
+
sys.modules.setdefault('distutils.command.egg_info', egg_info)
|
| 1133 |
+
|
| 1134 |
+
args = list(args)
|
| 1135 |
+
if self.verbose > 2:
|
| 1136 |
+
v = 'v' * (self.verbose - 1)
|
| 1137 |
+
args.insert(0, '-' + v)
|
| 1138 |
+
elif self.verbose < 2:
|
| 1139 |
+
args.insert(0, '-q')
|
| 1140 |
+
if self.dry_run:
|
| 1141 |
+
args.insert(0, '-n')
|
| 1142 |
+
log.info(
|
| 1143 |
+
"Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args)
|
| 1144 |
+
)
|
| 1145 |
+
try:
|
| 1146 |
+
run_setup(setup_script, args)
|
| 1147 |
+
except SystemExit as v:
|
| 1148 |
+
raise DistutilsError(
|
| 1149 |
+
"Setup script exited with %s" % (v.args[0],)
|
| 1150 |
+
) from v
|
| 1151 |
+
|
| 1152 |
+
def build_and_install(self, setup_script, setup_base):
|
| 1153 |
+
args = ['bdist_egg', '--dist-dir']
|
| 1154 |
+
|
| 1155 |
+
dist_dir = tempfile.mkdtemp(
|
| 1156 |
+
prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)
|
| 1157 |
+
)
|
| 1158 |
+
try:
|
| 1159 |
+
self._set_fetcher_options(os.path.dirname(setup_script))
|
| 1160 |
+
args.append(dist_dir)
|
| 1161 |
+
|
| 1162 |
+
self.run_setup(setup_script, setup_base, args)
|
| 1163 |
+
all_eggs = Environment([dist_dir])
|
| 1164 |
+
eggs = []
|
| 1165 |
+
for key in all_eggs:
|
| 1166 |
+
for dist in all_eggs[key]:
|
| 1167 |
+
eggs.append(self.install_egg(dist.location, setup_base))
|
| 1168 |
+
if not eggs and not self.dry_run:
|
| 1169 |
+
log.warn("No eggs found in %s (setup script problem?)",
|
| 1170 |
+
dist_dir)
|
| 1171 |
+
return eggs
|
| 1172 |
+
finally:
|
| 1173 |
+
rmtree(dist_dir)
|
| 1174 |
+
log.set_verbosity(self.verbose) # restore our log verbosity
|
| 1175 |
+
|
| 1176 |
+
def _set_fetcher_options(self, base):
|
| 1177 |
+
"""
|
| 1178 |
+
When easy_install is about to run bdist_egg on a source dist, that
|
| 1179 |
+
source dist might have 'setup_requires' directives, requiring
|
| 1180 |
+
additional fetching. Ensure the fetcher options given to easy_install
|
| 1181 |
+
are available to that command as well.
|
| 1182 |
+
"""
|
| 1183 |
+
# find the fetch options from easy_install and write them out
|
| 1184 |
+
# to the setup.cfg file.
|
| 1185 |
+
ei_opts = self.distribution.get_option_dict('easy_install').copy()
|
| 1186 |
+
fetch_directives = (
|
| 1187 |
+
'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts',
|
| 1188 |
+
)
|
| 1189 |
+
fetch_options = {}
|
| 1190 |
+
for key, val in ei_opts.items():
|
| 1191 |
+
if key not in fetch_directives:
|
| 1192 |
+
continue
|
| 1193 |
+
fetch_options[key] = val[1]
|
| 1194 |
+
# create a settings dictionary suitable for `edit_config`
|
| 1195 |
+
settings = dict(easy_install=fetch_options)
|
| 1196 |
+
cfg_filename = os.path.join(base, 'setup.cfg')
|
| 1197 |
+
setopt.edit_config(cfg_filename, settings)
|
| 1198 |
+
|
| 1199 |
+
def update_pth(self, dist): # noqa: C901 # is too complex (11) # FIXME
|
| 1200 |
+
if self.pth_file is None:
|
| 1201 |
+
return
|
| 1202 |
+
|
| 1203 |
+
for d in self.pth_file[dist.key]: # drop old entries
|
| 1204 |
+
if not self.multi_version and d.location == dist.location:
|
| 1205 |
+
continue
|
| 1206 |
+
|
| 1207 |
+
log.info("Removing %s from easy-install.pth file", d)
|
| 1208 |
+
self.pth_file.remove(d)
|
| 1209 |
+
if d.location in self.shadow_path:
|
| 1210 |
+
self.shadow_path.remove(d.location)
|
| 1211 |
+
|
| 1212 |
+
if not self.multi_version:
|
| 1213 |
+
if dist.location in self.pth_file.paths:
|
| 1214 |
+
log.info(
|
| 1215 |
+
"%s is already the active version in easy-install.pth",
|
| 1216 |
+
dist,
|
| 1217 |
+
)
|
| 1218 |
+
else:
|
| 1219 |
+
log.info("Adding %s to easy-install.pth file", dist)
|
| 1220 |
+
self.pth_file.add(dist) # add new entry
|
| 1221 |
+
if dist.location not in self.shadow_path:
|
| 1222 |
+
self.shadow_path.append(dist.location)
|
| 1223 |
+
|
| 1224 |
+
if self.dry_run:
|
| 1225 |
+
return
|
| 1226 |
+
|
| 1227 |
+
self.pth_file.save()
|
| 1228 |
+
|
| 1229 |
+
if dist.key != 'setuptools':
|
| 1230 |
+
return
|
| 1231 |
+
|
| 1232 |
+
# Ensure that setuptools itself never becomes unavailable!
|
| 1233 |
+
# XXX should this check for latest version?
|
| 1234 |
+
filename = os.path.join(self.install_dir, 'setuptools.pth')
|
| 1235 |
+
if os.path.islink(filename):
|
| 1236 |
+
os.unlink(filename)
|
| 1237 |
+
with open(filename, 'wt') as f:
|
| 1238 |
+
f.write(self.pth_file.make_relative(dist.location) + '\n')
|
| 1239 |
+
|
| 1240 |
+
def unpack_progress(self, src, dst):
|
| 1241 |
+
# Progress filter for unpacking
|
| 1242 |
+
log.debug("Unpacking %s to %s", src, dst)
|
| 1243 |
+
return dst # only unpack-and-compile skips files for dry run
|
| 1244 |
+
|
| 1245 |
+
def unpack_and_compile(self, egg_path, destination):
|
| 1246 |
+
to_compile = []
|
| 1247 |
+
to_chmod = []
|
| 1248 |
+
|
| 1249 |
+
def pf(src, dst):
|
| 1250 |
+
if dst.endswith('.py') and not src.startswith('EGG-INFO/'):
|
| 1251 |
+
to_compile.append(dst)
|
| 1252 |
+
elif dst.endswith('.dll') or dst.endswith('.so'):
|
| 1253 |
+
to_chmod.append(dst)
|
| 1254 |
+
self.unpack_progress(src, dst)
|
| 1255 |
+
return not self.dry_run and dst or None
|
| 1256 |
+
|
| 1257 |
+
unpack_archive(egg_path, destination, pf)
|
| 1258 |
+
self.byte_compile(to_compile)
|
| 1259 |
+
if not self.dry_run:
|
| 1260 |
+
for f in to_chmod:
|
| 1261 |
+
mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755
|
| 1262 |
+
chmod(f, mode)
|
| 1263 |
+
|
| 1264 |
+
def byte_compile(self, to_compile):
|
| 1265 |
+
if sys.dont_write_bytecode:
|
| 1266 |
+
return
|
| 1267 |
+
|
| 1268 |
+
from distutils.util import byte_compile
|
| 1269 |
+
|
| 1270 |
+
try:
|
| 1271 |
+
# try to make the byte compile messages quieter
|
| 1272 |
+
log.set_verbosity(self.verbose - 1)
|
| 1273 |
+
|
| 1274 |
+
byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run)
|
| 1275 |
+
if self.optimize:
|
| 1276 |
+
byte_compile(
|
| 1277 |
+
to_compile, optimize=self.optimize, force=1,
|
| 1278 |
+
dry_run=self.dry_run,
|
| 1279 |
+
)
|
| 1280 |
+
finally:
|
| 1281 |
+
log.set_verbosity(self.verbose) # restore original verbosity
|
| 1282 |
+
|
| 1283 |
+
__no_default_msg = textwrap.dedent("""
|
| 1284 |
+
bad install directory or PYTHONPATH
|
| 1285 |
+
|
| 1286 |
+
You are attempting to install a package to a directory that is not
|
| 1287 |
+
on PYTHONPATH and which Python does not read ".pth" files from. The
|
| 1288 |
+
installation directory you specified (via --install-dir, --prefix, or
|
| 1289 |
+
the distutils default setting) was:
|
| 1290 |
+
|
| 1291 |
+
%s
|
| 1292 |
+
|
| 1293 |
+
and your PYTHONPATH environment variable currently contains:
|
| 1294 |
+
|
| 1295 |
+
%r
|
| 1296 |
+
|
| 1297 |
+
Here are some of your options for correcting the problem:
|
| 1298 |
+
|
| 1299 |
+
* You can choose a different installation directory, i.e., one that is
|
| 1300 |
+
on PYTHONPATH or supports .pth files
|
| 1301 |
+
|
| 1302 |
+
* You can add the installation directory to the PYTHONPATH environment
|
| 1303 |
+
variable. (It must then also be on PYTHONPATH whenever you run
|
| 1304 |
+
Python and want to use the package(s) you are installing.)
|
| 1305 |
+
|
| 1306 |
+
* You can set up the installation directory to support ".pth" files by
|
| 1307 |
+
using one of the approaches described here:
|
| 1308 |
+
|
| 1309 |
+
https://setuptools.readthedocs.io/en/latest/deprecated/easy_install.html#custom-installation-locations
|
| 1310 |
+
|
| 1311 |
+
|
| 1312 |
+
Please make the appropriate changes for your system and try again.
|
| 1313 |
+
""").strip()
|
| 1314 |
+
|
| 1315 |
+
def create_home_path(self):
|
| 1316 |
+
"""Create directories under ~."""
|
| 1317 |
+
if not self.user:
|
| 1318 |
+
return
|
| 1319 |
+
home = convert_path(os.path.expanduser("~"))
|
| 1320 |
+
for name, path in self.config_vars.items():
|
| 1321 |
+
if path.startswith(home) and not os.path.isdir(path):
|
| 1322 |
+
self.debug_print("os.makedirs('%s', 0o700)" % path)
|
| 1323 |
+
os.makedirs(path, 0o700)
|
| 1324 |
+
|
| 1325 |
+
INSTALL_SCHEMES = dict(
|
| 1326 |
+
posix=dict(
|
| 1327 |
+
install_dir='$base/lib/python$py_version_short/site-packages',
|
| 1328 |
+
script_dir='$base/bin',
|
| 1329 |
+
),
|
| 1330 |
+
)
|
| 1331 |
+
|
| 1332 |
+
DEFAULT_SCHEME = dict(
|
| 1333 |
+
install_dir='$base/Lib/site-packages',
|
| 1334 |
+
script_dir='$base/Scripts',
|
| 1335 |
+
)
|
| 1336 |
+
|
| 1337 |
+
def _expand(self, *attrs):
|
| 1338 |
+
config_vars = self.get_finalized_command('install').config_vars
|
| 1339 |
+
|
| 1340 |
+
if self.prefix:
|
| 1341 |
+
# Set default install_dir/scripts from --prefix
|
| 1342 |
+
config_vars = config_vars.copy()
|
| 1343 |
+
config_vars['base'] = self.prefix
|
| 1344 |
+
scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME)
|
| 1345 |
+
for attr, val in scheme.items():
|
| 1346 |
+
if getattr(self, attr, None) is None:
|
| 1347 |
+
setattr(self, attr, val)
|
| 1348 |
+
|
| 1349 |
+
from distutils.util import subst_vars
|
| 1350 |
+
|
| 1351 |
+
for attr in attrs:
|
| 1352 |
+
val = getattr(self, attr)
|
| 1353 |
+
if val is not None:
|
| 1354 |
+
val = subst_vars(val, config_vars)
|
| 1355 |
+
if os.name == 'posix':
|
| 1356 |
+
val = os.path.expanduser(val)
|
| 1357 |
+
setattr(self, attr, val)
|
| 1358 |
+
|
| 1359 |
+
|
| 1360 |
+
def _pythonpath():
|
| 1361 |
+
items = os.environ.get('PYTHONPATH', '').split(os.pathsep)
|
| 1362 |
+
return filter(None, items)
|
| 1363 |
+
|
| 1364 |
+
|
| 1365 |
+
def get_site_dirs():
|
| 1366 |
+
"""
|
| 1367 |
+
Return a list of 'site' dirs
|
| 1368 |
+
"""
|
| 1369 |
+
|
| 1370 |
+
sitedirs = []
|
| 1371 |
+
|
| 1372 |
+
# start with PYTHONPATH
|
| 1373 |
+
sitedirs.extend(_pythonpath())
|
| 1374 |
+
|
| 1375 |
+
prefixes = [sys.prefix]
|
| 1376 |
+
if sys.exec_prefix != sys.prefix:
|
| 1377 |
+
prefixes.append(sys.exec_prefix)
|
| 1378 |
+
for prefix in prefixes:
|
| 1379 |
+
if not prefix:
|
| 1380 |
+
continue
|
| 1381 |
+
|
| 1382 |
+
if sys.platform in ('os2emx', 'riscos'):
|
| 1383 |
+
sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
|
| 1384 |
+
elif os.sep == '/':
|
| 1385 |
+
sitedirs.extend([
|
| 1386 |
+
os.path.join(
|
| 1387 |
+
prefix,
|
| 1388 |
+
"lib",
|
| 1389 |
+
"python{}.{}".format(*sys.version_info),
|
| 1390 |
+
"site-packages",
|
| 1391 |
+
),
|
| 1392 |
+
os.path.join(prefix, "lib", "site-python"),
|
| 1393 |
+
])
|
| 1394 |
+
else:
|
| 1395 |
+
sitedirs.extend([
|
| 1396 |
+
prefix,
|
| 1397 |
+
os.path.join(prefix, "lib", "site-packages"),
|
| 1398 |
+
])
|
| 1399 |
+
if sys.platform != 'darwin':
|
| 1400 |
+
continue
|
| 1401 |
+
|
| 1402 |
+
# for framework builds *only* we add the standard Apple
|
| 1403 |
+
# locations. Currently only per-user, but /Library and
|
| 1404 |
+
# /Network/Library could be added too
|
| 1405 |
+
if 'Python.framework' not in prefix:
|
| 1406 |
+
continue
|
| 1407 |
+
|
| 1408 |
+
home = os.environ.get('HOME')
|
| 1409 |
+
if not home:
|
| 1410 |
+
continue
|
| 1411 |
+
|
| 1412 |
+
home_sp = os.path.join(
|
| 1413 |
+
home,
|
| 1414 |
+
'Library',
|
| 1415 |
+
'Python',
|
| 1416 |
+
'{}.{}'.format(*sys.version_info),
|
| 1417 |
+
'site-packages',
|
| 1418 |
+
)
|
| 1419 |
+
sitedirs.append(home_sp)
|
| 1420 |
+
lib_paths = get_path('purelib'), get_path('platlib')
|
| 1421 |
+
|
| 1422 |
+
sitedirs.extend(s for s in lib_paths if s not in sitedirs)
|
| 1423 |
+
|
| 1424 |
+
if site.ENABLE_USER_SITE:
|
| 1425 |
+
sitedirs.append(site.USER_SITE)
|
| 1426 |
+
|
| 1427 |
+
with contextlib.suppress(AttributeError):
|
| 1428 |
+
sitedirs.extend(site.getsitepackages())
|
| 1429 |
+
|
| 1430 |
+
sitedirs = list(map(normalize_path, sitedirs))
|
| 1431 |
+
|
| 1432 |
+
return sitedirs
|
| 1433 |
+
|
| 1434 |
+
|
| 1435 |
+
def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME
|
| 1436 |
+
"""Yield sys.path directories that might contain "old-style" packages"""
|
| 1437 |
+
|
| 1438 |
+
seen = {}
|
| 1439 |
+
|
| 1440 |
+
for dirname in inputs:
|
| 1441 |
+
dirname = normalize_path(dirname)
|
| 1442 |
+
if dirname in seen:
|
| 1443 |
+
continue
|
| 1444 |
+
|
| 1445 |
+
seen[dirname] = 1
|
| 1446 |
+
if not os.path.isdir(dirname):
|
| 1447 |
+
continue
|
| 1448 |
+
|
| 1449 |
+
files = os.listdir(dirname)
|
| 1450 |
+
yield dirname, files
|
| 1451 |
+
|
| 1452 |
+
for name in files:
|
| 1453 |
+
if not name.endswith('.pth'):
|
| 1454 |
+
# We only care about the .pth files
|
| 1455 |
+
continue
|
| 1456 |
+
if name in ('easy-install.pth', 'setuptools.pth'):
|
| 1457 |
+
# Ignore .pth files that we control
|
| 1458 |
+
continue
|
| 1459 |
+
|
| 1460 |
+
# Read the .pth file
|
| 1461 |
+
f = open(os.path.join(dirname, name))
|
| 1462 |
+
lines = list(yield_lines(f))
|
| 1463 |
+
f.close()
|
| 1464 |
+
|
| 1465 |
+
# Yield existing non-dupe, non-import directory lines from it
|
| 1466 |
+
for line in lines:
|
| 1467 |
+
if line.startswith("import"):
|
| 1468 |
+
continue
|
| 1469 |
+
|
| 1470 |
+
line = normalize_path(line.rstrip())
|
| 1471 |
+
if line in seen:
|
| 1472 |
+
continue
|
| 1473 |
+
|
| 1474 |
+
seen[line] = 1
|
| 1475 |
+
if not os.path.isdir(line):
|
| 1476 |
+
continue
|
| 1477 |
+
|
| 1478 |
+
yield line, os.listdir(line)
|
| 1479 |
+
|
| 1480 |
+
|
| 1481 |
+
def extract_wininst_cfg(dist_filename):
|
| 1482 |
+
"""Extract configuration data from a bdist_wininst .exe
|
| 1483 |
+
|
| 1484 |
+
Returns a configparser.RawConfigParser, or None
|
| 1485 |
+
"""
|
| 1486 |
+
f = open(dist_filename, 'rb')
|
| 1487 |
+
try:
|
| 1488 |
+
endrec = zipfile._EndRecData(f)
|
| 1489 |
+
if endrec is None:
|
| 1490 |
+
return None
|
| 1491 |
+
|
| 1492 |
+
prepended = (endrec[9] - endrec[5]) - endrec[6]
|
| 1493 |
+
if prepended < 12: # no wininst data here
|
| 1494 |
+
return None
|
| 1495 |
+
f.seek(prepended - 12)
|
| 1496 |
+
|
| 1497 |
+
tag, cfglen, bmlen = struct.unpack("<iii", f.read(12))
|
| 1498 |
+
if tag not in (0x1234567A, 0x1234567B):
|
| 1499 |
+
return None # not a valid tag
|
| 1500 |
+
|
| 1501 |
+
f.seek(prepended - (12 + cfglen))
|
| 1502 |
+
init = {'version': '', 'target_version': ''}
|
| 1503 |
+
cfg = configparser.RawConfigParser(init)
|
| 1504 |
+
try:
|
| 1505 |
+
part = f.read(cfglen)
|
| 1506 |
+
# Read up to the first null byte.
|
| 1507 |
+
config = part.split(b'\0', 1)[0]
|
| 1508 |
+
# Now the config is in bytes, but for RawConfigParser, it should
|
| 1509 |
+
# be text, so decode it.
|
| 1510 |
+
config = config.decode(sys.getfilesystemencoding())
|
| 1511 |
+
cfg.readfp(io.StringIO(config))
|
| 1512 |
+
except configparser.Error:
|
| 1513 |
+
return None
|
| 1514 |
+
if not cfg.has_section('metadata') or not cfg.has_section('Setup'):
|
| 1515 |
+
return None
|
| 1516 |
+
return cfg
|
| 1517 |
+
|
| 1518 |
+
finally:
|
| 1519 |
+
f.close()
|
| 1520 |
+
|
| 1521 |
+
|
| 1522 |
+
def get_exe_prefixes(exe_filename):
|
| 1523 |
+
"""Get exe->egg path translations for a given .exe file"""
|
| 1524 |
+
|
| 1525 |
+
prefixes = [
|
| 1526 |
+
('PURELIB/', ''),
|
| 1527 |
+
('PLATLIB/pywin32_system32', ''),
|
| 1528 |
+
('PLATLIB/', ''),
|
| 1529 |
+
('SCRIPTS/', 'EGG-INFO/scripts/'),
|
| 1530 |
+
('DATA/lib/site-packages', ''),
|
| 1531 |
+
]
|
| 1532 |
+
z = zipfile.ZipFile(exe_filename)
|
| 1533 |
+
try:
|
| 1534 |
+
for info in z.infolist():
|
| 1535 |
+
name = info.filename
|
| 1536 |
+
parts = name.split('/')
|
| 1537 |
+
if len(parts) == 3 and parts[2] == 'PKG-INFO':
|
| 1538 |
+
if parts[1].endswith('.egg-info'):
|
| 1539 |
+
prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/'))
|
| 1540 |
+
break
|
| 1541 |
+
if len(parts) != 2 or not name.endswith('.pth'):
|
| 1542 |
+
continue
|
| 1543 |
+
if name.endswith('-nspkg.pth'):
|
| 1544 |
+
continue
|
| 1545 |
+
if parts[0].upper() in ('PURELIB', 'PLATLIB'):
|
| 1546 |
+
contents = z.read(name).decode()
|
| 1547 |
+
for pth in yield_lines(contents):
|
| 1548 |
+
pth = pth.strip().replace('\\', '/')
|
| 1549 |
+
if not pth.startswith('import'):
|
| 1550 |
+
prefixes.append((('%s/%s/' % (parts[0], pth)), ''))
|
| 1551 |
+
finally:
|
| 1552 |
+
z.close()
|
| 1553 |
+
prefixes = [(x.lower(), y) for x, y in prefixes]
|
| 1554 |
+
prefixes.sort()
|
| 1555 |
+
prefixes.reverse()
|
| 1556 |
+
return prefixes
|
| 1557 |
+
|
| 1558 |
+
|
| 1559 |
+
class PthDistributions(Environment):
|
| 1560 |
+
"""A .pth file with Distribution paths in it"""
|
| 1561 |
+
|
| 1562 |
+
dirty = False
|
| 1563 |
+
|
| 1564 |
+
def __init__(self, filename, sitedirs=()):
|
| 1565 |
+
self.filename = filename
|
| 1566 |
+
self.sitedirs = list(map(normalize_path, sitedirs))
|
| 1567 |
+
self.basedir = normalize_path(os.path.dirname(self.filename))
|
| 1568 |
+
self._load()
|
| 1569 |
+
Environment.__init__(self, [], None, None)
|
| 1570 |
+
for path in yield_lines(self.paths):
|
| 1571 |
+
list(map(self.add, find_distributions(path, True)))
|
| 1572 |
+
|
| 1573 |
+
def _load(self):
|
| 1574 |
+
self.paths = []
|
| 1575 |
+
saw_import = False
|
| 1576 |
+
seen = dict.fromkeys(self.sitedirs)
|
| 1577 |
+
if os.path.isfile(self.filename):
|
| 1578 |
+
f = open(self.filename, 'rt')
|
| 1579 |
+
for line in f:
|
| 1580 |
+
if line.startswith('import'):
|
| 1581 |
+
saw_import = True
|
| 1582 |
+
continue
|
| 1583 |
+
path = line.rstrip()
|
| 1584 |
+
self.paths.append(path)
|
| 1585 |
+
if not path.strip() or path.strip().startswith('#'):
|
| 1586 |
+
continue
|
| 1587 |
+
# skip non-existent paths, in case somebody deleted a package
|
| 1588 |
+
# manually, and duplicate paths as well
|
| 1589 |
+
path = self.paths[-1] = normalize_path(
|
| 1590 |
+
os.path.join(self.basedir, path)
|
| 1591 |
+
)
|
| 1592 |
+
if not os.path.exists(path) or path in seen:
|
| 1593 |
+
self.paths.pop() # skip it
|
| 1594 |
+
self.dirty = True # we cleaned up, so we're dirty now :)
|
| 1595 |
+
continue
|
| 1596 |
+
seen[path] = 1
|
| 1597 |
+
f.close()
|
| 1598 |
+
|
| 1599 |
+
if self.paths and not saw_import:
|
| 1600 |
+
self.dirty = True # ensure anything we touch has import wrappers
|
| 1601 |
+
while self.paths and not self.paths[-1].strip():
|
| 1602 |
+
self.paths.pop()
|
| 1603 |
+
|
| 1604 |
+
def save(self):
|
| 1605 |
+
"""Write changed .pth file back to disk"""
|
| 1606 |
+
if not self.dirty:
|
| 1607 |
+
return
|
| 1608 |
+
|
| 1609 |
+
rel_paths = list(map(self.make_relative, self.paths))
|
| 1610 |
+
if rel_paths:
|
| 1611 |
+
log.debug("Saving %s", self.filename)
|
| 1612 |
+
lines = self._wrap_lines(rel_paths)
|
| 1613 |
+
data = '\n'.join(lines) + '\n'
|
| 1614 |
+
|
| 1615 |
+
if os.path.islink(self.filename):
|
| 1616 |
+
os.unlink(self.filename)
|
| 1617 |
+
with open(self.filename, 'wt') as f:
|
| 1618 |
+
f.write(data)
|
| 1619 |
+
|
| 1620 |
+
elif os.path.exists(self.filename):
|
| 1621 |
+
log.debug("Deleting empty %s", self.filename)
|
| 1622 |
+
os.unlink(self.filename)
|
| 1623 |
+
|
| 1624 |
+
self.dirty = False
|
| 1625 |
+
|
| 1626 |
+
@staticmethod
|
| 1627 |
+
def _wrap_lines(lines):
|
| 1628 |
+
return lines
|
| 1629 |
+
|
| 1630 |
+
def add(self, dist):
|
| 1631 |
+
"""Add `dist` to the distribution map"""
|
| 1632 |
+
new_path = (
|
| 1633 |
+
dist.location not in self.paths and (
|
| 1634 |
+
dist.location not in self.sitedirs or
|
| 1635 |
+
# account for '.' being in PYTHONPATH
|
| 1636 |
+
dist.location == os.getcwd()
|
| 1637 |
+
)
|
| 1638 |
+
)
|
| 1639 |
+
if new_path:
|
| 1640 |
+
self.paths.append(dist.location)
|
| 1641 |
+
self.dirty = True
|
| 1642 |
+
Environment.add(self, dist)
|
| 1643 |
+
|
| 1644 |
+
def remove(self, dist):
|
| 1645 |
+
"""Remove `dist` from the distribution map"""
|
| 1646 |
+
while dist.location in self.paths:
|
| 1647 |
+
self.paths.remove(dist.location)
|
| 1648 |
+
self.dirty = True
|
| 1649 |
+
Environment.remove(self, dist)
|
| 1650 |
+
|
| 1651 |
+
def make_relative(self, path):
|
| 1652 |
+
npath, last = os.path.split(normalize_path(path))
|
| 1653 |
+
baselen = len(self.basedir)
|
| 1654 |
+
parts = [last]
|
| 1655 |
+
sep = os.altsep == '/' and '/' or os.sep
|
| 1656 |
+
while len(npath) >= baselen:
|
| 1657 |
+
if npath == self.basedir:
|
| 1658 |
+
parts.append(os.curdir)
|
| 1659 |
+
parts.reverse()
|
| 1660 |
+
return sep.join(parts)
|
| 1661 |
+
npath, last = os.path.split(npath)
|
| 1662 |
+
parts.append(last)
|
| 1663 |
+
else:
|
| 1664 |
+
return path
|
| 1665 |
+
|
| 1666 |
+
|
| 1667 |
+
class RewritePthDistributions(PthDistributions):
|
| 1668 |
+
@classmethod
|
| 1669 |
+
def _wrap_lines(cls, lines):
|
| 1670 |
+
yield cls.prelude
|
| 1671 |
+
for line in lines:
|
| 1672 |
+
yield line
|
| 1673 |
+
yield cls.postlude
|
| 1674 |
+
|
| 1675 |
+
prelude = _one_liner("""
|
| 1676 |
+
import sys
|
| 1677 |
+
sys.__plen = len(sys.path)
|
| 1678 |
+
""")
|
| 1679 |
+
postlude = _one_liner("""
|
| 1680 |
+
import sys
|
| 1681 |
+
new = sys.path[sys.__plen:]
|
| 1682 |
+
del sys.path[sys.__plen:]
|
| 1683 |
+
p = getattr(sys, '__egginsert', 0)
|
| 1684 |
+
sys.path[p:p] = new
|
| 1685 |
+
sys.__egginsert = p + len(new)
|
| 1686 |
+
""")
|
| 1687 |
+
|
| 1688 |
+
|
| 1689 |
+
if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite':
|
| 1690 |
+
PthDistributions = RewritePthDistributions
|
| 1691 |
+
|
| 1692 |
+
|
| 1693 |
+
def _first_line_re():
|
| 1694 |
+
"""
|
| 1695 |
+
Return a regular expression based on first_line_re suitable for matching
|
| 1696 |
+
strings.
|
| 1697 |
+
"""
|
| 1698 |
+
if isinstance(first_line_re.pattern, str):
|
| 1699 |
+
return first_line_re
|
| 1700 |
+
|
| 1701 |
+
# first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern.
|
| 1702 |
+
return re.compile(first_line_re.pattern.decode())
|
| 1703 |
+
|
| 1704 |
+
|
| 1705 |
+
def auto_chmod(func, arg, exc):
|
| 1706 |
+
if func in [os.unlink, os.remove] and os.name == 'nt':
|
| 1707 |
+
chmod(arg, stat.S_IWRITE)
|
| 1708 |
+
return func(arg)
|
| 1709 |
+
et, ev, _ = sys.exc_info()
|
| 1710 |
+
# TODO: This code doesn't make sense. What is it trying to do?
|
| 1711 |
+
raise (ev[0], ev[1] + (" %s %s" % (func, arg)))
|
| 1712 |
+
|
| 1713 |
+
|
| 1714 |
+
def update_dist_caches(dist_path, fix_zipimporter_caches):
|
| 1715 |
+
"""
|
| 1716 |
+
Fix any globally cached `dist_path` related data
|
| 1717 |
+
|
| 1718 |
+
`dist_path` should be a path of a newly installed egg distribution (zipped
|
| 1719 |
+
or unzipped).
|
| 1720 |
+
|
| 1721 |
+
sys.path_importer_cache contains finder objects that have been cached when
|
| 1722 |
+
importing data from the original distribution. Any such finders need to be
|
| 1723 |
+
cleared since the replacement distribution might be packaged differently,
|
| 1724 |
+
e.g. a zipped egg distribution might get replaced with an unzipped egg
|
| 1725 |
+
folder or vice versa. Having the old finders cached may then cause Python
|
| 1726 |
+
to attempt loading modules from the replacement distribution using an
|
| 1727 |
+
incorrect loader.
|
| 1728 |
+
|
| 1729 |
+
zipimport.zipimporter objects are Python loaders charged with importing
|
| 1730 |
+
data packaged inside zip archives. If stale loaders referencing the
|
| 1731 |
+
original distribution, are left behind, they can fail to load modules from
|
| 1732 |
+
the replacement distribution. E.g. if an old zipimport.zipimporter instance
|
| 1733 |
+
is used to load data from a new zipped egg archive, it may cause the
|
| 1734 |
+
operation to attempt to locate the requested data in the wrong location -
|
| 1735 |
+
one indicated by the original distribution's zip archive directory
|
| 1736 |
+
information. Such an operation may then fail outright, e.g. report having
|
| 1737 |
+
read a 'bad local file header', or even worse, it may fail silently &
|
| 1738 |
+
return invalid data.
|
| 1739 |
+
|
| 1740 |
+
zipimport._zip_directory_cache contains cached zip archive directory
|
| 1741 |
+
information for all existing zipimport.zipimporter instances and all such
|
| 1742 |
+
instances connected to the same archive share the same cached directory
|
| 1743 |
+
information.
|
| 1744 |
+
|
| 1745 |
+
If asked, and the underlying Python implementation allows it, we can fix
|
| 1746 |
+
all existing zipimport.zipimporter instances instead of having to track
|
| 1747 |
+
them down and remove them one by one, by updating their shared cached zip
|
| 1748 |
+
archive directory information. This, of course, assumes that the
|
| 1749 |
+
replacement distribution is packaged as a zipped egg.
|
| 1750 |
+
|
| 1751 |
+
If not asked to fix existing zipimport.zipimporter instances, we still do
|
| 1752 |
+
our best to clear any remaining zipimport.zipimporter related cached data
|
| 1753 |
+
that might somehow later get used when attempting to load data from the new
|
| 1754 |
+
distribution and thus cause such load operations to fail. Note that when
|
| 1755 |
+
tracking down such remaining stale data, we can not catch every conceivable
|
| 1756 |
+
usage from here, and we clear only those that we know of and have found to
|
| 1757 |
+
cause problems if left alive. Any remaining caches should be updated by
|
| 1758 |
+
whomever is in charge of maintaining them, i.e. they should be ready to
|
| 1759 |
+
handle us replacing their zip archives with new distributions at runtime.
|
| 1760 |
+
|
| 1761 |
+
"""
|
| 1762 |
+
# There are several other known sources of stale zipimport.zipimporter
|
| 1763 |
+
# instances that we do not clear here, but might if ever given a reason to
|
| 1764 |
+
# do so:
|
| 1765 |
+
# * Global setuptools pkg_resources.working_set (a.k.a. 'master working
|
| 1766 |
+
# set') may contain distributions which may in turn contain their
|
| 1767 |
+
# zipimport.zipimporter loaders.
|
| 1768 |
+
# * Several zipimport.zipimporter loaders held by local variables further
|
| 1769 |
+
# up the function call stack when running the setuptools installation.
|
| 1770 |
+
# * Already loaded modules may have their __loader__ attribute set to the
|
| 1771 |
+
# exact loader instance used when importing them. Python 3.4 docs state
|
| 1772 |
+
# that this information is intended mostly for introspection and so is
|
| 1773 |
+
# not expected to cause us problems.
|
| 1774 |
+
normalized_path = normalize_path(dist_path)
|
| 1775 |
+
_uncache(normalized_path, sys.path_importer_cache)
|
| 1776 |
+
if fix_zipimporter_caches:
|
| 1777 |
+
_replace_zip_directory_cache_data(normalized_path)
|
| 1778 |
+
else:
|
| 1779 |
+
# Here, even though we do not want to fix existing and now stale
|
| 1780 |
+
# zipimporter cache information, we still want to remove it. Related to
|
| 1781 |
+
# Python's zip archive directory information cache, we clear each of
|
| 1782 |
+
# its stale entries in two phases:
|
| 1783 |
+
# 1. Clear the entry so attempting to access zip archive information
|
| 1784 |
+
# via any existing stale zipimport.zipimporter instances fails.
|
| 1785 |
+
# 2. Remove the entry from the cache so any newly constructed
|
| 1786 |
+
# zipimport.zipimporter instances do not end up using old stale
|
| 1787 |
+
# zip archive directory information.
|
| 1788 |
+
# This whole stale data removal step does not seem strictly necessary,
|
| 1789 |
+
# but has been left in because it was done before we started replacing
|
| 1790 |
+
# the zip archive directory information cache content if possible, and
|
| 1791 |
+
# there are no relevant unit tests that we can depend on to tell us if
|
| 1792 |
+
# this is really needed.
|
| 1793 |
+
_remove_and_clear_zip_directory_cache_data(normalized_path)
|
| 1794 |
+
|
| 1795 |
+
|
| 1796 |
+
def _collect_zipimporter_cache_entries(normalized_path, cache):
|
| 1797 |
+
"""
|
| 1798 |
+
Return zipimporter cache entry keys related to a given normalized path.
|
| 1799 |
+
|
| 1800 |
+
Alternative path spellings (e.g. those using different character case or
|
| 1801 |
+
those using alternative path separators) related to the same path are
|
| 1802 |
+
included. Any sub-path entries are included as well, i.e. those
|
| 1803 |
+
corresponding to zip archives embedded in other zip archives.
|
| 1804 |
+
|
| 1805 |
+
"""
|
| 1806 |
+
result = []
|
| 1807 |
+
prefix_len = len(normalized_path)
|
| 1808 |
+
for p in cache:
|
| 1809 |
+
np = normalize_path(p)
|
| 1810 |
+
if (np.startswith(normalized_path) and
|
| 1811 |
+
np[prefix_len:prefix_len + 1] in (os.sep, '')):
|
| 1812 |
+
result.append(p)
|
| 1813 |
+
return result
|
| 1814 |
+
|
| 1815 |
+
|
| 1816 |
+
def _update_zipimporter_cache(normalized_path, cache, updater=None):
|
| 1817 |
+
"""
|
| 1818 |
+
Update zipimporter cache data for a given normalized path.
|
| 1819 |
+
|
| 1820 |
+
Any sub-path entries are processed as well, i.e. those corresponding to zip
|
| 1821 |
+
archives embedded in other zip archives.
|
| 1822 |
+
|
| 1823 |
+
Given updater is a callable taking a cache entry key and the original entry
|
| 1824 |
+
(after already removing the entry from the cache), and expected to update
|
| 1825 |
+
the entry and possibly return a new one to be inserted in its place.
|
| 1826 |
+
Returning None indicates that the entry should not be replaced with a new
|
| 1827 |
+
one. If no updater is given, the cache entries are simply removed without
|
| 1828 |
+
any additional processing, the same as if the updater simply returned None.
|
| 1829 |
+
|
| 1830 |
+
"""
|
| 1831 |
+
for p in _collect_zipimporter_cache_entries(normalized_path, cache):
|
| 1832 |
+
# N.B. pypy's custom zipimport._zip_directory_cache implementation does
|
| 1833 |
+
# not support the complete dict interface:
|
| 1834 |
+
# * Does not support item assignment, thus not allowing this function
|
| 1835 |
+
# to be used only for removing existing cache entries.
|
| 1836 |
+
# * Does not support the dict.pop() method, forcing us to use the
|
| 1837 |
+
# get/del patterns instead. For more detailed information see the
|
| 1838 |
+
# following links:
|
| 1839 |
+
# https://github.com/pypa/setuptools/issues/202#issuecomment-202913420
|
| 1840 |
+
# http://bit.ly/2h9itJX
|
| 1841 |
+
old_entry = cache[p]
|
| 1842 |
+
del cache[p]
|
| 1843 |
+
new_entry = updater and updater(p, old_entry)
|
| 1844 |
+
if new_entry is not None:
|
| 1845 |
+
cache[p] = new_entry
|
| 1846 |
+
|
| 1847 |
+
|
| 1848 |
+
def _uncache(normalized_path, cache):
|
| 1849 |
+
_update_zipimporter_cache(normalized_path, cache)
|
| 1850 |
+
|
| 1851 |
+
|
| 1852 |
+
def _remove_and_clear_zip_directory_cache_data(normalized_path):
|
| 1853 |
+
def clear_and_remove_cached_zip_archive_directory_data(path, old_entry):
|
| 1854 |
+
old_entry.clear()
|
| 1855 |
+
|
| 1856 |
+
_update_zipimporter_cache(
|
| 1857 |
+
normalized_path, zipimport._zip_directory_cache,
|
| 1858 |
+
updater=clear_and_remove_cached_zip_archive_directory_data)
|
| 1859 |
+
|
| 1860 |
+
|
| 1861 |
+
# PyPy Python implementation does not allow directly writing to the
|
| 1862 |
+
# zipimport._zip_directory_cache and so prevents us from attempting to correct
|
| 1863 |
+
# its content. The best we can do there is clear the problematic cache content
|
| 1864 |
+
# and have PyPy repopulate it as needed. The downside is that if there are any
|
| 1865 |
+
# stale zipimport.zipimporter instances laying around, attempting to use them
|
| 1866 |
+
# will fail due to not having its zip archive directory information available
|
| 1867 |
+
# instead of being automatically corrected to use the new correct zip archive
|
| 1868 |
+
# directory information.
|
| 1869 |
+
if '__pypy__' in sys.builtin_module_names:
|
| 1870 |
+
_replace_zip_directory_cache_data = \
|
| 1871 |
+
_remove_and_clear_zip_directory_cache_data
|
| 1872 |
+
else:
|
| 1873 |
+
|
| 1874 |
+
def _replace_zip_directory_cache_data(normalized_path):
|
| 1875 |
+
def replace_cached_zip_archive_directory_data(path, old_entry):
|
| 1876 |
+
# N.B. In theory, we could load the zip directory information just
|
| 1877 |
+
# once for all updated path spellings, and then copy it locally and
|
| 1878 |
+
# update its contained path strings to contain the correct
|
| 1879 |
+
# spelling, but that seems like a way too invasive move (this cache
|
| 1880 |
+
# structure is not officially documented anywhere and could in
|
| 1881 |
+
# theory change with new Python releases) for no significant
|
| 1882 |
+
# benefit.
|
| 1883 |
+
old_entry.clear()
|
| 1884 |
+
zipimport.zipimporter(path)
|
| 1885 |
+
old_entry.update(zipimport._zip_directory_cache[path])
|
| 1886 |
+
return old_entry
|
| 1887 |
+
|
| 1888 |
+
_update_zipimporter_cache(
|
| 1889 |
+
normalized_path, zipimport._zip_directory_cache,
|
| 1890 |
+
updater=replace_cached_zip_archive_directory_data)
|
| 1891 |
+
|
| 1892 |
+
|
| 1893 |
+
def is_python(text, filename='<string>'):
|
| 1894 |
+
"Is this string a valid Python script?"
|
| 1895 |
+
try:
|
| 1896 |
+
compile(text, filename, 'exec')
|
| 1897 |
+
except (SyntaxError, TypeError):
|
| 1898 |
+
return False
|
| 1899 |
+
else:
|
| 1900 |
+
return True
|
| 1901 |
+
|
| 1902 |
+
|
| 1903 |
+
def is_sh(executable):
|
| 1904 |
+
"""Determine if the specified executable is a .sh (contains a #! line)"""
|
| 1905 |
+
try:
|
| 1906 |
+
with io.open(executable, encoding='latin-1') as fp:
|
| 1907 |
+
magic = fp.read(2)
|
| 1908 |
+
except (OSError, IOError):
|
| 1909 |
+
return executable
|
| 1910 |
+
return magic == '#!'
|
| 1911 |
+
|
| 1912 |
+
|
| 1913 |
+
def nt_quote_arg(arg):
|
| 1914 |
+
"""Quote a command line argument according to Windows parsing rules"""
|
| 1915 |
+
return subprocess.list2cmdline([arg])
|
| 1916 |
+
|
| 1917 |
+
|
| 1918 |
+
def is_python_script(script_text, filename):
|
| 1919 |
+
"""Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
|
| 1920 |
+
"""
|
| 1921 |
+
if filename.endswith('.py') or filename.endswith('.pyw'):
|
| 1922 |
+
return True # extension says it's Python
|
| 1923 |
+
if is_python(script_text, filename):
|
| 1924 |
+
return True # it's syntactically valid Python
|
| 1925 |
+
if script_text.startswith('#!'):
|
| 1926 |
+
# It begins with a '#!' line, so check if 'python' is in it somewhere
|
| 1927 |
+
return 'python' in script_text.splitlines()[0].lower()
|
| 1928 |
+
|
| 1929 |
+
return False # Not any Python I can recognize
|
| 1930 |
+
|
| 1931 |
+
|
| 1932 |
+
try:
|
| 1933 |
+
from os import chmod as _chmod
|
| 1934 |
+
except ImportError:
|
| 1935 |
+
# Jython compatibility
|
| 1936 |
+
def _chmod(*args):
|
| 1937 |
+
pass
|
| 1938 |
+
|
| 1939 |
+
|
| 1940 |
+
def chmod(path, mode):
|
| 1941 |
+
log.debug("changing mode of %s to %o", path, mode)
|
| 1942 |
+
try:
|
| 1943 |
+
_chmod(path, mode)
|
| 1944 |
+
except os.error as e:
|
| 1945 |
+
log.debug("chmod failed: %s", e)
|
| 1946 |
+
|
| 1947 |
+
|
| 1948 |
+
class CommandSpec(list):
|
| 1949 |
+
"""
|
| 1950 |
+
A command spec for a #! header, specified as a list of arguments akin to
|
| 1951 |
+
those passed to Popen.
|
| 1952 |
+
"""
|
| 1953 |
+
|
| 1954 |
+
options = []
|
| 1955 |
+
split_args = dict()
|
| 1956 |
+
|
| 1957 |
+
@classmethod
|
| 1958 |
+
def best(cls):
|
| 1959 |
+
"""
|
| 1960 |
+
Choose the best CommandSpec class based on environmental conditions.
|
| 1961 |
+
"""
|
| 1962 |
+
return cls
|
| 1963 |
+
|
| 1964 |
+
@classmethod
|
| 1965 |
+
def _sys_executable(cls):
|
| 1966 |
+
_default = os.path.normpath(sys.executable)
|
| 1967 |
+
return os.environ.get('__PYVENV_LAUNCHER__', _default)
|
| 1968 |
+
|
| 1969 |
+
@classmethod
|
| 1970 |
+
def from_param(cls, param):
|
| 1971 |
+
"""
|
| 1972 |
+
Construct a CommandSpec from a parameter to build_scripts, which may
|
| 1973 |
+
be None.
|
| 1974 |
+
"""
|
| 1975 |
+
if isinstance(param, cls):
|
| 1976 |
+
return param
|
| 1977 |
+
if isinstance(param, list):
|
| 1978 |
+
return cls(param)
|
| 1979 |
+
if param is None:
|
| 1980 |
+
return cls.from_environment()
|
| 1981 |
+
# otherwise, assume it's a string.
|
| 1982 |
+
return cls.from_string(param)
|
| 1983 |
+
|
| 1984 |
+
@classmethod
|
| 1985 |
+
def from_environment(cls):
|
| 1986 |
+
return cls([cls._sys_executable()])
|
| 1987 |
+
|
| 1988 |
+
@classmethod
|
| 1989 |
+
def from_string(cls, string):
|
| 1990 |
+
"""
|
| 1991 |
+
Construct a command spec from a simple string representing a command
|
| 1992 |
+
line parseable by shlex.split.
|
| 1993 |
+
"""
|
| 1994 |
+
items = shlex.split(string, **cls.split_args)
|
| 1995 |
+
return cls(items)
|
| 1996 |
+
|
| 1997 |
+
def install_options(self, script_text):
|
| 1998 |
+
self.options = shlex.split(self._extract_options(script_text))
|
| 1999 |
+
cmdline = subprocess.list2cmdline(self)
|
| 2000 |
+
if not isascii(cmdline):
|
| 2001 |
+
self.options[:0] = ['-x']
|
| 2002 |
+
|
| 2003 |
+
@staticmethod
|
| 2004 |
+
def _extract_options(orig_script):
|
| 2005 |
+
"""
|
| 2006 |
+
Extract any options from the first line of the script.
|
| 2007 |
+
"""
|
| 2008 |
+
first = (orig_script + '\n').splitlines()[0]
|
| 2009 |
+
match = _first_line_re().match(first)
|
| 2010 |
+
options = match.group(1) or '' if match else ''
|
| 2011 |
+
return options.strip()
|
| 2012 |
+
|
| 2013 |
+
def as_header(self):
|
| 2014 |
+
return self._render(self + list(self.options))
|
| 2015 |
+
|
| 2016 |
+
@staticmethod
|
| 2017 |
+
def _strip_quotes(item):
|
| 2018 |
+
_QUOTES = '"\''
|
| 2019 |
+
for q in _QUOTES:
|
| 2020 |
+
if item.startswith(q) and item.endswith(q):
|
| 2021 |
+
return item[1:-1]
|
| 2022 |
+
return item
|
| 2023 |
+
|
| 2024 |
+
@staticmethod
|
| 2025 |
+
def _render(items):
|
| 2026 |
+
cmdline = subprocess.list2cmdline(
|
| 2027 |
+
CommandSpec._strip_quotes(item.strip()) for item in items)
|
| 2028 |
+
return '#!' + cmdline + '\n'
|
| 2029 |
+
|
| 2030 |
+
|
| 2031 |
+
# For pbr compat; will be removed in a future version.
|
| 2032 |
+
sys_executable = CommandSpec._sys_executable()
|
| 2033 |
+
|
| 2034 |
+
|
| 2035 |
+
class WindowsCommandSpec(CommandSpec):
|
| 2036 |
+
split_args = dict(posix=False)
|
| 2037 |
+
|
| 2038 |
+
|
| 2039 |
+
class ScriptWriter:
|
| 2040 |
+
"""
|
| 2041 |
+
Encapsulates behavior around writing entry point scripts for console and
|
| 2042 |
+
gui apps.
|
| 2043 |
+
"""
|
| 2044 |
+
|
| 2045 |
+
template = textwrap.dedent(r"""
|
| 2046 |
+
# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r
|
| 2047 |
+
import re
|
| 2048 |
+
import sys
|
| 2049 |
+
|
| 2050 |
+
# for compatibility with easy_install; see #2198
|
| 2051 |
+
__requires__ = %(spec)r
|
| 2052 |
+
|
| 2053 |
+
try:
|
| 2054 |
+
from importlib.metadata import distribution
|
| 2055 |
+
except ImportError:
|
| 2056 |
+
try:
|
| 2057 |
+
from importlib_metadata import distribution
|
| 2058 |
+
except ImportError:
|
| 2059 |
+
from pkg_resources import load_entry_point
|
| 2060 |
+
|
| 2061 |
+
|
| 2062 |
+
def importlib_load_entry_point(spec, group, name):
|
| 2063 |
+
dist_name, _, _ = spec.partition('==')
|
| 2064 |
+
matches = (
|
| 2065 |
+
entry_point
|
| 2066 |
+
for entry_point in distribution(dist_name).entry_points
|
| 2067 |
+
if entry_point.group == group and entry_point.name == name
|
| 2068 |
+
)
|
| 2069 |
+
return next(matches).load()
|
| 2070 |
+
|
| 2071 |
+
|
| 2072 |
+
globals().setdefault('load_entry_point', importlib_load_entry_point)
|
| 2073 |
+
|
| 2074 |
+
|
| 2075 |
+
if __name__ == '__main__':
|
| 2076 |
+
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
| 2077 |
+
sys.exit(load_entry_point(%(spec)r, %(group)r, %(name)r)())
|
| 2078 |
+
""").lstrip()
|
| 2079 |
+
|
| 2080 |
+
command_spec_class = CommandSpec
|
| 2081 |
+
|
| 2082 |
+
@classmethod
|
| 2083 |
+
def get_script_args(cls, dist, executable=None, wininst=False):
|
| 2084 |
+
# for backward compatibility
|
| 2085 |
+
warnings.warn("Use get_args", EasyInstallDeprecationWarning)
|
| 2086 |
+
writer = (WindowsScriptWriter if wininst else ScriptWriter).best()
|
| 2087 |
+
header = cls.get_script_header("", executable, wininst)
|
| 2088 |
+
return writer.get_args(dist, header)
|
| 2089 |
+
|
| 2090 |
+
@classmethod
|
| 2091 |
+
def get_script_header(cls, script_text, executable=None, wininst=False):
|
| 2092 |
+
# for backward compatibility
|
| 2093 |
+
warnings.warn(
|
| 2094 |
+
"Use get_header", EasyInstallDeprecationWarning, stacklevel=2)
|
| 2095 |
+
if wininst:
|
| 2096 |
+
executable = "python.exe"
|
| 2097 |
+
return cls.get_header(script_text, executable)
|
| 2098 |
+
|
| 2099 |
+
@classmethod
|
| 2100 |
+
def get_args(cls, dist, header=None):
|
| 2101 |
+
"""
|
| 2102 |
+
Yield write_script() argument tuples for a distribution's
|
| 2103 |
+
console_scripts and gui_scripts entry points.
|
| 2104 |
+
"""
|
| 2105 |
+
if header is None:
|
| 2106 |
+
header = cls.get_header()
|
| 2107 |
+
spec = str(dist.as_requirement())
|
| 2108 |
+
for type_ in 'console', 'gui':
|
| 2109 |
+
group = type_ + '_scripts'
|
| 2110 |
+
for name, ep in dist.get_entry_map(group).items():
|
| 2111 |
+
cls._ensure_safe_name(name)
|
| 2112 |
+
script_text = cls.template % locals()
|
| 2113 |
+
args = cls._get_script_args(type_, name, header, script_text)
|
| 2114 |
+
for res in args:
|
| 2115 |
+
yield res
|
| 2116 |
+
|
| 2117 |
+
@staticmethod
|
| 2118 |
+
def _ensure_safe_name(name):
|
| 2119 |
+
"""
|
| 2120 |
+
Prevent paths in *_scripts entry point names.
|
| 2121 |
+
"""
|
| 2122 |
+
has_path_sep = re.search(r'[\\/]', name)
|
| 2123 |
+
if has_path_sep:
|
| 2124 |
+
raise ValueError("Path separators not allowed in script names")
|
| 2125 |
+
|
| 2126 |
+
@classmethod
|
| 2127 |
+
def get_writer(cls, force_windows):
|
| 2128 |
+
# for backward compatibility
|
| 2129 |
+
warnings.warn("Use best", EasyInstallDeprecationWarning)
|
| 2130 |
+
return WindowsScriptWriter.best() if force_windows else cls.best()
|
| 2131 |
+
|
| 2132 |
+
@classmethod
|
| 2133 |
+
def best(cls):
|
| 2134 |
+
"""
|
| 2135 |
+
Select the best ScriptWriter for this environment.
|
| 2136 |
+
"""
|
| 2137 |
+
if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'):
|
| 2138 |
+
return WindowsScriptWriter.best()
|
| 2139 |
+
else:
|
| 2140 |
+
return cls
|
| 2141 |
+
|
| 2142 |
+
@classmethod
|
| 2143 |
+
def _get_script_args(cls, type_, name, header, script_text):
|
| 2144 |
+
# Simply write the stub with no extension.
|
| 2145 |
+
yield (name, header + script_text)
|
| 2146 |
+
|
| 2147 |
+
@classmethod
|
| 2148 |
+
def get_header(cls, script_text="", executable=None):
|
| 2149 |
+
"""Create a #! line, getting options (if any) from script_text"""
|
| 2150 |
+
cmd = cls.command_spec_class.best().from_param(executable)
|
| 2151 |
+
cmd.install_options(script_text)
|
| 2152 |
+
return cmd.as_header()
|
| 2153 |
+
|
| 2154 |
+
|
| 2155 |
+
class WindowsScriptWriter(ScriptWriter):
|
| 2156 |
+
command_spec_class = WindowsCommandSpec
|
| 2157 |
+
|
| 2158 |
+
@classmethod
|
| 2159 |
+
def get_writer(cls):
|
| 2160 |
+
# for backward compatibility
|
| 2161 |
+
warnings.warn("Use best", EasyInstallDeprecationWarning)
|
| 2162 |
+
return cls.best()
|
| 2163 |
+
|
| 2164 |
+
@classmethod
|
| 2165 |
+
def best(cls):
|
| 2166 |
+
"""
|
| 2167 |
+
Select the best ScriptWriter suitable for Windows
|
| 2168 |
+
"""
|
| 2169 |
+
writer_lookup = dict(
|
| 2170 |
+
executable=WindowsExecutableLauncherWriter,
|
| 2171 |
+
natural=cls,
|
| 2172 |
+
)
|
| 2173 |
+
# for compatibility, use the executable launcher by default
|
| 2174 |
+
launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable')
|
| 2175 |
+
return writer_lookup[launcher]
|
| 2176 |
+
|
| 2177 |
+
@classmethod
|
| 2178 |
+
def _get_script_args(cls, type_, name, header, script_text):
|
| 2179 |
+
"For Windows, add a .py extension"
|
| 2180 |
+
ext = dict(console='.pya', gui='.pyw')[type_]
|
| 2181 |
+
if ext not in os.environ['PATHEXT'].lower().split(';'):
|
| 2182 |
+
msg = (
|
| 2183 |
+
"{ext} not listed in PATHEXT; scripts will not be "
|
| 2184 |
+
"recognized as executables."
|
| 2185 |
+
).format(**locals())
|
| 2186 |
+
warnings.warn(msg, UserWarning)
|
| 2187 |
+
old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe']
|
| 2188 |
+
old.remove(ext)
|
| 2189 |
+
header = cls._adjust_header(type_, header)
|
| 2190 |
+
blockers = [name + x for x in old]
|
| 2191 |
+
yield name + ext, header + script_text, 't', blockers
|
| 2192 |
+
|
| 2193 |
+
@classmethod
|
| 2194 |
+
def _adjust_header(cls, type_, orig_header):
|
| 2195 |
+
"""
|
| 2196 |
+
Make sure 'pythonw' is used for gui and 'python' is used for
|
| 2197 |
+
console (regardless of what sys.executable is).
|
| 2198 |
+
"""
|
| 2199 |
+
pattern = 'pythonw.exe'
|
| 2200 |
+
repl = 'python.exe'
|
| 2201 |
+
if type_ == 'gui':
|
| 2202 |
+
pattern, repl = repl, pattern
|
| 2203 |
+
pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE)
|
| 2204 |
+
new_header = pattern_ob.sub(string=orig_header, repl=repl)
|
| 2205 |
+
return new_header if cls._use_header(new_header) else orig_header
|
| 2206 |
+
|
| 2207 |
+
@staticmethod
|
| 2208 |
+
def _use_header(new_header):
|
| 2209 |
+
"""
|
| 2210 |
+
Should _adjust_header use the replaced header?
|
| 2211 |
+
|
| 2212 |
+
On non-windows systems, always use. On
|
| 2213 |
+
Windows systems, only use the replaced header if it resolves
|
| 2214 |
+
to an executable on the system.
|
| 2215 |
+
"""
|
| 2216 |
+
clean_header = new_header[2:-1].strip('"')
|
| 2217 |
+
return sys.platform != 'win32' or find_executable(clean_header)
|
| 2218 |
+
|
| 2219 |
+
|
| 2220 |
+
class WindowsExecutableLauncherWriter(WindowsScriptWriter):
|
| 2221 |
+
@classmethod
|
| 2222 |
+
def _get_script_args(cls, type_, name, header, script_text):
|
| 2223 |
+
"""
|
| 2224 |
+
For Windows, add a .py extension and an .exe launcher
|
| 2225 |
+
"""
|
| 2226 |
+
if type_ == 'gui':
|
| 2227 |
+
launcher_type = 'gui'
|
| 2228 |
+
ext = '-script.pyw'
|
| 2229 |
+
old = ['.pyw']
|
| 2230 |
+
else:
|
| 2231 |
+
launcher_type = 'cli'
|
| 2232 |
+
ext = '-script.py'
|
| 2233 |
+
old = ['.py', '.pyc', '.pyo']
|
| 2234 |
+
hdr = cls._adjust_header(type_, header)
|
| 2235 |
+
blockers = [name + x for x in old]
|
| 2236 |
+
yield (name + ext, hdr + script_text, 't', blockers)
|
| 2237 |
+
yield (
|
| 2238 |
+
name + '.exe', get_win_launcher(launcher_type),
|
| 2239 |
+
'b' # write in binary mode
|
| 2240 |
+
)
|
| 2241 |
+
if not is_64bit():
|
| 2242 |
+
# install a manifest for the launcher to prevent Windows
|
| 2243 |
+
# from detecting it as an installer (which it will for
|
| 2244 |
+
# launchers like easy_install.exe). Consider only
|
| 2245 |
+
# adding a manifest for launchers detected as installers.
|
| 2246 |
+
# See Distribute #143 for details.
|
| 2247 |
+
m_name = name + '.exe.manifest'
|
| 2248 |
+
yield (m_name, load_launcher_manifest(name), 't')
|
| 2249 |
+
|
| 2250 |
+
|
| 2251 |
+
# for backward-compatibility
|
| 2252 |
+
get_script_args = ScriptWriter.get_script_args
|
| 2253 |
+
get_script_header = ScriptWriter.get_script_header
|
| 2254 |
+
|
| 2255 |
+
|
| 2256 |
+
def get_win_launcher(type):
|
| 2257 |
+
"""
|
| 2258 |
+
Load the Windows launcher (executable) suitable for launching a script.
|
| 2259 |
+
|
| 2260 |
+
`type` should be either 'cli' or 'gui'
|
| 2261 |
+
|
| 2262 |
+
Returns the executable as a byte string.
|
| 2263 |
+
"""
|
| 2264 |
+
launcher_fn = '%s.exe' % type
|
| 2265 |
+
if is_64bit():
|
| 2266 |
+
launcher_fn = launcher_fn.replace(".", "-64.")
|
| 2267 |
+
else:
|
| 2268 |
+
launcher_fn = launcher_fn.replace(".", "-32.")
|
| 2269 |
+
return resource_string('setuptools', launcher_fn)
|
| 2270 |
+
|
| 2271 |
+
|
| 2272 |
+
def load_launcher_manifest(name):
|
| 2273 |
+
manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml')
|
| 2274 |
+
return manifest.decode('utf-8') % vars()
|
| 2275 |
+
|
| 2276 |
+
|
| 2277 |
+
def rmtree(path, ignore_errors=False, onerror=auto_chmod):
|
| 2278 |
+
return shutil.rmtree(path, ignore_errors, onerror)
|
| 2279 |
+
|
| 2280 |
+
|
| 2281 |
+
def current_umask():
|
| 2282 |
+
tmp = os.umask(0o022)
|
| 2283 |
+
os.umask(tmp)
|
| 2284 |
+
return tmp
|
| 2285 |
+
|
| 2286 |
+
|
| 2287 |
+
class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
|
| 2288 |
+
"""
|
| 2289 |
+
Warning for EasyInstall deprecations, bypassing suppression.
|
| 2290 |
+
"""
|