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.
Files changed (37) hide show
  1. {ducktools_pythonfinder-0.4.6/src/ducktools_pythonfinder.egg-info → ducktools_pythonfinder-0.5.0}/PKG-INFO +11 -5
  2. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/README.md +10 -4
  3. ducktools_pythonfinder-0.5.0/src/ducktools/pythonfinder/_version.py +2 -0
  4. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/linux/__init__.py +6 -2
  5. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/shared.py +63 -1
  6. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/win32/__init__.py +6 -2
  7. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0/src/ducktools_pythonfinder.egg-info}/PKG-INFO +11 -5
  8. ducktools_pythonfinder-0.4.6/src/ducktools/pythonfinder/_version.py +0 -2
  9. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/.gitignore +0 -0
  10. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/LICENSE +0 -0
  11. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/MANIFEST.in +0 -0
  12. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/pyproject.toml +0 -0
  13. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/build_zipapp.py +0 -0
  14. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/detail_this_python.py +0 -0
  15. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/scripts/print_python_versions.py +0 -0
  16. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/setup.cfg +0 -0
  17. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/__init__.py +0 -0
  18. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/__main__.py +0 -0
  19. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/darwin/__init__.py +0 -0
  20. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/details_script.py +0 -0
  21. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/linux/pyenv_search.py +0 -0
  22. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/pythonorg_search.py +0 -0
  23. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/win32/pyenv_search.py +0 -0
  24. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools/pythonfinder/win32/registry_search.py +0 -0
  25. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/SOURCES.txt +0 -0
  26. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/dependency_links.txt +0 -0
  27. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/requires.txt +0 -0
  28. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/src/ducktools_pythonfinder.egg-info/top_level.txt +0 -0
  29. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/conftest.py +0 -0
  30. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/python_versions.txt +0 -0
  31. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/release.json +0 -0
  32. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/sources/release_file.json +0 -0
  33. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_details_script.py +0 -0
  34. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_foldersearch.py +0 -0
  35. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_orgsearch.py +0 -0
  36. {ducktools_pythonfinder-0.4.6 → ducktools_pythonfinder-0.5.0}/tests/test_pyenv.py +0 -0
  37. {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.4.6
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 and then for any
85
- `python*` binaries found on `path`. For those found on `path` they will be made
86
- to run a small script to identify the version.
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 and then for any
57
- `python*` binaries found on `path`. For those found on `path` they will be made
58
- to run a small script to identify the version.
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.
@@ -0,0 +1,2 @@
1
+ __version__ = "0.5.0"
2
+ __version_tuple__ = (0, 5, 0)
@@ -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(get_pyenv_pythons(), get_path_pythons()):
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)
@@ -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, basenames: tuple[str] = ("python", "pypy")
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(get_registered_pythons(), get_pyenv_pythons()):
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.4.6
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 and then for any
85
- `python*` binaries found on `path`. For those found on `path` they will be made
86
- to run a small script to identify the version.
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.
@@ -1,2 +0,0 @@
1
- __version__ = "0.4.6"
2
- __version_tuple__ = (0, 4, 6)