From 290a9fe8afba1ac8a4a4cd130c87469052bbbd00 Mon Sep 17 00:00:00 2001 From: acse-jj123 Date: Tue, 17 Oct 2023 11:05:07 +0100 Subject: [PATCH] checkpoint3 --- .eggs/README.txt | 6 + .../EGG-INFO/LICENSE | 17 + .../EGG-INFO/PKG-INFO | 164 + .../EGG-INFO/RECORD | 35 + .../EGG-INFO/WHEEL | 5 + .../EGG-INFO/entry_points.txt | 41 + .../EGG-INFO/requires.txt | 22 + .../EGG-INFO/top_level.txt | 1 + .../setuptools_scm/.git_archival.txt | 4 + .../setuptools_scm/__init__.py | 30 + .../setuptools_scm/__main__.py | 6 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 1003 bytes .../__pycache__/_config.cpython-311.pyc | Bin 0 -> 7892 bytes .../__pycache__/_entrypoints.cpython-311.pyc | Bin 0 -> 6670 bytes .../_get_version_impl.cpython-311.pyc | Bin 0 -> 7460 bytes .../__pycache__/_log.cpython-311.pyc | Bin 0 -> 5388 bytes .../_modify_version.cpython-311.pyc | Bin 0 -> 3000 bytes .../__pycache__/_overrides.cpython-311.pyc | Bin 0 -> 2662 bytes .../__pycache__/_run_cmd.cpython-311.pyc | Bin 0 -> 10227 bytes .../__pycache__/_types.cpython-311.pyc | Bin 0 -> 1225 bytes .../__pycache__/_version_cls.cpython-311.pyc | Bin 0 -> 4357 bytes .../__pycache__/discover.cpython-311.pyc | Bin 0 -> 3341 bytes .../__pycache__/git.cpython-311.pyc | Bin 0 -> 15166 bytes .../__pycache__/integration.cpython-311.pyc | Bin 0 -> 1674 bytes .../__pycache__/scm_workdir.cpython-311.pyc | Bin 0 -> 1121 bytes .../__pycache__/version.cpython-311.pyc | Bin 0 -> 20370 bytes .../setuptools_scm/_cli.py | 85 + .../setuptools_scm/_config.py | 151 + .../setuptools_scm/_entrypoints.py | 139 + .../setuptools_scm/_file_finders/__init__.py | 106 + .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 6043 bytes .../__pycache__/git.cpython-311.pyc | Bin 0 -> 6493 bytes .../setuptools_scm/_file_finders/git.py | 115 + .../setuptools_scm/_file_finders/hg.py | 72 + .../setuptools_scm/_get_version_impl.py | 174 + .../setuptools_scm/_integration/__init__.py | 0 .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 230 bytes .../__pycache__/dump_version.cpython-311.pyc | Bin 0 -> 3727 bytes .../pyproject_reading.cpython-311.pyc | Bin 0 -> 4174 bytes .../__pycache__/setuptools.cpython-311.pyc | Bin 0 -> 5482 bytes .../__pycache__/toml.cpython-311.pyc | Bin 0 -> 2663 bytes .../_integration/dump_version.py | 94 + .../_integration/pyproject_reading.py | 85 + .../setuptools_scm/_integration/setuptools.py | 121 + .../setuptools_scm/_integration/toml.py | 55 + .../setuptools_scm/_log.py | 85 + .../setuptools_scm/_modify_version.py | 61 + .../setuptools_scm/_overrides.py | 54 + .../setuptools_scm/_run_cmd.py | 207 ++ .../setuptools_scm/_types.py | 22 + .../setuptools_scm/_version_cls.py | 91 + .../setuptools_scm/discover.py | 69 + .../setuptools_scm/fallbacks.py | 44 + .../setuptools_scm/git.py | 336 ++ .../setuptools_scm/hg.py | 190 ++ .../setuptools_scm/hg_git.py | 155 + .../setuptools_scm/integration.py | 30 + .../setuptools_scm/scm_workdir.py | 15 + .../setuptools_scm/version.py | 440 +++ .../EGG-INFO/LICENSE | 279 ++ .../EGG-INFO/PKG-INFO | 66 + .../EGG-INFO/RECORD | 5 + .../EGG-INFO/WHEEL | 4 + .../typing_extensions.py | 2892 +++++++++++++++++ README.md | 2 + simple_functions.egg-info/PKG-INFO | 7 + simple_functions.egg-info/SOURCES.txt | 13 + .../dependency_links.txt | 1 + simple_functions.egg-info/top_level.txt | 1 + 69 files changed, 6597 insertions(+) create mode 100644 .eggs/README.txt create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/LICENSE create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/PKG-INFO create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/RECORD create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/WHEEL create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/entry_points.txt create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/requires.txt create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/top_level.txt create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/.git_archival.txt create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__init__.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__main__.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/__init__.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_config.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_entrypoints.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_get_version_impl.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_log.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_modify_version.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_overrides.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_run_cmd.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_types.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_version_cls.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/discover.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/git.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/integration.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/scm_workdir.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/version.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_cli.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_config.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_entrypoints.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__init__.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__pycache__/__init__.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__pycache__/git.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/git.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/hg.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_get_version_impl.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__init__.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/__init__.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/dump_version.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/pyproject_reading.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/setuptools.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/toml.cpython-311.pyc create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/dump_version.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/pyproject_reading.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/setuptools.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/toml.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_log.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_modify_version.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_overrides.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_run_cmd.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_types.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_version_cls.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/discover.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/fallbacks.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/git.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg_git.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/integration.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/scm_workdir.py create mode 100644 .eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/version.py create mode 100644 .eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/LICENSE create mode 100644 .eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/PKG-INFO create mode 100644 .eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/RECORD create mode 100644 .eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/WHEEL create mode 100644 .eggs/typing_extensions-4.8.0-py3.11.egg/typing_extensions.py create mode 100644 simple_functions.egg-info/PKG-INFO create mode 100644 simple_functions.egg-info/SOURCES.txt create mode 100644 simple_functions.egg-info/dependency_links.txt create mode 100644 simple_functions.egg-info/top_level.txt diff --git a/.eggs/README.txt b/.eggs/README.txt new file mode 100644 index 0000000..5d01668 --- /dev/null +++ b/.eggs/README.txt @@ -0,0 +1,6 @@ +This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins. + +This directory caches those eggs to prevent repeated downloads. + +However, it is safe to delete this directory. + diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/LICENSE b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/LICENSE new file mode 100644 index 0000000..89de354 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/LICENSE @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/PKG-INFO b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/PKG-INFO new file mode 100644 index 0000000..184f32c --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/PKG-INFO @@ -0,0 +1,164 @@ +Metadata-Version: 2.1 +Name: setuptools-scm +Version: 8.0.4 +Summary: the blessed package to manage your versions by scm tags +Author-email: Ronny Pfannschmidt +License: Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +Project-URL: documentation, https://setuptools-scm.readthedocs.io/ +Project-URL: repository, https://github.com/pypa/setuptools_scm/ +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Software Development :: Version Control +Classifier: Topic :: System :: Software Distribution +Classifier: Topic :: Utilities +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: packaging >=20 +Requires-Dist: setuptools +Requires-Dist: typing-extensions +Requires-Dist: tomli >=1 ; python_version < "3.11" +Provides-Extra: docs +Requires-Dist: entangled-cli[rich] ; extra == 'docs' +Requires-Dist: mkdocs ; extra == 'docs' +Requires-Dist: mkdocs-entangled-plugin ; extra == 'docs' +Requires-Dist: mkdocs-material ; extra == 'docs' +Requires-Dist: mkdocstrings[python] ; extra == 'docs' +Requires-Dist: pygments ; extra == 'docs' +Provides-Extra: rich +Requires-Dist: rich ; extra == 'rich' +Provides-Extra: test +Requires-Dist: build ; extra == 'test' +Requires-Dist: pytest ; extra == 'test' +Requires-Dist: rich ; extra == 'test' +Requires-Dist: wheel ; extra == 'test' +Provides-Extra: toml + +# setuptools_scm +[![github ci](https://github.com/pypa/setuptools_scm/workflows/python%20tests+artifacts+release/badge.svg)](https://github.com/pypa/setuptools_scm/actions) +[![Documentation Status](https://readthedocs.org/projects/setuptools-scm/badge/?version=latest)](https://setuptools-scm.readthedocs.io/en/latest/?badge=latest) +[![tidelift](https://tidelift.com/badges/package/pypi/setuptools-scm) ](https://tidelift.com/subscription/pkg/pypi-setuptools-scm?utm_source=pypi-setuptools-scm&utm_medium=readme) + +## about + +[setuptools-scm] extracts Python package versions from `git` or +`hg` metadata instead of declaring them as the version argument +or in an SCM managed file. + +Additionally, [setuptools-scm] provides setuptools +with a list of files that are managed by the SCM
+(i.e. it automatically adds **all of** the SCM-managed files to the sdist).
+Unwanted files must be excluded via `MANIFEST.in`. + + +## `pyproject.toml` usage + +The preferred way to configure [setuptools-scm] is to author +settings in a `tool.setuptools_scm` section of `pyproject.toml`. + +This feature requires setuptools 60 or later. +First, ensure that [setuptools-scm] is present during the project's +build step by specifying it as one of the build requirements. + +```toml +[build-system] +requires = [ + "setuptools>=60", + "setuptools-scm>=8.0"] +``` + +That will be sufficient to require [setuptools-scm] for projects +that support [PEP 518] like [pip] and [build]. + +[pip]: https://pypi.org/project/pip +[build]: https://pypi.org/project/build +[PEP 518]: https://peps.python.org/pep-0518/ + + +To enable version inference, you need to set the version +dynamically in the `project` section of `pyproject.toml`: + +```toml title="pyproject.toml" +[project] +# version = "0.0.1" # Remove any existing version parameter. +dynamic = ["version"] +[tool.setuptools_scm] +``` + +Additionally, a version file can be written by specifying: + +```toml title="pyproject.toml" +[tool.setuptools_scm] +version_file = "pkg/_version.py" +``` + +Where `pkg` is the name of your package. + +If you need to confirm which version string is being generated or debug the configuration, +you can install [setuptools-scm] directly in your working environment and run: + +```console +$ python -m setuptools_scm +# To explore other options, try: +$ python -m setuptools_scm --help +``` + +For further configuration see the [documentation]. + +[setuptools-scm]: https://github.com/pypa/setuptools_scm +[documentation]: https://setuptools-scm.readthedocs.io/ + + +## Interaction with Enterprise Distributions + +Some enterprise distributions like RHEL7 +ship rather old setuptools versions. + +In those cases its typically possible to build by using an sdist against `setuptools_scm<2.0`. +As those old setuptools versions lack sensible types for versions, +modern [setuptools-scm] is unable to support them sensibly. + +It's strongly recommended to build a wheel artifact using modern Python and setuptools, +then installing the artifact instead of trying to run against old setuptools versions. + + +## Code of Conduct + + +Everyone interacting in the [setuptools-scm] project's codebases, issue +trackers, chat rooms, and mailing lists is expected to follow the +[PSF Code of Conduct]. + +[PSF Code of Conduct]: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md + + +## Security Contact + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/RECORD b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/RECORD new file mode 100644 index 0000000..ebcb4ba --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/RECORD @@ -0,0 +1,35 @@ +setuptools_scm/.git_archival.txt,sha256=7hhQtCsXxyEnQcc8hjZYFcJAwBDbwynYLopeiYEn6m0,125 +setuptools_scm/__init__.py,sha256=bM4TUtVIcPgNzNkmKN6N-wXs9A06cJfPHVYgIHuY4r4,861 +setuptools_scm/__main__.py,sha256=PUkvI9W-hylvxv5sd1sosqWXEliN3d30x7BIKVEAQaQ,98 +setuptools_scm/_cli.py,sha256=gsBkEmv7SKu8nZBYpXerzCZ1zZg7yEAQHMrEVbJ_q5M,2890 +setuptools_scm/_config.py,sha256=29pxSz30qLob5F5RX9v_0tahovFw5aGx5A3cX1a6foM,4964 +setuptools_scm/_entrypoints.py,sha256=zwJOqeb7sjC9vJtiANojUov40Xe8mpdZNhxWDCdbBsU,3793 +setuptools_scm/_get_version_impl.py,sha256=FhHrF5K4Nlgt9c9UsULQzUsqj0PzGwx6H6ZBQjYUWcw,5942 +setuptools_scm/_log.py,sha256=5GQzzFBBoldPlBSEdzdWHJvq-6O0x74WkYkCVkTghTY,2135 +setuptools_scm/_modify_version.py,sha256=3dGCx9wzIeRuxZkV69_tw7TqCXAfFyi1BpIQpyPItF8,1747 +setuptools_scm/_overrides.py,sha256=iA3XDa-RYKKGLgYYb3hkmmh4YHovhkBF404AmZ_8hxE,1654 +setuptools_scm/_run_cmd.py,sha256=jcP20Qp4izQMLU3AI5GtbjfnEoLt3LLFrFigSm0UUSs,5912 +setuptools_scm/_types.py,sha256=WvfAIDbCOr2_IQPztoLEO-Qhsvhz7JGk8HaEpqTp1bM,604 +setuptools_scm/_version_cls.py,sha256=G5d8sJXPmHRrfrTtmYWt2RVVnGlp3xvnE183EWVlOOc,2925 +setuptools_scm/discover.py,sha256=TGlKeP-uLSWmBLIGL6es4etKfbvOUdjDjcxgZxYrLxk,2026 +setuptools_scm/fallbacks.py,sha256=59W02TAzq7iIZ1uSRSZH7ELwY958KU4yNh7v5-0FCEs,1447 +setuptools_scm/git.py,sha256=DO8Dk6rlMTKR143AgdCm6c2WCEp6OiOn5UAul6uB5fM,10365 +setuptools_scm/hg.py,sha256=LracAVnGGluu4xk28JtgpZxc5wR9s3CMGIaX40Eyhng,6190 +setuptools_scm/hg_git.py,sha256=CCZm1ErjeS0sPkKC2COjT_d4omZK21FrTiIg4GwH5LA,4545 +setuptools_scm/integration.py,sha256=a0c6-lIBSzKgNJybvE76jkKL8sdJuHtkvAx3IwTPkK0,805 +setuptools_scm/scm_workdir.py,sha256=oreoRhJfvhhxVGIhDPWH8-dg9umsmZM0sV2oRIzGXc8,327 +setuptools_scm/version.py,sha256=klVnCWFwY7OlTNPvSum3VhTSlBBcMwDpIcb7n_Ndprw,13835 +setuptools_scm/_file_finders/__init__.py,sha256=Gc7CcjwzlC7jXstfQysYl5wv-x8RalTAnzieM6mSAVU,3686 +setuptools_scm/_file_finders/git.py,sha256=XpYe2h80g_nOFxZR3E2gwma_geOT4CE8oP2T33dQzPI,4179 +setuptools_scm/_file_finders/hg.py,sha256=V6T9s91xigTtn1TRlwqnrgZV4eHuqixovF0CwMI3lXQ,2256 +setuptools_scm/_integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +setuptools_scm/_integration/dump_version.py,sha256=ixcET9z3-oNdx6mM-yYbV9xktHsdPfCmHCCKGRA0_eo,2584 +setuptools_scm/_integration/pyproject_reading.py,sha256=6PEog4x2TofynEnN4rkjcmfIMys49nO4TtNdt6wLLzg,2589 +setuptools_scm/_integration/setuptools.py,sha256=kdM2C4jtAchJQCQnxWj_x1FoeD1B5SO9OF6to2oxr4c,3420 +setuptools_scm/_integration/toml.py,sha256=P3MBO01jBeaEYeaqR_vfDiaDaytOhLvYmzSISoJ7EUg,1379 +setuptools_scm-8.0.4.dist-info/LICENSE,sha256=iYB6zyMJvShfAzQE7nhYFgLzzZuBmhasLw5fYP9KRz4,1023 +setuptools_scm-8.0.4.dist-info/METADATA,sha256=XktL5dowfcRZfNPKaf4lPx83_gRFXVLZwqhFLxC17k8,6403 +setuptools_scm-8.0.4.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92 +setuptools_scm-8.0.4.dist-info/entry_points.txt,sha256=TxfQoR1oJCfa_OWTNvozyEymcj-Avnq8kE3RLO7cN44,1725 +setuptools_scm-8.0.4.dist-info/top_level.txt,sha256=kiu-91q3_rJLUoc2wl8_lC4cIlpgtgdD_4NaChF4hOA,15 +setuptools_scm-8.0.4.dist-info/RECORD,, diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/WHEEL b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/WHEEL new file mode 100644 index 0000000..7e68873 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/entry_points.txt b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/entry_points.txt new file mode 100644 index 0000000..f19235d --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/entry_points.txt @@ -0,0 +1,41 @@ +[distutils.setup_keywords] +use_scm_version = setuptools_scm._integration.setuptools:version_keyword + +[setuptools.file_finders] +setuptools_scm = setuptools_scm._file_finders:find_files + +[setuptools.finalize_distribution_options] +setuptools_scm = setuptools_scm._integration.setuptools:infer_version + +[setuptools_scm.files_command] +.git = setuptools_scm._file_finders.git:git_find_files +.hg = setuptools_scm._file_finders.hg:hg_find_files + +[setuptools_scm.files_command_fallback] +.git_archival.txt = setuptools_scm._file_finders.git:git_archive_find_files +.hg_archival.txt = setuptools_scm._file_finders.hg:hg_archive_find_files + +[setuptools_scm.local_scheme] +dirty-tag = setuptools_scm.version:get_local_dirty_tag +no-local-version = setuptools_scm.version:get_no_local_node +node-and-date = setuptools_scm.version:get_local_node_and_date +node-and-timestamp = setuptools_scm.version:get_local_node_and_timestamp + +[setuptools_scm.parse_scm] +.git = setuptools_scm.git:parse +.hg = setuptools_scm.hg:parse + +[setuptools_scm.parse_scm_fallback] +.git_archival.txt = setuptools_scm.git:parse_archival +.hg_archival.txt = setuptools_scm.hg:parse_archival +PKG-INFO = setuptools_scm.fallbacks:parse_pkginfo +pyproject.toml = setuptools_scm.fallbacks:fallback_version +setup.py = setuptools_scm.fallbacks:fallback_version + +[setuptools_scm.version_scheme] +calver-by-date = setuptools_scm.version:calver_by_date +guess-next-dev = setuptools_scm.version:guess_next_dev_version +no-guess-dev = setuptools_scm.version:no_guess_dev_version +post-release = setuptools_scm.version:postrelease_version +python-simplified-semver = setuptools_scm.version:simplified_semver_version +release-branch-semver = setuptools_scm.version:release_branch_semver_version diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/requires.txt b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/requires.txt new file mode 100644 index 0000000..818a19b --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/requires.txt @@ -0,0 +1,22 @@ +packaging>=20 +setuptools +typing-extensions + +[docs] +entangled-cli[rich] +mkdocs +mkdocs-entangled-plugin +mkdocs-material +mkdocstrings[python] +pygments + +[rich] +rich + +[test] +build +pytest +rich +wheel + +[toml] diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/top_level.txt b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/top_level.txt new file mode 100644 index 0000000..cba8d88 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/EGG-INFO/top_level.txt @@ -0,0 +1 @@ +setuptools_scm diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/.git_archival.txt b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/.git_archival.txt new file mode 100644 index 0000000..8fb235d --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ +ref-names: $Format:%D$ diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__init__.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__init__.py new file mode 100644 index 0000000..aa40ab3 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__init__.py @@ -0,0 +1,30 @@ +""" +:copyright: 2010-2023 by Ronny Pfannschmidt +:license: MIT +""" +from __future__ import annotations + +from ._config import Configuration +from ._config import DEFAULT_LOCAL_SCHEME # soft deprecated +from ._config import DEFAULT_VERSION_SCHEME # soft deprecated +from ._get_version_impl import _get_version # soft deprecated +from ._get_version_impl import get_version # soft deprecated +from ._integration.dump_version import dump_version # soft deprecated +from ._version_cls import NonNormalizedVersion +from ._version_cls import Version +from .version import ScmVersion + + +# Public API +__all__ = [ + # soft deprecated imports, left for backward compatibility + "get_version", + "_get_version", + "dump_version", + "DEFAULT_VERSION_SCHEME", + "DEFAULT_LOCAL_SCHEME", + "Configuration", + "Version", + "ScmVersion", + "NonNormalizedVersion", +] diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__main__.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__main__.py new file mode 100644 index 0000000..dab6068 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__main__.py @@ -0,0 +1,6 @@ +from __future__ import annotations + +from ._cli import main + +if __name__ == "__main__": + main() diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/__init__.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a515684603878cf91b74a1d3a404fa7adbda43d8 GIT binary patch literal 1003 zcmZuuO>fgM7`FSBG->vMCeXxz0;htObQ=d$5YkkNnACM>-6jzUSta(eOm-6G11URk z<_~b^g7`N%RyiSY+O5)VJ7K$&H3;X?qsQ-Szwh(L-wi_peBFORuRptU- zf8pXQz`zC=;tGYVVpkx*Ra~Q0RO{y{7 z)}_{Hiy5{dwa)d5y&`psuCg_I4FVTn;~TWs@yZxWE_p|o9vx)D=&N=gNqV=ff5I-ip_QC$Kb|t3jz(VIIf@G3-fgfMNdCces z{+Z{dkqq-g8?Og%_D+V!Xn5G)8=`Ul?ciX*<98SF)4|br|8R7hX(5*+=o5)zURbm# zZ(BHJ;Zk~I6!@bcViW3J5`6minsO_(vBMU-X4K?PBUO-ixJVJy5L6e`5@ZO{IgL7Z z3I!n?I0zLQLT71`Mg*aVzck<(M@~DxDQk#o#rpCD$YUX$_Y<9qP2~9rapynCTpmXH zDO!u!kV9i>LV7BcKYv7;6Q(AVBJ=}X^P=E}S|>3d-Ma85zI(wemYoNTSaFi#%;FA6 z1{ grohb0n1Y9S8B_2eFJq?adSwO{^jQ&KbdQhs8|dU5t^fc4 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_config.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59b60bf0fcbd3bbf073903293020ef5dd99327d6 GIT binary patch literal 7892 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 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_entrypoints.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_entrypoints.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eb03c913c8c733f3262d1eb9588eed965705957b GIT binary patch literal 6670 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 Jd<$UA^#7{6L?-|M literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_log.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_log.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76571f8034d77d97ed7d74ed91bea37deeef5722 GIT binary patch literal 5388 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 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_modify_version.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_modify_version.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..32702909316774ca26cad57216ec5f477c1fad13 GIT binary patch literal 3000 zcmaJ@-ER|D7QZv&kHlX|lae^J=?;Y!+$1(p5R0~meQ4>2c1aPmutjL6gYS(qV9$*1 zy{5$2$gTRoO8bzlDy0=5@gUezz?)S$7d zQHx!O!`vht`7CxJL7%57Xp?jg%|JT><1DnJbc&8co1)Wn0@^gy&yqs^7ko)U3(~gh zdeWAT=ZfWDv~V(E$u*yeAa|8<0V|e}+;J;`0d0`rOxC$uM%_U%paXyH@iFLZkS5t2 ztVCL>-G!&_4WGOS&$P6b-ZGjR7^N>i(dNLWQQzj$L6ZtG4&EU_!mnSdI%P0``9Zwu zmF=pC!Ga0pi70&_z|PWT$95~1Yo*%Ss#jwrA?tLll`B>*gEld%Ef8+NU0a5($$1%_4rpGwtvr)tclg z;S+M`F#^851wn8}k9zV`(1dy84uTt74r0D1WaF4=S2?rkn&}ABHgV46tjcV`=ApAv z7l5iMJ+o40LYQ)unRTDqk~I=VR9*xyQs?Yyot@;|;{}aRfPn(7G5HvtV$`xJwNRH& z!8nV{$3cJ-lG*j?PBIVmK`!4No9bjvhxL)6kEQ-cK=g<{n(8G8ET(7sH8#tigAJaf zU`w-UE_*JExF`;b%0*Y91MEN-XOgp4maK@uX>(xX1Ok;S2Nvu?GnVKx#Dr<){jvA zZy%Y|5z=B-zY`X`gd5M{q>JYm$bz0$NQttU`D`{6u z*tHD6N(QL9?Bl1~nBXpxxfF4ATod1VxS#`Pg(qDSHo2^o@^XrEH}M=&4K;#)9cgY2Zk zg17WK!fVH&MKR;zba{BpTwLwiNE1 zRoFGYAJz|`&Sem7@*tD@=R50v-#ovSS=i1jv`==EnRY9rc8_S;<4?sS!$4R;0N4O) zisWZEnx8lSb>oX0|H#}-tjD?&`OaA3&i*gySB2Y!P5Y|_7-AhMgzV2+vUv85Q|C^e zIs5K=%RyQ?HD&>s@N`2KgI&XHa03Q-@u0C`5lI*gqobXNOKInm12xDXRBvkkHSR(L z+=G8uR5saNKStxb=|ffsNMmY_UPoj9q-5XZRtr++E3k1RId|RlC~Gxl`<>$M>P8S} z*X*(kVyGTu!=qb}W}GrB=pmN4qd*%6yq)g9FT9p4j4ca|;d7vL7_}`B$l}~*tsY6n zQ(q=;XFBpZUP>a}l0CvkIA9TQ0=a z_04gYzyPaN%2T%)_<0^?!%J_cpYs;=TxqFW({kB0IXEdVf&T087e_zv0VDg_(^_KoU^UWW(_APDiTk6D?l=u3dJ<2AI9~P=N zpfFncd$ZH9UPy!?f&^BP_uIYH(bW3WH)Mj8Wv$fV`;J)_M>6m~pg4#EkqdN7hW^6q zK6Di(3Ke1M^#3912r8jG895GLPW37~!IwY@$tb=D(K9qn>yno{(fW{#w$<+;+1rWM wUP9L<;Bz4&QgQ7ixHuwWJcBAx@zSXFT8~6Uenf+)j*2N=JA&`nRj5<_3esh?i2wiq literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_overrides.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_overrides.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64a5e3abfd9e3c4249200da3715ffeb7d94502d5 GIT binary patch literal 2662 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 I0Fx^J2eZ++YybcN literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_types.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/_types.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fa66bbf7fc630dede6326cf219c98992d2436c9 GIT binary patch literal 1225 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 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/discover.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/discover.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92503c4bcaa3a12ad50b63303bad063e70e6f850 GIT binary patch literal 3341 zcmbVO-ESLJ7QZtdkH=2^5vR>Z%WkI$rSht=3zV|5Dx__jq7(=fH7nt6HJ*6J_JkRa zb!Xg=tb-y{K^H}$LPh0aAM&t*qQ1bt0RO-k8DWi7sS-kheTr1Agz~iK+=(4eOZH)} z$9K-$d+xa(=l473ewj=r2$W;*A&=1|<>*+~aRSxJNXiaVD|2GRL9Jn|zsv zcf^cXLRnyKf*G~MvdH8p$gy$^WKoNmk`*t$j@mb>e6UMaqfh1t;U2#Q!fS*BzqrG5Af!XWC$j-9e;Fv1P=Y1svfHrR^@gmuJ?%$!4uoT3uvjo*I@Y^K+IYbU+?g;-VZWT8#^%JShEBNcjj_eRF zD)%R*?wz-b4|vkz3~Bai!e)x zwh_!m4d!%4wJR0Whc5j+q>j-XE-A24TF)BwrcI4zU0zm!XD#`pb2%6Dc^d)*($5!R zsDt5R1%i+tH5_%>@goq1{HUfcx9bBkOv6d-k%1lo+0R(23*lxzfYDiKeg@SPr~sQ8 zA|-CEe)Rqa?|-&@w|>w3)Z9LM|8RFQ-ZWIV z=~+Nzd>XKO=j=mi?34J%aWDJaeW5GO_oR7GntwEwx&0EIf;raZFvpa-;VKvejhi|~ z4oCMB`|I;XU_QiBItD{`PYmMn^^q+&`2~!}S1}&nsE(o(@>mcf&j70SVk9&T%Jwh@ z4qEW7aUBk#C)jx~v;}D5A;0lfWFx{6H@>eA_~%!mgYPgCE|DA8Hw2z^B2VHPdfwQG zcA_goG`p#R4MJ`b%59CiO_P5u(h=H zH!TX>5!ECdP?$cNQL8}^Zn~q?31OI}2D^nRRW;4E|0_G}yT2$i-v$(wU3-`ZLUauv zQj~$^`)T(yTREmMssoEEl~B%62JAI-r&2jBuTsO+<(l1w#1>=}oUKv`DY zxJ*BKQ#ISVKcQTB{mqN7EnHF-t}3O!y!Glr=^CRkMY{W9u;iQ=DhtIES zKCibN1RkCZoDK^NGi>23I>7cu*+ui9dItW^cTnwRut^e?K3e=>(Mz4WfAs58S19&` zq9+vlLct3^Kc{9PfK2vsi`~?fUh2vYiA85vb(`;J=e+FP_LXk7(91$x5#!JU)$I#? z2ruvba4heo@#$x#AEu9Q^V=8x^=dbLx|co;F(^6nFf(y4{%PDhI)9&j{X#c$u9rFI zWzO~G**oIhWPft{j)cG8c9Li~GMJY|p&VBloDedPT^lIoX^OO?S*Sw&c(in8*pHey zDL7#^o*gsmXJ?JkDzJ1CHIMiSMX9ynQl~2l#jrw;L4}tWw_zH~!Bs|t`y(7a#c)E= zLH-^(kogpe>hp^0$CQzf$bjTab=|$#FieeMC;-Esa1i?LE5dfn{Jbljw`{F#>aWn3 zp$h|`1GjMkmkN&SlUXnPJR9>2QWLJVn_8~ D>oY?A literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/git.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/git.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..336bc400355978190c36f41d8e3b191ea2d5d8e5 GIT binary patch literal 15166 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 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/integration.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/integration.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c29b320f474f5862f01ff016b0cc8c8be0135384 GIT binary patch literal 1674 zcma)6-)kI29G~6WU%AWO#cQ$tW@1g`O0s9M4A&4&HO>>Qe~ z!KDaR5p1Q9KHgKRq=Jt=_~4&#CkKXwK)|QI1@e|Bzq6N1dJ)9g+3(JGzCY$O-yi$9 zTrMIQFW)lhOaY<41v47Jiy<8npj(I_B6-M{nvx{evL`p?{99-i;9Kw%Uu~)&Q;6zm zzTPw>BqJ)XP2_HX(Big)&M4UPlX{cn#I>68fQubn@5JlO(Fd#(_3M{X~2()D`7x!f@97yjZxlV!BK^{E&eI& z%!%#KTk;S>P7R=NS?Q3$30o+U(u@2ABti)qhuwWfcIt)5PYUCDn-W(}<=x|Op6-Yh zQ4+*Y0))_-I+7<6QMUo*&I!_O@UU~@1p=)RT?Bel7J*LWZ7|&#nWN1@Qs|1C{c9xB z8Jr3~cdC>q-Ml1DcZRER?`J%y|Kp}cf)e%Y9TFANKC$upFiY6Rz8ytw;NUh3eeAnF zZA3BckZ@kC@o|QW7{+2`Guy|a2o`gSd5HNc&8=|T_2{!|$CisD7dUK>E6-uKjYZ+i zVMc8-1R$Iby)aR8i+H?>in(lML+$YP`~sAwL4#IE0RP6h9Pdm#I&ZN!6K^O2Hxmg3 z-N|ck3}rWL7E`t{HPR6bh!c%hT2gx={mnIU$*V0M&gZa|>w zvq|dPu4h72z#pp$TO(&g8z=&Jrn;Q^ab06NNSP?Rp`JE0%5sdu0utXJDA~Nh%z%mJM{1`}z4yKS%O~2Z! zJ%67+xb*PSU$xmkYqP)Vz1nQQwlJtI+|&0I{hRA|ulFi%bjdH*o_zS*)jvMz&n*q+ zmio%_Kw0i7%lk^bH$L~vFW&p?+uPsYPT$|Hoc|&GE_~$lE3<>jY3b)qOn0yRbiS{c1I6qq=5DE)esBm-A=4|PfQxP%MqP9mD+wa*R4->m z%W8MvM@21*i5Aav$h8B7#6)Xmx+p}?y)!Hc#6)H?+2YxRL-`VDQkEH(71+LT@El0< zfc=cvYhwKhkR#(AKO`NGzRTVOR{X=_yFd;Kk|gb-*L&l0A63%)*+tbfe|FIez45t^ iUh0j{eeFW(473Z6jJ`HK(5BPEfmV~I4$yy*9OFMROQD|t literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/scm_workdir.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/scm_workdir.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d60ccf98dafe114d9598979b89edaebc60c318b GIT binary patch literal 1121 zcmZ`%L2J}N6rM@4o9u3P73-l=(6)Gq(2b=lcqm>(iajhssbVfenwf61W|DO#tE}{} zmHvlb1)(DSGb{8^0z$!4Z(G(=Prgaob=Tr#^76emZ{GXf%llTXmJzJ^w{^CT5&ET+ z>s81B9_;}*L=;gRB92{*71lzH>#m+*Jv4a1EdVxXAuMv!H8WfcEnad<7-@*WVowZuhkwCwb#BnHz^!f7B`r~?I zxzk&%udFDCf6g87As_RW)H^+K8}fd-d)1@*B)^)XH4CDTe%2PhJUm%i{ZVV2)EWb; zF#yVG(JS{=NPAgZZImVCcq8aiMI#mAKH6R=wew74ZkaR207e literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/version.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__pycache__/version.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2842b661f0a5a73d53cb6c2a034bffdd95e0cb9e GIT binary patch literal 20370 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 None: + opts = _get_cli_opts(args) + inferred_root: str = opts.root or "." + + pyproject = opts.config or _find_pyproject(inferred_root) + + try: + config = Configuration.from_file( + pyproject, + root=(os.path.abspath(opts.root) if opts.root is not None else None), + ) + except (LookupError, FileNotFoundError) as ex: + # no pyproject.toml OR no [tool.setuptools_scm] + print( + f"Warning: could not use {os.path.relpath(pyproject)}," + " using default configuration.\n" + f" Reason: {ex}.", + file=sys.stderr, + ) + config = Configuration(inferred_root) + + version = _get_version(config, force_write_version_files=False) + if version is None: + raise SystemExit("ERROR: no version found for", opts) + if opts.strip_dev: + version = version.partition(".dev")[0] + print(version) + + if opts.command == "ls": + for fname in find_files(config.root): + print(fname) + + +def _get_cli_opts(args: list[str] | None) -> argparse.Namespace: + prog = "python -m setuptools_scm" + desc = "Print project version according to SCM metadata" + parser = argparse.ArgumentParser(prog, description=desc) + # By default, help for `--help` starts with lower case, so we keep the pattern: + parser.add_argument( + "-r", + "--root", + default=None, + help='directory managed by the SCM, default: inferred from config file, or "."', + ) + parser.add_argument( + "-c", + "--config", + default=None, + metavar="PATH", + help="path to 'pyproject.toml' with setuptools_scm config, " + "default: looked up in the current or parent directories", + ) + parser.add_argument( + "--strip-dev", + action="store_true", + help="remove the dev/local parts of the version before printing the version", + ) + sub = parser.add_subparsers(title="extra commands", dest="command", metavar="") + # We avoid `metavar` to prevent printing repetitive information + desc = "List files managed by the SCM" + sub.add_parser("ls", help=desc[0].lower() + desc[1:], description=desc) + return parser.parse_args(args) + + +def _find_pyproject(parent: str) -> str: + for directory in walk_potential_roots(os.path.abspath(parent)): + pyproject = os.path.join(directory, "pyproject.toml") + if os.path.isfile(pyproject): + return pyproject + + return os.path.abspath( + "pyproject.toml" + ) # use default name to trigger the default errors diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_config.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_config.py new file mode 100644 index 0000000..5e5feb1 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_config.py @@ -0,0 +1,151 @@ +""" configuration """ +from __future__ import annotations + +import dataclasses +import os +import re +import warnings +from pathlib import Path +from typing import Any +from typing import Pattern +from typing import Protocol + +from . import _log +from . import _types as _t +from ._integration.pyproject_reading import ( + get_args_for_pyproject as _get_args_for_pyproject, +) +from ._integration.pyproject_reading import read_pyproject as _read_pyproject +from ._overrides import read_toml_overrides +from ._version_cls import _validate_version_cls +from ._version_cls import _VersionT +from ._version_cls import Version as _Version + +log = _log.log.getChild("config") + +DEFAULT_TAG_REGEX = re.compile( + r"^(?:[\w-]+-)?(?P[vV]?\d+(?:\.\d+){0,2}[^\+]*)(?:\+.*)?$" +) +"""default tag regex that tries to match PEP440 style versions +with prefix consisting of dashed words""" + +DEFAULT_VERSION_SCHEME = "guess-next-dev" +DEFAULT_LOCAL_SCHEME = "node-and-date" + + +def _check_tag_regex(value: str | Pattern[str] | None) -> Pattern[str]: + if not value: + regex = DEFAULT_TAG_REGEX + else: + regex = re.compile(value) + + group_names = regex.groupindex.keys() + if regex.groups == 0 or (regex.groups > 1 and "version" not in group_names): + warnings.warn( + "Expected tag_regex to contain a single match group or a group named" + " 'version' to identify the version part of any tag." + ) + + return regex + + +class ParseFunction(Protocol): + def __call__( + self, root: _t.PathT, *, config: Configuration + ) -> _t.SCMVERSION | None: + ... + + +def _check_absolute_root(root: _t.PathT, relative_to: _t.PathT | None) -> str: + log.debug("check absolute root=%s relative_to=%s", root, relative_to) + if relative_to: + if ( + os.path.isabs(root) + and os.path.isabs(relative_to) + and not os.path.commonpath([root, relative_to]) == root + ): + warnings.warn( + f"absolute root path '{root}' overrides relative_to '{relative_to}'" + ) + if os.path.isdir(relative_to): + warnings.warn( + "relative_to is expected to be a file," + f" its the directory {relative_to}\n" + "assuming the parent directory was passed" + ) + log.debug("dir %s", relative_to) + root = os.path.join(relative_to, root) + else: + log.debug("file %s", relative_to) + root = os.path.join(os.path.dirname(relative_to), root) + return os.path.abspath(root) + + +@dataclasses.dataclass +class Configuration: + """Global configuration model""" + + relative_to: _t.PathT | None = None + root: _t.PathT = "." + version_scheme: _t.VERSION_SCHEME = DEFAULT_VERSION_SCHEME + local_scheme: _t.VERSION_SCHEME = DEFAULT_LOCAL_SCHEME + tag_regex: Pattern[str] = DEFAULT_TAG_REGEX + parentdir_prefix_version: str | None = None + fallback_version: str | None = None + fallback_root: _t.PathT = "." + write_to: _t.PathT | None = None + write_to_template: str | None = None + version_file: _t.PathT | None = None + version_file_template: str | None = None + parse: ParseFunction | None = None + git_describe_command: _t.CMD_TYPE | None = None + dist_name: str | None = None + version_cls: type[_VersionT] = _Version + search_parent_directories: bool = False + + parent: _t.PathT | None = None + + @property + def absolute_root(self) -> str: + return _check_absolute_root(self.root, self.relative_to) + + @classmethod + def from_file( + cls, + name: str | os.PathLike[str] = "pyproject.toml", + dist_name: str | None = None, + _require_section: bool = True, + **kwargs: Any, + ) -> Configuration: + """ + Read Configuration from pyproject.toml (or similar). + Raises exceptions when file is not found or toml is + not installed or the file has invalid format or does + not contain the [tool.setuptools_scm] section. + """ + + pyproject_data = _read_pyproject(Path(name), require_section=_require_section) + args = _get_args_for_pyproject(pyproject_data, dist_name, kwargs) + + args.update(read_toml_overrides(args["dist_name"])) + relative_to = args.pop("relative_to", name) + return cls.from_data(relative_to=relative_to, data=args) + + @classmethod + def from_data( + cls, relative_to: str | os.PathLike[str], data: dict[str, Any] + ) -> Configuration: + """ + given configuration data + create a config instance after validating tag regex/version class + """ + tag_regex = _check_tag_regex(data.pop("tag_regex", None)) + version_cls = _validate_version_cls( + data.pop("version_cls", None), data.pop("normalize", True) + ) + return cls( + relative_to, + version_cls=version_cls, + tag_regex=tag_regex, + **data, + ) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_entrypoints.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_entrypoints.py new file mode 100644 index 0000000..50c9182 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_entrypoints.py @@ -0,0 +1,139 @@ +from __future__ import annotations + +import sys +from typing import Any +from typing import Callable +from typing import cast +from typing import Iterator +from typing import overload +from typing import TYPE_CHECKING + +from . import _log +from . import version + +if TYPE_CHECKING: + from . import _types as _t + from ._config import Configuration, ParseFunction + + +from importlib.metadata import EntryPoint as EntryPoint + + +if sys.version_info[:2] < (3, 10): + from importlib.metadata import entry_points as legacy_entry_points + + class EntryPoints: + _groupdata: list[EntryPoint] + + def __init__(self, groupdata: list[EntryPoint]) -> None: + self._groupdata = groupdata + + def select(self, name: str) -> EntryPoints: + return EntryPoints([x for x in self._groupdata if x.name == name]) + + def __iter__(self) -> Iterator[EntryPoint]: + return iter(self._groupdata) + + def entry_points(group: str) -> EntryPoints: + return EntryPoints(legacy_entry_points()[group]) + +else: + from importlib.metadata import entry_points, EntryPoints + + +log = _log.log.getChild("entrypoints") + + +def version_from_entrypoint( + config: Configuration, *, entrypoint: str, root: _t.PathT +) -> version.ScmVersion | None: + from .discover import iter_matching_entrypoints + + log.debug("version_from_ep %s in %s", entrypoint, root) + for ep in iter_matching_entrypoints(root, entrypoint, config): + fn: ParseFunction = ep.load() + maybe_version: version.ScmVersion | None = fn(root, config=config) + log.debug("%s found %r", ep, maybe_version) + if maybe_version is not None: + return maybe_version + return None + + +def iter_entry_points(group: str, name: str | None = None) -> Iterator[EntryPoint]: + eps: EntryPoints = entry_points(group=group) + res = eps if name is None else eps.select(name=name) + + return iter(res) + + +def _get_ep(group: str, name: str) -> Any | None: + for ep in iter_entry_points(group, name): + log.debug("ep found: %s", ep.name) + return ep.load() + else: + return None + + +def _get_from_object_reference_str(path: str, group: str) -> Any | None: + # todo: remove for importlib native spelling + ep = EntryPoint(path, path, group) + try: + return ep.load() + except (AttributeError, ModuleNotFoundError): + return None + + +def _iter_version_schemes( + entrypoint: str, + scheme_value: _t.VERSION_SCHEMES, + _memo: set[object] | None = None, +) -> Iterator[Callable[[version.ScmVersion], str]]: + if _memo is None: + _memo = set() + if isinstance(scheme_value, str): + scheme_value = cast( + "_t.VERSION_SCHEMES", + _get_ep(entrypoint, scheme_value) + or _get_from_object_reference_str(scheme_value, entrypoint), + ) + + if isinstance(scheme_value, (list, tuple)): + for variant in scheme_value: + if variant not in _memo: + _memo.add(variant) + yield from _iter_version_schemes(entrypoint, variant, _memo=_memo) + elif callable(scheme_value): + yield scheme_value + + +@overload +def _call_version_scheme( + version: version.ScmVersion, + entrypoint: str, + given_value: _t.VERSION_SCHEMES, + default: str, +) -> str: + ... + + +@overload +def _call_version_scheme( + version: version.ScmVersion, + entrypoint: str, + given_value: _t.VERSION_SCHEMES, + default: None, +) -> str | None: + ... + + +def _call_version_scheme( + version: version.ScmVersion, + entrypoint: str, + given_value: _t.VERSION_SCHEMES, + default: str | None, +) -> str | None: + for scheme in _iter_version_schemes(entrypoint, given_value): + result = scheme(version) + if result is not None: + return result + return default diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__init__.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__init__.py new file mode 100644 index 0000000..591aa90 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__init__.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import itertools +import os +from typing import Callable +from typing import TYPE_CHECKING + +from .. import _log +from .. import _types as _t +from .._entrypoints import iter_entry_points + +if TYPE_CHECKING: + from typing_extensions import TypeGuard + + +log = _log.log.getChild("file_finder") + + +def scm_find_files( + path: _t.PathT, + scm_files: set[str], + scm_dirs: set[str], + force_all_files: bool = False, +) -> list[str]: + """ setuptools compatible file finder that follows symlinks + + - path: the root directory from which to search + - scm_files: set of scm controlled files and symlinks + (including symlinks to directories) + - scm_dirs: set of scm controlled directories + (including directories containing no scm controlled files) + - force_all_files: ignore ``scm_files`` and ``scm_dirs`` and list everything. + + scm_files and scm_dirs must be absolute with symlinks resolved (realpath), + with normalized case (normcase) + + Spec here: http://setuptools.readthedocs.io/en/latest/setuptools.html#\ + adding-support-for-revision-control-systems + """ + realpath = os.path.normcase(os.path.realpath(path)) + seen: set[str] = set() + res: list[str] = [] + for dirpath, dirnames, filenames in os.walk(realpath, followlinks=True): + # dirpath with symlinks resolved + realdirpath = os.path.normcase(os.path.realpath(dirpath)) + + def _link_not_in_scm(n: str, realdirpath: str = realdirpath) -> bool: + fn = os.path.join(realdirpath, os.path.normcase(n)) + return os.path.islink(fn) and fn not in scm_files + + if not force_all_files and realdirpath not in scm_dirs: + # directory not in scm, don't walk it's content + dirnames[:] = [] + continue + if os.path.islink(dirpath) and not os.path.relpath( + realdirpath, realpath + ).startswith(os.pardir): + # a symlink to a directory not outside path: + # we keep it in the result and don't walk its content + res.append(os.path.join(path, os.path.relpath(dirpath, path))) + dirnames[:] = [] + continue + if realdirpath in seen: + # symlink loop protection + dirnames[:] = [] + continue + dirnames[:] = [ + dn for dn in dirnames if force_all_files or not _link_not_in_scm(dn) + ] + for filename in filenames: + if not force_all_files and _link_not_in_scm(filename): + continue + # dirpath + filename with symlinks preserved + fullfilename = os.path.join(dirpath, filename) + is_tracked = os.path.normcase(os.path.realpath(fullfilename)) in scm_files + if force_all_files or is_tracked: + res.append(os.path.join(path, os.path.relpath(fullfilename, realpath))) + seen.add(realdirpath) + return res + + +def is_toplevel_acceptable(toplevel: str | None) -> TypeGuard[str]: + """ """ + if toplevel is None: + return False + + ignored: list[str] = os.environ.get("SETUPTOOLS_SCM_IGNORE_VCS_ROOTS", "").split( + os.pathsep + ) + ignored = [os.path.normcase(p) for p in ignored] + + log.debug("toplevel: %r\n ignored %s", toplevel, ignored) + + return toplevel not in ignored + + +def find_files(path: _t.PathT = "") -> list[str]: + for ep in itertools.chain( + iter_entry_points("setuptools_scm.files_command"), + iter_entry_points("setuptools_scm.files_command_fallback"), + ): + command: Callable[[_t.PathT], list[str]] = ep.load() + res: list[str] = command(path) + if res: + return res + return [] diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__pycache__/__init__.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f015dae687d3b569b9f90172fc3d970d9cdc8d91 GIT binary patch literal 6043 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 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/git.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/git.py new file mode 100644 index 0000000..873b4ba --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/git.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +import logging +import os +import subprocess +import tarfile +from typing import IO + +from . import is_toplevel_acceptable +from . import scm_find_files +from .. import _types as _t +from .._run_cmd import run as _run +from ..integration import data_from_mime + +log = logging.getLogger(__name__) + + +def _git_toplevel(path: str) -> str | None: + try: + cwd = os.path.abspath(path or ".") + res = _run(["git", "rev-parse", "HEAD"], cwd=cwd) + if res.returncode: + # BAIL if there is no commit + log.error("listing git files failed - pretending there aren't any") + return None + res = _run( + ["git", "rev-parse", "--show-prefix"], + cwd=cwd, + ) + if res.returncode: + return None + out = res.stdout[:-1] # remove the trailing pathsep + if not out: + out = cwd + else: + # Here, ``out`` is a relative path to root of git. + # ``cwd`` is absolute path to current working directory. + # the below method removes the length of ``out`` from + # ``cwd``, which gives the git toplevel + assert cwd.replace("\\", "/").endswith(out), f"cwd={cwd!r}\nout={out!r}" + # In windows cwd contains ``\`` which should be replaced by ``/`` + # for this assertion to work. Length of string isn't changed by replace + # ``\\`` is just and escape for `\` + out = cwd[: -len(out)] + log.debug("find files toplevel %s", out) + return os.path.normcase(os.path.realpath(out.strip())) + except subprocess.CalledProcessError: + # git returned error, we are not in a git repo + return None + except OSError: + # git command not found, probably + return None + + +def _git_interpret_archive(fd: IO[bytes], toplevel: str) -> tuple[set[str], set[str]]: + with tarfile.open(fileobj=fd, mode="r|*") as tf: + git_files = set() + git_dirs = {toplevel} + for member in tf.getmembers(): + name = os.path.normcase(member.name).replace("/", os.path.sep) + if member.type == tarfile.DIRTYPE: + git_dirs.add(name) + else: + git_files.add(name) + return git_files, git_dirs + + +def _git_ls_files_and_dirs(toplevel: str) -> tuple[set[str], set[str]]: + # use git archive instead of git ls-file to honor + # export-ignore git attribute + + cmd = ["git", "archive", "--prefix", toplevel + os.path.sep, "HEAD"] + proc = subprocess.Popen( + cmd, stdout=subprocess.PIPE, cwd=toplevel, stderr=subprocess.DEVNULL + ) + assert proc.stdout is not None + try: + try: + return _git_interpret_archive(proc.stdout, toplevel) + finally: + # ensure we avoid resource warnings by cleaning up the process + proc.stdout.close() + proc.terminate() + except Exception: + if proc.wait() != 0: + log.error("listing git files failed - pretending there aren't any") + return set(), set() + + +def git_find_files(path: _t.PathT = "") -> list[str]: + toplevel = _git_toplevel(os.fspath(path)) + if not is_toplevel_acceptable(toplevel): + return [] + fullpath = os.path.abspath(os.path.normpath(path)) + if not fullpath.startswith(toplevel): + log.warning("toplevel mismatch computed %s vs resolved %s ", toplevel, fullpath) + git_files, git_dirs = _git_ls_files_and_dirs(toplevel) + return scm_find_files(path, git_files, git_dirs) + + +def git_archive_find_files(path: _t.PathT = "") -> list[str]: + # This function assumes that ``path`` is obtained from a git archive + # and therefore all the files that should be ignored were already removed. + archival = os.path.join(path, ".git_archival.txt") + if not os.path.exists(archival): + return [] + + data = data_from_mime(archival) + + if "$Format" in data.get("node", ""): + # Substitutions have not been performed, so not a reliable archive + return [] + + log.warning("git archive detected - fallback to listing all files") + return scm_find_files(path, set(), set(), force_all_files=True) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/hg.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/hg.py new file mode 100644 index 0000000..f87ba06 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_file_finders/hg.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +import logging +import os +import subprocess + +from .. import _types as _t +from .._file_finders import is_toplevel_acceptable +from .._file_finders import scm_find_files +from .._run_cmd import run as _run +from ..integration import data_from_mime + +log = logging.getLogger(__name__) + + +def _hg_toplevel(path: str) -> str | None: + try: + res = _run( + ["hg", "root"], + cwd=(path or "."), + ) + res.check_returncode() + return os.path.normcase(os.path.realpath(res.stdout)) + except subprocess.CalledProcessError: + # hg returned error, we are not in a mercurial repo + return None + except OSError: + # hg command not found, probably + return None + + +def _hg_ls_files_and_dirs(toplevel: str) -> tuple[set[str], set[str]]: + hg_files: set[str] = set() + hg_dirs = {toplevel} + res = _run(["hg", "files"], cwd=toplevel) + if res.returncode: + return set(), set() + for name in res.stdout.splitlines(): + name = os.path.normcase(name).replace("/", os.path.sep) + fullname = os.path.join(toplevel, name) + hg_files.add(fullname) + dirname = os.path.dirname(fullname) + while len(dirname) > len(toplevel) and dirname not in hg_dirs: + hg_dirs.add(dirname) + dirname = os.path.dirname(dirname) + return hg_files, hg_dirs + + +def hg_find_files(path: str = "") -> list[str]: + toplevel = _hg_toplevel(path) + if not is_toplevel_acceptable(toplevel): + return [] + assert toplevel is not None + hg_files, hg_dirs = _hg_ls_files_and_dirs(toplevel) + return scm_find_files(path, hg_files, hg_dirs) + + +def hg_archive_find_files(path: _t.PathT = "") -> list[str]: + # This function assumes that ``path`` is obtained from a mercurial archive + # and therefore all the files that should be ignored were already removed. + archival = os.path.join(path, ".hg_archival.txt") + if not os.path.exists(archival): + return [] + + data = data_from_mime(archival) + + if "node" not in data: + # Ensure file is valid + return [] + + log.warning("hg archive detected - fallback to listing all files") + return scm_find_files(path, set(), set(), force_all_files=True) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_get_version_impl.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_get_version_impl.py new file mode 100644 index 0000000..2d9d947 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_get_version_impl.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +import logging +import re +import warnings +from pathlib import Path +from typing import Any +from typing import NoReturn +from typing import Pattern + +from . import _config +from . import _entrypoints +from . import _run_cmd +from . import _types as _t +from ._config import Configuration +from ._overrides import _read_pretended_version_for +from ._version_cls import _validate_version_cls +from .version import format_version as _format_version +from .version import ScmVersion + +_log = logging.getLogger(__name__) + + +def parse_scm_version(config: Configuration) -> ScmVersion | None: + try: + if config.parse is not None: + parse_result = config.parse(config.absolute_root, config=config) + if parse_result is not None and not isinstance(parse_result, ScmVersion): + raise TypeError( + f"version parse result was {str!r}\n" + "please return a parsed version (ScmVersion)" + ) + return parse_result + else: + return _entrypoints.version_from_entrypoint( + config, + entrypoint="setuptools_scm.parse_scm", + root=config.absolute_root, + ) + except _run_cmd.CommandNotFoundError as e: + _log.exception("command %s not found while parsing the scm, using fallbacks", e) + return None + + +def parse_fallback_version(config: Configuration) -> ScmVersion | None: + return _entrypoints.version_from_entrypoint( + config, + entrypoint="setuptools_scm.parse_scm_fallback", + root=config.fallback_root, + ) + + +def parse_version(config: Configuration) -> ScmVersion | None: + return ( + _read_pretended_version_for(config) + or parse_scm_version(config) + or parse_fallback_version(config) + ) + + +def write_version_files( + config: Configuration, version: str, scm_version: ScmVersion +) -> None: + if config.write_to is not None: + from ._integration.dump_version import dump_version + + dump_version( + root=config.root, + version=version, + scm_version=scm_version, + write_to=config.write_to, + template=config.write_to_template, + ) + if config.version_file: + from ._integration.dump_version import write_version_to_path + + version_file = Path(config.version_file) + assert not version_file.is_absolute(), f"{version_file=}" + # todo: use a better name than fallback root + assert config.relative_to is not None + target = Path(config.relative_to).parent.joinpath(version_file) + write_version_to_path( + target, + template=config.version_file_template, + version=version, + scm_version=scm_version, + ) + + +def _get_version( + config: Configuration, force_write_version_files: bool | None = None +) -> str | None: + parsed_version = parse_version(config) + if parsed_version is None: + return None + version_string = _format_version(parsed_version) + if force_write_version_files is None: + force_write_version_files = True + warnings.warn( + "force_write_version_files ought to be set," + " presuming the legacy True value", + DeprecationWarning, + ) + + if force_write_version_files: + write_version_files(config, version=version_string, scm_version=parsed_version) + + return version_string + + +def _version_missing(config: Configuration) -> NoReturn: + raise LookupError( + f"setuptools-scm was unable to detect version for {config.absolute_root}.\n\n" + "Make sure you're either building from a fully intact git repository " + "or PyPI tarballs. Most other sources (such as GitHub's tarballs, a " + "git checkout without the .git folder) don't contain the necessary " + "metadata and will not work.\n\n" + "For example, if you're using pip, instead of " + "https://github.com/user/proj/archive/master.zip " + "use git+https://github.com/user/proj.git#egg=proj" + ) + + +def get_version( + root: _t.PathT = ".", + version_scheme: _t.VERSION_SCHEME = _config.DEFAULT_VERSION_SCHEME, + local_scheme: _t.VERSION_SCHEME = _config.DEFAULT_LOCAL_SCHEME, + write_to: _t.PathT | None = None, + write_to_template: str | None = None, + version_file: _t.PathT | None = None, + version_file_template: str | None = None, + relative_to: _t.PathT | None = None, + tag_regex: str | Pattern[str] = _config.DEFAULT_TAG_REGEX, + parentdir_prefix_version: str | None = None, + fallback_version: str | None = None, + fallback_root: _t.PathT = ".", + parse: Any | None = None, + git_describe_command: _t.CMD_TYPE | None = None, + dist_name: str | None = None, + version_cls: Any | None = None, + normalize: bool = True, + search_parent_directories: bool = False, +) -> str: + """ + If supplied, relative_to should be a file from which root may + be resolved. Typically called by a script or module that is not + in the root of the repository to direct setuptools_scm to the + root of the repository by supplying ``__file__``. + """ + + version_cls = _validate_version_cls(version_cls, normalize) + del normalize + tag_regex = parse_tag_regex(tag_regex) + config = Configuration(**locals()) + maybe_version = _get_version(config, force_write_version_files=True) + + if maybe_version is None: + _version_missing(config) + return maybe_version + + +def parse_tag_regex(tag_regex: str | Pattern[str]) -> Pattern[str]: + if isinstance(tag_regex, str): + if tag_regex == "": + warnings.warn( + DeprecationWarning( + "empty regex for tag regex is invalid, using default" + ) + ) + return _config.DEFAULT_TAG_REGEX + else: + return re.compile(tag_regex) + else: + return tag_regex diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__init__.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/__init__.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f47c3c797cf47f9c9fd1053135aa53a74b1c63d GIT binary patch literal 230 zcmZ8bF$%&k6iqCO2*m?<0*B^XbZ`)l;35uAp|l~UG)+j-At&(&;<>y)p<5>tu#0ba z|God-@Lp-ULIImQVex(ff*)cydbn9;EYzZCc`ZTuhms7e z>naaIYGy>yKq;uy5(wkmf@QALPN~LHTgvQ6cI1$0zbAPf3x7FK(K^OW;e={|1}7Y) eMEh}hlB((&b~f{{ByP3qKz)KS?$Jah3BNBIAwE(7 literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/dump_version.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/dump_version.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0d79e5657be16ba016a2ac2b4fb11d7398c80d3 GIT binary patch literal 3727 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 XJw%eZgLUF17r9<;tWJJ`ur2*R)|d$a literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/toml.cpython-311.pyc b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__pycache__/toml.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0105570a357a37d83ead41131bb66507de158983 GIT binary patch literal 2663 zcmaJDO>f-R@$qB1pVI2fUQ4o9lq132*wQ9&4ET`NFl0G4;wph9AH<{}=zUKs+Wgo) za-*y&+d|;O+At8^tV2=gQYS@YtSCjhG4IuJI6YEZ5{7WM`v1m z2Iu<K}#PR`@(=n>j6Ax3`s7T%; zboe2mBP{<+0vqroLpw>wY5Ae7oucAAshoa}?1~WO4aaeP!#7>Wn}fCdq2VvXEM0b5 zFlA;8%Q9|T3`I4=^Krgn)^P4wSp0BSpSd_Vj_}t%dJPU@7fmc1y+<__~6$!^qaHuw{9#PEN*;o`O56gNN#{@Tt=ld zWlKiW^7jXhXsc`Loa?Yi;mmJxr-l|fLjeLj5?*`*#8Z+bYhzb+XXR$jw_eB3N ziiE7aCY>j55FdRy7!!m~2xLuI7d|6CT0IzBM|3(o$egqWy4{(=w`<}enI|jcQ)!W` z2o-s5HP!T&rY=GVGt8;E)O6~r>ZGUIrsn~DPHk}JHEkf(gV3mxypoEtoEcR2*{6P# z#U$t$=&1jyX|Xxizv?y}I?K7sBMH-xqU?6FUXl0^xX7`JBbge$;b8z&Ro!n^Z+VP+ z)jOu))bH3;yS41vtm^qq+Nzp%gK^Wasx?!$8+LV?)$3l>gJd*(*R?#|tJzZ*r{9`> zXR6UUKmGRGsPLM+s+*3_>O3yUDmpveXhr?WDPX17T#!3H9|w<4!sFS1*2$ijO^t=c z!O!nMzQ487zQ0|p?i8zS`NuxeH@rFY=)sc*L8koj$08}5+9Rpd=qnWF2iljyLjS)C z#m}!lz8)OE__vAg(%Xe=JB4dO;aWI2(w@WLULIb1`SPV#1dE>?KSRDad-<63_aOmr z4OoZcpjw0%Bfxq}7|{euG!bqyfk{-1J63`ol%rmKW|I#mQBK!wmo_b=3%dT>rePgOin@NJnRWe75UuVU4&g62KqAKAq}(y#u(mjIMtm+pRi26|r|>fRI91S-F>GEe^ByAbu%>Wv(f zvWnfHVu7hx;p&vSV*1Ofp?VEggCbU!joMw+TvA=fY607HEYo4CZ8TKVQ|sm@%!#+* z=*hnDyHzF5)i3!Ztf7O_FeO1BMTQthF;dVfqaMDbs&Qtb(qUifE{F0*J383mZ-LSj zJl;(}P~sU<=)!F0YDWw_MM+Q z2RGf2Vd}#ZwBFgsCo)jGj-iugHx?xvRcBH|LmG7l;AeBS;&EO}nEB_+shFuA& zNf6G3^4XvpcFADS4ZBM2;qpI}()UVfQ`uI=c9gMoX?OV4W^L>I=JM~$>-m73Nno3t z35UnG&TmbAIU1aPXJ_~V3NIwEO)l&yIbm#%{0tfqgc0=Ub+obgZ{+^xl_--F-~#_2 ID9-190R*6k9{>OV literal 0 HcmV?d00001 diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/dump_version.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/dump_version.py new file mode 100644 index 0000000..d890243 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/dump_version.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +import warnings +from pathlib import Path + +from .. import _types as _t +from .._log import log as parent_log +from .._version_cls import _version_as_tuple +from ..version import ScmVersion + + +log = parent_log.getChild("dump_version") + +TEMPLATES = { + ".py": """\ +# file generated by setuptools_scm +# don't change, don't track in version control +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple, Union + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = {version!r} +__version_tuple__ = version_tuple = {version_tuple!r} +""", + ".txt": "{version}", +} + + +def dump_version( + root: _t.PathT, + version: str, + write_to: _t.PathT, + template: str | None = None, + scm_version: ScmVersion | None = None, +) -> None: + assert isinstance(version, str) + root = Path(root) + write_to = Path(write_to) + if write_to.is_absolute(): + # trigger warning on escape + write_to.relative_to(root) + warnings.warn( + f"{write_to=!s} is a absolute path," + " please switch to using a relative version file", + DeprecationWarning, + ) + target = write_to + else: + target = Path(root).joinpath(write_to) + write_version_to_path( + target, template=template, version=version, scm_version=scm_version + ) + + +def _validate_template(target: Path, template: str | None) -> str: + if template == "": + warnings.warn(f"{template=} looks like a error, using default instead") + template = None + if template is None: + template = TEMPLATES.get(target.suffix) + + if template is None: + raise ValueError( + f"bad file format: {target.suffix!r} (of {target})\n" + "only *.txt and *.py have a default template" + ) + else: + return template + + +def write_version_to_path( + target: Path, template: str | None, version: str, scm_version: ScmVersion | None +) -> None: + final_template = _validate_template(target, template) + log.debug("dump %s into %s", version, target) + version_tuple = _version_as_tuple(version) + if scm_version is not None: + content = final_template.format( + version=version, + version_tuple=version_tuple, + scm_version=scm_version, + ) + else: + content = final_template.format(version=version, version_tuple=version_tuple) + + target.write_text(content, encoding="utf-8") diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/pyproject_reading.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/pyproject_reading.py new file mode 100644 index 0000000..c9818a2 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/pyproject_reading.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import warnings +from pathlib import Path +from typing import NamedTuple + +from .. import _log +from .setuptools import read_dist_name_from_setup_cfg +from .toml import read_toml_content +from .toml import TOML_RESULT + + +log = _log.log.getChild("pyproject_reading") + +_ROOT = "root" + + +class PyProjectData(NamedTuple): + path: Path + tool_name: str + project: TOML_RESULT + section: TOML_RESULT + + @property + def project_name(self) -> str | None: + return self.project.get("name") + + +def read_pyproject( + path: Path = Path("pyproject.toml"), + tool_name: str = "setuptools_scm", + require_section: bool = True, +) -> PyProjectData: + defn = read_toml_content(path, None if require_section else {}) + try: + section = defn.get("tool", {})[tool_name] + except LookupError as e: + error = f"{path} does not contain a tool.{tool_name} section" + if require_section: + raise LookupError(error) from e + else: + log.warning("toml section missing %r", error) + section = {} + + project = defn.get("project", {}) + return PyProjectData(path, tool_name, project, section) + + +def get_args_for_pyproject( + pyproject: PyProjectData, + dist_name: str | None, + kwargs: TOML_RESULT, +) -> TOML_RESULT: + """drops problematic details and figures the distribution name""" + section = pyproject.section.copy() + kwargs = kwargs.copy() + if "relative_to" in section: + relative = section.pop("relative_to") + warnings.warn( + f"{pyproject.path}: at [tool.{pyproject.tool_name}]\n" + f"ignoring value relative_to={relative!r}" + " as its always relative to the config file" + ) + if "dist_name" in section: + if dist_name is None: + dist_name = section.pop("dist_name") + else: + assert dist_name == section["dist_name"] + section.pop("dist_name") + if dist_name is None: + # minimal pep 621 support for figuring the pretend keys + dist_name = pyproject.project_name + if dist_name is None: + dist_name = read_dist_name_from_setup_cfg() + if _ROOT in kwargs: + if kwargs[_ROOT] is None: + kwargs.pop(_ROOT, None) + elif _ROOT in section: + if section[_ROOT] != kwargs[_ROOT]: + warnings.warn( + f"root {section[_ROOT]} is overridden" + f" by the cli arg {kwargs[_ROOT]}" + ) + section.pop(_ROOT, None) + return {"dist_name": dist_name, **section, **kwargs} diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/setuptools.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/setuptools.py new file mode 100644 index 0000000..f574d23 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/setuptools.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +import logging +import os +import warnings +from typing import Any +from typing import Callable + +import setuptools + +from .. import _config + +log = logging.getLogger(__name__) + + +def read_dist_name_from_setup_cfg( + input: str | os.PathLike[str] = "setup.cfg", +) -> str | None: + # minimal effort to read dist_name off setup.cfg metadata + import configparser + + parser = configparser.ConfigParser() + parser.read([input], encoding="utf-8") + dist_name = parser.get("metadata", "name", fallback=None) + return dist_name + + +def _warn_on_old_setuptools(_version: str = setuptools.__version__) -> None: + if int(_version.split(".")[0]) < 61: + warnings.warn( + RuntimeWarning( + f""" +ERROR: setuptools=={_version} is used in combination with setuptools_scm>=8.x + +Your build configuration is incomplete and previously worked by accident! +setuptools_scm requires setuptools>=61 + +Suggested workaround if applicable: + - migrating from the deprecated setup_requires mechanism to pep517/518 + and using a pyproject.toml to declare build dependencies + which are reliably pre-installed before running the build tools +""" + ) + ) + + +def _assign_version( + dist: setuptools.Distribution, config: _config.Configuration +) -> None: + from .._get_version_impl import _get_version, _version_missing + + # todo: build time plugin + maybe_version = _get_version(config, force_write_version_files=True) + + if maybe_version is None: + _version_missing(config) + else: + assert dist.metadata.version is None + dist.metadata.version = maybe_version + + +_warn_on_old_setuptools() + + +def _log_hookstart(hook: str, dist: setuptools.Distribution) -> None: + log.debug("%s %r", hook, vars(dist.metadata)) + + +def version_keyword( + dist: setuptools.Distribution, + keyword: str, + value: bool | dict[str, Any] | Callable[[], dict[str, Any]], +) -> None: + overrides: dict[str, Any] + if value is True: + overrides = {} + elif callable(value): + overrides = value() + else: + assert isinstance(value, dict), "version_keyword expects a dict or True" + overrides = value + + assert ( + "dist_name" not in overrides + ), "dist_name may not be specified in the setup keyword " + dist_name: str | None = dist.metadata.name + _log_hookstart("version_keyword", dist) + + if dist.metadata.version is not None: + warnings.warn(f"version of {dist_name} already set") + return + + if dist_name is None: + dist_name = read_dist_name_from_setup_cfg() + + config = _config.Configuration.from_file( + dist_name=dist_name, + _require_section=False, + **overrides, + ) + _assign_version(dist, config) + + +def infer_version(dist: setuptools.Distribution) -> None: + _log_hookstart("infer_version", dist) + log.debug("dist %s %s", id(dist), id(dist.metadata)) + if dist.metadata.version is not None: + return # metadata already added by hook + dist_name = dist.metadata.name + if dist_name is None: + dist_name = read_dist_name_from_setup_cfg() + if not os.path.isfile("pyproject.toml"): + return + if dist_name == "setuptools_scm": + return + try: + config = _config.Configuration.from_file(dist_name=dist_name) + except LookupError as e: + log.warning(e) + else: + _assign_version(dist, config) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/toml.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/toml.py new file mode 100644 index 0000000..a08b7b8 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/toml.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +import sys +from pathlib import Path +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import TYPE_CHECKING +from typing import TypedDict + +if sys.version_info >= (3, 11): + from tomllib import loads as load_toml +else: + from tomli import loads as load_toml + +if TYPE_CHECKING: + from typing_extensions import TypeAlias + +from .. import _log + +log = _log.log.getChild("toml") + +TOML_RESULT: TypeAlias = Dict[str, Any] +TOML_LOADER: TypeAlias = Callable[[str], TOML_RESULT] + + +def read_toml_content(path: Path, default: TOML_RESULT | None = None) -> TOML_RESULT: + try: + data = path.read_text(encoding="utf-8") + except FileNotFoundError: + if default is None: + raise + else: + log.debug("%s missing, presuming default %r", path, default) + return default + else: + return load_toml(data) + + +class _CheatTomlData(TypedDict): + cheat: dict[str, Any] + + +def load_toml_or_inline_map(data: str | None) -> dict[str, Any]: + """ + load toml data - with a special hack if only a inline map is given + """ + if not data: + return {} + elif data[0] == "{": + data = "cheat=" + data + loaded: _CheatTomlData = cast(_CheatTomlData, load_toml(data)) + return loaded["cheat"] + return load_toml(data) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_log.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_log.py new file mode 100644 index 0000000..1247d46 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_log.py @@ -0,0 +1,85 @@ +""" +logging helpers, supports vendoring +""" +from __future__ import annotations + +import contextlib +import logging +import os +import sys +from typing import IO +from typing import Iterator +from typing import Mapping + +log = logging.getLogger(__name__.rsplit(".", 1)[0]) +log.propagate = False + + +class AlwaysStdErrHandler(logging.StreamHandler): # type: ignore[type-arg] + def __init___(self) -> None: + super().__init__(sys.stderr) + + @property # type: ignore [override] + def stream(self) -> IO[str]: + return sys.stderr + + @stream.setter + def stream(self, value: IO[str]) -> None: + assert value is sys.stderr + + +def make_default_handler() -> logging.Handler: + try: + from rich.console import Console + + console = Console(stderr=True) + from rich.logging import RichHandler + + return RichHandler(console=console) + except ImportError: + handler = AlwaysStdErrHandler() + handler.setFormatter(logging.Formatter("%(levelname)s %(name)s %(message)s")) + return handler + + +_default_handler = make_default_handler() + +log.addHandler(_default_handler) + + +def _default_log_level(_env: Mapping[str, str] = os.environ) -> int: + val: str | None = _env.get("SETUPTOOLS_SCM_DEBUG") + return logging.WARN if val is None else logging.DEBUG + + +log.setLevel(_default_log_level()) + + +@contextlib.contextmanager +def defer_to_pytest() -> Iterator[None]: + log.propagate = True + old_level = log.level + log.setLevel(logging.NOTSET) + log.removeHandler(_default_handler) + try: + yield + finally: + log.addHandler(_default_handler) + log.propagate = False + log.setLevel(old_level) + + +@contextlib.contextmanager +def enable_debug(handler: logging.Handler = _default_handler) -> Iterator[None]: + log.addHandler(handler) + old_level = log.level + log.setLevel(logging.DEBUG) + old_handler_level = handler.level + handler.setLevel(logging.DEBUG) + try: + yield + finally: + log.setLevel(old_level) + handler.setLevel(old_handler_level) + if handler is not _default_handler: + log.removeHandler(handler) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_modify_version.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_modify_version.py new file mode 100644 index 0000000..63c0dfd --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_modify_version.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import re + +from . import _types as _t + + +def strip_local(version_string: str) -> str: + public, sep, local = version_string.partition("+") + return public + + +def _add_post(version: str) -> str: + if "post" in version: + raise ValueError( + f"{version} already is a post release, refusing to guess the update" + ) + return f"{version}.post1" + + +def _bump_dev(version: str) -> str | None: + if ".dev" not in version: + return None + + prefix, tail = version.rsplit(".dev", 1) + if tail != "0": + raise ValueError( + "choosing custom numbers for the `.devX` distance " + "is not supported.\n " + f"The {version} can't be bumped\n" + "Please drop the tag or create a new supported one ending in .dev0" + ) + return prefix + + +def _bump_regex(version: str) -> str: + match = re.match(r"(.*?)(\d+)$", version) + if match is None: + raise ValueError( + f"{version} does not end with a number to bump, " + "please correct or use a custom version scheme" + ) + else: + prefix, tail = match.groups() + return f"{prefix}{int(tail) + 1}" + + +def _format_local_with_time(version: _t.SCMVERSION, time_format: str) -> str: + if version.exact or version.node is None: + return version.format_choice( + "", "+d{time:{time_format}}", time_format=time_format + ) + else: + return version.format_choice( + "+{node}", "+{node}.d{time:{time_format}}", time_format=time_format + ) + + +def _dont_guess_next_version(tag_version: _t.SCMVERSION) -> str: + version = strip_local(str(tag_version.tag)) + return _bump_dev(version) or _add_post(version) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_overrides.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_overrides.py new file mode 100644 index 0000000..792bfd2 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_overrides.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import os +import re +from typing import Any + +from . import _config +from . import _log +from . import version +from ._integration.toml import load_toml_or_inline_map + +log = _log.log.getChild("overrides") + +PRETEND_KEY = "SETUPTOOLS_SCM_PRETEND_VERSION" +PRETEND_KEY_NAMED = PRETEND_KEY + "_FOR_{name}" + + +def read_named_env( + *, tool: str = "SETUPTOOLS_SCM", name: str, dist_name: str | None +) -> str | None: + """ """ + if dist_name is not None: + # Normalize the dist name as per PEP 503. + normalized_dist_name = re.sub(r"[-_.]+", "-", dist_name) + env_var_dist_name = normalized_dist_name.replace("-", "_").upper() + val = os.environ.get(f"{tool}_{name}_FOR_{env_var_dist_name}") + if val is not None: + return val + return os.environ.get(f"{tool}_{name}") + + +def _read_pretended_version_for( + config: _config.Configuration, +) -> version.ScmVersion | None: + """read a a overridden version from the environment + + tries ``SETUPTOOLS_SCM_PRETEND_VERSION`` + and ``SETUPTOOLS_SCM_PRETEND_VERSION_FOR_$UPPERCASE_DIST_NAME`` + """ + log.debug("dist name: %s", config.dist_name) + + pretended = read_named_env(name="PRETEND_VERSION", dist_name=config.dist_name) + + if pretended: + # we use meta here since the pretended version + # must adhere to the pep to begin with + return version.meta(tag=pretended, preformatted=True, config=config) + else: + return None + + +def read_toml_overrides(dist_name: str | None) -> dict[str, Any]: + data = read_named_env(name="OVERRIDES", dist_name=dist_name) + return load_toml_or_inline_map(data) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_run_cmd.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_run_cmd.py new file mode 100644 index 0000000..1b80d28 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_run_cmd.py @@ -0,0 +1,207 @@ +from __future__ import annotations + +import os +import shlex +import subprocess +import textwrap +import warnings +from typing import Callable +from typing import Final +from typing import Mapping +from typing import overload +from typing import Sequence +from typing import TYPE_CHECKING +from typing import TypeVar + +from . import _log +from . import _types as _t + +if TYPE_CHECKING: + BaseCompletedProcess = subprocess.CompletedProcess[str] +else: + BaseCompletedProcess = subprocess.CompletedProcess + +# pick 40 seconds +# unfortunately github CI for windows sometimes needs +# up to 30 seconds to start a command + +BROKEN_TIMEOUT: Final[int] = 40 + +log = _log.log.getChild("run_cmd") + +PARSE_RESULT = TypeVar("PARSE_RESULT") +T = TypeVar("T") + + +class CompletedProcess(BaseCompletedProcess): + @classmethod + def from_raw( + cls, input: BaseCompletedProcess, strip: bool = True + ) -> CompletedProcess: + return cls( + args=input.args, + returncode=input.returncode, + stdout=input.stdout.strip() if strip and input.stdout else input.stdout, + stderr=input.stderr.strip() if strip and input.stderr else input.stderr, + ) + + @overload + def parse_success( + self, + parse: Callable[[str], PARSE_RESULT], + default: None = None, + error_msg: str | None = None, + ) -> PARSE_RESULT | None: + ... + + @overload + def parse_success( + self, + parse: Callable[[str], PARSE_RESULT], + default: T, + error_msg: str | None = None, + ) -> PARSE_RESULT | T: + ... + + def parse_success( + self, + parse: Callable[[str], PARSE_RESULT], + default: T | None = None, + error_msg: str | None = None, + ) -> PARSE_RESULT | T | None: + if self.returncode: + if error_msg: + log.warning("%s %s", error_msg, self) + return default + else: + return parse(self.stdout) + + +def no_git_env(env: Mapping[str, str]) -> dict[str, str]: + # adapted from pre-commit + # Too many bugs dealing with environment variables and GIT: + # https://github.com/pre-commit/pre-commit/issues/300 + # In git 2.6.3 (maybe others), git exports GIT_WORK_TREE while running + # pre-commit hooks + # In git 1.9.1 (maybe others), git exports GIT_DIR and GIT_INDEX_FILE + # while running pre-commit hooks in submodules. + # GIT_DIR: Causes git clone to clone wrong thing + # GIT_INDEX_FILE: Causes 'error invalid object ...' during commit + for k, v in env.items(): + if k.startswith("GIT_"): + log.debug("%s: %s", k, v) + return { + k: v + for k, v in env.items() + if not k.startswith("GIT_") + or k in ("GIT_EXEC_PATH", "GIT_SSH", "GIT_SSH_COMMAND") + } + + +def avoid_pip_isolation(env: Mapping[str, str]) -> dict[str, str]: + """ + pip build isolation can break Mercurial + (see https://github.com/pypa/pip/issues/10635) + + pip uses PYTHONNOUSERSITE and a path in PYTHONPATH containing "pip-build-env-". + """ + new_env = {k: v for k, v in env.items() if k != "PYTHONNOUSERSITE"} + if "PYTHONPATH" not in new_env: + return new_env + + new_env["PYTHONPATH"] = os.pathsep.join( + [ + path + for path in new_env["PYTHONPATH"].split(os.pathsep) + if "pip-build-env-" not in path + ] + ) + return new_env + + +def ensure_stripped_str(str_or_bytes: str | bytes) -> str: + if isinstance(str_or_bytes, str): + return str_or_bytes.strip() + else: + return str_or_bytes.decode("utf-8", "surrogateescape").strip() + + +def run( + cmd: _t.CMD_TYPE, + cwd: _t.PathT, + *, + strip: bool = True, + trace: bool = True, + timeout: int = BROKEN_TIMEOUT, + check: bool = False, +) -> CompletedProcess: + if isinstance(cmd, str): + cmd = shlex.split(cmd) + else: + cmd = [os.fspath(x) for x in cmd] + cmd_4_trace = " ".join(map(_unsafe_quote_for_display, cmd)) + log.debug("at %s\n $ %s ", cwd, cmd_4_trace) + res = subprocess.run( + cmd, + capture_output=True, + cwd=os.fspath(cwd), + env=dict( + avoid_pip_isolation(no_git_env(os.environ)), + # os.environ, + # try to disable i18n, but still allow UTF-8 encoded text. + LC_ALL="C.UTF-8", + LANGUAGE="", + HGPLAIN="1", + ), + text=True, + timeout=timeout, + ) + + res = CompletedProcess.from_raw(res, strip=strip) + if trace: + if res.stdout: + log.debug("out:\n%s", textwrap.indent(res.stdout, " ")) + if res.stderr: + log.debug("err:\n%s", textwrap.indent(res.stderr, " ")) + if res.returncode: + log.debug("ret: %s", res.returncode) + if check: + res.check_returncode() + return res + + +def _unsafe_quote_for_display(item: _t.PathT) -> str: + # give better results than shlex.join in our cases + text = os.fspath(item) + return text if all(c not in text for c in " {[:") else f'"{text}"' + + +def has_command( + name: str, args: Sequence[str] = ["version"], warn: bool = True +) -> bool: + try: + p = run([name, *args], cwd=".", timeout=BROKEN_TIMEOUT) + if p.returncode != 0: + log.error(f"Command '{name}' returned non-zero. This is stderr:") + log.error(p.stderr) + except OSError as e: + log.warning("command %s missing: %s", name, e) + res = False + except subprocess.TimeoutExpired as e: + log.warning("command %s timed out %s", name, e) + res = False + + else: + res = not p.returncode + if not res and warn: + warnings.warn("%r was not found" % name, category=RuntimeWarning) + return res + + +class CommandNotFoundError(LookupError, FileNotFoundError): + pass + + +def require_command(name: str) -> None: + if not has_command(name, warn=False): + raise CommandNotFoundError(name) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_types.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_types.py new file mode 100644 index 0000000..df8fa94 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_types.py @@ -0,0 +1,22 @@ +from __future__ import annotations + +import os +from typing import Callable +from typing import List +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + + +if TYPE_CHECKING: + from typing_extensions import TypeAlias + from . import version + +PathT: TypeAlias = Union["os.PathLike[str]", str] + +CMD_TYPE: TypeAlias = Union[Sequence[PathT], str] + +VERSION_SCHEME: TypeAlias = Union[str, Callable[["version.ScmVersion"], str]] +VERSION_SCHEMES: TypeAlias = Union[List[str], Tuple[str, ...], VERSION_SCHEME] +SCMVERSION: TypeAlias = "version.ScmVersion" diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_version_cls.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_version_cls.py new file mode 100644 index 0000000..3fd4a32 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_version_cls.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from typing import cast +from typing import Type +from typing import Union + +try: + from packaging.version import InvalidVersion + from packaging.version import Version as Version +except ImportError: + from setuptools.extern.packaging.version import InvalidVersion # type: ignore + from setuptools.extern.packaging.version import Version as Version # type: ignore +from . import _log + +log = _log.log.getChild("version_cls") + + +class NonNormalizedVersion(Version): + """A non-normalizing version handler. + + You can use this class to preserve version verification but skip normalization. + For example you can use this to avoid git release candidate version tags + ("1.0.0-rc1") to be normalized to "1.0.0rc1". Only use this if you fully + trust the version tags. + """ + + def __init__(self, version: str) -> None: + # parse and validate using parent + super().__init__(version) + + # store raw for str + self._raw_version = version + + def __str__(self) -> str: + # return the non-normalized version (parent returns the normalized) + return self._raw_version + + def __repr__(self) -> str: + # same pattern as parent + return f"" + + +def _version_as_tuple(version_str: str) -> tuple[int | str, ...]: + try: + parsed_version = Version(version_str) + except InvalidVersion as e: + log.error("failed to parse version %s: %s", e, version_str) + return (version_str,) + else: + version_fields: tuple[int | str, ...] = parsed_version.release + if parsed_version.dev is not None: + version_fields += (f"dev{parsed_version.dev}",) + if parsed_version.local is not None: + version_fields += (parsed_version.local,) + return version_fields + + +_VersionT = Union[Version, NonNormalizedVersion] + + +def import_name(name: str) -> object: + import importlib + + pkg_name, cls_name = name.rsplit(".", 1) + pkg = importlib.import_module(pkg_name) + return getattr(pkg, cls_name) + + +def _validate_version_cls( + version_cls: type[_VersionT] | str | None, normalize: bool +) -> type[_VersionT]: + if not normalize: + if version_cls is not None: + raise ValueError( + "Providing a custom `version_cls` is not permitted when " + "`normalize=False`" + ) + return NonNormalizedVersion + else: + # Use `version_cls` if provided, default to packaging or pkg_resources + if version_cls is None: + return Version + elif isinstance(version_cls, str): + try: + return cast(Type[_VersionT], import_name(version_cls)) + except: # noqa + raise ValueError( + f"Unable to import version_cls='{version_cls}'" + ) from None + else: + return version_cls diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/discover.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/discover.py new file mode 100644 index 0000000..b12b2f1 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/discover.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +import os +from pathlib import Path +from typing import Iterable +from typing import Iterator + +from . import _entrypoints +from . import _log +from . import _types as _t +from ._config import Configuration + +log = _log.log.getChild("discover") + + +def walk_potential_roots(root: _t.PathT, search_parents: bool = True) -> Iterator[Path]: + """ + Iterate though a path and each of its parents. + :param root: File path. + :param search_parents: If ``False`` the parents are not considered. + """ + root = Path(root) + yield root + if search_parents: + yield from root.parents + + +def match_entrypoint(root: _t.PathT, name: str) -> bool: + """ + Consider a ``root`` as entry-point. + :param root: File path. + :param name: Subdirectory name. + :return: ``True`` if a subdirectory ``name`` exits in ``root``. + """ + + if os.path.exists(os.path.join(root, name)): + if not os.path.isabs(name): + return True + log.debug("ignoring bad ep %s", name) + + return False + + +# blocked entrypints from legacy plugins +_BLOCKED_EP_TARGETS = {"setuptools_scm_git_archive:parse"} + + +def iter_matching_entrypoints( + root: _t.PathT, entrypoint: str, config: Configuration +) -> Iterable[_entrypoints.EntryPoint]: + """ + Consider different entry-points in ``root`` and optionally its parents. + :param root: File path. + :param entrypoint: Entry-point to consider. + :param config: Configuration, + read ``search_parent_directories``, write found parent to ``parent``. + """ + + log.debug("looking for ep %s in %s", entrypoint, root) + from ._entrypoints import iter_entry_points + + for wd in walk_potential_roots(root, config.search_parent_directories): + for ep in iter_entry_points(entrypoint): + if ep.value in _BLOCKED_EP_TARGETS: + continue + if match_entrypoint(wd, ep.name): + log.debug("found ep %s in %s", ep, wd) + config.parent = wd + yield ep diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/fallbacks.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/fallbacks.py new file mode 100644 index 0000000..e1ea60c --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/fallbacks.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +import logging +import os +from pathlib import Path +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from . import _types as _t +from . import Configuration +from .integration import data_from_mime +from .version import meta +from .version import ScmVersion +from .version import tag_to_version + +log = logging.getLogger(__name__) + +_UNKNOWN = "UNKNOWN" + + +def parse_pkginfo(root: _t.PathT, config: Configuration) -> ScmVersion | None: + pkginfo = Path(root) / "PKG-INFO" + log.debug("pkginfo %s", pkginfo) + data = data_from_mime(pkginfo) + version = data.get("Version", _UNKNOWN) + if version != _UNKNOWN: + return meta(version, preformatted=True, config=config) + else: + return None + + +def fallback_version(root: _t.PathT, config: Configuration) -> ScmVersion | None: + if config.parentdir_prefix_version is not None: + _, parent_name = os.path.split(os.path.abspath(root)) + if parent_name.startswith(config.parentdir_prefix_version): + version = tag_to_version( + parent_name[len(config.parentdir_prefix_version) :], config + ) + if version is not None: + return meta(str(version), preformatted=True, config=config) + if config.fallback_version is not None: + log.debug("FALLBACK %s", config.fallback_version) + return meta(config.fallback_version, preformatted=True, config=config) + return None diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/git.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/git.py new file mode 100644 index 0000000..d511961 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/git.py @@ -0,0 +1,336 @@ +from __future__ import annotations + +import dataclasses +import logging +import os +import re +import shlex +import warnings +from datetime import date +from datetime import datetime +from datetime import timezone +from os.path import samefile +from pathlib import Path +from typing import Callable +from typing import Sequence +from typing import TYPE_CHECKING + +from . import _types as _t +from . import Configuration +from . import discover +from ._run_cmd import CompletedProcess as _CompletedProcess +from ._run_cmd import require_command as _require_command +from ._run_cmd import run as _run +from .integration import data_from_mime +from .scm_workdir import Workdir +from .version import meta +from .version import ScmVersion +from .version import tag_to_version + +if TYPE_CHECKING: + from . import hg_git +log = logging.getLogger(__name__) + +REF_TAG_RE = re.compile(r"(?<=\btag: )([^,]+)\b") +DESCRIBE_UNSUPPORTED = "%(describe" + +# If testing command in shell make sure to quote the match argument like +# '*[0-9]*' as it will expand before being sent to git if there are any matching +# files in current directory. +DEFAULT_DESCRIBE = [ + "git", + "describe", + "--dirty", + "--tags", + "--long", + "--match", + "*[0-9]*", +] + + +def run_git( + args: Sequence[str | os.PathLike[str]], + repo: Path, + *, + check: bool = False, + timeout: int = 20, +) -> _CompletedProcess: + return _run( + ["git", "--git-dir", repo / ".git", *args], + cwd=repo, + check=check, + timeout=timeout, + ) + + +class GitWorkdir(Workdir): + """experimental, may change at any time""" + + @classmethod + def from_potential_worktree(cls, wd: _t.PathT) -> GitWorkdir | None: + wd = Path(wd).resolve() + real_wd = run_git(["rev-parse", "--show-prefix"], wd).parse_success(parse=str) + if real_wd is None: + return None + else: + real_wd = real_wd[:-1] # remove the trailing pathsep + + if not real_wd: + real_wd = os.fspath(wd) + else: + str_wd = os.fspath(wd) + assert str_wd.replace("\\", "/").endswith(real_wd) + # In windows wd contains ``\`` which should be replaced by ``/`` + # for this assertion to work. Length of string isn't changed by replace + # ``\\`` is just and escape for `\` + real_wd = str_wd[: -len(real_wd)] + log.debug("real root %s", real_wd) + if not samefile(real_wd, wd): + return None + + return cls(Path(real_wd)) + + def is_dirty(self) -> bool: + return run_git( + ["status", "--porcelain", "--untracked-files=no"], self.path + ).parse_success( + parse=bool, + default=False, + ) + + def get_branch(self) -> str | None: + return run_git( + ["rev-parse", "--abbrev-ref", "HEAD"], + self.path, + ).parse_success( + parse=str, + error_msg="branch err (abbrev-err)", + ) or run_git( + ["symbolic-ref", "--short", "HEAD"], + self.path, + ).parse_success( + parse=str, + error_msg="branch err (symbolic-ref)", + ) + + def get_head_date(self) -> date | None: + def parse_timestamp(timestamp_text: str) -> date | None: + if "%c" in timestamp_text: + log.warning("git too old -> timestamp is %r", timestamp_text) + return None + return datetime.fromisoformat(timestamp_text).date() + + res = run_git( + [ + *("-c", "log.showSignature=false"), + *("log", "-n", "1", "HEAD"), + "--format=%cI", + ], + self.path, + ) + return res.parse_success( + parse=parse_timestamp, + error_msg="logging the iso date for head failed", + ) + + def is_shallow(self) -> bool: + return self.path.joinpath(".git/shallow").is_file() + + def fetch_shallow(self) -> None: + run_git(["fetch", "--unshallow"], self.path, check=True, timeout=240) + + def node(self) -> str | None: + def _unsafe_short_node(node: str) -> str: + return node[:7] + + return run_git( + ["rev-parse", "--verify", "--quiet", "HEAD"], self.path + ).parse_success( + parse=_unsafe_short_node, + ) + + def count_all_nodes(self) -> int: + res = run_git(["rev-list", "HEAD"], self.path) + return res.stdout.count("\n") + 1 + + def default_describe(self) -> _CompletedProcess: + return run_git(DEFAULT_DESCRIBE[1:], self.path) + + +def warn_on_shallow(wd: GitWorkdir) -> None: + """experimental, may change at any time""" + if wd.is_shallow(): + warnings.warn(f'"{wd.path}" is shallow and may cause errors') + + +def fetch_on_shallow(wd: GitWorkdir) -> None: + """experimental, may change at any time""" + if wd.is_shallow(): + warnings.warn(f'"{wd.path}" was shallow, git fetch was used to rectify') + wd.fetch_shallow() + + +def fail_on_shallow(wd: GitWorkdir) -> None: + """experimental, may change at any time""" + if wd.is_shallow(): + raise ValueError( + f'{wd.path} is shallow, please correct with "git fetch --unshallow"' + ) + + +def get_working_directory(config: Configuration, root: _t.PathT) -> GitWorkdir | None: + """ + Return the working directory (``GitWorkdir``). + """ + + if config.parent: # todo broken + return GitWorkdir.from_potential_worktree(config.parent) + + for potential_root in discover.walk_potential_roots( + root, search_parents=config.search_parent_directories + ): + potential_wd = GitWorkdir.from_potential_worktree(potential_root) + if potential_wd is not None: + return potential_wd + + return GitWorkdir.from_potential_worktree(root) + + +def parse( + root: _t.PathT, + config: Configuration, + describe_command: str | list[str] | None = None, + pre_parse: Callable[[GitWorkdir], None] = warn_on_shallow, +) -> ScmVersion | None: + """ + :param pre_parse: experimental pre_parse action, may change at any time + """ + _require_command("git") + wd = get_working_directory(config, root) + if wd: + return _git_parse_inner( + config, wd, describe_command=describe_command, pre_parse=pre_parse + ) + else: + return None + + +def version_from_describe( + wd: GitWorkdir | hg_git.GitWorkdirHgClient, + config: Configuration, + describe_command: _t.CMD_TYPE | None, +) -> ScmVersion | None: + pass + + if config.git_describe_command is not None: + describe_command = config.git_describe_command + + if describe_command is not None: + if isinstance(describe_command, str): + describe_command = shlex.split(describe_command) + # todo: figure how to ensure git with gitdir gets correctly invoked + if describe_command[0] == "git": + describe_res = run_git(describe_command[1:], wd.path) + else: + describe_res = _run(describe_command, wd.path) + else: + describe_res = wd.default_describe() + + def parse_describe(output: str) -> ScmVersion: + tag, distance, node, dirty = _git_parse_describe(output) + return meta(tag=tag, distance=distance, dirty=dirty, node=node, config=config) + + return describe_res.parse_success(parse=parse_describe) + + +def _git_parse_inner( + config: Configuration, + wd: GitWorkdir | hg_git.GitWorkdirHgClient, + pre_parse: None | (Callable[[GitWorkdir | hg_git.GitWorkdirHgClient], None]) = None, + describe_command: _t.CMD_TYPE | None = None, +) -> ScmVersion: + if pre_parse: + pre_parse(wd) + + version = version_from_describe(wd, config, describe_command) + + if version is None: + # If 'git git_describe_command' failed, try to get the information otherwise. + tag = config.version_cls("0.0") + node = wd.node() + if node is None: + distance = 0 + dirty = True + else: + distance = wd.count_all_nodes() + node = "g" + node + dirty = wd.is_dirty() + version = meta( + tag=tag, distance=distance, dirty=dirty, node=node, config=config + ) + branch = wd.get_branch() + node_date = wd.get_head_date() or datetime.now(timezone.utc).date() + return dataclasses.replace(version, branch=branch, node_date=node_date) + + +def _git_parse_describe( + describe_output: str, +) -> tuple[str, int, str | None, bool]: + # 'describe_output' looks e.g. like 'v1.5.0-0-g4060507' or + # 'v1.15.1rc1-37-g9bd1298-dirty'. + # It may also just be a bare tag name if this is a tagged commit and we are + # parsing a .git_archival.txt file. + + if describe_output.endswith("-dirty"): + dirty = True + describe_output = describe_output[:-6] + else: + dirty = False + + split = describe_output.rsplit("-", 2) + if len(split) < 3: # probably a tagged commit + tag = describe_output + number = 0 + node = None + else: + tag, number_, node = split + number = int(number_) + return tag, number, node, dirty + + +def archival_to_version( + data: dict[str, str], config: Configuration +) -> ScmVersion | None: + node: str | None + log.debug("data %s", data) + archival_describe = data.get("describe-name", DESCRIBE_UNSUPPORTED) + if DESCRIBE_UNSUPPORTED in archival_describe: + warnings.warn("git archive did not support describe output") + else: + tag, number, node, _ = _git_parse_describe(archival_describe) + return meta( + tag, + config=config, + distance=number, + node=node, + ) + + for ref in REF_TAG_RE.findall(data.get("ref-names", "")): + version = tag_to_version(ref, config) + if version is not None: + return meta(version, config=config) + else: + node = data.get("node") + if node is None: + return None + elif "$FORMAT" in node.upper(): + warnings.warn("unprocessed git archival found (no export subst applied)") + return None + else: + return meta("0.0", node=node, config=config) + + +def parse_archival(root: _t.PathT, config: Configuration) -> ScmVersion | None: + archival = os.path.join(root, ".git_archival.txt") + data = data_from_mime(archival) + return archival_to_version(data, config=config) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg.py new file mode 100644 index 0000000..522dfb6 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg.py @@ -0,0 +1,190 @@ +from __future__ import annotations + +import datetime +import logging +import os +from pathlib import Path +from typing import TYPE_CHECKING + +from . import Configuration +from ._version_cls import Version +from .integration import data_from_mime +from .scm_workdir import Workdir +from .version import meta +from .version import ScmVersion +from .version import tag_to_version + +if TYPE_CHECKING: + from . import _types as _t + +from ._run_cmd import run as _run, require_command as _require_command + +log = logging.getLogger(__name__) + + +class HgWorkdir(Workdir): + @classmethod + def from_potential_worktree(cls, wd: _t.PathT) -> HgWorkdir | None: + res = _run(["hg", "root"], wd) + if res.returncode: + return None + return cls(Path(res.stdout)) + + def get_meta(self, config: Configuration) -> ScmVersion | None: + node: str + tags_str: str + bookmark: str + node_date_str: str + node, tags_str, bookmark, node_date_str = self.hg_log( + ".", "{node}\n{tag}\n{bookmark}\n{date|shortdate}" + ).split("\n") + + # TODO: support bookmarks and topics (but nowadays bookmarks are + # mainly used to emulate Git branches, which is already supported with + # the dedicated class GitWorkdirHgClient) + + branch, dirty_str, dirty_date = _run( + ["hg", "id", "-T", "{branch}\n{if(dirty, 1, 0)}\n{date|shortdate}"], + cwd=self.path, + check=True, + ).stdout.split("\n") + dirty = bool(int(dirty_str)) + node_date = datetime.date.fromisoformat(dirty_date if dirty else node_date_str) + + if node == "0" * len(node): + log.debug("initial node %s", self.path) + return meta( + Version("0.0"), + config=config, + dirty=dirty, + branch=branch, + node_date=node_date, + ) + + node = "h" + node[:7] + + tags = tags_str.split() + if "tip" in tags: + # tip is not a real tag + tags.remove("tip") + + if tags: + tag = tag_to_version(tags[0], config) + if tag: + return meta(tag, dirty=dirty, branch=branch, config=config) + + try: + tag_str = self.get_latest_normalizable_tag() + if tag_str is None: + dist = self.get_distance_revs("") + else: + dist = self.get_distance_revs(tag_str) + + if tag_str == "null" or tag_str is None: + tag = Version("0.0") + dist += 1 + else: + tag = tag_to_version(tag_str, config=config) + assert tag is not None + + if self.check_changes_since_tag(tag_str) or dirty: + return meta( + tag, + distance=dist, + node=node, + dirty=dirty, + branch=branch, + config=config, + node_date=node_date, + ) + else: + return meta(tag, config=config, node_date=node_date) + + except ValueError as e: + log.exception("error %s", e) + pass # unpacking failed, old hg + + return None + + def hg_log(self, revset: str, template: str) -> str: + cmd = ["hg", "log", "-r", revset, "-T", template] + + return _run(cmd, cwd=self.path, check=True).stdout + + def get_latest_normalizable_tag(self) -> str | None: + # Gets all tags containing a '.' (see #229) from oldest to newest + outlines = self.hg_log( + revset="ancestors(.) and tag('re:\\.')", + template="{tags}{if(tags, '\n', '')}", + ).split() + if not outlines: + return None + tag = outlines[-1].split()[-1] + return tag + + def get_distance_revs(self, rev1: str, rev2: str = ".") -> int: + revset = f"({rev1}::{rev2})" + out = self.hg_log(revset, ".") + return len(out) - 1 + + def check_changes_since_tag(self, tag: str | None) -> bool: + if tag == "0.0" or tag is None: + return True + + revset = ( + "(branch(.)" # look for revisions in this branch only + f" and tag({tag!r})::." # after the last tag + # ignore commits that only modify .hgtags and nothing else: + " and (merge() or file('re:^(?!\\.hgtags).*$'))" + f" and not tag({tag!r}))" # ignore the tagged commit itself + ) + + return bool(self.hg_log(revset, ".")) + + +def parse(root: _t.PathT, config: Configuration) -> ScmVersion | None: + _require_command("hg") + if os.path.exists(os.path.join(root, ".hg/git")): + res = _run(["hg", "path"], root) + if not res.returncode: + for line in res.stdout.split("\n"): + if line.startswith("default ="): + path = Path(line.split()[2]) + if path.name.endswith(".git") or (path / ".git").exists(): + from .git import _git_parse_inner + from .hg_git import GitWorkdirHgClient + + wd_hggit = GitWorkdirHgClient.from_potential_worktree(root) + if wd_hggit: + return _git_parse_inner(config, wd_hggit) + + wd = HgWorkdir.from_potential_worktree(config.absolute_root) + + if wd is None: + return None + + return wd.get_meta(config) + + +def archival_to_version(data: dict[str, str], config: Configuration) -> ScmVersion: + log.debug("data %s", data) + node = data.get("node", "")[:12] + if node: + node = "h" + node + if "tag" in data: + return meta(data["tag"], config=config) + elif "latesttag" in data: + return meta( + data["latesttag"], + distance=int(data["latesttagdistance"]), + node=node, + config=config, + ) + else: + return meta(config.version_cls("0.0"), node=node, config=config) + + +def parse_archival(root: _t.PathT, config: Configuration) -> ScmVersion: + archival = os.path.join(root, ".hg_archival.txt") + data = data_from_mime(archival) + return archival_to_version(data, config=config) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg_git.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg_git.py new file mode 100644 index 0000000..b6c3036 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/hg_git.py @@ -0,0 +1,155 @@ +from __future__ import annotations + +import logging +import os +from contextlib import suppress +from datetime import date +from pathlib import Path + +from . import _types as _t +from ._run_cmd import CompletedProcess as _CompletedProcess +from ._run_cmd import require_command +from ._run_cmd import run as _run +from .git import GitWorkdir +from .hg import HgWorkdir + +log = logging.getLogger(__name__) + +_FAKE_GIT_DESCRIBE_ERROR = _CompletedProcess( + "fake git describe output for hg", + 1, + "<>hg git failed to describe", +) + + +class GitWorkdirHgClient(GitWorkdir, HgWorkdir): + COMMAND = "hg" + + @classmethod + def from_potential_worktree(cls, wd: _t.PathT) -> GitWorkdirHgClient | None: + require_command("hg") + res = _run(["hg", "root"], cwd=wd).parse_success(parse=Path) + if res is None: + return None + return cls(res) + + def is_dirty(self) -> bool: + res = _run(["hg", "id", "-T", "{dirty}"], cwd=self.path, check=True) + return bool(res.stdout) + + def get_branch(self) -> str | None: + res = _run(["hg", "id", "-T", "{bookmarks}"], cwd=self.path) + if res.returncode: + log.info("branch err %s", res) + return None + return res.stdout + + def get_head_date(self) -> date | None: + return _run('hg log -r . -T "{shortdate(date)}"', cwd=self.path).parse_success( + parse=date.fromisoformat, error_msg="head date err" + ) + + def is_shallow(self) -> bool: + return False + + def fetch_shallow(self) -> None: + pass + + def get_hg_node(self) -> str | None: + res = _run('hg log -r . -T "{node}"', cwd=self.path) + if res.returncode: + return None + else: + return res.stdout + + def _hg2git(self, hg_node: str) -> str | None: + with suppress(FileNotFoundError): + with open(os.path.join(self.path, ".hg/git-mapfile")) as map_items: + for item in map_items: + if hg_node in item: + git_node, hg_node = item.split() + return git_node + return None + + def node(self) -> str | None: + hg_node = self.get_hg_node() + if hg_node is None: + return None + + git_node = self._hg2git(hg_node) + + if git_node is None: + # trying again after hg -> git + _run(["hg", "gexport"], cwd=self.path) + git_node = self._hg2git(hg_node) + + if git_node is None: + log.debug("Cannot get git node so we use hg node %s", hg_node) + + if hg_node == "0" * len(hg_node): + # mimic Git behavior + return None + + return hg_node + + return git_node[:7] + + def count_all_nodes(self) -> int: + res = _run(["hg", "log", "-r", "ancestors(.)", "-T", "."], cwd=self.path) + return len(res.stdout) + + def default_describe(self) -> _CompletedProcess: + """ + Tentative to reproduce the output of + + `git describe --dirty --tags --long --match *[0-9]*` + + """ + res = _run( + [ + "hg", + "log", + "-r", + "(reverse(ancestors(.)) and tag(r're:v?[0-9].*'))", + "-T", + "{tags}{if(tags, ' ', '')}", + ], + cwd=self.path, + ) + if res.returncode: + return _FAKE_GIT_DESCRIBE_ERROR + hg_tags: list[str] = res.stdout.split() + + if not hg_tags: + return _FAKE_GIT_DESCRIBE_ERROR + + with self.path.joinpath(".hg/git-tags").open() as fp: + git_tags: dict[str, str] = dict(line.split()[::-1] for line in fp) + + tag: str + for hg_tag in hg_tags: + if hg_tag in git_tags: + tag = hg_tag + break + else: + logging.warning("tag not found hg=%s git=%s", hg_tags, git_tags) + return _FAKE_GIT_DESCRIBE_ERROR + + res = _run(["hg", "log", "-r", f"'{tag}'::.", "-T", "."], cwd=self.path) + if res.returncode: + return _FAKE_GIT_DESCRIBE_ERROR + distance = len(res.stdout) - 1 + + node = self.node() + assert node is not None + desc = f"{tag}-{distance}-g{node}" + + if self.is_dirty(): + desc += "-dirty" + log.debug("faked describe %r", desc) + return _CompletedProcess( + ["setuptools-scm", "faked", "describe"], + returncode=0, + stdout=desc, + stderr="", + ) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/integration.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/integration.py new file mode 100644 index 0000000..390b0a7 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/integration.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +import logging +import textwrap +from pathlib import Path + +from . import _types as _t + +log = logging.getLogger(__name__) + + +def data_from_mime(path: _t.PathT, content: None | str = None) -> dict[str, str]: + """return a mapping from mime/pseudo-mime content + :param path: path to the mime file + :param content: content of the mime file, if None, read from path + :rtype: dict[str, str] + + """ + + if content is None: + content = Path(path).read_text(encoding="utf-8") + log.debug("mime %s content:\n%s", path, textwrap.indent(content, " ")) + + from email.parser import HeaderParser + + parser = HeaderParser() + message = parser.parsestr(content) + data = dict(message.items()) + log.debug("mime %s data:\n%s", path, data) + return data diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/scm_workdir.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/scm_workdir.py new file mode 100644 index 0000000..9879549 --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/scm_workdir.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path + +from ._config import Configuration +from .version import ScmVersion + + +@dataclass() +class Workdir: + path: Path + + def run_describe(self, config: Configuration) -> ScmVersion: + raise NotImplementedError(self.run_describe) diff --git a/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/version.py b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/version.py new file mode 100644 index 0000000..f43e14b --- /dev/null +++ b/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/version.py @@ -0,0 +1,440 @@ +from __future__ import annotations + +import dataclasses +import logging +import os +import re +import warnings +from datetime import date +from datetime import datetime +from datetime import timezone +from typing import Any +from typing import Callable +from typing import Match +from typing import TYPE_CHECKING + +from . import _entrypoints +from . import _modify_version + +if TYPE_CHECKING: + from typing_extensions import Concatenate + from typing_extensions import ParamSpec + + _P = ParamSpec("_P") + +from typing import TypedDict + + +from ._version_cls import Version as PkgVersion, _VersionT +from . import _version_cls as _v +from . import _config + +log = logging.getLogger(__name__) + + +SEMVER_MINOR = 2 +SEMVER_PATCH = 3 +SEMVER_LEN = 3 + + +class _TagDict(TypedDict): + version: str + prefix: str + suffix: str + + +def _parse_version_tag( + tag: str | object, config: _config.Configuration +) -> _TagDict | None: + match = config.tag_regex.match(str(tag)) + + if match: + key: str | int = 1 if len(match.groups()) == 1 else "version" + full = match.group(0) + log.debug("%r %r %s", tag, config.tag_regex, match) + log.debug( + "key %s data %s, %s, %r", key, match.groupdict(), match.groups(), full + ) + result = _TagDict( + version=match.group(key), + prefix=full[: match.start(key)], + suffix=full[match.end(key) :], + ) + + log.debug("tag %r parsed to %r", tag, result) + assert result["version"] + return result + else: + log.debug("tag %r did not parse", tag) + + return None + + +def callable_or_entrypoint(group: str, callable_or_name: str | Any) -> Any: + log.debug("ep %r %r", group, callable_or_name) + + if callable(callable_or_name): + return callable_or_name + from ._entrypoints import iter_entry_points + + for ep in iter_entry_points(group, callable_or_name): + log.debug("ep found: %s", ep.name) + return ep.load() + + +def tag_to_version( + tag: _VersionT | str, config: _config.Configuration +) -> _VersionT | None: + """ + take a tag that might be prefixed with a keyword and return only the version part + """ + log.debug("tag %s", tag) + + tag_dict = _parse_version_tag(tag, config) + if tag_dict is None or not tag_dict.get("version", None): + warnings.warn(f"tag {tag!r} no version found") + return None + + version_str = tag_dict["version"] + log.debug("version pre parse %s", version_str) + + if suffix := tag_dict.get("suffix", ""): + warnings.warn(f"tag {tag!r} will be stripped of its suffix {suffix!r}") + + version: _VersionT = config.version_cls(version_str) + log.debug("version=%r", version) + + return version + + +def _source_epoch_or_utc_now() -> datetime: + if "SOURCE_DATE_EPOCH" in os.environ: + date_epoch = int(os.environ["SOURCE_DATE_EPOCH"]) + return datetime.fromtimestamp(date_epoch, timezone.utc) + else: + return datetime.now(timezone.utc) + + +@dataclasses.dataclass +class ScmVersion: + """represents a parsed version from scm""" + + tag: _v.Version | _v.NonNormalizedVersion | str + """the related tag or preformatted version string""" + config: _config.Configuration + """the configuration used to parse the version""" + distance: int = 0 + """the number of commits since the tag""" + node: str | None = None + """the shortened node id""" + dirty: bool = False + """whether the working copy had uncommitted changes""" + preformatted: bool = False + """whether the version string was preformatted""" + branch: str | None = None + """the branch name if any""" + node_date: date | None = None + """the date of the commit if available""" + time: datetime = dataclasses.field(default_factory=_source_epoch_or_utc_now) + """the current time or source epoch time + only set for unit-testing version schemes + for real usage it must be `now(utc)` or `SOURCE_EPOCH` + """ + + @property + def exact(self) -> bool: + """returns true checked out exactly on a tag and no local changes apply""" + return self.distance == 0 and not self.dirty + + def __repr__(self) -> str: + return ( + f"" + ) + + def format_with(self, fmt: str, **kw: object) -> str: + """format a given format string with attributes of this object""" + return fmt.format( + time=self.time, + tag=self.tag, + distance=self.distance, + node=self.node, + dirty=self.dirty, + branch=self.branch, + node_date=self.node_date, + **kw, + ) + + def format_choice(self, clean_format: str, dirty_format: str, **kw: object) -> str: + """given `clean_format` and `dirty_format` + + choose one based on `self.dirty` and format it using `self.format_with`""" + + return self.format_with(dirty_format if self.dirty else clean_format, **kw) + + def format_next_version( + self, + guess_next: Callable[Concatenate[ScmVersion, _P], str], + fmt: str = "{guessed}.dev{distance}", + *k: _P.args, + **kw: _P.kwargs, + ) -> str: + guessed = guess_next(self, *k, **kw) + return self.format_with(fmt, guessed=guessed) + + +def _parse_tag( + tag: _VersionT | str, preformatted: bool, config: _config.Configuration +) -> _VersionT | str: + if preformatted: + return tag + elif not isinstance(tag, config.version_cls): + version = tag_to_version(tag, config) + assert version is not None + return version + else: + return tag + + +def meta( + tag: str | _VersionT, + *, + distance: int = 0, + dirty: bool = False, + node: str | None = None, + preformatted: bool = False, + branch: str | None = None, + config: _config.Configuration, + node_date: date | None = None, +) -> ScmVersion: + parsed_version = _parse_tag(tag, preformatted, config) + log.info("version %s -> %s", tag, parsed_version) + assert parsed_version is not None, "Can't parse version %s" % tag + return ScmVersion( + parsed_version, + distance=distance, + node=node, + dirty=dirty, + preformatted=preformatted, + branch=branch, + config=config, + node_date=node_date, + ) + + +def guess_next_version(tag_version: ScmVersion) -> str: + version = _modify_version.strip_local(str(tag_version.tag)) + return _modify_version._bump_dev(version) or _modify_version._bump_regex(version) + + +def guess_next_dev_version(version: ScmVersion) -> str: + if version.exact: + return version.format_with("{tag}") + else: + return version.format_next_version(guess_next_version) + + +def guess_next_simple_semver( + version: ScmVersion, retain: int, increment: bool = True +) -> str: + try: + parts = [int(i) for i in str(version.tag).split(".")[:retain]] + except ValueError: + raise ValueError(f"{version} can't be parsed as numeric version") from None + while len(parts) < retain: + parts.append(0) + if increment: + parts[-1] += 1 + while len(parts) < SEMVER_LEN: + parts.append(0) + return ".".join(str(i) for i in parts) + + +def simplified_semver_version(version: ScmVersion) -> str: + if version.exact: + return guess_next_simple_semver(version, retain=SEMVER_LEN, increment=False) + else: + if version.branch is not None and "feature" in version.branch: + return version.format_next_version( + guess_next_simple_semver, retain=SEMVER_MINOR + ) + else: + return version.format_next_version( + guess_next_simple_semver, retain=SEMVER_PATCH + ) + + +def release_branch_semver_version(version: ScmVersion) -> str: + if version.exact: + return version.format_with("{tag}") + if version.branch is not None: + # Does the branch name (stripped of namespace) parse as a version? + branch_ver_data = _parse_version_tag( + version.branch.split("/")[-1], version.config + ) + if branch_ver_data is not None: + branch_ver = branch_ver_data["version"] + if branch_ver[0] == "v": + # Allow branches that start with 'v', similar to Version. + branch_ver = branch_ver[1:] + # Does the branch version up to the minor part match the tag? If not it + # might be like, an issue number or something and not a version number, so + # we only want to use it if it matches. + tag_ver_up_to_minor = str(version.tag).split(".")[:SEMVER_MINOR] + branch_ver_up_to_minor = branch_ver.split(".")[:SEMVER_MINOR] + if branch_ver_up_to_minor == tag_ver_up_to_minor: + # We're in a release/maintenance branch, next is a patch/rc/beta bump: + return version.format_next_version(guess_next_version) + # We're in a development branch, next is a minor bump: + return version.format_next_version(guess_next_simple_semver, retain=SEMVER_MINOR) + + +def release_branch_semver(version: ScmVersion) -> str: + warnings.warn( + "release_branch_semver is deprecated and will be removed in the future. " + "Use release_branch_semver_version instead", + category=DeprecationWarning, + stacklevel=2, + ) + return release_branch_semver_version(version) + + +def no_guess_dev_version(version: ScmVersion) -> str: + if version.exact: + return version.format_with("{tag}") + else: + return version.format_next_version(_modify_version._dont_guess_next_version) + + +_DATE_REGEX = re.compile( + r""" + ^(?P + (?P[vV]?) + (?P\d{2}|\d{4})(?:\.\d{1,2}){2}) + (?:\.(?P\d*))?$ + """, + re.VERBOSE, +) + + +def date_ver_match(ver: str) -> Match[str] | None: + return _DATE_REGEX.match(ver) + + +def guess_next_date_ver( + version: ScmVersion, + node_date: date | None = None, + date_fmt: str | None = None, + version_cls: type | None = None, +) -> str: + """ + same-day -> patch +1 + other-day -> today + + distance is always added as .devX + """ + match = date_ver_match(str(version.tag)) + if match is None: + warnings.warn( + f"{version} does not correspond to a valid versioning date, " + "assuming legacy version" + ) + if date_fmt is None: + date_fmt = "%y.%m.%d" + else: + # deduct date format if not provided + if date_fmt is None: + date_fmt = "%Y.%m.%d" if len(match.group("year")) == 4 else "%y.%m.%d" + if prefix := match.group("prefix"): + if not date_fmt.startswith(prefix): + date_fmt = prefix + date_fmt + + today = version.time.date() + head_date = node_date or today + # compute patch + if match is None: + tag_date = today + else: + tag_date = ( + datetime.strptime(match.group("date"), date_fmt) + .replace(tzinfo=timezone.utc) + .date() + ) + if tag_date == head_date: + patch = "0" if match is None else (match.group("patch") or "0") + patch = int(patch) + 1 + else: + if tag_date > head_date and match is not None: + # warn on future times + warnings.warn( + f"your previous tag ({tag_date})" + f" is ahead your node date ({head_date})" + ) + patch = 0 + next_version = "{node_date:{date_fmt}}.{patch}".format( + node_date=head_date, date_fmt=date_fmt, patch=patch + ) + # rely on the Version object to ensure consistency (e.g. remove leading 0s) + if version_cls is None: + version_cls = PkgVersion + next_version = str(version_cls(next_version)) + return next_version + + +def calver_by_date(version: ScmVersion) -> str: + if version.exact and not version.dirty: + return version.format_with("{tag}") + # TODO: move the release-X check to a new scheme + if version.branch is not None and version.branch.startswith("release-"): + branch_ver = _parse_version_tag(version.branch.split("-")[-1], version.config) + if branch_ver is not None: + ver = branch_ver["version"] + match = date_ver_match(ver) + if match: + return ver + return version.format_next_version( + guess_next_date_ver, + node_date=version.node_date, + version_cls=version.config.version_cls, + ) + + +def get_local_node_and_date(version: ScmVersion) -> str: + return _modify_version._format_local_with_time(version, time_format="%Y%m%d") + + +def get_local_node_and_timestamp(version: ScmVersion) -> str: + return _modify_version._format_local_with_time(version, time_format="%Y%m%d%H%M%S") + + +def get_local_dirty_tag(version: ScmVersion) -> str: + return version.format_choice("", "+dirty") + + +def get_no_local_node(version: ScmVersion) -> str: + return "" + + +def postrelease_version(version: ScmVersion) -> str: + if version.exact: + return version.format_with("{tag}") + else: + return version.format_with("{tag}.post{distance}") + + +def format_version(version: ScmVersion) -> str: + log.debug("scm version %s", version) + log.debug("config %s", version.config) + if version.preformatted: + assert isinstance(version.tag, str) + return version.tag + main_version = _entrypoints._call_version_scheme( + version, "setuptools_scm.version_scheme", version.config.version_scheme, None + ) + log.debug("version %s", main_version) + assert main_version is not None + local_version = _entrypoints._call_version_scheme( + version, "setuptools_scm.local_scheme", version.config.local_scheme, "+unknown" + ) + log.debug("local_version %s", local_version) + return main_version + local_version diff --git a/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/LICENSE b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/LICENSE new file mode 100644 index 0000000..f26bcf4 --- /dev/null +++ b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/LICENSE @@ -0,0 +1,279 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see https://opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +Python software and documentation are licensed under the +Python Software Foundation License Version 2. + +Starting with Python 3.8.6, examples, recipes, and other code in +the documentation are dual licensed under the PSF License Version 2 +and the Zero-Clause BSD license. + +Some software incorporated into Python is under different licenses. +The licenses are listed with code falling under that license. + + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION +---------------------------------------------------------------------- + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/PKG-INFO b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/PKG-INFO new file mode 100644 index 0000000..dc7c951 --- /dev/null +++ b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/PKG-INFO @@ -0,0 +1,66 @@ +Metadata-Version: 2.1 +Name: typing_extensions +Version: 4.8.0 +Summary: Backported and Experimental Type Hints for Python 3.8+ +Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing +Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Topic :: Software Development +Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues +Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md +Project-URL: Documentation, https://typing-extensions.readthedocs.io/ +Project-URL: Home, https://github.com/python/typing_extensions +Project-URL: Q & A, https://github.com/python/typing/discussions +Project-URL: Repository, https://github.com/python/typing_extensions + +# Typing Extensions + +[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) + +[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) – +[PyPI](https://pypi.org/project/typing-extensions/) + +## Overview + +The `typing_extensions` module serves two related purposes: + +- Enable use of new type system features on older Python versions. For example, + `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows + users on previous Python versions to use it too. +- Enable experimentation with new type system PEPs before they are accepted and + added to the `typing` module. + +`typing_extensions` is treated specially by static type checkers such as +mypy and pyright. Objects defined in `typing_extensions` are treated the same +way as equivalent forms in `typing`. + +`typing_extensions` uses +[Semantic Versioning](https://semver.org/). The +major version will be incremented only for backwards-incompatible changes. +Therefore, it's safe to depend +on `typing_extensions` like this: `typing_extensions >=x.y, <(x+1)`, +where `x.y` is the first version that includes all features you need. + +## Included items + +See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a +complete listing of module contents. + +## Contributing + +See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md) +for how to contribute to `typing_extensions`. + diff --git a/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/RECORD b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/RECORD new file mode 100644 index 0000000..9fdd2a5 --- /dev/null +++ b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/RECORD @@ -0,0 +1,5 @@ +typing_extensions.py,sha256=ktWhnF_DOJuyvxy6jW0ndns3KA4byTEB9DzTtEMl26M,103397 +typing_extensions-4.8.0.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 +typing_extensions-4.8.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +typing_extensions-4.8.0.dist-info/METADATA,sha256=FwHgtsuPpRLjEsgt7mXT_fzt0jErWt5vEa2ia2kRMaY,2966 +typing_extensions-4.8.0.dist-info/RECORD,, diff --git a/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/WHEEL b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/.eggs/typing_extensions-4.8.0-py3.11.egg/EGG-INFO/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/.eggs/typing_extensions-4.8.0-py3.11.egg/typing_extensions.py b/.eggs/typing_extensions-4.8.0-py3.11.egg/typing_extensions.py new file mode 100644 index 0000000..c96bf90 --- /dev/null +++ b/.eggs/typing_extensions-4.8.0-py3.11.egg/typing_extensions.py @@ -0,0 +1,2892 @@ +import abc +import collections +import collections.abc +import functools +import inspect +import operator +import sys +import types as _types +import typing +import warnings + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'Buffer', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsAbs', + 'SupportsBytes', + 'SupportsComplex', + 'SupportsFloat', + 'SupportsIndex', + 'SupportsInt', + 'SupportsRound', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'deprecated', + 'Doc', + 'get_overloads', + 'final', + 'get_args', + 'get_origin', + 'get_original_bases', + 'get_protocol_members', + 'get_type_hints', + 'IntVar', + 'is_protocol', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeAliasType', + 'TypeGuard', + 'TYPE_CHECKING', + 'Never', + 'NoReturn', + 'Required', + 'NotRequired', + + # Pure aliases, have always been in typing + 'AbstractSet', + 'AnyStr', + 'BinaryIO', + 'Callable', + 'Collection', + 'Container', + 'Dict', + 'ForwardRef', + 'FrozenSet', + 'Generator', + 'Generic', + 'Hashable', + 'IO', + 'ItemsView', + 'Iterable', + 'Iterator', + 'KeysView', + 'List', + 'Mapping', + 'MappingView', + 'Match', + 'MutableMapping', + 'MutableSequence', + 'MutableSet', + 'Optional', + 'Pattern', + 'Reversible', + 'Sequence', + 'Set', + 'Sized', + 'TextIO', + 'Tuple', + 'Union', + 'ValuesView', + 'cast', + 'no_type_check', + 'no_type_check_decorator', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + + +class _Sentinel: + def __repr__(self): + return "" + + +_marker = _Sentinel() + + +def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + f" actual {alen}, expected {elen}") + + +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +elif sys.version_info >= (3, 9): + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) +else: + def _should_collect_from_parameters(t): + return isinstance(t, typing._GenericAlias) and not t._special + + +def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + for t in types: + if ( + isinstance(t, typevar_types) and + t not in tvars and + not _is_unpack(t) + ): + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + return tuple(tvars) + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + + +class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + +Final = typing.Final + +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +def IntVar(name): + return typing.TypeVar(name) + + +# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 +if sys.version_info >= (3, 10, 1): + Literal = typing.Literal +else: + def _flatten_literal_params(parameters): + """An internal helper for Literal creation: flatten Literals among parameters""" + params = [] + for p in parameters: + if isinstance(p, _LiteralGenericAlias): + params.extend(p.__args__) + else: + params.append(p) + return tuple(params) + + def _value_and_type_iter(params): + for p in params: + yield p, type(p) + + class _LiteralGenericAlias(typing._GenericAlias, _root=True): + def __eq__(self, other): + if not isinstance(other, _LiteralGenericAlias): + return NotImplemented + these_args_deduped = set(_value_and_type_iter(self.__args__)) + other_args_deduped = set(_value_and_type_iter(other.__args__)) + return these_args_deduped == other_args_deduped + + def __hash__(self): + return hash(frozenset(_value_and_type_iter(self.__args__))) + + class _LiteralForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, doc: str): + self._name = 'Literal' + self._doc = self.__doc__ = doc + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + + parameters = _flatten_literal_params(parameters) + + val_type_pairs = list(_value_and_type_iter(parameters)) + try: + deduped_pairs = set(val_type_pairs) + except TypeError: + # unhashable parameters + pass + else: + # similar logic to typing._deduplicate on Python 3.9+ + if len(deduped_pairs) < len(val_type_pairs): + new_parameters = [] + for pair in val_type_pairs: + if pair in deduped_pairs: + new_parameters.append(pair[0]) + deduped_pairs.remove(pair) + assert not deduped_pairs, deduped_pairs + parameters = tuple(new_parameters) + + return _LiteralGenericAlias(self, parameters) + + Literal = _LiteralForm(doc="""\ + A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +ContextManager = typing.ContextManager +AsyncContextManager = typing.AsyncContextManager +DefaultDict = typing.DefaultDict +OrderedDict = typing.OrderedDict +Counter = typing.Counter +ChainMap = typing.ChainMap +AsyncGenerator = typing.AsyncGenerator +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +_PROTO_ALLOWLIST = { + 'collections.abc': [ + 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', + 'Hashable', 'Sized', 'Container', 'Collection', 'Reversible', 'Buffer', + ], + 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], + 'typing_extensions': ['Buffer'], +} + + +_EXCLUDED_ATTRS = { + "__abstractmethods__", "__annotations__", "__weakref__", "_is_protocol", + "_is_runtime_protocol", "__dict__", "__slots__", "__parameters__", + "__orig_bases__", "__module__", "_MutableMapping__marker", "__doc__", + "__subclasshook__", "__orig_class__", "__init__", "__new__", + "__protocol_attrs__", "__callable_proto_members_only__", +} + +if sys.version_info >= (3, 9): + _EXCLUDED_ATTRS.add("__class_getitem__") + +if sys.version_info >= (3, 12): + _EXCLUDED_ATTRS.add("__type_params__") + +_EXCLUDED_ATTRS = frozenset(_EXCLUDED_ATTRS) + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in {'Protocol', 'Generic'}: + continue + annotations = getattr(base, '__annotations__', {}) + for attr in (*base.__dict__, *annotations): + if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): + attrs.add(attr) + return attrs + + +def _caller(depth=2): + try: + return sys._getframe(depth).f_globals.get('__name__', '__main__') + except (AttributeError, ValueError): # For platforms without _getframe() + return None + + +# The performance of runtime-checkable protocols is significantly improved on Python 3.12, +# so we backport the 3.12 version of Protocol to Python <=3.11 +if sys.version_info >= (3, 12): + Protocol = typing.Protocol +else: + def _allow_reckless_class_checks(depth=3): + """Allow instance and class checks for special stdlib modules. + The abc and functools modules indiscriminately call isinstance() and + issubclass() on the whole MRO of a user class, which may contain protocols. + """ + return _caller(depth) in {'abc', 'functools', None} + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + # Inheriting from typing._ProtocolMeta isn't actually desirable, + # but is necessary to allow typing.Protocol and typing_extensions.Protocol + # to mix without getting TypeErrors about "metaclass conflict" + class _ProtocolMeta(type(typing.Protocol)): + # This metaclass is somewhat unfortunate, + # but is necessary for several reasons... + # + # NOTE: DO NOT call super() in any methods in this class + # That would call the methods on typing._ProtocolMeta on Python 3.8-3.11 + # and those are slow + def __new__(mcls, name, bases, namespace, **kwargs): + if name == "Protocol" and len(bases) < 2: + pass + elif {Protocol, typing.Protocol} & set(bases): + for base in bases: + if not ( + base in {object, typing.Generic, Protocol, typing.Protocol} + or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) + or is_protocol(base) + ): + raise TypeError( + f"Protocols can only inherit from other protocols, " + f"got {base!r}" + ) + return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) + + def __init__(cls, *args, **kwargs): + abc.ABCMeta.__init__(cls, *args, **kwargs) + if getattr(cls, "_is_protocol", False): + cls.__protocol_attrs__ = _get_protocol_attrs(cls) + # PEP 544 prohibits using issubclass() + # with protocols that have non-method members. + cls.__callable_proto_members_only__ = all( + callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__ + ) + + def __subclasscheck__(cls, other): + if cls is Protocol: + return type.__subclasscheck__(cls, other) + if ( + getattr(cls, '_is_protocol', False) + and not _allow_reckless_class_checks() + ): + if not isinstance(other, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + if ( + not cls.__callable_proto_members_only__ + and cls.__dict__.get("__subclasshook__") is _proto_hook + ): + raise TypeError( + "Protocols with non-method members don't support issubclass()" + ) + if not getattr(cls, '_is_runtime_protocol', False): + raise TypeError( + "Instance and class checks can only be used with " + "@runtime_checkable protocols" + ) + return abc.ABCMeta.__subclasscheck__(cls, other) + + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if cls is Protocol: + return type.__instancecheck__(cls, instance) + if not getattr(cls, "_is_protocol", False): + # i.e., it's a concrete subclass of a protocol + return abc.ABCMeta.__instancecheck__(cls, instance) + + if ( + not getattr(cls, '_is_runtime_protocol', False) and + not _allow_reckless_class_checks() + ): + raise TypeError("Instance and class checks can only be used with" + " @runtime_checkable protocols") + + if abc.ABCMeta.__instancecheck__(cls, instance): + return True + + for attr in cls.__protocol_attrs__: + try: + val = inspect.getattr_static(instance, attr) + except AttributeError: + break + if val is None and callable(getattr(cls, attr, None)): + break + else: + return True + + return False + + def __eq__(cls, other): + # Hack so that typing.Generic.__class_getitem__ + # treats typing_extensions.Protocol + # as equivalent to typing.Protocol + if abc.ABCMeta.__eq__(cls, other) is True: + return True + return cls is Protocol and other is typing.Protocol + + # This has to be defined, or the abc-module cache + # complains about classes with this metaclass being unhashable, + # if we define only __eq__! + def __hash__(cls) -> int: + return type.__hash__(cls) + + @classmethod + def _proto_hook(cls, other): + if not cls.__dict__.get('_is_protocol', False): + return NotImplemented + + for attr in cls.__protocol_attrs__: + for base in other.__mro__: + # Check if the members appears in the class dictionary... + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + + # ...or in annotations, if it is a sub-protocol. + annotations = getattr(base, '__annotations__', {}) + if ( + isinstance(annotations, collections.abc.Mapping) + and attr in annotations + and is_protocol(other) + ): + break + else: + return NotImplemented + return True + + class Protocol(typing.Generic, metaclass=_ProtocolMeta): + __doc__ = typing.Protocol.__doc__ + __slots__ = () + _is_protocol = True + _is_runtime_protocol = False + + def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', False): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: + cls.__init__ = _no_init + + +# The "runtime" alias exists for backwards compatibility. +runtime = runtime_checkable = typing.runtime_checkable + + +# Our version of runtime-checkable protocols is faster on Python 3.8-3.11 +if sys.version_info >= (3, 12): + SupportsInt = typing.SupportsInt + SupportsFloat = typing.SupportsFloat + SupportsComplex = typing.SupportsComplex + SupportsBytes = typing.SupportsBytes + SupportsIndex = typing.SupportsIndex + SupportsAbs = typing.SupportsAbs + SupportsRound = typing.SupportsRound +else: + @runtime_checkable + class SupportsInt(Protocol): + """An ABC with one abstract method __int__.""" + __slots__ = () + + @abc.abstractmethod + def __int__(self) -> int: + pass + + @runtime_checkable + class SupportsFloat(Protocol): + """An ABC with one abstract method __float__.""" + __slots__ = () + + @abc.abstractmethod + def __float__(self) -> float: + pass + + @runtime_checkable + class SupportsComplex(Protocol): + """An ABC with one abstract method __complex__.""" + __slots__ = () + + @abc.abstractmethod + def __complex__(self) -> complex: + pass + + @runtime_checkable + class SupportsBytes(Protocol): + """An ABC with one abstract method __bytes__.""" + __slots__ = () + + @abc.abstractmethod + def __bytes__(self) -> bytes: + pass + + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + @runtime_checkable + class SupportsAbs(Protocol[T_co]): + """ + An ABC with one abstract method __abs__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __abs__(self) -> T_co: + pass + + @runtime_checkable + class SupportsRound(Protocol[T_co]): + """ + An ABC with one abstract method __round__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __round__(self, ndigits: int = 0) -> T_co: + pass + + +def _ensure_subclassable(mro_entries): + def inner(func): + if sys.implementation.name == "pypy" and sys.version_info < (3, 9): + cls_dict = { + "__call__": staticmethod(func), + "__mro_entries__": staticmethod(mro_entries) + } + t = type(func.__name__, (), cls_dict) + return functools.update_wrapper(t(), func) + else: + func.__mro_entries__ = mro_entries + return func + return inner + + +if sys.version_info >= (3, 13): + # The standard library TypedDict in Python 3.8 does not store runtime information + # about which (if any) keys are optional. See https://bugs.python.org/issue38834 + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + # Aaaand on 3.12 we add __orig_bases__ to TypedDict + # to enable better runtime introspection. + # On 3.13 we deprecate some odd ways of creating TypedDicts. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + # 3.10.0 and later + _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters + + class _TypedDictMeta(type): + def __new__(cls, name, bases, ns, total=True): + """Create new typed dict class object. + + This method is called when TypedDict is subclassed, + or when TypedDict is instantiated. This way + TypedDict supports all three syntax forms described in its docstring. + Subclasses and instances of TypedDict return actual dictionaries. + """ + for base in bases: + if type(base) is not _TypedDictMeta and base is not typing.Generic: + raise TypeError('cannot inherit from both a TypedDict type ' + 'and a non-TypedDict base class') + + if any(issubclass(b, typing.Generic) for b in bases): + generic_base = (typing.Generic,) + else: + generic_base = () + + # typing.py generally doesn't let you inherit from plain Generic, unless + # the name of the class happens to be "Protocol" + tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns) + tp_dict.__name__ = name + if tp_dict.__qualname__ == "Protocol": + tp_dict.__qualname__ = name + + if not hasattr(tp_dict, '__orig_bases__'): + tp_dict.__orig_bases__ = bases + + annotations = {} + own_annotations = ns.get('__annotations__', {}) + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + if _TAKES_MODULE: + own_annotations = { + n: typing._type_check(tp, msg, module=tp_dict.__module__) + for n, tp in own_annotations.items() + } + else: + own_annotations = { + n: typing._type_check(tp, msg) + for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + + for base in bases: + annotations.update(base.__dict__.get('__annotations__', {})) + required_keys.update(base.__dict__.get('__required_keys__', ())) + optional_keys.update(base.__dict__.get('__optional_keys__', ())) + + annotations.update(own_annotations) + for annotation_key, annotation_type in own_annotations.items(): + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + annotation_origin = get_origin(annotation_type) + + if annotation_origin is Required: + required_keys.add(annotation_key) + elif annotation_origin is NotRequired: + optional_keys.add(annotation_key) + elif total: + required_keys.add(annotation_key) + else: + optional_keys.add(annotation_key) + + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + if not hasattr(tp_dict, '__total__'): + tp_dict.__total__ = total + return tp_dict + + __call__ = dict # static method + + def __subclasscheck__(cls, other): + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + + __instancecheck__ = __subclasscheck__ + + _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) + + @_ensure_subclassable(lambda bases: (_TypedDict,)) + def TypedDict(typename, fields=_marker, /, *, total=True, **kwargs): + """A simple typed namespace. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type such that a type checker will expect all + instances to have a certain set of keys, where each key is + associated with a value of a consistent type. This expectation + is not checked at runtime. + + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports an additional equivalent form:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + By default, all keys must be present in a TypedDict. It is possible + to override this by specifying totality:: + + class Point2D(TypedDict, total=False): + x: int + y: int + + This means that a Point2D TypedDict can have any of the keys omitted. A type + checker is only expected to support a literal False or True as the value of + the total argument. True is the default, and makes all items defined in the + class body be required. + + The Required and NotRequired special forms can also be used to mark + individual keys as being required or not required:: + + class Point2D(TypedDict): + x: int # the "x" key must always be present (Required is the default) + y: NotRequired[int] # the "y" key can be omitted + + See PEP 655 for more details on Required and NotRequired. + """ + if fields is _marker or fields is None: + if fields is _marker: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + + example = f"`{typename} = TypedDict({typename!r}, {{}})`" + deprecation_msg = ( + f"{deprecated_thing} is deprecated and will be disallowed in " + "Python 3.15. To create a TypedDict class with 0 fields " + "using the functional syntax, pass an empty dictionary, e.g. " + ) + example + "." + warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + if kwargs: + warnings.warn( + "The kwargs-based syntax for TypedDict definitions is deprecated " + "in Python 3.11, will be removed in Python 3.13, and may not be " + "understood by third-party type checkers.", + DeprecationWarning, + stacklevel=2, + ) + + ns = {'__annotations__': dict(fields)} + module = _caller() + if module is not None: + # Setting correct module is necessary to make typed dict classes pickleable. + ns['__module__'] = module + + td = _TypedDictMeta(typename, (), ns, total=total) + td.__orig_bases__ = (TypedDict,) + return td + + if hasattr(typing, "_TypedDictMeta"): + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + else: + _TYPEDDICT_TYPES = (_TypedDictMeta,) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + # On 3.8, this would otherwise return True + if hasattr(typing, "TypedDict") and tp is typing.TypedDict: + return False + return isinstance(tp, _TYPEDDICT_TYPES) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(val, typ, /): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return val + + +if hasattr(typing, "Required"): # 3.11+ + get_type_hints = typing.get_type_hints +else: # <=3.10 + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, _AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return _types.GenericAlias(t.__origin__, stripped_args) + if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if hasattr(typing, "Annotated"): # 3.9+ + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + else: # 3.8 + hint = typing.get_type_hints(obj, globalns=globalns, localns=localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + +# Python 3.9+ has PEP 593 (Annotated) +if hasattr(typing, 'Annotated'): + Annotated = typing.Annotated + # Not exported and not a public API, but needed for get_origin() and get_args() + # to work. + _AnnotatedAlias = typing._AnnotatedAlias +# 3.8 +else: + class _AnnotatedAlias(typing._GenericAlias, _root=True): + """Runtime representation of an annotated type. + + At its core 'Annotated[t, dec1, dec2, ...]' is an alias for the type 't' + with extra annotations. The alias behaves like a normal typing alias, + instantiating is the same as instantiating the underlying type, binding + it to types is also the same. + """ + def __init__(self, origin, metadata): + if isinstance(origin, _AnnotatedAlias): + metadata = origin.__metadata__ + metadata + origin = origin.__origin__ + super().__init__(origin, origin) + self.__metadata__ = metadata + + def copy_with(self, params): + assert len(params) == 1 + new_type = params[0] + return _AnnotatedAlias(new_type, self.__metadata__) + + def __repr__(self): + return (f"typing_extensions.Annotated[{typing._type_repr(self.__origin__)}, " + f"{', '.join(repr(a) for a in self.__metadata__)}]") + + def __reduce__(self): + return operator.getitem, ( + Annotated, (self.__origin__,) + self.__metadata__ + ) + + def __eq__(self, other): + if not isinstance(other, _AnnotatedAlias): + return NotImplemented + if self.__origin__ != other.__origin__: + return False + return self.__metadata__ == other.__metadata__ + + def __hash__(self): + return hash((self.__origin__, self.__metadata__)) + + class Annotated: + """Add context specific metadata to a type. + + Example: Annotated[int, runtime_check.Unsigned] indicates to the + hypothetical runtime_check module that this type is an unsigned int. + Every other consumer of this type can ignore this metadata and treat + this type as int. + + The first argument to Annotated must be a valid type (and will be in + the __origin__ field), the remaining arguments are kept as a tuple in + the __extra__ field. + + Details: + + - It's an error to call `Annotated` with less than two arguments. + - Nested Annotated are flattened:: + + Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3] + + - Instantiating an annotated type is equivalent to instantiating the + underlying type:: + + Annotated[C, Ann1](5) == C(5) + + - Annotated can be used as a generic type alias:: + + Optimized = Annotated[T, runtime.Optimize()] + Optimized[int] == Annotated[int, runtime.Optimize()] + + OptimizedList = Annotated[List[T], runtime.Optimize()] + OptimizedList[int] == Annotated[List[int], runtime.Optimize()] + """ + + __slots__ = () + + def __new__(cls, *args, **kwargs): + raise TypeError("Type Annotated cannot be instantiated.") + + @typing._tp_cache + def __class_getitem__(cls, params): + if not isinstance(params, tuple) or len(params) < 2: + raise TypeError("Annotated[...] should be used " + "with at least two arguments (a type and an " + "annotation).") + allowed_special_forms = (ClassVar, Final) + if get_origin(params[0]) in allowed_special_forms: + origin = params[0] + else: + msg = "Annotated[t, ...]: t must be a type." + origin = typing._type_check(params[0], msg) + metadata = tuple(params[1:]) + return _AnnotatedAlias(origin, metadata) + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + f"Cannot subclass {cls.__module__}.Annotated" + ) + +# Python 3.8 has get_origin() and get_args() but those implementations aren't +# Annotated-aware, so we can't use those. Python 3.9's versions don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +if sys.version_info[:2] >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.8-3.9 +else: + try: + # 3.9+ + from typing import _BaseGenericAlias + except ImportError: + _BaseGenericAlias = typing._GenericAlias + try: + # 3.9+ + from typing import GenericAlias as _typing_GenericAlias + except ImportError: + _typing_GenericAlias = typing._GenericAlias + + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, _AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias, _BaseGenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, _AnnotatedAlias): + return (tp.__origin__,) + tp.__metadata__ + if isinstance(tp, (typing._GenericAlias, _typing_GenericAlias)): + if getattr(tp, "_special", False): + return () + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") +# 3.8 +else: + TypeAlias = _ExtensionsSpecialForm( + 'TypeAlias', + doc="""Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example + above.""" + ) + + +def _set_default(type_param, default): + if isinstance(default, (tuple, list)): + type_param.__default__ = tuple((typing._type_check(d, "Default must be a type") + for d in default)) + elif default != _marker: + if isinstance(type_param, ParamSpec) and default is ...: # ... not valid <3.11 + type_param.__default__ = default + else: + type_param.__default__ = typing._type_check(default, "Default must be a type") + else: + type_param.__default__ = None + + +def _set_module(typevarlike): + # for pickling: + def_mod = _caller(depth=3) + if def_mod != 'typing_extensions': + typevarlike.__module__ = def_mod + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + __init__ = _set_default + + +# Classes using this metaclass must provide a _backported_typevarlike ClassVar +class _TypeVarLikeMeta(type): + def __instancecheck__(cls, __instance: Any) -> bool: + return isinstance(__instance, cls._backported_typevarlike) + + +# Add default and infer_variance parameters from PEP 696 and 695 +class TypeVar(metaclass=_TypeVarLikeMeta): + """Type variable.""" + + _backported_typevarlike = typing.TypeVar + + def __new__(cls, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=_marker, infer_variance=False): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant, + infer_variance=infer_variance) + else: + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant) + if infer_variance and (covariant or contravariant): + raise ValueError("Variance cannot be specified with infer_variance.") + typevar.__infer_variance__ = infer_variance + _set_default(typevar, default) + _set_module(typevar) + return typevar + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.8-3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + +# 3.10+ +if hasattr(typing, 'ParamSpec'): + + # Add default parameter - PEP 696 + class ParamSpec(metaclass=_TypeVarLikeMeta): + """Parameter specification.""" + + _backported_typevarlike = typing.ParamSpec + + def __new__(cls, name, *, bound=None, + covariant=False, contravariant=False, + infer_variance=False, default=_marker): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented, can pass infer_variance to typing.TypeVar + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant, + infer_variance=infer_variance) + else: + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant) + paramspec.__infer_variance__ = infer_variance + + _set_default(paramspec, default) + _set_module(paramspec) + return paramspec + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") + +# 3.8-3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + infer_variance=False, default=_marker): + super().__init__([self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + self.__infer_variance__ = bool(infer_variance) + if bound: + self.__bound__ = typing._type_check(bound, 'Bound must be a type.') + else: + self.__bound__ = None + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__infer_variance__: + prefix = '' + elif self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + +# 3.8-3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + # Flag in 3.8. + _special = False + + def __init__(self, origin, args): + super().__init__(args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + +# 3.8-3.9 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not isinstance(parameters[-1], ParamSpec): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = tuple(typing._type_check(p, msg) for p in parameters) + return _ConcatenateGenericAlias(self, parameters) + + +# 3.10+ +if hasattr(typing, 'Concatenate'): + Concatenate = typing.Concatenate + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias # noqa: F811 +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) +# 3.8 +else: + class _ConcatenateForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + return _concatenate_getitem(self, parameters) + + Concatenate = _ConcatenateForm( + 'Concatenate', + doc="""Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """) + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +elif sys.version_info[:2] >= (3, 9): + @_ExtensionsSpecialForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) +# 3.8 +else: + class _TypeGuardForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type') + return typing._GenericAlias(self, (item,)) + + TypeGuard = _TypeGuardForm( + 'TypeGuard', + doc="""Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """) + + +# Vendored from cpython typing._SpecialFrom +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +if hasattr(typing, "LiteralString"): # 3.11+ + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): # 3.11+ + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): # 3.11+ + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): # 3.11+ + Required = typing.Required + NotRequired = typing.NotRequired +elif sys.version_info[:2] >= (3, 9): # 3.9-3.10 + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + +else: # 3.8 + class _RequiredForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + Required = _RequiredForm( + 'Required', + doc="""A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """) + NotRequired = _RequiredForm( + 'NotRequired', + doc="""A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """) + + +_UNPACK_DOC = """\ +Type unpack operator. + +The type unpack operator takes the child types from some container type, +such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For +example: + + # For some generic class `Foo`: + Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] + + Ts = TypeVarTuple('Ts') + # Specifies that `Bar` is generic in an arbitrary number of types. + # (Think of `Ts` as a tuple of an arbitrary number of individual + # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the + # `Generic[]`.) + class Bar(Generic[Unpack[Ts]]): ... + Bar[int] # Valid + Bar[int, str] # Also valid + +From Python 3.11, this can also be done using the `*` operator: + + Foo[*tuple[int, str]] + class Bar(Generic[*Ts]): ... + +The operator can also be used along with a `TypedDict` to annotate +`**kwargs` in a function signature. For instance: + + class Movie(TypedDict): + name: str + year: int + + # This function expects two keyword arguments - *name* of type `str` and + # *year* of type `int`. + def foo(**kwargs: Unpack[Movie]): ... + +Note that there is only some runtime checking of this operator. Not +everything the runtime allows may be accepted by static type checkers. + +For more information, see PEP 646 and PEP 692. +""" + + +if sys.version_info >= (3, 12): # PEP 692 changed the repr of Unpack[] + Unpack = typing.Unpack + + def _is_unpack(obj): + return get_origin(obj) is Unpack + +elif sys.version_info[:2] >= (3, 9): # 3.9+ + class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, getitem): + super().__init__(getitem) + self.__doc__ = _UNPACK_DOC + + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + @_UnpackSpecialForm + def Unpack(self, parameters): + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + +else: # 3.8 + class _UnpackAlias(typing._GenericAlias, _root=True): + __class__ = typing.TypeVar + + class _UnpackForm(_ExtensionsSpecialForm, _root=True): + def __getitem__(self, parameters): + item = typing._type_check(parameters, + f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + Unpack = _UnpackForm('Unpack', doc=_UNPACK_DOC) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +if hasattr(typing, "TypeVarTuple"): # 3.11+ + + # Add default parameter - PEP 696 + class TypeVarTuple(metaclass=_TypeVarLikeMeta): + """Type variable tuple.""" + + _backported_typevarlike = typing.TypeVarTuple + + def __new__(cls, name, *, default=_marker): + tvt = typing.TypeVarTuple(name) + _set_default(tvt, default) + _set_module(tvt) + return tvt + + def __init_subclass__(self, *args, **kwds): + raise TypeError("Cannot subclass special typing classes") + +else: # <=3.10 + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, default=_marker): + self.__name__ = name + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + return self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): # 3.11+ + reveal_type = typing.reveal_type +else: # <=3.10 + def reveal_type(obj: T, /) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) + return obj + + +if hasattr(typing, "assert_never"): # 3.11+ + assert_never = typing.assert_never +else: # <=3.10 + def assert_never(arg: Never, /) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + raise AssertionError("Expected code to be unreachable") + + +if sys.version_info >= (3, 12): # 3.12+ + # dataclass_transform exists in 3.11 but lacks the frozen_default parameter + dataclass_transform = typing.dataclass_transform +else: # <=3.11 + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + frozen_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``frozen_default`` indicates whether the ``frozen`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "frozen_default": frozen_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): # 3.12+ + override = typing.override +else: # <=3.11 + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(arg: _F, /) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: ... + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + There is no runtime checking of these properties. The decorator + sets the ``__override__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + + See PEP 698 for details. + + """ + try: + arg.__override__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return arg + + +if hasattr(typing, "deprecated"): + deprecated = typing.deprecated +else: + _T = typing.TypeVar("_T") + + def deprecated( + msg: str, + /, + *, + category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, + stacklevel: int = 1, + ) -> typing.Callable[[_T], _T]: + """Indicate that a class, function or overload is deprecated. + + Usage: + + @deprecated("Use B instead") + class A: + pass + + @deprecated("Use g instead") + def f(): + pass + + @overload + @deprecated("int support is deprecated") + def g(x: int) -> int: ... + @overload + def g(x: str) -> int: ... + + When this decorator is applied to an object, the type checker + will generate a diagnostic on usage of the deprecated object. + + The warning specified by ``category`` will be emitted on use + of deprecated objects. For functions, that happens on calls; + for classes, on instantiation. If the ``category`` is ``None``, + no warning is emitted. The ``stacklevel`` determines where the + warning is emitted. If it is ``1`` (the default), the warning + is emitted at the direct caller of the deprecated object; if it + is higher, it is emitted further up the stack. + + The decorator sets the ``__deprecated__`` + attribute on the decorated object to the deprecation message + passed to the decorator. If applied to an overload, the decorator + must be after the ``@overload`` decorator for the attribute to + exist on the overload as returned by ``get_overloads()``. + + See PEP 702 for details. + + """ + def decorator(arg: _T, /) -> _T: + if category is None: + arg.__deprecated__ = msg + return arg + elif isinstance(arg, type): + original_new = arg.__new__ + has_init = arg.__init__ is not object.__init__ + + @functools.wraps(original_new) + def __new__(cls, *args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + if original_new is not object.__new__: + return original_new(cls, *args, **kwargs) + # Mirrors a similar check in object.__new__. + elif not has_init and (args or kwargs): + raise TypeError(f"{cls.__name__}() takes no arguments") + else: + return original_new(cls) + + arg.__new__ = staticmethod(__new__) + arg.__deprecated__ = __new__.__deprecated__ = msg + return arg + elif callable(arg): + @functools.wraps(arg) + def wrapper(*args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return arg(*args, **kwargs) + + arg.__deprecated__ = wrapper.__deprecated__ = msg + return wrapper + else: + raise TypeError( + "@deprecated decorator with non-None category must be applied to " + f"a class or callable, not {arg!r}" + ) + + return decorator + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + typing._collect_type_vars = _collect_type_vars + typing._check_generic = _check_generic + + +# Backport typing.NamedTuple as it exists in Python 3.13. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +# On 3.12, we added __orig_bases__ to call-based NamedTuples +# On 3.13, we deprecated kwargs-based NamedTuples +if sys.version_info >= (3, 13): + NamedTuple = typing.NamedTuple +else: + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + # The `_field_types` attribute was removed in 3.9; + # in earlier versions, it is the same as the `__annotations__` attribute + if sys.version_info < (3, 9): + nm_tpl._field_types = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + types = ns.get('__annotations__', {}) + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + if hasattr(typing, '_generic_class_getitem'): # 3.12+ + nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) + else: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key in ns: + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields and key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + @_ensure_subclassable(_namedtuple_mro_entries) + def NamedTuple(typename, fields=_marker, /, **kwargs): + """Typed version of namedtuple. + + Usage:: + + class Employee(NamedTuple): + name: str + id: int + + This is equivalent to:: + + Employee = collections.namedtuple('Employee', ['name', 'id']) + + The resulting class has an extra __annotations__ attribute, giving a + dict that maps field names to types. (The field names are also in + the _fields attribute, which is part of the namedtuple API.) + An alternative equivalent functional syntax is also accepted:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + """ + if fields is _marker: + if kwargs: + deprecated_thing = "Creating NamedTuple classes using keyword arguments" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "Use the class-based or functional syntax instead." + ) + else: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif fields is None: + if kwargs: + raise TypeError( + "Cannot pass `None` as the 'fields' parameter " + "and also specify fields using keyword arguments" + ) + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + if fields is _marker or fields is None: + warnings.warn( + deprecation_msg.format(name=deprecated_thing, remove="3.15"), + DeprecationWarning, + stacklevel=2, + ) + fields = kwargs.items() + nt = _make_nmtuple(typename, fields, module=_caller()) + nt.__orig_bases__ = (NamedTuple,) + return nt + + +if hasattr(collections.abc, "Buffer"): + Buffer = collections.abc.Buffer +else: + class Buffer(abc.ABC): + """Base class for classes that implement the buffer protocol. + + The buffer protocol allows Python objects to expose a low-level + memory buffer interface. Before Python 3.12, it is not possible + to implement the buffer protocol in pure Python code, or even + to check whether a class implements the buffer protocol. In + Python 3.12 and higher, the ``__buffer__`` method allows access + to the buffer protocol from Python code, and the + ``collections.abc.Buffer`` ABC allows checking whether a class + implements the buffer protocol. + + To indicate support for the buffer protocol in earlier versions, + inherit from this ABC, either in a stub file or at runtime, + or use ABC registration. This ABC provides no methods, because + there is no Python-accessible methods shared by pre-3.12 buffer + classes. It is useful primarily for static checks. + + """ + + # As a courtesy, register the most common stdlib buffer classes. + Buffer.register(memoryview) + Buffer.register(bytearray) + Buffer.register(bytes) + + +# Backport of types.get_original_bases, available on 3.12+ in CPython +if hasattr(_types, "get_original_bases"): + get_original_bases = _types.get_original_bases +else: + def get_original_bases(cls, /): + """Return the class's "original" bases prior to modification by `__mro_entries__`. + + Examples:: + + from typing import TypeVar, Generic + from typing_extensions import NamedTuple, TypedDict + + T = TypeVar("T") + class Foo(Generic[T]): ... + class Bar(Foo[int], float): ... + class Baz(list[str]): ... + Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) + Spam = TypedDict("Spam", {"a": int, "b": str}) + + assert get_original_bases(Bar) == (Foo[int], float) + assert get_original_bases(Baz) == (list[str],) + assert get_original_bases(Eggs) == (NamedTuple,) + assert get_original_bases(Spam) == (TypedDict,) + assert get_original_bases(int) == (object,) + """ + try: + return cls.__dict__.get("__orig_bases__", cls.__bases__) + except AttributeError: + raise TypeError( + f'Expected an instance of type, not {type(cls).__name__!r}' + ) from None + + +# NewType is a class on Python 3.10+, making it pickleable +# The error message for subclassing instances of NewType was improved on 3.11+ +if sys.version_info >= (3, 11): + NewType = typing.NewType +else: + class NewType: + """NewType creates simple unique types with almost zero + runtime overhead. NewType(name, tp) is considered a subtype of tp + by static type checkers. At runtime, NewType(name, tp) returns + a dummy callable that simply returns its argument. Usage:: + UserId = NewType('UserId', int) + def name_by_id(user_id: UserId) -> str: + ... + UserId('user') # Fails type check + name_by_id(42) # Fails type check + name_by_id(UserId(42)) # OK + num = UserId(5) + 1 # type: int + """ + + def __call__(self, obj): + return obj + + def __init__(self, name, tp): + self.__qualname__ = name + if '.' in name: + name = name.rpartition('.')[-1] + self.__name__ = name + self.__supertype__ = tp + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __mro_entries__(self, bases): + # We defined __mro_entries__ to get a better error message + # if a user attempts to subclass a NewType instance. bpo-46170 + supercls_name = self.__name__ + + class Dummy: + def __init_subclass__(cls): + subcls_name = cls.__name__ + raise TypeError( + f"Cannot subclass an instance of NewType. " + f"Perhaps you were looking for: " + f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" + ) + + return (Dummy,) + + def __repr__(self): + return f'{self.__module__}.{self.__qualname__}' + + def __reduce__(self): + return self.__qualname__ + + if sys.version_info >= (3, 10): + # PEP 604 methods + # It doesn't make sense to have these methods on Python <3.10 + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + +if hasattr(typing, "TypeAliasType"): + TypeAliasType = typing.TypeAliasType +else: + def _is_unionable(obj): + """Corresponds to is_unionable() in unionobject.c in CPython.""" + return obj is None or isinstance(obj, ( + type, + _types.GenericAlias, + _types.UnionType, + TypeAliasType, + )) + + class TypeAliasType: + """Create named, parameterized type aliases. + + This provides a backport of the new `type` statement in Python 3.12: + + type ListOrSet[T] = list[T] | set[T] + + is equivalent to: + + T = TypeVar("T") + ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) + + The name ListOrSet can then be used as an alias for the type it refers to. + + The type_params argument should contain all the type parameters used + in the value of the type alias. If the alias is not generic, this + argument is omitted. + + Static type checkers should only support type aliases declared using + TypeAliasType that follow these rules: + + - The first argument (the name) must be a string literal. + - The TypeAliasType instance must be immediately assigned to a variable + of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, + as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). + + """ + + def __init__(self, name: str, value, *, type_params=()): + if not isinstance(name, str): + raise TypeError("TypeAliasType name must be a string") + self.__value__ = value + self.__type_params__ = type_params + + parameters = [] + for type_param in type_params: + if isinstance(type_param, TypeVarTuple): + parameters.extend(type_param) + else: + parameters.append(type_param) + self.__parameters__ = tuple(parameters) + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + # Setting this attribute closes the TypeAliasType from further modification + self.__name__ = name + + def __setattr__(self, name: str, value: object, /) -> None: + if hasattr(self, "__name__"): + self._raise_attribute_error(name) + super().__setattr__(name, value) + + def __delattr__(self, name: str, /) -> Never: + self._raise_attribute_error(name) + + def _raise_attribute_error(self, name: str) -> Never: + # Match the Python 3.12 error messages exactly + if name == "__name__": + raise AttributeError("readonly attribute") + elif name in {"__value__", "__type_params__", "__parameters__", "__module__"}: + raise AttributeError( + f"attribute '{name}' of 'typing.TypeAliasType' objects " + "is not writable" + ) + else: + raise AttributeError( + f"'typing.TypeAliasType' object has no attribute '{name}'" + ) + + def __repr__(self) -> str: + return self.__name__ + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + parameters = [ + typing._type_check( + item, f'Subscripting {self.__name__} requires a type.' + ) + for item in parameters + ] + return typing._GenericAlias(self, tuple(parameters)) + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + "type 'typing_extensions.TypeAliasType' is not an acceptable base type" + ) + + # The presence of this method convinces typing._type_check + # that TypeAliasTypes are types. + def __call__(self): + raise TypeError("Type alias is not callable") + + if sys.version_info >= (3, 10): + def __or__(self, right): + # For forward compatibility with 3.12, reject Unions + # that are not accepted by the built-in Union. + if not _is_unionable(right): + return NotImplemented + return typing.Union[self, right] + + def __ror__(self, left): + if not _is_unionable(left): + return NotImplemented + return typing.Union[left, self] + + +if hasattr(typing, "is_protocol"): + is_protocol = typing.is_protocol + get_protocol_members = typing.get_protocol_members +else: + def is_protocol(tp: type, /) -> bool: + """Return True if the given type is a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, is_protocol + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> is_protocol(P) + True + >>> is_protocol(int) + False + """ + return ( + isinstance(tp, type) + and getattr(tp, '_is_protocol', False) + and tp is not Protocol + and tp is not typing.Protocol + ) + + def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]: + """Return the set of members defined in a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) + frozenset({'a', 'b'}) + + Raise a TypeError for arguments that are not Protocols. + """ + if not is_protocol(tp): + raise TypeError(f'{tp!r} is not a Protocol') + if hasattr(tp, '__protocol_attrs__'): + return frozenset(tp.__protocol_attrs__) + return frozenset(_get_protocol_attrs(tp)) + + +if hasattr(typing, "Doc"): + Doc = typing.Doc +else: + class Doc: + """Define the documentation of a type annotation using ``Annotated``, to be + used in class attributes, function and method parameters, return values, + and variables. + + The value should be a positional-only string literal to allow static tools + like editors and documentation generators to use it. + + This complements docstrings. + + The string value passed is available in the attribute ``documentation``. + + Example:: + + >>> from typing_extensions import Annotated, Doc + >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ... + """ + def __init__(self, documentation: str, /) -> None: + self.documentation = documentation + + def __repr__(self) -> str: + return f"Doc({self.documentation!r})" + + def __hash__(self) -> int: + return hash(self.documentation) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Doc): + return NotImplemented + return self.documentation == other.documentation + + +# Aliases for items that have always been in typing. +# Explicitly assign these (rather than using `from typing import *` at the top), +# so that we get a CI error if one of these is deleted from typing.py +# in a future version of Python +AbstractSet = typing.AbstractSet +AnyStr = typing.AnyStr +BinaryIO = typing.BinaryIO +Callable = typing.Callable +Collection = typing.Collection +Container = typing.Container +Dict = typing.Dict +ForwardRef = typing.ForwardRef +FrozenSet = typing.FrozenSet +Generator = typing.Generator +Generic = typing.Generic +Hashable = typing.Hashable +IO = typing.IO +ItemsView = typing.ItemsView +Iterable = typing.Iterable +Iterator = typing.Iterator +KeysView = typing.KeysView +List = typing.List +Mapping = typing.Mapping +MappingView = typing.MappingView +Match = typing.Match +MutableMapping = typing.MutableMapping +MutableSequence = typing.MutableSequence +MutableSet = typing.MutableSet +Optional = typing.Optional +Pattern = typing.Pattern +Reversible = typing.Reversible +Sequence = typing.Sequence +Set = typing.Set +Sized = typing.Sized +TextIO = typing.TextIO +Tuple = typing.Tuple +Union = typing.Union +ValuesView = typing.ValuesView +cast = typing.cast +no_type_check = typing.no_type_check +no_type_check_decorator = typing.no_type_check_decorator diff --git a/README.md b/README.md index e715af5..0f8a1ef 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # CI MPM Toy repo with some simple functions for the CI lecture + +test change! diff --git a/simple_functions.egg-info/PKG-INFO b/simple_functions.egg-info/PKG-INFO new file mode 100644 index 0000000..4612ff5 --- /dev/null +++ b/simple_functions.egg-info/PKG-INFO @@ -0,0 +1,7 @@ +Metadata-Version: 2.1 +Name: simple-functions +Version: 0.1.dev14+g336efd1 +Summary: Environment for playing with CI. +Home-page: https://github.com/rhodrin/ci_mpm +Author: Imperial College London +Author-email: rhodri.nelson@imperial.ac.uk diff --git a/simple_functions.egg-info/SOURCES.txt b/simple_functions.egg-info/SOURCES.txt new file mode 100644 index 0000000..70eeb0c --- /dev/null +++ b/simple_functions.egg-info/SOURCES.txt @@ -0,0 +1,13 @@ +README.md +environment.yml +requirements.txt +setup.py +.github/workflows/flake8.yml +.github/workflows/pytest-unit-tests.yml +simple_functions/__init__.py +simple_functions/functions1.py +simple_functions.egg-info/PKG-INFO +simple_functions.egg-info/SOURCES.txt +simple_functions.egg-info/dependency_links.txt +simple_functions.egg-info/top_level.txt +tests/test_simple_functions.py \ No newline at end of file diff --git a/simple_functions.egg-info/dependency_links.txt b/simple_functions.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/simple_functions.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/simple_functions.egg-info/top_level.txt b/simple_functions.egg-info/top_level.txt new file mode 100644 index 0000000..a4ba85f --- /dev/null +++ b/simple_functions.egg-info/top_level.txt @@ -0,0 +1 @@ +simple_functions