ducktools-pythonfinder 0.4.6__tar.gz → 0.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.
- {ducktools_pythonfinder-0.4.6/src/ducktools_pythonfinder.egg-info → ducktools_pythonfinder-0.5.0}/PKG-INFO +11 -5
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/README.md +10 -4
- ducktools_pythonfinder-0.5.0/src/ducktools/pythonfinder/_version.py +2 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/linux/__init__.py +6 -2
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/shared.py +63 -1
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/win32/__init__.py +6 -2
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0/src/ducktools_pythonfinder.egg-info}/PKG-INFO +11 -5
- ducktools_pythonfinder-0.4.6/src/ducktools/pythonfinder/_version.py +0 -2
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/.gitignore +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/LICENSE +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/MANIFEST.in +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/pyproject.toml +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/build_zipapp.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/detail_this_python.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/print_python_versions.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/setup.cfg +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/__init__.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/__main__.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/darwin/__init__.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/details_script.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/linux/pyenv_search.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/pythonorg_search.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/win32/pyenv_search.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/win32/registry_search.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/SOURCES.txt +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/dependency_links.txt +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/requires.txt +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/top_level.txt +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/conftest.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/python_versions.txt +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/release.json +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/release_file.json +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_details_script.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_foldersearch.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_orgsearch.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_pyenv.py +0 -0
- {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_shared.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ducktools-pythonfinder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Cross platform tool to find available python installations
|
|
5
5
|
Author: David C Ellis
|
|
6
6
|
Project-URL: Homepage, https://github.com/davidcellis/ducktools-pythonfinder
|
|
@@ -77,13 +77,19 @@ The module provides two main functions for searching for local python installs:
|
|
|
77
77
|
* `get_python_installs` is a generator that will yield each python version it discovers
|
|
78
78
|
* `list_python_installs` will take the python versions discovered by `get_python_installs`
|
|
79
79
|
and return a sorted list from newest to oldest python version discovered.
|
|
80
|
+
* For the purposes of sorting, prerelease versions are considered older than any released
|
|
81
|
+
version.
|
|
80
82
|
|
|
81
83
|
On Windows these methods will search the registry for PEP514 recorded python installs
|
|
82
|
-
before checking for any `pyenv-win` installs that have not been registered.
|
|
84
|
+
before checking for any `pyenv-win` installs that have not been registered. Finally, if
|
|
85
|
+
`uv` is available it will try to find Python installs managed by `uv`.
|
|
83
86
|
|
|
84
|
-
On Linux and MacOS this will search for `pyenv` installs first
|
|
85
|
-
`
|
|
86
|
-
|
|
87
|
+
On Linux and MacOS this will search for `pyenv` installs first,
|
|
88
|
+
if `uv` is available it will then try to find `uv` managed python installs.
|
|
89
|
+
Finally it will search `PATH` for any other `python*` binaries that might be available.
|
|
90
|
+
|
|
91
|
+
If a python install is found twice (for instance a pyenv install in the windows registry)
|
|
92
|
+
it will only be returned the first time it is found.
|
|
87
93
|
|
|
88
94
|
The python installs will be returned as instances of `PythonInstall` which will
|
|
89
95
|
contain version info and executable path along with some other useful metadata.
|
|
@@ -49,13 +49,19 @@ The module provides two main functions for searching for local python installs:
|
|
|
49
49
|
* `get_python_installs` is a generator that will yield each python version it discovers
|
|
50
50
|
* `list_python_installs` will take the python versions discovered by `get_python_installs`
|
|
51
51
|
and return a sorted list from newest to oldest python version discovered.
|
|
52
|
+
* For the purposes of sorting, prerelease versions are considered older than any released
|
|
53
|
+
version.
|
|
52
54
|
|
|
53
55
|
On Windows these methods will search the registry for PEP514 recorded python installs
|
|
54
|
-
before checking for any `pyenv-win` installs that have not been registered.
|
|
56
|
+
before checking for any `pyenv-win` installs that have not been registered. Finally, if
|
|
57
|
+
`uv` is available it will try to find Python installs managed by `uv`.
|
|
55
58
|
|
|
56
|
-
On Linux and MacOS this will search for `pyenv` installs first
|
|
57
|
-
`
|
|
58
|
-
|
|
59
|
+
On Linux and MacOS this will search for `pyenv` installs first,
|
|
60
|
+
if `uv` is available it will then try to find `uv` managed python installs.
|
|
61
|
+
Finally it will search `PATH` for any other `python*` binaries that might be available.
|
|
62
|
+
|
|
63
|
+
If a python install is found twice (for instance a pyenv install in the windows registry)
|
|
64
|
+
it will only be returned the first time it is found.
|
|
59
65
|
|
|
60
66
|
The python installs will be returned as instances of `PythonInstall` which will
|
|
61
67
|
contain version info and executable path along with some other useful metadata.
|
|
@@ -27,7 +27,7 @@ import os.path
|
|
|
27
27
|
import itertools
|
|
28
28
|
from _collections_abc import Iterator
|
|
29
29
|
|
|
30
|
-
from ..shared import PythonInstall, get_folder_pythons
|
|
30
|
+
from ..shared import PythonInstall, get_folder_pythons, get_uv_pythons
|
|
31
31
|
from .pyenv_search import get_pyenv_pythons
|
|
32
32
|
|
|
33
33
|
|
|
@@ -57,7 +57,11 @@ def get_path_pythons() -> Iterator[PythonInstall]:
|
|
|
57
57
|
def get_python_installs():
|
|
58
58
|
listed_pythons = set()
|
|
59
59
|
|
|
60
|
-
for py in itertools.chain(
|
|
60
|
+
for py in itertools.chain(
|
|
61
|
+
get_pyenv_pythons(),
|
|
62
|
+
get_uv_pythons(),
|
|
63
|
+
get_path_pythons(),
|
|
64
|
+
):
|
|
61
65
|
if py.executable not in listed_pythons:
|
|
62
66
|
yield py
|
|
63
67
|
listed_pythons.add(py.executable)
|
{ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/shared.py
RENAMED
|
@@ -26,6 +26,8 @@ import sys
|
|
|
26
26
|
import os
|
|
27
27
|
import os.path
|
|
28
28
|
|
|
29
|
+
from _collections_abc import Iterator
|
|
30
|
+
|
|
29
31
|
from ducktools.classbuilder import slotclass, Field, SlotFields
|
|
30
32
|
from ducktools.lazyimporter import LazyImporter, ModuleImport, FromImport
|
|
31
33
|
|
|
@@ -112,6 +114,9 @@ class DetailsScript:
|
|
|
112
114
|
self._source_code = f.read()
|
|
113
115
|
elif os.path.splitext(archive_path := sys.argv[0])[1].startswith(".pyz"):
|
|
114
116
|
script_path = os.path.relpath(details_script.__file__, archive_path)
|
|
117
|
+
if sys.platform == "win32":
|
|
118
|
+
# Windows paths have backslashes, these do not work in zipfiles
|
|
119
|
+
script_path = script_path.replace("\\", "/")
|
|
115
120
|
script = _laz.zipfile.Path(archive_path, script_path)
|
|
116
121
|
self._source_code = script.read_text()
|
|
117
122
|
else:
|
|
@@ -226,7 +231,8 @@ def get_install_details(executable: str) -> PythonInstall | None:
|
|
|
226
231
|
|
|
227
232
|
|
|
228
233
|
def get_folder_pythons(
|
|
229
|
-
base_folder: str | os.PathLike,
|
|
234
|
+
base_folder: str | os.PathLike,
|
|
235
|
+
basenames: tuple[str] = ("python", "pypy")
|
|
230
236
|
):
|
|
231
237
|
regexes = [_python_exe_regex(name) for name in basenames]
|
|
232
238
|
|
|
@@ -240,3 +246,59 @@ def get_folder_pythons(
|
|
|
240
246
|
install = get_install_details(file_path.path)
|
|
241
247
|
if install:
|
|
242
248
|
yield install
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
# UV Specific finder
|
|
252
|
+
def _get_uv_python_path() -> str | None:
|
|
253
|
+
try:
|
|
254
|
+
uv_python_find = _laz.subprocess.run(
|
|
255
|
+
["uv", "python", "dir"],
|
|
256
|
+
check=True,
|
|
257
|
+
text=True,
|
|
258
|
+
capture_output=True
|
|
259
|
+
)
|
|
260
|
+
except _laz.subprocess.CalledProcessError:
|
|
261
|
+
uv_python_dir = None
|
|
262
|
+
else:
|
|
263
|
+
# remove newline
|
|
264
|
+
uv_python_dir = uv_python_find.stdout.strip()
|
|
265
|
+
|
|
266
|
+
return uv_python_dir
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _implementation_from_uv_dir(direntry: os.DirEntry) -> PythonInstall | None:
|
|
270
|
+
python_exe = "python.exe" if sys.platform == "win32" else "bin/python"
|
|
271
|
+
python_path = os.path.join(direntry, python_exe)
|
|
272
|
+
|
|
273
|
+
install: PythonInstall | None = None
|
|
274
|
+
|
|
275
|
+
if os.path.exists(python_path):
|
|
276
|
+
try:
|
|
277
|
+
implementation, version, platform, arch, _ = direntry.name.split("-")
|
|
278
|
+
except ValueError:
|
|
279
|
+
# Directory name format has changed
|
|
280
|
+
# Slow backup - ask python itself
|
|
281
|
+
install = get_install_details(python_path)
|
|
282
|
+
else:
|
|
283
|
+
if implementation == "cpython":
|
|
284
|
+
install = PythonInstall.from_str(
|
|
285
|
+
version=version,
|
|
286
|
+
executable=python_path,
|
|
287
|
+
architecture="32bit" if arch in {"i686", "armv7"} else "64bit",
|
|
288
|
+
implementation=implementation,
|
|
289
|
+
)
|
|
290
|
+
else:
|
|
291
|
+
# Get additional alternate implementation details
|
|
292
|
+
install = get_install_details(python_path)
|
|
293
|
+
|
|
294
|
+
return install
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def get_uv_pythons() -> Iterator[PythonInstall]:
|
|
298
|
+
# This takes some shortcuts over the regular pythonfinder
|
|
299
|
+
# As the UV folders give the python version and the implementation
|
|
300
|
+
if uv_python_path := _get_uv_python_path():
|
|
301
|
+
with os.scandir(uv_python_path) as fld:
|
|
302
|
+
for f in fld:
|
|
303
|
+
if f.is_dir() and (install := _implementation_from_uv_dir(f)):
|
|
304
|
+
yield install
|
|
@@ -25,14 +25,18 @@ from __future__ import annotations
|
|
|
25
25
|
from _collections_abc import Iterator
|
|
26
26
|
import itertools
|
|
27
27
|
|
|
28
|
-
from ..shared import PythonInstall
|
|
28
|
+
from ..shared import PythonInstall, get_uv_pythons
|
|
29
29
|
from .pyenv_search import get_pyenv_pythons
|
|
30
30
|
from .registry_search import get_registered_pythons
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def get_python_installs() -> Iterator[PythonInstall]:
|
|
34
34
|
listed_installs = set()
|
|
35
|
-
for py in itertools.chain(
|
|
35
|
+
for py in itertools.chain(
|
|
36
|
+
get_registered_pythons(),
|
|
37
|
+
get_pyenv_pythons(),
|
|
38
|
+
get_uv_pythons(),
|
|
39
|
+
):
|
|
36
40
|
if py.executable not in listed_installs:
|
|
37
41
|
yield py
|
|
38
42
|
listed_installs.add(py.executable)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ducktools-pythonfinder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Cross platform tool to find available python installations
|
|
5
5
|
Author: David C Ellis
|
|
6
6
|
Project-URL: Homepage, https://github.com/davidcellis/ducktools-pythonfinder
|
|
@@ -77,13 +77,19 @@ The module provides two main functions for searching for local python installs:
|
|
|
77
77
|
* `get_python_installs` is a generator that will yield each python version it discovers
|
|
78
78
|
* `list_python_installs` will take the python versions discovered by `get_python_installs`
|
|
79
79
|
and return a sorted list from newest to oldest python version discovered.
|
|
80
|
+
* For the purposes of sorting, prerelease versions are considered older than any released
|
|
81
|
+
version.
|
|
80
82
|
|
|
81
83
|
On Windows these methods will search the registry for PEP514 recorded python installs
|
|
82
|
-
before checking for any `pyenv-win` installs that have not been registered.
|
|
84
|
+
before checking for any `pyenv-win` installs that have not been registered. Finally, if
|
|
85
|
+
`uv` is available it will try to find Python installs managed by `uv`.
|
|
83
86
|
|
|
84
|
-
On Linux and MacOS this will search for `pyenv` installs first
|
|
85
|
-
`
|
|
86
|
-
|
|
87
|
+
On Linux and MacOS this will search for `pyenv` installs first,
|
|
88
|
+
if `uv` is available it will then try to find `uv` managed python installs.
|
|
89
|
+
Finally it will search `PATH` for any other `python*` binaries that might be available.
|
|
90
|
+
|
|
91
|
+
If a python install is found twice (for instance a pyenv install in the windows registry)
|
|
92
|
+
it will only be returned the first time it is found.
|
|
87
93
|
|
|
88
94
|
The python installs will be returned as instances of `PythonInstall` which will
|
|
89
95
|
contain version info and executable path along with some other useful metadata.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/print_python_versions.py
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/__init__.py
RENAMED
|
File without changes
|
{ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/__main__.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
|
{ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/python_versions.txt
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/release_file.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|