python-discovery 1.1.0__tar.gz → 1.1.2__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.
Files changed (53) hide show
  1. python_discovery-1.1.2/.github/FUNDING.yaml +1 -0
  2. python_discovery-1.1.2/.github/SECURITY.md +9 -0
  3. python_discovery-1.1.2/.github/release.yaml +5 -0
  4. {python_discovery-1.1.0 → python_discovery-1.1.2}/.github/workflows/check.yaml +3 -0
  5. {python_discovery-1.1.0 → python_discovery-1.1.2}/.github/workflows/release.yaml +5 -2
  6. {python_discovery-1.1.0 → python_discovery-1.1.2}/.pre-commit-config.yaml +4 -4
  7. {python_discovery-1.1.0 → python_discovery-1.1.2}/PKG-INFO +39 -4
  8. python_discovery-1.1.2/README.md +43 -0
  9. {python_discovery-1.1.0 → python_discovery-1.1.2}/pyproject.toml +17 -17
  10. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_cached_py_info.py +6 -2
  11. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_py_info.py +17 -5
  12. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/conftest.py +2 -1
  13. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/py_info/test_py_info.py +1 -1
  14. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_cached_py_info.py +13 -0
  15. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_py_info_extra.py +22 -18
  16. python_discovery-1.1.0/.github/release.yml +0 -5
  17. python_discovery-1.1.0/README.md +0 -8
  18. /python_discovery-1.1.0/.github/dependabot.yml → /python_discovery-1.1.2/.github/dependabot.yaml +0 -0
  19. {python_discovery-1.1.0 → python_discovery-1.1.2}/.gitignore +0 -0
  20. {python_discovery-1.1.0 → python_discovery-1.1.2}/.readthedocs.yaml +0 -0
  21. {python_discovery-1.1.0 → python_discovery-1.1.2}/.readthedocs.yml +0 -0
  22. {python_discovery-1.1.0 → python_discovery-1.1.2}/CODE_OF_CONDUCT.md +0 -0
  23. {python_discovery-1.1.0 → python_discovery-1.1.2}/LICENSE +0 -0
  24. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/_static/custom.css +0 -0
  25. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/_static/logo.svg +0 -0
  26. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/conf.py +0 -0
  27. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/explanation.rst +0 -0
  28. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/how-to/standalone-usage.rst +0 -0
  29. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/index.rst +0 -0
  30. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/reference/api.rst +0 -0
  31. {python_discovery-1.1.0 → python_discovery-1.1.2}/docs/tutorial/getting-started.rst +0 -0
  32. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/__init__.py +0 -0
  33. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_cache.py +0 -0
  34. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_compat.py +0 -0
  35. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_discovery.py +0 -0
  36. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_py_spec.py +0 -0
  37. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_specifier.py +0 -0
  38. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_windows/__init__.py +0 -0
  39. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_windows/_pep514.py +0 -0
  40. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/_windows/_propose.py +0 -0
  41. {python_discovery-1.1.0 → python_discovery-1.1.2}/src/python_discovery/py.typed +0 -0
  42. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/py_info/test_py_info_exe_based_of.py +0 -0
  43. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_cache.py +0 -0
  44. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_discovery.py +0 -0
  45. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_discovery_extra.py +0 -0
  46. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_py_spec.py +0 -0
  47. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_py_spec_extra.py +0 -0
  48. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/test_specifier.py +0 -0
  49. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/windows/conftest.py +0 -0
  50. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/windows/test_windows.py +0 -0
  51. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/windows/test_windows_pep514.py +0 -0
  52. {python_discovery-1.1.0 → python_discovery-1.1.2}/tests/windows/winreg_mock_values.py +0 -0
  53. {python_discovery-1.1.0 → python_discovery-1.1.2}/tox.toml +0 -0
@@ -0,0 +1 @@
1
+ github: gaborbernat
@@ -0,0 +1,9 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Only the latest released version is supported with security updates. Older versions will not receive patches.
6
+
7
+ ## Reporting a Vulnerability
8
+
9
+ Please report security vulnerabilities via [GitHub's private vulnerability reporting](../../security/advisories/new).
@@ -0,0 +1,5 @@
1
+ changelog:
2
+ exclude:
3
+ authors:
4
+ - dependabot[bot]
5
+ - pre-commit-ci[bot]
@@ -12,6 +12,9 @@ concurrency:
12
12
  group: check-${{ github.ref }}
13
13
  cancel-in-progress: true
14
14
 
15
+ permissions:
16
+ contents: read
17
+
15
18
  jobs:
16
19
  test:
17
20
  runs-on: ubuntu-latest
@@ -3,6 +3,9 @@ on:
3
3
  push:
4
4
  tags: ["*"]
5
5
 
6
+ permissions:
7
+ contents: read
8
+
6
9
  env:
7
10
  dists-artifact-name: python-package-distributions
8
11
 
@@ -22,7 +25,7 @@ jobs:
22
25
  - name: Build package
23
26
  run: uv build --python 3.14 --python-preference only-managed --sdist --wheel . --out-dir dist
24
27
  - name: Store the distribution packages
25
- uses: actions/upload-artifact@v6
28
+ uses: actions/upload-artifact@v7
26
29
  with:
27
30
  name: ${{ env.dists-artifact-name }}
28
31
  path: dist/*
@@ -38,7 +41,7 @@ jobs:
38
41
  id-token: write
39
42
  steps:
40
43
  - name: Download all the dists
41
- uses: actions/download-artifact@v7
44
+ uses: actions/download-artifact@v8
42
45
  with:
43
46
  name: ${{ env.dists-artifact-name }}
44
47
  path: dist/
@@ -5,21 +5,21 @@ 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.36.1
8
+ rev: 0.37.0
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.1
13
+ rev: v2.4.2
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.11.1"
18
+ rev: "v2.16.2"
19
19
  hooks:
20
20
  - id: pyproject-fmt
21
21
  - repo: https://github.com/astral-sh/ruff-pre-commit
22
- rev: "v0.14.14"
22
+ rev: "v0.15.5"
23
23
  hooks:
24
24
  - id: ruff-format
25
25
  - id: ruff
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-discovery
3
- Version: 1.1.0
3
+ Version: 1.1.2
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
@@ -64,8 +64,43 @@ Description-Content-Type: text/markdown
64
64
  # [`python-discovery`](https://python-discovery.readthedocs.io/en/latest/)
65
65
 
66
66
  [![PyPI](https://img.shields.io/pypi/v/python-discovery?style=flat-square)](https://pypi.org/project/python-discovery/)
67
- [![Supported Python
68
- versions](https://img.shields.io/pypi/pyversions/python-discovery.svg)](https://pypi.org/project/python-discovery/)
67
+ [![Supported Python versions](https://img.shields.io/pypi/pyversions/python-discovery.svg)](https://pypi.org/project/python-discovery/)
69
68
  [![Downloads](https://static.pepy.tech/badge/python-discovery/month)](https://pepy.tech/project/python-discovery)
70
- [![check](https://github.com/tox-dev/python-discovery/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/python-discovery/actions/workflows/check.yaml)
69
+ [![check](https://github.com/tox-dev/python-discovery/actions/workflows/check.yaml/badge.svg)](https://github.com/tox-dev/python-discovery/actions/workflows/check.yaml)
71
70
  [![Documentation Status](https://readthedocs.org/projects/python-discovery/badge/?version=latest)](https://python-discovery.readthedocs.io/en/latest/?badge=latest)
71
+
72
+ ## What is python-discovery?
73
+
74
+ `python-discovery` is a library for discovering Python interpreters installed on your machine. You may have multiple
75
+ Python versions from system packages, [pyenv](https://github.com/pyenv/pyenv), [mise](https://mise.jdx.dev/),
76
+ [asdf](https://asdf-vm.com/), [uv](https://docs.astral.sh/uv/), or the Windows registry (PEP 514). This library finds
77
+ the right one for you.
78
+
79
+ Give it a requirement like `python3.12` or `>=3.11,<3.13`, and it searches all known locations, verifies each candidate,
80
+ and returns detailed metadata about the match. Results are cached to disk so repeated lookups are fast.
81
+
82
+ ## Usage
83
+
84
+ ```python
85
+ from pathlib import Path
86
+
87
+ from python_discovery import DiskCache, get_interpreter
88
+
89
+ cache = DiskCache(root=Path("~/.cache/python-discovery").expanduser())
90
+ result = get_interpreter("python3.12", cache=cache)
91
+ if result is not None:
92
+ print(result.executable) # /usr/bin/python3.12
93
+ print(result.implementation) # CPython
94
+ print(result.version_info[:3]) # (3, 12, 1)
95
+ ```
96
+
97
+ The `get_interpreter()` function accepts various specification formats:
98
+
99
+ - Absolute path: `/usr/bin/python3.12`
100
+ - Version: `3.12`
101
+ - Implementation prefix: `cpython3.12`
102
+ - PEP 440 specifier: `>=3.10`, `>=3.11,<3.13`
103
+
104
+ ## Documentation
105
+
106
+ Full documentation is available at [python-discovery.readthedocs.io](https://python-discovery.readthedocs.io/en/latest/)
@@ -0,0 +1,43 @@
1
+ # [`python-discovery`](https://python-discovery.readthedocs.io/en/latest/)
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/python-discovery?style=flat-square)](https://pypi.org/project/python-discovery/)
4
+ [![Supported Python versions](https://img.shields.io/pypi/pyversions/python-discovery.svg)](https://pypi.org/project/python-discovery/)
5
+ [![Downloads](https://static.pepy.tech/badge/python-discovery/month)](https://pepy.tech/project/python-discovery)
6
+ [![check](https://github.com/tox-dev/python-discovery/actions/workflows/check.yaml/badge.svg)](https://github.com/tox-dev/python-discovery/actions/workflows/check.yaml)
7
+ [![Documentation Status](https://readthedocs.org/projects/python-discovery/badge/?version=latest)](https://python-discovery.readthedocs.io/en/latest/?badge=latest)
8
+
9
+ ## What is python-discovery?
10
+
11
+ `python-discovery` is a library for discovering Python interpreters installed on your machine. You may have multiple
12
+ Python versions from system packages, [pyenv](https://github.com/pyenv/pyenv), [mise](https://mise.jdx.dev/),
13
+ [asdf](https://asdf-vm.com/), [uv](https://docs.astral.sh/uv/), or the Windows registry (PEP 514). This library finds
14
+ the right one for you.
15
+
16
+ Give it a requirement like `python3.12` or `>=3.11,<3.13`, and it searches all known locations, verifies each candidate,
17
+ and returns detailed metadata about the match. Results are cached to disk so repeated lookups are fast.
18
+
19
+ ## Usage
20
+
21
+ ```python
22
+ from pathlib import Path
23
+
24
+ from python_discovery import DiskCache, get_interpreter
25
+
26
+ cache = DiskCache(root=Path("~/.cache/python-discovery").expanduser())
27
+ result = get_interpreter("python3.12", cache=cache)
28
+ if result is not None:
29
+ print(result.executable) # /usr/bin/python3.12
30
+ print(result.implementation) # CPython
31
+ print(result.version_info[:3]) # (3, 12, 1)
32
+ ```
33
+
34
+ The `get_interpreter()` function accepts various specification formats:
35
+
36
+ - Absolute path: `/usr/bin/python3.12`
37
+ - Version: `3.12`
38
+ - Implementation prefix: `cpython3.12`
39
+ - PEP 440 specifier: `>=3.10`, `>=3.11,<3.13`
40
+
41
+ ## Documentation
42
+
43
+ Full documentation is available at [python-discovery.readthedocs.io](https://python-discovery.readthedocs.io/en/latest/)
@@ -129,31 +129,20 @@ count = true
129
129
  [tool.pyproject-fmt]
130
130
  max_supported_python = "3.14"
131
131
 
132
- [tool.pytest.ini_options]
133
- markers = [ "graalpy" ]
132
+ [tool.pytest]
133
+ ini_options.markers = [ "graalpy" ]
134
134
 
135
135
  [tool.coverage]
136
- run.source = [
137
- "python_discovery",
138
- "tests",
139
- ]
140
- run.dynamic_context = "test_function"
141
136
  run.branch = true
137
+ run.dynamic_context = "test_function"
142
138
  run.parallel = true
143
139
  run.plugins = [
144
140
  "covdefaults",
145
141
  ]
146
- report.fail_under = 100
147
- report.show_missing = true
148
- report.partial_branches = [
149
- "assert any\\(",
150
- ]
151
- report.omit = [
152
- "src/python_discovery/_windows/*",
153
- "tests/windows/*",
142
+ run.source = [
143
+ "python_discovery",
144
+ "tests",
154
145
  ]
155
- html.show_contexts = true
156
- html.skip_covered = false
157
146
  paths.source = [
158
147
  "src",
159
148
  ".tox*/*/lib/python*/site-packages",
@@ -162,6 +151,17 @@ paths.source = [
162
151
  "*/src",
163
152
  "*\\src",
164
153
  ]
154
+ report.fail_under = 100
155
+ report.omit = [
156
+ "src/python_discovery/_windows/*",
157
+ "tests/windows/*",
158
+ ]
159
+ report.partial_branches = [
160
+ "assert any\\(",
161
+ ]
162
+ report.show_missing = true
163
+ html.show_contexts = true
164
+ html.skip_covered = false
165
165
 
166
166
  [tool.ty]
167
167
  src.exclude = [ "tests/windows/winreg_mock_values.py" ]
@@ -15,7 +15,7 @@ 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 # noqa: S404
18
+ from subprocess import Popen, TimeoutExpired # noqa: S404
19
19
  from typing import TYPE_CHECKING, Final
20
20
 
21
21
  from ._cache import NoOpCache
@@ -206,8 +206,12 @@ def _run_subprocess(
206
206
  encoding="utf-8",
207
207
  errors="backslashreplace",
208
208
  )
209
- out, err = process.communicate()
209
+ out, err = process.communicate(timeout=5)
210
210
  code = process.returncode
211
+ except TimeoutExpired:
212
+ process.kill()
213
+ process.communicate()
214
+ out, err, code = "", "timed out", -1
211
215
  except OSError as os_error:
212
216
  out, err, code = "", os_error.strerror, os_error.errno
213
217
  if code != 0:
@@ -469,12 +469,24 @@ class PythonInfo: # noqa: PLR0904
469
469
  if spec.version_specifier is None: # pragma: no cover
470
470
  return True
471
471
  version_info = self.version_info
472
- release = f"{version_info.major}.{version_info.minor}.{version_info.micro}"
473
- if version_info.releaselevel != "final":
474
- suffix = {"alpha": "a", "beta": "b", "candidate": "rc"}.get(version_info.releaselevel)
475
- if suffix is not None: # pragma: no branch # releaselevel is always alpha/beta/candidate here
472
+ for specifier in spec.version_specifier:
473
+ assert specifier.version is not None # noqa: S101
474
+ numeric_version = specifier.version_str
475
+ for prefix in ("rc", "b", "a"):
476
+ if prefix in numeric_version:
477
+ numeric_version = numeric_version.split(prefix)[0]
478
+ break
479
+ precision = numeric_version.count(".") + 1
480
+ release = ".".join(str(c) for c in [version_info.major, version_info.minor, version_info.micro][:precision])
481
+ if (
482
+ version_info.releaselevel != "final"
483
+ and (precision == 3 or specifier.version.pre_type is not None) # noqa: PLR2004
484
+ and (suffix := {"alpha": "a", "beta": "b", "candidate": "rc"}.get(version_info.releaselevel))
485
+ ):
476
486
  release = f"{release}{suffix}{version_info.serial}"
477
- return spec.version_specifier.contains(release)
487
+ if not specifier.contains(release):
488
+ return False
489
+ return True
478
490
 
479
491
  _current_system = None
480
492
  _current = None
@@ -26,4 +26,5 @@ def _ensure_py_info_cache_empty(session_cache: DiskCache) -> Generator[None]:
26
26
  def _skip_if_test_in_system(session_cache: DiskCache) -> None:
27
27
  current = PythonInfo.current(session_cache)
28
28
  if current.system_executable is not None: # pragma: no cover
29
- pytest.skip("test not valid if run under system")
29
+ msg = "test not valid if run under system"
30
+ raise pytest.skip.Exception(msg)
@@ -338,7 +338,7 @@ def test_py_info_machine_property() -> None:
338
338
  assert machine is not None
339
339
  assert isinstance(machine, str)
340
340
  assert len(machine) > 0
341
- known_isas = {"arm64", "x86_64", "x86", "ppc64le", "ppc64", "s390x", "riscv64"}
341
+ known_isas = {"arm64", "i686", "ppc64", "ppc64le", "riscv64", "s390x", "x86", "x86_64"}
342
342
  assert machine in known_isas, f"unexpected machine value: {machine}"
343
343
 
344
344
 
@@ -5,6 +5,7 @@ import logging
5
5
  import os
6
6
  import sys
7
7
  from pathlib import Path
8
+ from subprocess import TimeoutExpired
8
9
  from typing import TYPE_CHECKING
9
10
  from unittest.mock import MagicMock, patch
10
11
 
@@ -110,6 +111,18 @@ def test_run_subprocess_with_cookies(mocker: MockerFixture) -> None:
110
111
  assert mock_stdout.write.call_count == 2
111
112
 
112
113
 
114
+ def test_run_subprocess_timeout(mocker: MockerFixture) -> None:
115
+ mock_process = MagicMock()
116
+ mock_process.communicate.side_effect = [TimeoutExpired(cmd="python", timeout=30), ("", "")]
117
+ mocker.patch("python_discovery._cached_py_info.Popen", return_value=mock_process)
118
+ failure, result = _run_subprocess(PythonInfo, sys.executable, dict(os.environ))
119
+ assert failure is not None
120
+ assert "timed out" in str(failure)
121
+ assert result is None
122
+ mock_process.kill.assert_called_once()
123
+ assert mock_process.communicate.call_count == 2
124
+
125
+
113
126
  def test_run_subprocess_nonzero_exit(mocker: MockerFixture) -> None:
114
127
  mock_process = MagicMock()
115
128
  mock_process.communicate.return_value = ("some output", "some error")
@@ -276,25 +276,29 @@ def test_satisfies_version_specifier_fails() -> None:
276
276
  assert CURRENT.satisfies(spec, impl_must_match=False) is False
277
277
 
278
278
 
279
- def test_satisfies_prerelease_version() -> None:
279
+ @pytest.mark.parametrize(
280
+ ("version_info", "spec_str", "expected"),
281
+ [
282
+ pytest.param(VersionInfo(3, 14, 0, "alpha", 1), ">=3.14.0a1", True, id="alpha_match_exact"),
283
+ pytest.param(VersionInfo(3, 14, 0, "beta", 1), ">=3.14.0b1", True, id="beta_match_exact"),
284
+ pytest.param(VersionInfo(3, 14, 0, "candidate", 1), ">=3.14.0rc1", True, id="rc_match_exact"),
285
+ pytest.param(VersionInfo(3, 15, 0, "alpha", 6), ">=3.15", True, id="prerelease_match_major_minor"),
286
+ pytest.param(VersionInfo(3, 15, 0, "alpha", 6), ">=3.15.0", False, id="prerelease_not_match_full_precision"),
287
+ pytest.param(VersionInfo(3, 15, 0, "alpha", 5), "<3.15.0a6", True, id="earlier_prerelease_less_than"),
288
+ pytest.param(VersionInfo(3, 15, 0, "alpha", 6), "<3.15.0a6", False, id="prerelease_not_less_than_itself"),
289
+ pytest.param(VersionInfo(3, 15, 0, "alpha", 6), ">=3.15.0a6", True, id="prerelease_match_itself"),
290
+ pytest.param(VersionInfo(3, 15, 0, "alpha", 6), ">=3.15.0a7", False, id="prerelease_not_match_later"),
291
+ pytest.param(VersionInfo(3, 15, 0, "final", 0), ">=3.15.0a6", True, id="final_greater_than_prerelease"),
292
+ pytest.param(VersionInfo(3, 15, 0, "final", 0), "<3.15.0a6", False, id="final_not_less_than_prerelease"),
293
+ pytest.param(VersionInfo(3, 15, 0, "final", 0), ">=3.15", True, id="final_match_major_minor"),
294
+ pytest.param(VersionInfo(3, 15, 1, "alpha", 1), ">=3.15.0", True, id="later_micro_prerelease_match"),
295
+ ],
296
+ )
297
+ def test_satisfies_version_specifier_prerelease(version_info: VersionInfo, spec_str: str, expected: bool) -> None:
280
298
  info = copy.deepcopy(CURRENT)
281
- info.version_info = VersionInfo(3, 14, 0, "alpha", 1)
282
- spec = PythonSpec.from_string_spec(">=3.14.0a1")
283
- assert info.satisfies(spec, impl_must_match=False) is True
284
-
285
-
286
- def test_satisfies_prerelease_beta() -> None:
287
- info = copy.deepcopy(CURRENT)
288
- info.version_info = VersionInfo(3, 14, 0, "beta", 1)
289
- spec = PythonSpec.from_string_spec(">=3.14.0b1")
290
- assert info.satisfies(spec, impl_must_match=False) is True
291
-
292
-
293
- def test_satisfies_prerelease_candidate() -> None:
294
- info = copy.deepcopy(CURRENT)
295
- info.version_info = VersionInfo(3, 14, 0, "candidate", 1)
296
- spec = PythonSpec.from_string_spec(">=3.14.0rc1")
297
- assert info.satisfies(spec, impl_must_match=False) is True
299
+ info.version_info = version_info
300
+ spec = PythonSpec.from_string_spec(spec_str)
301
+ assert info.satisfies(spec, impl_must_match=False) is expected
298
302
 
299
303
 
300
304
  def test_satisfies_path_not_abs_basename_match() -> None:
@@ -1,5 +0,0 @@
1
- changelog:
2
- exclude:
3
- authors:
4
- - dependabot
5
- - pre-commit-ci
@@ -1,8 +0,0 @@
1
- # [`python-discovery`](https://python-discovery.readthedocs.io/en/latest/)
2
-
3
- [![PyPI](https://img.shields.io/pypi/v/python-discovery?style=flat-square)](https://pypi.org/project/python-discovery/)
4
- [![Supported Python
5
- versions](https://img.shields.io/pypi/pyversions/python-discovery.svg)](https://pypi.org/project/python-discovery/)
6
- [![Downloads](https://static.pepy.tech/badge/python-discovery/month)](https://pepy.tech/project/python-discovery)
7
- [![check](https://github.com/tox-dev/python-discovery/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/python-discovery/actions/workflows/check.yaml)
8
- [![Documentation Status](https://readthedocs.org/projects/python-discovery/badge/?version=latest)](https://python-discovery.readthedocs.io/en/latest/?badge=latest)