python-discovery 1.3.0__tar.gz → 1.3.1__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.3.1/.github/workflows/prepare-release.yaml +100 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.pre-commit-config.yaml +1 -1
- {python_discovery-1.3.0 → python_discovery-1.3.1}/PKG-INFO +3 -1
- python_discovery-1.3.1/docs/changelog/template.jinja2 +38 -0
- python_discovery-1.3.1/docs/changelog.rst +125 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/conf.py +7 -1
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/index.rst +6 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/pyproject.toml +34 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_py_info.py +2 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_py_spec.py +4 -0
- python_discovery-1.3.1/tasks/release.py +167 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_py_info_extra.py +6 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_py_spec.py +13 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tox.toml +9 -2
- python_discovery-1.3.0/docs/changelog/59.bugfix.rst +0 -1
- python_discovery-1.3.0/docs/changelog/65.bugfix.rst +0 -3
- python_discovery-1.3.0/docs/changelog/65.feature.rst +0 -3
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.github/FUNDING.yaml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.github/SECURITY.md +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.github/dependabot.yaml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.github/release.yaml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.github/workflows/check.yaml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.github/workflows/release.yaml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.gitignore +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.readthedocs.yaml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/.readthedocs.yml +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/CODE_OF_CONDUCT.md +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/LICENSE +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/README.md +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/_static/custom.css +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/_static/logo.svg +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/explanation.rst +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/how-to/standalone-usage.rst +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/reference/api.rst +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/reference/environment-variables.rst +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/docs/tutorial/getting-started.rst +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/__init__.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_cache.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_cached_py_info.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_compat.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_discovery.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_specifier.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_windows/__init__.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_windows/_pep514.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/_windows/_propose.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/src/python_discovery/py.typed +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/conftest.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/py_info/test_py_info.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/py_info/test_py_info_exe_based_of.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_cache.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_cached_py_info.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_discovery.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_discovery_extra.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_iter_interpreters.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_py_spec_extra.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/test_specifier.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/windows/conftest.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/windows/test_windows.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/windows/test_windows_pep514.py +0 -0
- {python_discovery-1.3.0 → python_discovery-1.3.1}/tests/windows/winreg_mock_values.py +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: Prepare Release
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
inputs:
|
|
5
|
+
bump:
|
|
6
|
+
description: "Version bump type"
|
|
7
|
+
required: true
|
|
8
|
+
type: choice
|
|
9
|
+
options:
|
|
10
|
+
- auto
|
|
11
|
+
- major
|
|
12
|
+
- minor
|
|
13
|
+
- patch
|
|
14
|
+
default: auto
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
env:
|
|
20
|
+
FORCE_COLOR: 1
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
prepare-release:
|
|
24
|
+
runs-on: ubuntu-24.04
|
|
25
|
+
environment: release-auth
|
|
26
|
+
permissions:
|
|
27
|
+
contents: write
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 0
|
|
32
|
+
token: ${{ secrets.RELEASE_PAT }}
|
|
33
|
+
persist-credentials: true
|
|
34
|
+
|
|
35
|
+
- name: Install the latest version of uv
|
|
36
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
37
|
+
with:
|
|
38
|
+
enable-cache: true
|
|
39
|
+
cache-dependency-glob: "pyproject.toml"
|
|
40
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
+
|
|
42
|
+
- name: Configure git
|
|
43
|
+
run: |
|
|
44
|
+
git config user.name "${GITHUB_ACTOR}"
|
|
45
|
+
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
|
46
|
+
|
|
47
|
+
- name: Calculate next version
|
|
48
|
+
id: version
|
|
49
|
+
env:
|
|
50
|
+
BUMP: ${{ inputs.bump }}
|
|
51
|
+
run: |
|
|
52
|
+
current=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0")
|
|
53
|
+
echo "Current version: $current"
|
|
54
|
+
|
|
55
|
+
IFS='.' read -r major minor patch <<< "$current"
|
|
56
|
+
|
|
57
|
+
bump_type="$BUMP"
|
|
58
|
+
if [ "$bump_type" = "auto" ]; then
|
|
59
|
+
feature_count=$(find docs/changelog -name "*.feature.rst" 2>/dev/null | wc -l)
|
|
60
|
+
breaking_count=$(find docs/changelog -name "*.breaking.rst" 2>/dev/null | wc -l)
|
|
61
|
+
if [ "$breaking_count" -gt 0 ]; then
|
|
62
|
+
bump_type="major"
|
|
63
|
+
echo "Auto-detected: major bump (found $breaking_count breaking changelog(s))"
|
|
64
|
+
elif [ "$feature_count" -gt 0 ]; then
|
|
65
|
+
bump_type="minor"
|
|
66
|
+
echo "Auto-detected: minor bump (found $feature_count feature changelog(s))"
|
|
67
|
+
else
|
|
68
|
+
bump_type="patch"
|
|
69
|
+
echo "Auto-detected: patch bump (no feature changelogs)"
|
|
70
|
+
fi
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
case "$bump_type" in
|
|
74
|
+
major)
|
|
75
|
+
next="$((major + 1)).0.0"
|
|
76
|
+
;;
|
|
77
|
+
minor)
|
|
78
|
+
next="$major.$((minor + 1)).0"
|
|
79
|
+
;;
|
|
80
|
+
patch)
|
|
81
|
+
next="$major.$minor.$((patch + 1))"
|
|
82
|
+
;;
|
|
83
|
+
esac
|
|
84
|
+
|
|
85
|
+
echo "Next version: $next"
|
|
86
|
+
echo "version=$next" >> $GITHUB_OUTPUT
|
|
87
|
+
|
|
88
|
+
- name: Install tox
|
|
89
|
+
run: uv tool install --python-preference only-managed --python 3.14 tox@latest --with tox-uv
|
|
90
|
+
|
|
91
|
+
- name: Run release process
|
|
92
|
+
run: tox run -e release -- ${STEPS_VERSION_OUTPUTS_VERSION}
|
|
93
|
+
env:
|
|
94
|
+
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
|
|
95
|
+
STEPS_VERSION_OUTPUTS_VERSION: ${{ steps.version.outputs.version }}
|
|
96
|
+
|
|
97
|
+
- name: Display completion message
|
|
98
|
+
run: echo "Release ${STEPS_VERSION_OUTPUTS_VERSION} prepared and pushed successfully!"
|
|
99
|
+
env:
|
|
100
|
+
STEPS_VERSION_OUTPUTS_VERSION: ${{ steps.version.outputs.version }}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-discovery
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.1
|
|
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
|
|
@@ -53,6 +53,8 @@ Requires-Dist: furo>=2025.12.19; extra == 'docs'
|
|
|
53
53
|
Requires-Dist: sphinx-autodoc-typehints>=3.6.3; extra == 'docs'
|
|
54
54
|
Requires-Dist: sphinx>=9.1; extra == 'docs'
|
|
55
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'
|
|
56
58
|
Provides-Extra: testing
|
|
57
59
|
Requires-Dist: covdefaults>=2.3; extra == 'testing'
|
|
58
60
|
Requires-Dist: coverage>=7.5.4; extra == 'testing'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{% set top_underline = "*" %}
|
|
2
|
+
{% set underline = "=" %}
|
|
3
|
+
{% if versiondata.name %}
|
|
4
|
+
{{ top_underline * ((versiondata.version + versiondata.date)|length + 5)}}
|
|
5
|
+
v{{ versiondata.version }} ({{ versiondata.date }})
|
|
6
|
+
{{ top_underline * ((versiondata.version + versiondata.date)|length + 5)}}
|
|
7
|
+
{% else %}
|
|
8
|
+
{{ top_underline * ((versiondata.version + versiondata.date)|length + 4)}}
|
|
9
|
+
{{ versiondata.version }} ({{ versiondata.date }})
|
|
10
|
+
{{ top_underline * ((versiondata.version + versiondata.date)|length + 4)}}
|
|
11
|
+
{% endif %}
|
|
12
|
+
|
|
13
|
+
{% for section, _ in sections.items() %}
|
|
14
|
+
{% if sections[section] %}
|
|
15
|
+
{% for category, val in definitions.items() if category in sections[section]%}
|
|
16
|
+
{{ definitions[category]['name'] }} - {{ versiondata.version }}
|
|
17
|
+
{{ underline * ((definitions[category]['name'] + versiondata.version)|length + 3)}}
|
|
18
|
+
{% if definitions[category]['showcontent'] %}
|
|
19
|
+
{% for text, values in sections[section][category].items() %}
|
|
20
|
+
- {{ text }} ({{ values|join(', ') }})
|
|
21
|
+
{% endfor %}
|
|
22
|
+
|
|
23
|
+
{% else %}
|
|
24
|
+
- {{ sections[section][category]['']|join(', ') }}
|
|
25
|
+
|
|
26
|
+
{% endif %}
|
|
27
|
+
{% if sections[section][category]|length == 0 %}
|
|
28
|
+
No significant changes.
|
|
29
|
+
|
|
30
|
+
{% else %}
|
|
31
|
+
{% endif %}
|
|
32
|
+
{% endfor %}
|
|
33
|
+
{% else %}
|
|
34
|
+
No significant changes.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% endfor %}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#################
|
|
2
|
+
Release History
|
|
3
|
+
#################
|
|
4
|
+
|
|
5
|
+
.. towncrier-draft-entries::
|
|
6
|
+
|
|
7
|
+
.. towncrier release notes start
|
|
8
|
+
|
|
9
|
+
********************
|
|
10
|
+
v1.3.1 (2026-05-12)
|
|
11
|
+
********************
|
|
12
|
+
|
|
13
|
+
Bug fixes - 1.3.1
|
|
14
|
+
=================
|
|
15
|
+
- export normalize_isa and deprecate KNOWN_ARCHITECTURES - by :user:`rahuldevikar`. (:issue:`59`)
|
|
16
|
+
- discover uv-managed Pythons on Windows. Previously the glob assumed Unix layout (``<root>/<key>/bin/python``) and
|
|
17
|
+
silently found nothing on Windows, where uv places ``python.exe`` directly under the install root - by
|
|
18
|
+
:user:`gaborbernat`. (:issue:`65`)
|
|
19
|
+
- Canonicalize GraalVM to match GraalPy Python interpreter in PythonSpec and PythonInfo. - by :user:`timfel`. (:issue:`73`)
|
|
20
|
+
|
|
21
|
+
********************
|
|
22
|
+
v1.3.0 (2026-05-05)
|
|
23
|
+
********************
|
|
24
|
+
|
|
25
|
+
Features - 1.3.0
|
|
26
|
+
================
|
|
27
|
+
|
|
28
|
+
- Add :func:`~python_discovery.iter_interpreters` for enumerating every discovered interpreter, with PATH and
|
|
29
|
+
UV-install support for non-CPython implementations listed in :data:`~python_discovery.KNOWN_IMPLEMENTATIONS`
|
|
30
|
+
(:pull:`71`)
|
|
31
|
+
|
|
32
|
+
********************
|
|
33
|
+
v1.2.2 (2026-04-06)
|
|
34
|
+
********************
|
|
35
|
+
|
|
36
|
+
Features - 1.2.2
|
|
37
|
+
================
|
|
38
|
+
|
|
39
|
+
- Export ``normalize_isa`` and deprecate ``KNOWN_ARCHITECTURES`` (:pull:`62`)
|
|
40
|
+
|
|
41
|
+
********************
|
|
42
|
+
v1.2.1 (2026-03-26)
|
|
43
|
+
********************
|
|
44
|
+
|
|
45
|
+
Features - 1.2.1
|
|
46
|
+
================
|
|
47
|
+
|
|
48
|
+
- Expose ``KNOWN_ARCHITECTURES`` as public API (:pull:`56`)
|
|
49
|
+
|
|
50
|
+
Contributor-facing changes - 1.2.1
|
|
51
|
+
==================================
|
|
52
|
+
|
|
53
|
+
- Add zizmor security auditing for workflows (:pull:`55`)
|
|
54
|
+
|
|
55
|
+
********************
|
|
56
|
+
v1.2.0 (2026-03-18)
|
|
57
|
+
********************
|
|
58
|
+
|
|
59
|
+
Features - 1.2.0
|
|
60
|
+
================
|
|
61
|
+
|
|
62
|
+
- Increase interpreter query timeout to 15s, with an override (:pull:`53`)
|
|
63
|
+
|
|
64
|
+
********************
|
|
65
|
+
v1.1.3 (2026-03-10)
|
|
66
|
+
********************
|
|
67
|
+
|
|
68
|
+
Bug fixes - 1.1.3
|
|
69
|
+
=================
|
|
70
|
+
|
|
71
|
+
- Add ``loongarch64`` to known ISAs (:pull:`50`)
|
|
72
|
+
|
|
73
|
+
********************
|
|
74
|
+
v1.1.2 (2026-03-09)
|
|
75
|
+
********************
|
|
76
|
+
|
|
77
|
+
Bug fixes - 1.1.2
|
|
78
|
+
=================
|
|
79
|
+
|
|
80
|
+
- Match prerelease versions against ``major.minor`` specs (:pull:`48`)
|
|
81
|
+
- Drain pipes after killing a timed-out interpreter probe (:pull:`49`)
|
|
82
|
+
|
|
83
|
+
Improved documentation - 1.1.2
|
|
84
|
+
==============================
|
|
85
|
+
|
|
86
|
+
- Add package description and usage to the README (:pull:`46`)
|
|
87
|
+
|
|
88
|
+
********************
|
|
89
|
+
v1.1.1 (2026-03-06)
|
|
90
|
+
********************
|
|
91
|
+
|
|
92
|
+
Bug fixes - 1.1.1
|
|
93
|
+
=================
|
|
94
|
+
|
|
95
|
+
- Add a timeout to interpreter probing (:pull:`42`)
|
|
96
|
+
- Add ``i686`` to known ISAs (:pull:`43`)
|
|
97
|
+
|
|
98
|
+
Contributor-facing changes - 1.1.1
|
|
99
|
+
==================================
|
|
100
|
+
|
|
101
|
+
- Add a security policy and workflow permissions hardening (:pull:`33`)
|
|
102
|
+
|
|
103
|
+
********************
|
|
104
|
+
v1.1.0 (2026-02-26)
|
|
105
|
+
********************
|
|
106
|
+
|
|
107
|
+
Features - 1.1.0
|
|
108
|
+
================
|
|
109
|
+
|
|
110
|
+
- Add a ``predicate`` parameter to :func:`~python_discovery.get_interpreter` (:pull:`31`)
|
|
111
|
+
|
|
112
|
+
Improved documentation - 1.1.0
|
|
113
|
+
==============================
|
|
114
|
+
|
|
115
|
+
- Fix the ReadTheDocs build (:pull:`29`)
|
|
116
|
+
- Add ``:param:`` descriptions to all public APIs (:pull:`32`)
|
|
117
|
+
|
|
118
|
+
********************
|
|
119
|
+
v1.0.0 (2026-02-25)
|
|
120
|
+
********************
|
|
121
|
+
|
|
122
|
+
Features - 1.0.0
|
|
123
|
+
================
|
|
124
|
+
|
|
125
|
+
- Initial release as a standalone package, extracted from ``virtualenv`` (:pull:`28`)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from datetime import datetime, timezone
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
from python_discovery import __version__
|
|
8
9
|
|
|
@@ -19,8 +20,13 @@ extensions = [
|
|
|
19
20
|
"sphinx.ext.intersphinx",
|
|
20
21
|
"sphinx_autodoc_typehints",
|
|
21
22
|
"sphinxcontrib.mermaid",
|
|
23
|
+
"sphinxcontrib.towncrier.ext",
|
|
22
24
|
]
|
|
23
25
|
|
|
26
|
+
towncrier_draft_autoversion_mode = "draft"
|
|
27
|
+
towncrier_draft_include_empty = True
|
|
28
|
+
towncrier_draft_working_directory = Path(__file__).parent.parent
|
|
29
|
+
|
|
24
30
|
extlinks = {
|
|
25
31
|
"issue": ("https://github.com/tox-dev/python-discovery/issues/%s", "#%s"),
|
|
26
32
|
"pull": ("https://github.com/tox-dev/python-discovery/pull/%s", "PR #%s"),
|
|
@@ -33,7 +39,7 @@ intersphinx_mapping = {
|
|
|
33
39
|
|
|
34
40
|
templates_path = []
|
|
35
41
|
source_suffix = ".rst"
|
|
36
|
-
exclude_patterns = ["_build", "changelog
|
|
42
|
+
exclude_patterns = ["_build", "changelog/*"]
|
|
37
43
|
|
|
38
44
|
main_doc = "index"
|
|
39
45
|
pygments_style = "default"
|
|
@@ -50,6 +50,8 @@ optional-dependencies.docs = [
|
|
|
50
50
|
"sphinx>=9.1",
|
|
51
51
|
"sphinx-autodoc-typehints>=3.6.3",
|
|
52
52
|
"sphinxcontrib-mermaid>=2",
|
|
53
|
+
"sphinxcontrib-towncrier>=0.4",
|
|
54
|
+
"towncrier>=25.8",
|
|
53
55
|
]
|
|
54
56
|
optional-dependencies.testing = [
|
|
55
57
|
"covdefaults>=2.3",
|
|
@@ -64,6 +66,14 @@ urls.Homepage = "https://github.com/tox-dev/python-discovery"
|
|
|
64
66
|
urls.Source = "https://github.com/tox-dev/python-discovery"
|
|
65
67
|
urls.Tracker = "https://github.com/tox-dev/python-discovery/issues"
|
|
66
68
|
|
|
69
|
+
[dependency-groups]
|
|
70
|
+
release = [
|
|
71
|
+
"gitpython>=3.1.46",
|
|
72
|
+
"packaging>=26",
|
|
73
|
+
"pre-commit>=4.5.1",
|
|
74
|
+
"towncrier>=25.8",
|
|
75
|
+
]
|
|
76
|
+
|
|
67
77
|
[tool.hatch]
|
|
68
78
|
version.source = "vcs"
|
|
69
79
|
|
|
@@ -98,6 +108,12 @@ lint.per-file-ignores."src/python_discovery/_py_info.py" = [
|
|
|
98
108
|
lint.per-file-ignores."src/python_discovery/_windows/_pep514.py" = [
|
|
99
109
|
"PTH", # os.path.exists is monkeypatched in tests; pathlib.Path.exists bypasses the mock
|
|
100
110
|
]
|
|
111
|
+
lint.per-file-ignores."tasks/**/*.py" = [
|
|
112
|
+
"D", # release helper scripts, not API
|
|
113
|
+
"INP001", # no __init__.py in tasks directory
|
|
114
|
+
"S404", # subprocess import (release tooling)
|
|
115
|
+
"S603", # `subprocess` call: argv built from trusted inputs (version, gh CLI)
|
|
116
|
+
]
|
|
101
117
|
lint.per-file-ignores."tests/**/*.py" = [
|
|
102
118
|
"D", # don't care about documentation in tests
|
|
103
119
|
"FBT", # don't care about booleans as positional arguments in tests
|
|
@@ -180,3 +196,21 @@ report.partial_branches = [
|
|
|
180
196
|
report.show_missing = true
|
|
181
197
|
html.show_contexts = true
|
|
182
198
|
html.skip_covered = false
|
|
199
|
+
|
|
200
|
+
[tool.towncrier]
|
|
201
|
+
name = "python-discovery"
|
|
202
|
+
filename = "docs/changelog.rst"
|
|
203
|
+
directory = "docs/changelog"
|
|
204
|
+
title_format = false
|
|
205
|
+
issue_format = ":issue:`{issue}`"
|
|
206
|
+
template = "docs/changelog/template.jinja2"
|
|
207
|
+
type = [
|
|
208
|
+
{ directory = "breaking", name = "Backward incompatible changes", showcontent = true },
|
|
209
|
+
{ directory = "deprecation", name = "Deprecations (removal in next major release)", showcontent = true },
|
|
210
|
+
{ directory = "feature", name = "Features", showcontent = true },
|
|
211
|
+
{ directory = "bugfix", name = "Bug fixes", showcontent = true },
|
|
212
|
+
{ directory = "doc", name = "Improved documentation", showcontent = true },
|
|
213
|
+
{ directory = "packaging", name = "Packaging updates and notes for downstreams", showcontent = true },
|
|
214
|
+
{ directory = "contrib", name = "Contributor-facing changes", showcontent = true },
|
|
215
|
+
{ directory = "misc", name = "Miscellaneous internal changes", showcontent = true },
|
|
216
|
+
]
|
|
@@ -59,6 +59,8 @@ class PythonInfo: # noqa: PLR0904
|
|
|
59
59
|
def _init_identity(self) -> None:
|
|
60
60
|
self.platform = sys.platform
|
|
61
61
|
self.implementation = platform.python_implementation()
|
|
62
|
+
if self.implementation == "GraalVM":
|
|
63
|
+
self.implementation = "GraalPy"
|
|
62
64
|
if self.implementation == "PyPy":
|
|
63
65
|
self.pypy_version_info = tuple(sys.pypy_version_info) # ty: ignore[unresolved-attribute] # pypy only
|
|
64
66
|
|
|
@@ -77,6 +77,8 @@ def _parse_spec_pattern(string_spec: str) -> PythonSpec | None:
|
|
|
77
77
|
impl = groups["impl"]
|
|
78
78
|
if impl in {"py", "python"}:
|
|
79
79
|
impl = None
|
|
80
|
+
if impl == "graalvm":
|
|
81
|
+
impl = "graalpy"
|
|
80
82
|
arch = _int_or_none(groups["arch"])
|
|
81
83
|
machine = groups.get("machine")
|
|
82
84
|
if machine is not None:
|
|
@@ -97,6 +99,8 @@ def _parse_specifier(string_spec: str) -> PythonSpec | None:
|
|
|
97
99
|
return None
|
|
98
100
|
if impl in {"py", "python"}:
|
|
99
101
|
impl = None
|
|
102
|
+
if impl == "graalvm":
|
|
103
|
+
impl = "graalpy"
|
|
100
104
|
return PythonSpec(string_spec, impl, None, None, None, None, None, version_specifier=version_specifier)
|
|
101
105
|
|
|
102
106
|
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Handles creating a release commit and tag, then publishes the GitHub release."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from subprocess import CalledProcessError, check_call, run
|
|
7
|
+
|
|
8
|
+
from git import Commit, Head, Remote, Repo, TagReference
|
|
9
|
+
from packaging.version import Version
|
|
10
|
+
|
|
11
|
+
ROOT_SRC_DIR = Path(__file__).parents[1]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main(version_str: str) -> None:
|
|
15
|
+
version = Version(version_str)
|
|
16
|
+
repo = Repo(str(ROOT_SRC_DIR))
|
|
17
|
+
|
|
18
|
+
if repo.is_dirty():
|
|
19
|
+
msg = "Current repository is dirty. Please commit any changes and try again."
|
|
20
|
+
raise RuntimeError(msg)
|
|
21
|
+
upstream, release_branch = create_release_branch(repo, version)
|
|
22
|
+
main_pushed = False
|
|
23
|
+
tag_pushed = False
|
|
24
|
+
release_created = False
|
|
25
|
+
original_main_sha = upstream.refs.main.commit.hexsha
|
|
26
|
+
try:
|
|
27
|
+
release_commit = release_changelog(repo, version)
|
|
28
|
+
tag = tag_release_commit(release_commit, repo, version)
|
|
29
|
+
print("push release commit") # noqa: T201
|
|
30
|
+
repo.git.push(upstream.name, f"{release_branch}:main", "-f")
|
|
31
|
+
main_pushed = True
|
|
32
|
+
print("push release tag") # noqa: T201
|
|
33
|
+
repo.git.push(upstream.name, tag, "-f")
|
|
34
|
+
tag_pushed = True
|
|
35
|
+
create_github_release(version)
|
|
36
|
+
release_created = True
|
|
37
|
+
print("checkout main to new release and delete release branch") # noqa: T201
|
|
38
|
+
repo.heads.main.checkout()
|
|
39
|
+
repo.delete_head(release_branch, force=True)
|
|
40
|
+
print("delete remote release branch") # noqa: T201
|
|
41
|
+
repo.git.push(upstream.name, f":{release_branch}", "--no-verify")
|
|
42
|
+
upstream.fetch()
|
|
43
|
+
repo.git.reset("--hard", f"{upstream.name}/main")
|
|
44
|
+
print("All done!") # noqa: T201
|
|
45
|
+
except Exception:
|
|
46
|
+
cleanup_failed_release(
|
|
47
|
+
repo,
|
|
48
|
+
upstream,
|
|
49
|
+
version,
|
|
50
|
+
release_branch,
|
|
51
|
+
original_main_sha,
|
|
52
|
+
release_created=release_created,
|
|
53
|
+
tag_pushed=tag_pushed,
|
|
54
|
+
main_pushed=main_pushed,
|
|
55
|
+
)
|
|
56
|
+
raise
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def create_release_branch(repo: Repo, version: Version) -> tuple[Remote, Head]:
|
|
60
|
+
print("create release branch from upstream main") # noqa: T201
|
|
61
|
+
upstream = get_upstream(repo)
|
|
62
|
+
upstream.fetch()
|
|
63
|
+
branch_name = f"release-{version}"
|
|
64
|
+
release_branch = repo.create_head(branch_name, upstream.refs.main, force=True)
|
|
65
|
+
upstream.push(refspec=f"{branch_name}:{branch_name}", force=True)
|
|
66
|
+
release_branch.set_tracking_branch(upstream.refs[branch_name])
|
|
67
|
+
release_branch.checkout()
|
|
68
|
+
return upstream, release_branch
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def get_upstream(repo: Repo) -> Remote:
|
|
72
|
+
for remote in repo.remotes:
|
|
73
|
+
if any("tox-dev/python-discovery" in url for url in remote.urls):
|
|
74
|
+
return remote
|
|
75
|
+
msg = "could not find tox-dev/python-discovery remote"
|
|
76
|
+
raise RuntimeError(msg)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def release_changelog(repo: Repo, version: Version) -> Commit:
|
|
80
|
+
print("generate release commit") # noqa: T201
|
|
81
|
+
check_call(["towncrier", "build", "--yes", "--version", version.public], cwd=str(ROOT_SRC_DIR)) # noqa: S607
|
|
82
|
+
print("format changelog with pre-commit") # noqa: T201
|
|
83
|
+
changelog_path = ROOT_SRC_DIR / "docs" / "changelog.rst"
|
|
84
|
+
try:
|
|
85
|
+
check_call(["pre-commit", "run", "--files", str(changelog_path)], cwd=str(ROOT_SRC_DIR)) # noqa: S607
|
|
86
|
+
except CalledProcessError:
|
|
87
|
+
print("pre-commit made formatting changes, staging them") # noqa: T201
|
|
88
|
+
repo.index.add([str(changelog_path)])
|
|
89
|
+
return repo.index.commit(f"release {version}")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def tag_release_commit(release_commit: Commit, repo: Repo, version: Version) -> TagReference:
|
|
93
|
+
print("tag release commit") # noqa: T201
|
|
94
|
+
version_str = str(version)
|
|
95
|
+
if version_str in {tag.name for tag in repo.tags}:
|
|
96
|
+
print(f"delete existing tag {version_str}") # noqa: T201
|
|
97
|
+
repo.delete_tag(repo.tags[version_str])
|
|
98
|
+
print(f"create tag {version_str}") # noqa: T201
|
|
99
|
+
return repo.create_tag(version_str, ref=release_commit.hexsha, force=True)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def create_github_release(version: Version) -> None:
|
|
103
|
+
print("create github release") # noqa: T201
|
|
104
|
+
version_str = str(version)
|
|
105
|
+
try:
|
|
106
|
+
result = run(
|
|
107
|
+
["gh", "release", "create", version_str, "--title", f"v{version_str}", "--generate-notes"], # noqa: S607
|
|
108
|
+
cwd=str(ROOT_SRC_DIR),
|
|
109
|
+
capture_output=True,
|
|
110
|
+
text=True,
|
|
111
|
+
check=True,
|
|
112
|
+
)
|
|
113
|
+
if result.stdout:
|
|
114
|
+
print(result.stdout) # noqa: T201
|
|
115
|
+
except CalledProcessError as e:
|
|
116
|
+
print(f"gh release create failed with exit code {e.returncode}") # noqa: T201
|
|
117
|
+
if e.stdout:
|
|
118
|
+
print(f"stdout: {e.stdout}") # noqa: T201
|
|
119
|
+
if e.stderr:
|
|
120
|
+
print(f"stderr: {e.stderr}") # noqa: T201
|
|
121
|
+
raise
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def cleanup_failed_release( # noqa: PLR0913
|
|
125
|
+
repo: Repo,
|
|
126
|
+
upstream: Remote,
|
|
127
|
+
version: Version,
|
|
128
|
+
release_branch: Head,
|
|
129
|
+
original_main_sha: str,
|
|
130
|
+
*,
|
|
131
|
+
release_created: bool,
|
|
132
|
+
tag_pushed: bool,
|
|
133
|
+
main_pushed: bool,
|
|
134
|
+
) -> None:
|
|
135
|
+
print("Release failed! Cleaning up...") # noqa: T201
|
|
136
|
+
if release_created:
|
|
137
|
+
print(f"Deleting GitHub release {version}") # noqa: T201
|
|
138
|
+
try:
|
|
139
|
+
check_call(["gh", "release", "delete", str(version), "--yes"], cwd=str(ROOT_SRC_DIR)) # noqa: S607
|
|
140
|
+
except Exception as cleanup_error: # noqa: BLE001
|
|
141
|
+
print(f"Warning: Failed to delete GitHub release: {cleanup_error}") # noqa: T201
|
|
142
|
+
if tag_pushed:
|
|
143
|
+
print(f"Deleting remote tag {version}") # noqa: T201
|
|
144
|
+
try:
|
|
145
|
+
repo.git.push(upstream.name, f":refs/tags/{version}", "--no-verify")
|
|
146
|
+
except Exception as cleanup_error: # noqa: BLE001
|
|
147
|
+
print(f"Warning: Failed to delete remote tag: {cleanup_error}") # noqa: T201
|
|
148
|
+
if main_pushed:
|
|
149
|
+
print(f"Reverting main to {original_main_sha[:8]}") # noqa: T201
|
|
150
|
+
try:
|
|
151
|
+
repo.git.push(upstream.name, f"{original_main_sha}:main", "-f", "--no-verify")
|
|
152
|
+
except Exception as cleanup_error: # noqa: BLE001
|
|
153
|
+
print(f"Warning: Failed to revert main: {cleanup_error}") # noqa: T201
|
|
154
|
+
print("Deleting remote release branch") # noqa: T201
|
|
155
|
+
try:
|
|
156
|
+
repo.git.push(upstream.name, f":{release_branch}", "--no-verify")
|
|
157
|
+
except Exception as cleanup_error: # noqa: BLE001
|
|
158
|
+
print(f"Warning: Failed to delete remote branch: {cleanup_error}") # noqa: T201
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
if __name__ == "__main__":
|
|
162
|
+
import argparse
|
|
163
|
+
|
|
164
|
+
parser = argparse.ArgumentParser(prog="release")
|
|
165
|
+
parser.add_argument("--version", required=True)
|
|
166
|
+
options = parser.parse_args()
|
|
167
|
+
main(options.version)
|
|
@@ -32,6 +32,12 @@ def test_py_info_pypy_version(mocker: MockerFixture) -> None:
|
|
|
32
32
|
assert info.pypy_version_info == (7, 3, 11, "final", 0)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def test_py_info_canonicalizes_graalvm(mocker: MockerFixture) -> None:
|
|
36
|
+
mocker.patch("platform.python_implementation", return_value="GraalVM")
|
|
37
|
+
info = PythonInfo()
|
|
38
|
+
assert info.implementation == "GraalPy"
|
|
39
|
+
|
|
40
|
+
|
|
35
41
|
def test_has_venv_attribute() -> None:
|
|
36
42
|
info = PythonInfo()
|
|
37
43
|
assert isinstance(info.has_venv, bool)
|
|
@@ -155,6 +155,12 @@ def test_specifier_with_implementation() -> None:
|
|
|
155
155
|
assert spec.version_specifier == SpecifierSet.from_string(">=3.12")
|
|
156
156
|
|
|
157
157
|
|
|
158
|
+
def test_specifier_with_graalpy_implementation_alias() -> None:
|
|
159
|
+
spec = PythonSpec.from_string_spec("graalvm>=3.12")
|
|
160
|
+
assert spec.implementation == "graalpy"
|
|
161
|
+
assert spec.version_specifier == SpecifierSet.from_string(">=3.12")
|
|
162
|
+
|
|
163
|
+
|
|
158
164
|
def test_specifier_satisfies_with_partial_information() -> None:
|
|
159
165
|
spec = PythonSpec.from_string_spec(">=3.12")
|
|
160
166
|
candidate = PythonSpec.from_string_spec("python3.12")
|
|
@@ -245,3 +251,10 @@ def test_normalize_isa(isa: str, normalized: str) -> None:
|
|
|
245
251
|
)
|
|
246
252
|
def test_spec_repr_machine(spec_str: str, in_repr: str) -> None:
|
|
247
253
|
assert in_repr in repr(PythonSpec.from_string_spec(spec_str))
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
@pytest.mark.parametrize(("left", "right"), [("graalpy", "graalvm"), ("graalvm", "graalpy")])
|
|
257
|
+
def test_spec_satisfies_graalpy_implementation_aliases(left: str, right: str) -> None:
|
|
258
|
+
spec_1 = PythonSpec.from_string_spec(left)
|
|
259
|
+
spec_2 = PythonSpec.from_string_spec(right)
|
|
260
|
+
assert spec_1.satisfies(spec_2) is True
|
|
@@ -36,12 +36,12 @@ commands = [["pre-commit", "run", "--all-files", "--show-diff-on-failure"]]
|
|
|
36
36
|
|
|
37
37
|
[env."type-3.8"]
|
|
38
38
|
description = "run type check on code base (3.8)"
|
|
39
|
-
deps = ["ty==0.0.17"]
|
|
39
|
+
deps = ["gitpython>=3.1.46", "packaging>=26", "ty==0.0.17"]
|
|
40
40
|
commands = [["ty", "check", "--output-format", "concise", "--error-on-warning", "--python-version", "3.8", "."]]
|
|
41
41
|
|
|
42
42
|
[env."type-3.14"]
|
|
43
43
|
description = "run type check on code base (3.14)"
|
|
44
|
-
deps = ["ty==0.0.17"]
|
|
44
|
+
deps = ["gitpython>=3.1.46", "packaging>=26", "ty==0.0.17"]
|
|
45
45
|
commands = [["ty", "check", "--output-format", "concise", "--error-on-warning", "--python-version", "3.14", "."]]
|
|
46
46
|
|
|
47
47
|
[env.docs]
|
|
@@ -71,6 +71,13 @@ commands = [
|
|
|
71
71
|
["check-wheel-contents", "--no-config", "{env_tmp_dir}"],
|
|
72
72
|
]
|
|
73
73
|
|
|
74
|
+
[env.release]
|
|
75
|
+
description = "do a release, required posargs of the version number"
|
|
76
|
+
skip_install = true
|
|
77
|
+
dependency_groups = ["release"]
|
|
78
|
+
pass_env = ["GH_TOKEN"]
|
|
79
|
+
commands = [["python", "{tox_root}/tasks/release.py", "--version", "{posargs}"]]
|
|
80
|
+
|
|
74
81
|
[env.dev]
|
|
75
82
|
description = "generate a DEV environment"
|
|
76
83
|
package = "editable"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export normalize_isa and deprecate KNOWN_ARCHITECTURES - by :user:`rahuldevikar`.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_discovery-1.3.0 → python_discovery-1.3.1}/tests/py_info/test_py_info_exe_based_of.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|