python-discovery 1.4.3__tar.gz → 1.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_discovery-1.5.0/.github/FUNDING.yaml +2 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.github/workflows/check.yaml +3 -4
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.github/workflows/prepare-release.yaml +1 -10
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.github/workflows/release.yaml +1 -5
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.pre-commit-config.yaml +17 -10
- {python_discovery-1.4.3 → python_discovery-1.5.0}/PKG-INFO +2 -14
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/changelog.rst +19 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/conf.py +1 -1
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/explanation.rst +16 -2
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/how-to/standalone-usage.rst +21 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/tutorial/getting-started.rst +11 -5
- {python_discovery-1.4.3 → python_discovery-1.5.0}/pyproject.toml +17 -16
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_cache.py +5 -5
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_cached_py_info.py +4 -4
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_discovery.py +2 -2
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_py_info.py +23 -16
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_py_spec.py +14 -5
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_specifier.py +2 -2
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_windows/_pep514.py +11 -11
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tasks/release.py +35 -35
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/py_info/test_py_info.py +40 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_discovery.py +2 -1
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_py_info_extra.py +4 -1
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_py_spec.py +26 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_py_spec_extra.py +9 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_specifier.py +5 -5
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/windows/conftest.py +1 -1
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tox.toml +4 -4
- python_discovery-1.4.3/.github/FUNDING.yaml +0 -1
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.github/SECURITY.md +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.github/dependabot.yaml +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.github/release.yaml +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.gitignore +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.readthedocs.yaml +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/.readthedocs.yml +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/CODE_OF_CONDUCT.md +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/LICENSE +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/README.md +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/_static/custom.css +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/_static/logo.svg +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/changelog/template.jinja2 +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/index.rst +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/reference/api.rst +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/docs/reference/environment-variables.rst +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/__init__.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_compat.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_windows/__init__.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/_windows/_propose.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/src/python_discovery/py.typed +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/conftest.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/py_info/test_py_info_exe_based_of.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_cache.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_cached_py_info.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_discovery_extra.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/test_iter_interpreters.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/windows/test_windows.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/windows/test_windows_pep514.py +0 -0
- {python_discovery-1.4.3 → python_discovery-1.5.0}/tests/windows/winreg_mock_values.py +0 -0
|
@@ -7,14 +7,11 @@ on:
|
|
|
7
7
|
pull_request:
|
|
8
8
|
schedule:
|
|
9
9
|
- cron: "0 8 * * *"
|
|
10
|
-
|
|
11
10
|
concurrency:
|
|
12
11
|
group: check-${{ github.ref }}
|
|
13
12
|
cancel-in-progress: true
|
|
14
|
-
|
|
15
13
|
permissions:
|
|
16
14
|
contents: read
|
|
17
|
-
|
|
18
15
|
jobs:
|
|
19
16
|
test:
|
|
20
17
|
runs-on: ubuntu-latest
|
|
@@ -22,6 +19,8 @@ jobs:
|
|
|
22
19
|
fail-fast: false
|
|
23
20
|
matrix:
|
|
24
21
|
env:
|
|
22
|
+
- "3.15"
|
|
23
|
+
- "3.15t"
|
|
25
24
|
- "3.14"
|
|
26
25
|
- "3.13"
|
|
27
26
|
- "3.12"
|
|
@@ -39,7 +38,7 @@ jobs:
|
|
|
39
38
|
fetch-depth: 0
|
|
40
39
|
persist-credentials: false
|
|
41
40
|
- name: Install the latest version of uv
|
|
42
|
-
uses: astral-sh/setup-uv@
|
|
41
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
43
42
|
with:
|
|
44
43
|
enable-cache: false
|
|
45
44
|
cache-dependency-glob: "pyproject.toml"
|
|
@@ -12,13 +12,10 @@ on:
|
|
|
12
12
|
- minor
|
|
13
13
|
- patch
|
|
14
14
|
default: auto
|
|
15
|
-
|
|
16
15
|
permissions:
|
|
17
16
|
contents: read
|
|
18
|
-
|
|
19
17
|
env:
|
|
20
18
|
FORCE_COLOR: 1
|
|
21
|
-
|
|
22
19
|
jobs:
|
|
23
20
|
prepare-release:
|
|
24
21
|
runs-on: ubuntu-24.04
|
|
@@ -31,19 +28,16 @@ jobs:
|
|
|
31
28
|
fetch-depth: 0
|
|
32
29
|
token: ${{ secrets.RELEASE_PAT }}
|
|
33
30
|
persist-credentials: true
|
|
34
|
-
|
|
35
31
|
- name: Install the latest version of uv
|
|
36
|
-
uses: astral-sh/setup-uv@
|
|
32
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
37
33
|
with:
|
|
38
34
|
enable-cache: true
|
|
39
35
|
cache-dependency-glob: "pyproject.toml"
|
|
40
36
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
-
|
|
42
37
|
- name: Configure git
|
|
43
38
|
run: |
|
|
44
39
|
git config user.name "${GITHUB_ACTOR}"
|
|
45
40
|
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
|
46
|
-
|
|
47
41
|
- name: Calculate next version
|
|
48
42
|
id: version
|
|
49
43
|
env:
|
|
@@ -84,16 +78,13 @@ jobs:
|
|
|
84
78
|
|
|
85
79
|
echo "Next version: $next"
|
|
86
80
|
echo "version=$next" >> $GITHUB_OUTPUT
|
|
87
|
-
|
|
88
81
|
- name: Install tox
|
|
89
82
|
run: uv tool install --python-preference only-managed --python 3.14 tox@latest --with tox-uv
|
|
90
|
-
|
|
91
83
|
- name: Run release process
|
|
92
84
|
run: tox run -e release -- ${STEPS_VERSION_OUTPUTS_VERSION}
|
|
93
85
|
env:
|
|
94
86
|
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
|
|
95
87
|
STEPS_VERSION_OUTPUTS_VERSION: ${{ steps.version.outputs.version }}
|
|
96
|
-
|
|
97
88
|
- name: Display completion message
|
|
98
89
|
run: echo "Release ${STEPS_VERSION_OUTPUTS_VERSION} prepared and pushed successfully!"
|
|
99
90
|
env:
|
|
@@ -2,13 +2,10 @@ name: Release to PyPI
|
|
|
2
2
|
on:
|
|
3
3
|
push:
|
|
4
4
|
tags: ["*"]
|
|
5
|
-
|
|
6
5
|
permissions:
|
|
7
6
|
contents: read
|
|
8
|
-
|
|
9
7
|
env:
|
|
10
8
|
dists-artifact-name: python-package-distributions
|
|
11
|
-
|
|
12
9
|
jobs:
|
|
13
10
|
build:
|
|
14
11
|
runs-on: ubuntu-latest
|
|
@@ -18,7 +15,7 @@ jobs:
|
|
|
18
15
|
fetch-depth: 0
|
|
19
16
|
persist-credentials: false
|
|
20
17
|
- name: Install the latest version of uv
|
|
21
|
-
uses: astral-sh/setup-uv@
|
|
18
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
22
19
|
with:
|
|
23
20
|
enable-cache: false
|
|
24
21
|
cache-dependency-glob: "pyproject.toml"
|
|
@@ -30,7 +27,6 @@ jobs:
|
|
|
30
27
|
with:
|
|
31
28
|
name: ${{ env.dists-artifact-name }}
|
|
32
29
|
path: dist/*
|
|
33
|
-
|
|
34
30
|
release:
|
|
35
31
|
needs:
|
|
36
32
|
- build
|
|
@@ -5,34 +5,41 @@ repos:
|
|
|
5
5
|
- id: end-of-file-fixer
|
|
6
6
|
- id: trailing-whitespace
|
|
7
7
|
- repo: https://github.com/python-jsonschema/check-jsonschema
|
|
8
|
-
rev: 0.37.
|
|
8
|
+
rev: 0.37.4
|
|
9
9
|
hooks:
|
|
10
10
|
- id: check-github-workflows
|
|
11
11
|
args: ["--verbose"]
|
|
12
12
|
- repo: https://github.com/codespell-project/codespell
|
|
13
|
-
rev: v2.4.
|
|
13
|
+
rev: v2.4.3
|
|
14
14
|
hooks:
|
|
15
15
|
- id: codespell
|
|
16
16
|
additional_dependencies: ["tomli>=2.4"]
|
|
17
17
|
- repo: https://github.com/tox-dev/pyproject-fmt
|
|
18
|
-
rev: "v2.25.
|
|
18
|
+
rev: "v2.25.3"
|
|
19
19
|
hooks:
|
|
20
20
|
- id: pyproject-fmt
|
|
21
21
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
22
|
-
rev: "v0.15.
|
|
22
|
+
rev: "v0.15.22"
|
|
23
23
|
hooks:
|
|
24
24
|
- id: ruff-format
|
|
25
25
|
- id: ruff
|
|
26
26
|
args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"]
|
|
27
|
-
- repo: https://github.com/
|
|
28
|
-
rev: "
|
|
27
|
+
- repo: https://github.com/google/yamlfmt
|
|
28
|
+
rev: "v0.21.0"
|
|
29
29
|
hooks:
|
|
30
|
-
- id:
|
|
30
|
+
- id: yamlfmt
|
|
31
|
+
- repo: local
|
|
32
|
+
hooks:
|
|
33
|
+
- id: mdformat
|
|
34
|
+
name: mdformat
|
|
35
|
+
entry: mdformat --wrap 120
|
|
36
|
+
language: python
|
|
37
|
+
types: [markdown]
|
|
31
38
|
additional_dependencies:
|
|
32
|
-
-
|
|
33
|
-
-
|
|
39
|
+
- mdformat-gfm>=1
|
|
40
|
+
- mdformat-ruff>=0.1.3
|
|
34
41
|
- repo: https://github.com/zizmorcore/zizmor-pre-commit
|
|
35
|
-
rev: v1.
|
|
42
|
+
rev: v1.27.0
|
|
36
43
|
hooks:
|
|
37
44
|
- id: zizmor
|
|
38
45
|
- repo: meta
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-discovery
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: Python interpreter discovery
|
|
5
5
|
Project-URL: Changelog, https://github.com/tox-dev/python-discovery/releases
|
|
6
6
|
Project-URL: Documentation, https://python-discovery.readthedocs.io
|
|
@@ -42,25 +42,13 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
42
42
|
Classifier: Programming Language :: Python :: 3.12
|
|
43
43
|
Classifier: Programming Language :: Python :: 3.13
|
|
44
44
|
Classifier: Programming Language :: Python :: 3.14
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
45
46
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
46
47
|
Classifier: Topic :: Software Development :: Libraries
|
|
47
48
|
Classifier: Topic :: Utilities
|
|
48
49
|
Requires-Python: >=3.8
|
|
49
50
|
Requires-Dist: filelock>=3.15.4
|
|
50
51
|
Requires-Dist: platformdirs<5,>=4.3.6
|
|
51
|
-
Provides-Extra: docs
|
|
52
|
-
Requires-Dist: furo>=2025.12.19; extra == 'docs'
|
|
53
|
-
Requires-Dist: sphinx-autodoc-typehints>=3.6.3; extra == 'docs'
|
|
54
|
-
Requires-Dist: sphinx>=9.1; extra == 'docs'
|
|
55
|
-
Requires-Dist: sphinxcontrib-mermaid>=2; extra == 'docs'
|
|
56
|
-
Requires-Dist: sphinxcontrib-towncrier>=0.4; extra == 'docs'
|
|
57
|
-
Requires-Dist: towncrier>=25.8; extra == 'docs'
|
|
58
|
-
Provides-Extra: testing
|
|
59
|
-
Requires-Dist: covdefaults>=2.3; extra == 'testing'
|
|
60
|
-
Requires-Dist: coverage>=7.5.4; extra == 'testing'
|
|
61
|
-
Requires-Dist: pytest-mock>=3.14; extra == 'testing'
|
|
62
|
-
Requires-Dist: pytest>=8.3.5; extra == 'testing'
|
|
63
|
-
Requires-Dist: setuptools>=75.1; extra == 'testing'
|
|
64
52
|
Description-Content-Type: text/markdown
|
|
65
53
|
|
|
66
54
|
# [`python-discovery`](https://python-discovery.readthedocs.io/en/latest/)
|
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
|
|
7
7
|
.. towncrier release notes start
|
|
8
8
|
|
|
9
|
+
********************
|
|
10
|
+
v1.5.0 (2026-07-21)
|
|
11
|
+
********************
|
|
12
|
+
|
|
13
|
+
Packaging updates and notes for downstreams - 1.5.0
|
|
14
|
+
===================================================
|
|
15
|
+
- Declare support for Python 3.15 and run the test suite against it, currently in beta. (:issue:`104`)
|
|
16
|
+
|
|
17
|
+
********************
|
|
18
|
+
v1.4.4 (2026-07-08)
|
|
19
|
+
********************
|
|
20
|
+
|
|
21
|
+
Bug fixes - 1.4.4
|
|
22
|
+
=================
|
|
23
|
+
- Parse the debug build flag in interpreter specs - ``python3.13d`` and Debian's ``python3.13-dbg`` /
|
|
24
|
+
``python3.13-debug`` now select a ``Py_DEBUG`` interpreter instead of being misread as an ISA named ``dbg``.
|
|
25
|
+
Resolving a virtualenv to its base interpreter also checks the free-threaded and debug ABI flags, so a debug or
|
|
26
|
+
free-threaded environment no longer resolves to a release build of the same version - by :user:`gaborbernat`. (:issue:`96`)
|
|
27
|
+
|
|
9
28
|
********************
|
|
10
29
|
v1.4.3 (2026-07-03)
|
|
11
30
|
********************
|
|
@@ -11,7 +11,7 @@ company = "tox-dev"
|
|
|
11
11
|
name = "python-discovery"
|
|
12
12
|
version = ".".join(__version__.split(".")[:2])
|
|
13
13
|
release = __version__
|
|
14
|
-
copyright = f"2026-{datetime.now(tz=timezone.utc).year}, {company}" #
|
|
14
|
+
copyright = f"2026-{datetime.now(tz=timezone.utc).year}, {company}" # ruff:ignore[builtin-variable-shadowing]
|
|
15
15
|
|
|
16
16
|
extensions = [
|
|
17
17
|
"sphinx.ext.autodoc",
|
|
@@ -213,7 +213,7 @@ when encountering problematic interpreters.
|
|
|
213
213
|
Spec format reference
|
|
214
214
|
-----------------------
|
|
215
215
|
|
|
216
|
-
A spec string follows the pattern ``[impl][version][t][-arch][-machine]``. Every part is optional.
|
|
216
|
+
A spec string follows the pattern ``[impl][version][t][d][-arch][-machine]``. Every part is optional.
|
|
217
217
|
|
|
218
218
|
.. mermaid::
|
|
219
219
|
|
|
@@ -221,12 +221,14 @@ A spec string follows the pattern ``[impl][version][t][-arch][-machine]``. Every
|
|
|
221
221
|
Spec["Spec string"] --> Impl["impl<br>(optional)"]
|
|
222
222
|
Impl --> Version["version<br>(optional)"]
|
|
223
223
|
Version --> T["t<br>(optional)"]
|
|
224
|
-
T -->
|
|
224
|
+
T --> D["d / -dbg / -debug<br>(optional)"]
|
|
225
|
+
D --> Arch["-arch<br>(optional)"]
|
|
225
226
|
Arch --> Machine["-machine<br>(optional)"]
|
|
226
227
|
|
|
227
228
|
style Impl fill:#4a90d9,stroke:#2a5f8f,color:#fff
|
|
228
229
|
style Version fill:#4a9f4a,stroke:#2a6f2a,color:#fff
|
|
229
230
|
style T fill:#d9904a,stroke:#8f5f2a,color:#fff
|
|
231
|
+
style D fill:#4ad9c4,stroke:#2a8f7f,color:#fff
|
|
230
232
|
style Arch fill:#d94a4a,stroke:#8f2a2a,color:#fff
|
|
231
233
|
style Machine fill:#904ad9,stroke:#5f2a8f,color:#fff
|
|
232
234
|
|
|
@@ -237,9 +239,17 @@ A spec string follows the pattern ``[impl][version][t][-arch][-machine]``. Every
|
|
|
237
239
|
- **version** -- dotted version number (``3``, ``3.12``, or ``3.12.1``). You can also write
|
|
238
240
|
``312`` as shorthand for ``3.12``.
|
|
239
241
|
- **t** -- appended directly after the version. Matches free-threaded (no-GIL) builds only.
|
|
242
|
+
- **d** -- require a debug (``Py_DEBUG``) build. Written as ``d`` right after the version (the ABI flag
|
|
243
|
+
form, as in ``python3.13d``) or as Debian's ``-dbg`` / ``-debug`` suffix (``python3.13-dbg``). When
|
|
244
|
+
omitted the build type is unconstrained.
|
|
240
245
|
- **-arch** -- ``-32`` or ``-64`` for 32-bit or 64-bit interpreters.
|
|
241
246
|
- **-machine** -- the CPU instruction set: ``-arm64``, ``-x86_64``, ``-aarch64``, ``-riscv64``, etc.
|
|
242
247
|
|
|
248
|
+
Order matters: the parts appear in the sequence shown above. Combine the ABI flags as ``python3.13td``
|
|
249
|
+
(free-threaded then debug, the order CPython uses in ``sys.abiflags``), and keep ``-arch`` before
|
|
250
|
+
``-machine`` as in ``python3.13d-64-arm64``. Mixing ``d`` with ``-dbg`` in one spec, or swapping the arch
|
|
251
|
+
and machine segments, leaves the string unrecognized, so it falls back to a literal executable-name match.
|
|
252
|
+
|
|
243
253
|
**Full examples:**
|
|
244
254
|
|
|
245
255
|
.. list-table::
|
|
@@ -258,6 +268,10 @@ A spec string follows the pattern ``[impl][version][t][-arch][-machine]``. Every
|
|
|
258
268
|
- PyPy 3.9
|
|
259
269
|
* - ``python3.13t``
|
|
260
270
|
- Free-threaded (no-GIL) CPython 3.13
|
|
271
|
+
* - ``python3.13-dbg``
|
|
272
|
+
- Debug (``Py_DEBUG``) CPython 3.13 (``python3.13d`` also works)
|
|
273
|
+
* - ``python3.13td``
|
|
274
|
+
- Free-threaded debug CPython 3.13
|
|
261
275
|
* - ``python3.12-64``
|
|
262
276
|
- 64-bit CPython 3.12
|
|
263
277
|
* - ``python3.12-64-arm64``
|
|
@@ -16,6 +16,25 @@ standard locations.
|
|
|
16
16
|
if info is not None:
|
|
17
17
|
print(info.executable)
|
|
18
18
|
|
|
19
|
+
Select a debug build
|
|
20
|
+
----------------------
|
|
21
|
+
|
|
22
|
+
To require a debug (``Py_DEBUG``) interpreter, add the debug marker to the spec. Both the ABI-flag form
|
|
23
|
+
``python3.13d`` and the Debian package name ``python3.13-dbg`` work, and each resolves to the same
|
|
24
|
+
interpreter (Debian ships ``/usr/bin/python3.13d`` and ``/usr/bin/python3.13-dbg`` side by side). A spec with no
|
|
25
|
+
marker keeps matching either build, so reach for the marker only when you need the debug build.
|
|
26
|
+
|
|
27
|
+
.. code-block:: python
|
|
28
|
+
|
|
29
|
+
from python_discovery import get_interpreter
|
|
30
|
+
|
|
31
|
+
info = get_interpreter("python3.13-dbg")
|
|
32
|
+
if info is not None:
|
|
33
|
+
assert info.debug_build
|
|
34
|
+
|
|
35
|
+
Combine the marker with the free-threaded ``t`` flag to select a free-threaded debug build, written
|
|
36
|
+
``python3.13td`` (ABI-flag order is ``t`` then ``d``) or ``python3.13t-dbg``.
|
|
37
|
+
|
|
19
38
|
Restrict the search environment
|
|
20
39
|
---------------------------------
|
|
21
40
|
|
|
@@ -135,6 +154,7 @@ Once you have a :class:`~python_discovery.PythonInfo`, you can inspect everythin
|
|
|
135
154
|
+sysconfig_paths: dict
|
|
136
155
|
+machine: str
|
|
137
156
|
+free_threaded: bool
|
|
157
|
+
+debug_build: bool
|
|
138
158
|
}
|
|
139
159
|
|
|
140
160
|
.. code-block:: python
|
|
@@ -154,6 +174,7 @@ Once you have a :class:`~python_discovery.PythonInfo`, you can inspect everythin
|
|
|
154
174
|
info.platform # sys.platform value ("linux", "darwin", "win32").
|
|
155
175
|
info.machine # ISA: "arm64", "x86_64", etc.
|
|
156
176
|
info.free_threaded # True if this is a no-GIL build.
|
|
177
|
+
info.debug_build # True if this is a Py_DEBUG build.
|
|
157
178
|
info.sysconfig_vars # All sysconfig.get_config_vars() values.
|
|
158
179
|
info.sysconfig_paths # All sysconfig.get_paths() values.
|
|
159
180
|
|
|
@@ -142,12 +142,14 @@ You can add more constraints to narrow the search.
|
|
|
142
142
|
Spec["Spec string"] --> Impl["impl<br>(optional)"]
|
|
143
143
|
Impl --> Version["version<br>(optional)"]
|
|
144
144
|
Version --> T["t<br>(optional)"]
|
|
145
|
-
T -->
|
|
145
|
+
T --> D["d / -dbg / -debug<br>(optional)"]
|
|
146
|
+
D --> Arch["-arch<br>(optional)"]
|
|
146
147
|
Arch --> Machine["-machine<br>(optional)"]
|
|
147
148
|
|
|
148
149
|
style Impl fill:#4a90d9,stroke:#2a5f8f,color:#fff
|
|
149
150
|
style Version fill:#4a9f4a,stroke:#2a6f2a,color:#fff
|
|
150
151
|
style T fill:#d9904a,stroke:#8f5f2a,color:#fff
|
|
152
|
+
style D fill:#4ad9c4,stroke:#2a8f7f,color:#fff
|
|
151
153
|
style Arch fill:#d94a4a,stroke:#8f2a2a,color:#fff
|
|
152
154
|
style Machine fill:#904ad9,stroke:#5f2a8f,color:#fff
|
|
153
155
|
|
|
@@ -167,6 +169,8 @@ Common examples:
|
|
|
167
169
|
- PyPy 3.9
|
|
168
170
|
* - ``python3.13t``
|
|
169
171
|
- Free-threaded (no-GIL) CPython 3.13
|
|
172
|
+
* - ``python3.13-dbg``
|
|
173
|
+
- Debug (``Py_DEBUG``) CPython 3.13 (``python3.13d`` also works)
|
|
170
174
|
* - ``python3.12-64``
|
|
171
175
|
- 64-bit CPython 3.12
|
|
172
176
|
* - ``python3.12-64-arm64``
|
|
@@ -188,11 +192,12 @@ inspecting what a spec means or for building tools on top of python-discovery.
|
|
|
188
192
|
.. mermaid::
|
|
189
193
|
|
|
190
194
|
flowchart TD
|
|
191
|
-
Input["cpython3.
|
|
195
|
+
Input["cpython3.13td-64-arm64"] --> Parse["PythonSpec.from_string_spec()"]
|
|
192
196
|
Parse --> Spec["PythonSpec"]
|
|
193
197
|
Spec --> impl["implementation: cpython"]
|
|
194
|
-
Spec --> ver["major: 3, minor:
|
|
198
|
+
Spec --> ver["major: 3, minor: 13"]
|
|
195
199
|
Spec --> ft["free_threaded: True"]
|
|
200
|
+
Spec --> dbg["debug: True"]
|
|
196
201
|
Spec --> arch["architecture: 64"]
|
|
197
202
|
Spec --> mach["machine: arm64"]
|
|
198
203
|
|
|
@@ -203,11 +208,12 @@ inspecting what a spec means or for building tools on top of python-discovery.
|
|
|
203
208
|
|
|
204
209
|
from python_discovery import PythonSpec
|
|
205
210
|
|
|
206
|
-
spec = PythonSpec.from_string_spec("cpython3.
|
|
211
|
+
spec = PythonSpec.from_string_spec("cpython3.13td-64-arm64")
|
|
207
212
|
spec.implementation # "cpython"
|
|
208
213
|
spec.major # 3
|
|
209
|
-
spec.minor #
|
|
214
|
+
spec.minor # 13
|
|
210
215
|
spec.free_threaded # True
|
|
216
|
+
spec.debug # True
|
|
211
217
|
spec.architecture # 64
|
|
212
218
|
spec.machine # "arm64"
|
|
213
219
|
|
|
@@ -35,6 +35,7 @@ classifiers = [
|
|
|
35
35
|
"Programming Language :: Python :: 3.12",
|
|
36
36
|
"Programming Language :: Python :: 3.13",
|
|
37
37
|
"Programming Language :: Python :: 3.14",
|
|
38
|
+
"Programming Language :: Python :: 3.15",
|
|
38
39
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
39
40
|
"Topic :: Software Development :: Libraries",
|
|
40
41
|
"Topic :: Utilities",
|
|
@@ -46,21 +47,6 @@ dependencies = [
|
|
|
46
47
|
"filelock>=3.15.4",
|
|
47
48
|
"platformdirs<5,>=4.3.6",
|
|
48
49
|
]
|
|
49
|
-
optional-dependencies.docs = [
|
|
50
|
-
"furo>=2025.12.19",
|
|
51
|
-
"sphinx>=9.1",
|
|
52
|
-
"sphinx-autodoc-typehints>=3.6.3",
|
|
53
|
-
"sphinxcontrib-mermaid>=2",
|
|
54
|
-
"sphinxcontrib-towncrier>=0.4",
|
|
55
|
-
"towncrier>=25.8",
|
|
56
|
-
]
|
|
57
|
-
optional-dependencies.testing = [
|
|
58
|
-
"covdefaults>=2.3",
|
|
59
|
-
"coverage>=7.5.4",
|
|
60
|
-
"pytest>=8.3.5",
|
|
61
|
-
"pytest-mock>=3.14",
|
|
62
|
-
"setuptools>=75.1",
|
|
63
|
-
]
|
|
64
50
|
urls.Changelog = "https://github.com/tox-dev/python-discovery/releases"
|
|
65
51
|
urls.Documentation = "https://python-discovery.readthedocs.io"
|
|
66
52
|
urls.Homepage = "https://github.com/tox-dev/python-discovery"
|
|
@@ -68,6 +54,21 @@ urls.Source = "https://github.com/tox-dev/python-discovery"
|
|
|
68
54
|
urls.Tracker = "https://github.com/tox-dev/python-discovery/issues"
|
|
69
55
|
|
|
70
56
|
[dependency-groups]
|
|
57
|
+
test = [
|
|
58
|
+
"covdefaults>=2.3",
|
|
59
|
+
"coverage>=7.5.4",
|
|
60
|
+
"pytest>=8.3.5",
|
|
61
|
+
"pytest-mock>=3.14",
|
|
62
|
+
"setuptools>=75.1",
|
|
63
|
+
]
|
|
64
|
+
docs = [
|
|
65
|
+
"furo>=2025.12.19",
|
|
66
|
+
"sphinx>=9.1",
|
|
67
|
+
"sphinx-autodoc-typehints>=3.6.3",
|
|
68
|
+
"sphinxcontrib-mermaid>=2",
|
|
69
|
+
"sphinxcontrib-towncrier>=0.4",
|
|
70
|
+
"towncrier>=25.8",
|
|
71
|
+
]
|
|
71
72
|
release = [
|
|
72
73
|
"gitpython>=3.1.46",
|
|
73
74
|
"packaging>=26",
|
|
@@ -145,7 +146,7 @@ write-changes = true
|
|
|
145
146
|
count = true
|
|
146
147
|
|
|
147
148
|
[tool.pyproject-fmt]
|
|
148
|
-
max_supported_python = "3.
|
|
149
|
+
max_supported_python = "3.15"
|
|
149
150
|
|
|
150
151
|
[tool.ty]
|
|
151
152
|
src.exclude = [ "tests/windows/winreg_mock_values.py" ]
|
|
@@ -104,7 +104,7 @@ class DiskContentStore:
|
|
|
104
104
|
|
|
105
105
|
@contextmanager
|
|
106
106
|
def locked(self) -> Generator[None]:
|
|
107
|
-
from filelock import FileLock #
|
|
107
|
+
from filelock import FileLock # ruff:ignore[import-outside-top-level]
|
|
108
108
|
|
|
109
109
|
lock_path = self._folder / f"{self._key}.lock"
|
|
110
110
|
lock_path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -148,10 +148,10 @@ class DiskCache:
|
|
|
148
148
|
class NoOpContentStore(ContentStore):
|
|
149
149
|
"""Content store that does nothing -- implements ContentStore protocol."""
|
|
150
150
|
|
|
151
|
-
def exists(self) -> bool: #
|
|
151
|
+
def exists(self) -> bool: # ruff:ignore[no-self-use]
|
|
152
152
|
return False
|
|
153
153
|
|
|
154
|
-
def read(self) -> dict | None: #
|
|
154
|
+
def read(self) -> dict | None: # ruff:ignore[no-self-use]
|
|
155
155
|
return None
|
|
156
156
|
|
|
157
157
|
def write(self, content: dict) -> None:
|
|
@@ -161,14 +161,14 @@ class NoOpContentStore(ContentStore):
|
|
|
161
161
|
pass
|
|
162
162
|
|
|
163
163
|
@contextmanager
|
|
164
|
-
def locked(self) -> Generator[None]: #
|
|
164
|
+
def locked(self) -> Generator[None]: # ruff:ignore[no-self-use]
|
|
165
165
|
yield
|
|
166
166
|
|
|
167
167
|
|
|
168
168
|
class NoOpCache(PyInfoCache):
|
|
169
169
|
"""Cache that does nothing -- implements PyInfoCache protocol."""
|
|
170
170
|
|
|
171
|
-
def py_info(self, path: Path) -> NoOpContentStore: #
|
|
171
|
+
def py_info(self, path: Path) -> NoOpContentStore: # ruff:ignore[unused-method-argument, no-self-use]
|
|
172
172
|
return NoOpContentStore()
|
|
173
173
|
|
|
174
174
|
def py_info_clear(self) -> None:
|
|
@@ -8,14 +8,14 @@ import logging
|
|
|
8
8
|
import os
|
|
9
9
|
import pkgutil
|
|
10
10
|
import secrets
|
|
11
|
-
import subprocess #
|
|
11
|
+
import subprocess # ruff:ignore[suspicious-subprocess-import]
|
|
12
12
|
import sys
|
|
13
13
|
import tempfile
|
|
14
14
|
from collections import OrderedDict
|
|
15
15
|
from contextlib import contextmanager
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
from shlex import quote
|
|
18
|
-
from subprocess import Popen, TimeoutExpired #
|
|
18
|
+
from subprocess import Popen, TimeoutExpired # ruff:ignore[suspicious-subprocess-import]
|
|
19
19
|
from typing import TYPE_CHECKING, Final
|
|
20
20
|
|
|
21
21
|
from ._cache import NoOpCache
|
|
@@ -32,7 +32,7 @@ _CACHE[Path(sys.executable)] = PythonInfo()
|
|
|
32
32
|
_LOGGER: Final[logging.Logger] = logging.getLogger(__name__)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def from_exe( #
|
|
35
|
+
def from_exe( # ruff:ignore[too-many-arguments]
|
|
36
36
|
cls: type[PythonInfo],
|
|
37
37
|
cache: PyInfoCache | None,
|
|
38
38
|
exe: str,
|
|
@@ -197,7 +197,7 @@ def _run_subprocess(
|
|
|
197
197
|
env["PYTHONUTF8"] = "1"
|
|
198
198
|
_LOGGER.debug("get interpreter info via cmd: %s", LogCmd(cmd))
|
|
199
199
|
try:
|
|
200
|
-
process = Popen( #
|
|
200
|
+
process = Popen( # ruff:ignore[subprocess-without-shell-equals-true]
|
|
201
201
|
cmd,
|
|
202
202
|
universal_newlines=True,
|
|
203
203
|
stdin=subprocess.PIPE,
|
|
@@ -89,7 +89,7 @@ def iter_interpreters(
|
|
|
89
89
|
yield from _iter_for_spec(spec_str, first_with, cache, env_map, predicate, seen)
|
|
90
90
|
|
|
91
91
|
|
|
92
|
-
def _iter_for_spec( #
|
|
92
|
+
def _iter_for_spec( # ruff:ignore[too-many-arguments, too-many-positional-arguments]
|
|
93
93
|
spec_str: str | None,
|
|
94
94
|
try_first_with: tuple[str, ...],
|
|
95
95
|
cache: PyInfoCache | None,
|
|
@@ -231,7 +231,7 @@ def _propose_current_and_windows(
|
|
|
231
231
|
yield current_python, True
|
|
232
232
|
|
|
233
233
|
if IS_WIN: # pragma: win32 cover
|
|
234
|
-
from ._windows import propose_interpreters as win_propose #
|
|
234
|
+
from ._windows import propose_interpreters as win_propose # ruff:ignore[import-outside-top-level]
|
|
235
235
|
|
|
236
236
|
for interpreter in win_propose(spec, cache, env):
|
|
237
237
|
if _is_new_exe(str(interpreter.executable), tested_exes):
|