ducktools-pythonfinder 0.7.6__tar.gz → 0.7.8__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.7.6/src/ducktools_pythonfinder.egg-info → ducktools_pythonfinder-0.7.8}/PKG-INFO +1 -1
- ducktools_pythonfinder-0.7.8/src/ducktools/pythonfinder/_version.py +2 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/linux/__init__.py +2 -2
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/linux/pyenv_search.py +22 -4
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/venv.py +9 -15
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/win32/pyenv_search.py +12 -3
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8/src/ducktools_pythonfinder.egg-info}/PKG-INFO +1 -1
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_pyenv.py +30 -6
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_venv_finder.py +3 -2
- ducktools_pythonfinder-0.7.6/src/ducktools/pythonfinder/_version.py +0 -2
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/.gitignore +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/LICENSE +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/MANIFEST.in +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/README.md +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/pyproject.toml +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/scripts/build_zipapp.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/scripts/detail_this_python.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/scripts/list_python_venvs.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/scripts/print_python_versions.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/setup.cfg +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/__main__.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/darwin/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/details_script.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/package_list_script.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/pythonorg_search.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/shared.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/win32/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/win32/registry_search.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools_pythonfinder.egg-info/SOURCES.txt +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools_pythonfinder.egg-info/dependency_links.txt +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools_pythonfinder.egg-info/entry_points.txt +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools_pythonfinder.egg-info/requires.txt +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools_pythonfinder.egg-info/top_level.txt +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/conftest.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/sources/python_versions.txt +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/sources/release.json +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/sources/release_file.json +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_details_script.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_foldersearch.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_orgsearch.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_shared.py +0 -0
- {ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/test_uv_finder.py +0 -0
|
@@ -28,14 +28,14 @@ import itertools
|
|
|
28
28
|
from _collections_abc import Iterator
|
|
29
29
|
|
|
30
30
|
from ..shared import PythonInstall, get_folder_pythons, get_uv_pythons, get_uv_python_path
|
|
31
|
-
from .pyenv_search import get_pyenv_pythons
|
|
31
|
+
from .pyenv_search import get_pyenv_pythons, get_pyenv_root
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def get_path_pythons() -> Iterator[PythonInstall]:
|
|
35
35
|
exe_names = set()
|
|
36
36
|
|
|
37
37
|
path_folders = os.environ.get("PATH", "").split(":")
|
|
38
|
-
pyenv_root =
|
|
38
|
+
pyenv_root = get_pyenv_root()
|
|
39
39
|
uv_root = get_uv_python_path()
|
|
40
40
|
|
|
41
41
|
excluded_folders = [pyenv_root, uv_root]
|
|
@@ -31,28 +31,46 @@ import os
|
|
|
31
31
|
import os.path
|
|
32
32
|
from _collections_abc import Iterator
|
|
33
33
|
|
|
34
|
-
from ducktools.lazyimporter import LazyImporter, ModuleImport
|
|
34
|
+
from ducktools.lazyimporter import LazyImporter, FromImport, ModuleImport
|
|
35
35
|
|
|
36
36
|
from ..shared import PythonInstall, get_install_details, FULL_PY_VER_RE, version_str_to_tuple
|
|
37
37
|
|
|
38
38
|
_laz = LazyImporter(
|
|
39
39
|
[
|
|
40
40
|
ModuleImport("re"),
|
|
41
|
+
FromImport("subprocess", "run"),
|
|
41
42
|
]
|
|
42
43
|
)
|
|
43
44
|
|
|
44
45
|
# pyenv folder name for pypy
|
|
45
46
|
PYPY_VER_RE = r"^pypy(?P<pyversion>\d{1,2}\.\d+)-(?P<pypyversion>[\d\.]*)$"
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
|
|
49
|
+
def get_pyenv_root() -> str | None:
|
|
50
|
+
# Check if the environment variable exists, if so use that
|
|
51
|
+
# As a backup try to run pyenv to obtain the root folder
|
|
52
|
+
pyenv_root = os.environ.get("PYENV_ROOT")
|
|
53
|
+
if not pyenv_root:
|
|
54
|
+
try:
|
|
55
|
+
output = _laz.run(["pyenv", "root"], capture_output=True, text=True)
|
|
56
|
+
except FileNotFoundError:
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
pyenv_root = output.stdout.strip()
|
|
60
|
+
|
|
61
|
+
return pyenv_root
|
|
48
62
|
|
|
49
63
|
|
|
50
64
|
def get_pyenv_pythons(
|
|
51
|
-
versions_folder: str | os.PathLike =
|
|
65
|
+
versions_folder: str | os.PathLike | None = None,
|
|
52
66
|
*,
|
|
53
67
|
query_executables: bool = True,
|
|
54
68
|
) -> Iterator[PythonInstall]:
|
|
55
|
-
if
|
|
69
|
+
if versions_folder is None:
|
|
70
|
+
if pyenv_root := get_pyenv_root():
|
|
71
|
+
versions_folder = os.path.join(pyenv_root, "versions")
|
|
72
|
+
|
|
73
|
+
if versions_folder is None or not os.path.exists(versions_folder):
|
|
56
74
|
return
|
|
57
75
|
|
|
58
76
|
# Sorting puts standard python versions before alternate implementations
|
{ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/venv.py
RENAMED
|
@@ -175,27 +175,21 @@ class PythonVEnv(Prefab):
|
|
|
175
175
|
:param cfg_path: Path to a virtualenv config file
|
|
176
176
|
:return: PythonVEnv with details relative to that config file
|
|
177
177
|
"""
|
|
178
|
-
parent_path, version_str, parent_exe = None, None, None
|
|
179
178
|
venv_base = os.path.dirname(cfg_path)
|
|
180
179
|
|
|
181
180
|
with open(cfg_path, 'r') as f:
|
|
181
|
+
conf = {}
|
|
182
182
|
for line in f:
|
|
183
|
-
key, value =
|
|
183
|
+
key, _, value = [item.strip() for item in line.partition("=")]
|
|
184
|
+
conf[key] = value
|
|
184
185
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# venv and uv use different key names :)
|
|
189
|
-
version_str = value
|
|
190
|
-
elif key == "executable":
|
|
191
|
-
parent_exe = value
|
|
186
|
+
parent_path = conf.get("home")
|
|
187
|
+
version_str = conf.get("version", conf.get("version_info"))
|
|
188
|
+
parent_exe = conf.get("executable", conf.get("base-executable"))
|
|
192
189
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if parent_path is None or version_str is None:
|
|
197
|
-
# Not a valid venv
|
|
198
|
-
raise InvalidVEnvError(f"Path or version not defined in {cfg_path}")
|
|
190
|
+
if parent_path is None or version_str is None:
|
|
191
|
+
# Not a valid venv
|
|
192
|
+
raise InvalidVEnvError(f"Path or version not defined in {cfg_path}")
|
|
199
193
|
|
|
200
194
|
if sys.platform == "win32":
|
|
201
195
|
venv_exe = os.path.join(venv_base, "Scripts", "python.exe")
|
|
@@ -29,15 +29,24 @@ from _collections_abc import Iterator
|
|
|
29
29
|
from ..shared import PythonInstall, get_install_details
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
def get_pyenv_root() -> str | None:
|
|
33
|
+
# Check if the environment variable exists, if so use that
|
|
34
|
+
# Windows PYENV does not have the `pyenv root` command to use as a backup.
|
|
35
|
+
pyenv_root = os.environ.get("PYENV_ROOT")
|
|
36
|
+
return pyenv_root
|
|
33
37
|
|
|
34
38
|
|
|
35
39
|
def get_pyenv_pythons(
|
|
36
|
-
versions_folder: str | os.PathLike =
|
|
40
|
+
versions_folder: str | os.PathLike | None = None,
|
|
37
41
|
*,
|
|
38
42
|
query_executables: bool = True,
|
|
39
43
|
) -> Iterator[PythonInstall]:
|
|
40
|
-
|
|
44
|
+
|
|
45
|
+
if versions_folder is None:
|
|
46
|
+
if pyenv_root := get_pyenv_root():
|
|
47
|
+
versions_folder = os.path.join(pyenv_root, "versions")
|
|
48
|
+
|
|
49
|
+
if versions_folder is None or not os.path.exists(versions_folder):
|
|
41
50
|
return
|
|
42
51
|
|
|
43
52
|
for p in os.scandir(versions_folder):
|
|
@@ -25,6 +25,7 @@ import sys
|
|
|
25
25
|
import os
|
|
26
26
|
import os.path
|
|
27
27
|
import textwrap
|
|
28
|
+
import types
|
|
28
29
|
from pathlib import Path
|
|
29
30
|
|
|
30
31
|
import pytest
|
|
@@ -36,18 +37,39 @@ from ducktools.pythonfinder import details_script
|
|
|
36
37
|
if sys.platform == "win32":
|
|
37
38
|
from ducktools.pythonfinder.win32.pyenv_search import (
|
|
38
39
|
get_pyenv_pythons,
|
|
39
|
-
|
|
40
|
+
get_pyenv_root,
|
|
40
41
|
)
|
|
41
42
|
else:
|
|
42
43
|
from ducktools.pythonfinder.linux.pyenv_search import (
|
|
43
44
|
get_pyenv_pythons,
|
|
44
|
-
|
|
45
|
+
get_pyenv_root,
|
|
45
46
|
)
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
details_text = Path(details_script.__file__).read_text()
|
|
49
50
|
|
|
50
51
|
|
|
52
|
+
def test_get_pyenv_root_env():
|
|
53
|
+
fake_path = "path/to/pyenv"
|
|
54
|
+
with patch.dict(os.environ, {"PYENV_ROOT": fake_path}):
|
|
55
|
+
assert get_pyenv_root() == fake_path
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.mark.skipif(sys.platform == "win32", reason="Test for non-Windows only")
|
|
59
|
+
def test_get_pyenv_root_backup():
|
|
60
|
+
with patch.dict(os.environ) as patched:
|
|
61
|
+
if "PYENV_ROOT" in patched:
|
|
62
|
+
del patched["PYENV_ROOT"]
|
|
63
|
+
|
|
64
|
+
from ducktools.pythonfinder.linux.pyenv_search import _laz
|
|
65
|
+
with patch.object(_laz, "run") as run_mock:
|
|
66
|
+
run_mock.return_value = types.SimpleNamespace(stdout="path/to/pyenv\n")
|
|
67
|
+
pyenv_root = get_pyenv_root()
|
|
68
|
+
run_mock.assert_called_with(["pyenv", "root"], text=True, capture_output=True)
|
|
69
|
+
|
|
70
|
+
assert pyenv_root == "path/to/pyenv"
|
|
71
|
+
|
|
72
|
+
|
|
51
73
|
def test_no_versions_folder():
|
|
52
74
|
with patch("os.path.exists") as exists_mock:
|
|
53
75
|
exists_mock.return_value = False
|
|
@@ -59,18 +81,20 @@ def test_mock_versions_folder():
|
|
|
59
81
|
|
|
60
82
|
out_ver = "3.12.1"
|
|
61
83
|
if sys.platform == "win32":
|
|
62
|
-
|
|
84
|
+
versions_folder = os.path.join("c:", "fake", "versions")
|
|
85
|
+
out_executable = os.path.join(versions_folder, out_ver, "python.exe")
|
|
63
86
|
else:
|
|
64
|
-
|
|
87
|
+
versions_folder = "~/fake/versions"
|
|
88
|
+
out_executable = os.path.join(versions_folder, out_ver, "bin/python")
|
|
65
89
|
|
|
66
90
|
mock_dir_entry.name = out_ver
|
|
67
|
-
mock_dir_entry.path = os.path.join(
|
|
91
|
+
mock_dir_entry.path = os.path.join(versions_folder, out_ver)
|
|
68
92
|
|
|
69
93
|
with patch("os.path.exists") as exists_mock, patch("os.scandir") as scandir_mock:
|
|
70
94
|
exists_mock.return_value = True
|
|
71
95
|
scandir_mock.return_value = iter([mock_dir_entry])
|
|
72
96
|
|
|
73
|
-
python_versions = list(get_pyenv_pythons())
|
|
97
|
+
python_versions = list(get_pyenv_pythons(versions_folder="~/fake/versions"))
|
|
74
98
|
|
|
75
99
|
assert python_versions == [PythonInstall.from_str(version=out_ver, executable=out_executable, managed_by="pyenv")]
|
|
76
100
|
|
|
@@ -127,8 +127,9 @@ def test_found_parent(with_venvs, this_python, this_venv):
|
|
|
127
127
|
parent = venv_ex.get_parent_install()
|
|
128
128
|
assert os.path.dirname(parent.executable) == os.path.dirname(this_python.executable)
|
|
129
129
|
|
|
130
|
-
# venv
|
|
131
|
-
|
|
130
|
+
# venvs created by the venv module don't record prerelease details in the version
|
|
131
|
+
# That's not my fault that's venv!
|
|
132
|
+
assert venv_ex.version[:3] == parent.version[:3]
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
def test_found_parent_cache(with_venvs, this_python):
|
|
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.7.6 → ducktools_pythonfinder-0.7.8}/scripts/print_python_versions.py
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/__init__.py
RENAMED
|
File without changes
|
{ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/src/ducktools/pythonfinder/shared.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
|
{ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/sources/python_versions.txt
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.7.6 → ducktools_pythonfinder-0.7.8}/tests/sources/release_file.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|