ducktools-pythonfinder 0.8.7__tar.gz → 0.9.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.8.7/src/ducktools_pythonfinder.egg-info → ducktools_pythonfinder-0.9.0}/PKG-INFO +1 -1
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/__main__.py +3 -2
- ducktools_pythonfinder-0.9.0/src/ducktools/pythonfinder/_version.py +2 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/details_script.py +17 -3
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/linux/__init__.py +12 -1
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/shared.py +18 -4
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0/src/ducktools_pythonfinder.egg-info}/PKG-INFO +1 -1
- ducktools_pythonfinder-0.8.7/src/ducktools/pythonfinder/_version.py +0 -2
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/.gitignore +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/LICENSE +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/MANIFEST.in +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/README.md +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/pyproject.toml +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/scripts/build_zipapp.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/scripts/detail_this_python.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/scripts/list_python_venvs.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/scripts/print_python_versions.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/setup.cfg +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/__init__.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/darwin/__init__.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/linux/pyenv_search.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/package_list_script.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/pythonorg_search.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/venv.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/win32/__init__.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/win32/pyenv_search.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/win32/registry_search.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools_pythonfinder.egg-info/SOURCES.txt +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools_pythonfinder.egg-info/dependency_links.txt +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools_pythonfinder.egg-info/entry_points.txt +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools_pythonfinder.egg-info/requires.txt +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools_pythonfinder.egg-info/top_level.txt +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/conftest.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/sources/python_versions.txt +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/sources/release.json +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/sources/release_file.json +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_cache.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_details_script.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_foldersearch.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_orgsearch.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_pyenv.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_shared.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_uv_finder.py +0 -0
- {ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/test_venv_finder.py +0 -0
{ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/__main__.py
RENAMED
|
@@ -35,6 +35,7 @@ _laz = LazyImporter(
|
|
|
35
35
|
ModuleImport("argparse"),
|
|
36
36
|
ModuleImport("csv"),
|
|
37
37
|
ModuleImport("subprocess"),
|
|
38
|
+
ModuleImport("sysconfig"),
|
|
38
39
|
ModuleImport("platform"),
|
|
39
40
|
FromImport(".pythonorg_search", "PythonOrgSearch"),
|
|
40
41
|
FromImport("packaging.specifiers", "SpecifierSet"),
|
|
@@ -207,7 +208,7 @@ def display_local_installs(
|
|
|
207
208
|
version_str = f"*{version_str}"
|
|
208
209
|
elif (
|
|
209
210
|
sys.prefix != sys.base_prefix
|
|
210
|
-
and
|
|
211
|
+
and install.paths.get("stdlib") == _laz.sysconfig.get_path("stdlib")
|
|
211
212
|
):
|
|
212
213
|
version_str = f"**{version_str}"
|
|
213
214
|
|
|
@@ -240,7 +241,7 @@ def display_local_installs(
|
|
|
240
241
|
if sys.platform != "win32":
|
|
241
242
|
print("[] - This Python install is shadowed by another on Path")
|
|
242
243
|
print("* - This is the active Python executable used to call this module")
|
|
243
|
-
print("** - This is
|
|
244
|
+
print("** - This is a parent Python executable of the venv used to call this module")
|
|
244
245
|
print()
|
|
245
246
|
|
|
246
247
|
headings_str = f"| {headings[0]:<{max_version_len}s} | {headings[1]:<{max_executable_len}s} |"
|
|
@@ -46,7 +46,7 @@ def version_str_to_tuple(version):
|
|
|
46
46
|
releaselevel = "alpha"
|
|
47
47
|
elif releaselevel == "b":
|
|
48
48
|
releaselevel = "beta"
|
|
49
|
-
elif releaselevel
|
|
49
|
+
elif releaselevel in {"c", "rc"}:
|
|
50
50
|
releaselevel = "candidate"
|
|
51
51
|
else:
|
|
52
52
|
releaselevel = "final"
|
|
@@ -80,9 +80,14 @@ def get_details():
|
|
|
80
80
|
"graalpy_version": version_str_to_tuple(ver)
|
|
81
81
|
}
|
|
82
82
|
except (NameError, ValueError):
|
|
83
|
-
metadata = {"{}_version".format(implementation): sys.implementation.version}
|
|
83
|
+
metadata = {"{}_version".format(implementation): sys.implementation.version}
|
|
84
84
|
elif implementation != "cpython": # pragma: no cover
|
|
85
|
-
|
|
85
|
+
if implementation == "micropython":
|
|
86
|
+
imp_ver = sys.implementation.version[:3]
|
|
87
|
+
else:
|
|
88
|
+
imp_ver = sys.implementation.version
|
|
89
|
+
|
|
90
|
+
metadata = {"{}_version".format(implementation): imp_ver}
|
|
86
91
|
else:
|
|
87
92
|
metadata = {}
|
|
88
93
|
if sys.version_info >= (3, 13):
|
|
@@ -90,12 +95,21 @@ def get_details():
|
|
|
90
95
|
freethreaded = bool(sysconfig.get_config_var("Py_GIL_DISABLED"))
|
|
91
96
|
metadata["freethreaded"] = freethreaded
|
|
92
97
|
|
|
98
|
+
# Attempt to get the paths to stdlib etc from sysconfig
|
|
99
|
+
try:
|
|
100
|
+
import sysconfig # Exists in 2.7 and 3.2 onwards, missing in earlier and micropython
|
|
101
|
+
except ImportError:
|
|
102
|
+
paths = {}
|
|
103
|
+
else:
|
|
104
|
+
paths = sysconfig.get_paths()
|
|
105
|
+
|
|
93
106
|
install = dict(
|
|
94
107
|
version=list(sys.version_info),
|
|
95
108
|
executable=sys.executable,
|
|
96
109
|
architecture="64bit" if (sys.maxsize > 2**32) else "32bit",
|
|
97
110
|
implementation=implementation,
|
|
98
111
|
metadata=metadata,
|
|
112
|
+
paths=paths,
|
|
99
113
|
)
|
|
100
114
|
|
|
101
115
|
return install
|
|
@@ -37,6 +37,14 @@ from ..shared import (
|
|
|
37
37
|
from .pyenv_search import get_pyenv_pythons, get_pyenv_root
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
KNOWN_MANAGED_PATHS = {
|
|
41
|
+
"/usr/bin": "OS",
|
|
42
|
+
"/bin": "OS",
|
|
43
|
+
"/usr/sbin": "OS",
|
|
44
|
+
"/sbin": "OS",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
40
48
|
def get_path_pythons(*, finder: DetailFinder | None = None) -> Iterator[PythonInstall]:
|
|
41
49
|
exe_names = set()
|
|
42
50
|
|
|
@@ -46,7 +54,7 @@ def get_path_pythons(*, finder: DetailFinder | None = None) -> Iterator[PythonIn
|
|
|
46
54
|
|
|
47
55
|
excluded_folders = [pyenv_root, uv_root]
|
|
48
56
|
|
|
49
|
-
finder = DetailFinder if finder is None else finder
|
|
57
|
+
finder = DetailFinder() if finder is None else finder
|
|
50
58
|
|
|
51
59
|
for fld in path_folders:
|
|
52
60
|
# Don't retrieve pyenv installs
|
|
@@ -63,6 +71,9 @@ def get_path_pythons(*, finder: DetailFinder | None = None) -> Iterator[PythonIn
|
|
|
63
71
|
continue
|
|
64
72
|
|
|
65
73
|
for install in get_folder_pythons(fld, finder=finder):
|
|
74
|
+
if manager := KNOWN_MANAGED_PATHS.get(os.path.dirname(install.executable)):
|
|
75
|
+
install.managed_by = manager
|
|
76
|
+
|
|
66
77
|
name = os.path.basename(install.executable)
|
|
67
78
|
if name in exe_names:
|
|
68
79
|
install.shadowed = True
|
{ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/shared.py
RENAMED
|
@@ -80,7 +80,7 @@ else:
|
|
|
80
80
|
CACHE_FOLDER = os.path.join(USER_FOLDER, ".cache", "ducktools", "pythonfinder")
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
CACHE_VERSION =
|
|
83
|
+
CACHE_VERSION = 2
|
|
84
84
|
DETAILS_CACHE_PATH = os.path.join(CACHE_FOLDER, f"runtime_cache_v{CACHE_VERSION}.json")
|
|
85
85
|
INSTALLER_CACHE_PATH = os.path.join(CACHE_FOLDER, "installer_details.json")
|
|
86
86
|
|
|
@@ -321,6 +321,7 @@ class PythonInstall(Prefab):
|
|
|
321
321
|
implementation: str = "cpython"
|
|
322
322
|
managed_by: str | None = None
|
|
323
323
|
metadata: dict = attribute(default_factory=dict)
|
|
324
|
+
paths: dict[str, str] = attribute(default_factory=dict)
|
|
324
325
|
shadowed: bool = attribute(default=False, serialize=False)
|
|
325
326
|
_implementation_version: tuple[int, int, int, str, int] | None = attribute(default=None, private=True)
|
|
326
327
|
|
|
@@ -365,9 +366,13 @@ class PythonInstall(Prefab):
|
|
|
365
366
|
implementation: str = "cpython",
|
|
366
367
|
managed_by: str | None = None,
|
|
367
368
|
metadata: dict | None = None,
|
|
369
|
+
paths: dict | None = None,
|
|
368
370
|
):
|
|
369
371
|
version_tuple = version_str_to_tuple(version)
|
|
370
372
|
|
|
373
|
+
metadata = {} if metadata is None else metadata
|
|
374
|
+
paths = {} if paths is None else paths
|
|
375
|
+
|
|
371
376
|
# noinspection PyArgumentList
|
|
372
377
|
return cls(
|
|
373
378
|
version=version_tuple,
|
|
@@ -376,6 +381,7 @@ class PythonInstall(Prefab):
|
|
|
376
381
|
implementation=implementation,
|
|
377
382
|
managed_by=managed_by,
|
|
378
383
|
metadata=metadata,
|
|
384
|
+
paths=paths,
|
|
379
385
|
)
|
|
380
386
|
|
|
381
387
|
@classmethod
|
|
@@ -386,11 +392,14 @@ class PythonInstall(Prefab):
|
|
|
386
392
|
architecture,
|
|
387
393
|
implementation,
|
|
388
394
|
metadata,
|
|
395
|
+
paths=None,
|
|
389
396
|
managed_by=None,
|
|
390
397
|
):
|
|
391
398
|
if arch_ver := metadata.get(f"{implementation}_version"):
|
|
392
399
|
metadata[f"{implementation}_version"] = tuple(arch_ver)
|
|
393
400
|
|
|
401
|
+
paths = {} if paths is None else paths
|
|
402
|
+
|
|
394
403
|
# noinspection PyArgumentList
|
|
395
404
|
return cls(
|
|
396
405
|
version=tuple(version), # type: ignore
|
|
@@ -399,6 +408,7 @@ class PythonInstall(Prefab):
|
|
|
399
408
|
implementation=implementation,
|
|
400
409
|
managed_by=managed_by,
|
|
401
410
|
metadata=metadata,
|
|
411
|
+
paths=paths,
|
|
402
412
|
)
|
|
403
413
|
|
|
404
414
|
def get_pip_version(self) -> str | None:
|
|
@@ -430,7 +440,7 @@ def _python_exe_regex(basename: str = "python"):
|
|
|
430
440
|
|
|
431
441
|
def get_folder_pythons(
|
|
432
442
|
base_folder: str | os.PathLike,
|
|
433
|
-
basenames: tuple[str] = ("python", "pypy"),
|
|
443
|
+
basenames: tuple[str, ...] = ("python", "pypy", "micropython"),
|
|
434
444
|
finder: DetailFinder | None = None,
|
|
435
445
|
managed_by: str | None = None,
|
|
436
446
|
):
|
|
@@ -438,6 +448,8 @@ def get_folder_pythons(
|
|
|
438
448
|
|
|
439
449
|
finder = DetailFinder() if finder is None else finder
|
|
440
450
|
|
|
451
|
+
base_folder = str(base_folder)
|
|
452
|
+
|
|
441
453
|
with finder, os.scandir(base_folder) as fld:
|
|
442
454
|
for file_path in fld:
|
|
443
455
|
try:
|
|
@@ -452,11 +464,13 @@ def get_folder_pythons(
|
|
|
452
464
|
p = file_path.path
|
|
453
465
|
if file_path.is_symlink():
|
|
454
466
|
# Might be a venv - look for pyvenv.cfg in parent
|
|
455
|
-
|
|
456
|
-
|
|
467
|
+
dirname = os.path.dirname(p)
|
|
468
|
+
|
|
469
|
+
if os.path.exists(os.path.join(dirname, "../pyvenv.cfg")):
|
|
457
470
|
continue
|
|
458
471
|
else:
|
|
459
472
|
p = file_path.path
|
|
473
|
+
|
|
460
474
|
install = finder.get_install_details(p, managed_by=managed_by)
|
|
461
475
|
if install:
|
|
462
476
|
yield install
|
|
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.8.7 → ducktools_pythonfinder-0.9.0}/scripts/print_python_versions.py
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/src/ducktools/pythonfinder/venv.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
|
{ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.0}/tests/sources/python_versions.txt
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.8.7 → ducktools_pythonfinder-0.9.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|