ducktools-pythonfinder 0.6.6__tar.gz → 0.6.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.6.6/src/ducktools_pythonfinder.egg-info → ducktools_pythonfinder-0.6.8}/PKG-INFO +2 -2
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/__main__.py +39 -6
- ducktools_pythonfinder-0.6.8/src/ducktools/pythonfinder/_version.py +2 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/linux/pyenv_search.py +2 -1
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/shared.py +16 -5
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/win32/pyenv_search.py +4 -2
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/win32/registry_search.py +1 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8/src/ducktools_pythonfinder.egg-info}/PKG-INFO +2 -2
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/test_pyenv.py +7 -4
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/test_uv_finder.py +2 -0
- ducktools_pythonfinder-0.6.6/src/ducktools/pythonfinder/_version.py +0 -2
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/.gitignore +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/LICENSE +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/MANIFEST.in +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/README.md +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/pyproject.toml +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/scripts/build_zipapp.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/scripts/detail_this_python.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/scripts/print_python_versions.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/setup.cfg +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/__init__.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/darwin/__init__.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/details_script.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/linux/__init__.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/pythonorg_search.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/win32/__init__.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools_pythonfinder.egg-info/SOURCES.txt +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools_pythonfinder.egg-info/dependency_links.txt +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools_pythonfinder.egg-info/entry_points.txt +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools_pythonfinder.egg-info/requires.txt +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools_pythonfinder.egg-info/top_level.txt +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/conftest.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/sources/python_versions.txt +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/sources/release.json +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/sources/release_file.json +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/test_details_script.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/test_foldersearch.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/test_orgsearch.py +0 -0
- {ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/test_shared.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: ducktools-pythonfinder
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.8
|
|
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
|
{ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/__main__.py
RENAMED
|
@@ -74,8 +74,42 @@ def stop_autoclose():
|
|
|
74
74
|
_laz.subprocess.run("pause", shell=True)
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def
|
|
78
|
-
|
|
77
|
+
def _get_parser_class():
|
|
78
|
+
# This class is deferred to avoid the argparse import
|
|
79
|
+
# if there are no arguments to parse
|
|
80
|
+
|
|
81
|
+
class FixedArgumentParser(_laz.argparse.ArgumentParser):
|
|
82
|
+
"""
|
|
83
|
+
The builtin argument parser uses shutil to figure out the terminal width
|
|
84
|
+
to display help info. This one replaces the function that calls help info
|
|
85
|
+
and plugs in a value for width.
|
|
86
|
+
|
|
87
|
+
This prevents the unnecessary import.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def _get_formatter(self):
|
|
91
|
+
# Calculate width
|
|
92
|
+
try:
|
|
93
|
+
columns = int(os.environ['COLUMNS'])
|
|
94
|
+
except (KeyError, ValueError):
|
|
95
|
+
try:
|
|
96
|
+
size = os.get_terminal_size()
|
|
97
|
+
except (AttributeError, ValueError, OSError):
|
|
98
|
+
# get_terminal_size unsupported
|
|
99
|
+
columns = 80
|
|
100
|
+
else:
|
|
101
|
+
columns = size.columns
|
|
102
|
+
|
|
103
|
+
# noinspection PyArgumentList
|
|
104
|
+
return self.formatter_class(prog=self.prog, width=columns - 2)
|
|
105
|
+
|
|
106
|
+
return FixedArgumentParser
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_parser():
|
|
110
|
+
FixedArgumentParser = _get_parser_class() # noqa
|
|
111
|
+
|
|
112
|
+
parser = FixedArgumentParser(
|
|
79
113
|
prog="ducktools-pythonfinder",
|
|
80
114
|
description="Discover base Python installs",
|
|
81
115
|
)
|
|
@@ -122,9 +156,7 @@ def parse_args(args):
|
|
|
122
156
|
help="Include prerelease versions"
|
|
123
157
|
)
|
|
124
158
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return vals
|
|
159
|
+
return parser
|
|
128
160
|
|
|
129
161
|
|
|
130
162
|
def display_local_installs(
|
|
@@ -270,7 +302,8 @@ def main():
|
|
|
270
302
|
)
|
|
271
303
|
|
|
272
304
|
if sys.argv[1:]:
|
|
273
|
-
|
|
305
|
+
parser = get_parser()
|
|
306
|
+
vals = parser.parse_args(sys.argv[1:])
|
|
274
307
|
|
|
275
308
|
if vals.command == "online":
|
|
276
309
|
system = vals.system if vals.system else _laz.platform.system()
|
|
@@ -78,6 +78,7 @@ def get_pyenv_pythons(
|
|
|
78
78
|
version=version_tuple,
|
|
79
79
|
executable=executable,
|
|
80
80
|
metadata=metadata,
|
|
81
|
+
managed_by="pyenv",
|
|
81
82
|
)
|
|
82
|
-
elif query_executables and (install := get_install_details(executable)):
|
|
83
|
+
elif query_executables and (install := get_install_details(executable, managed_by="pyenv")):
|
|
83
84
|
yield install
|
{ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/shared.py
RENAMED
|
@@ -137,6 +137,7 @@ class PythonInstall(Prefab):
|
|
|
137
137
|
executable: str
|
|
138
138
|
architecture: str = "64bit"
|
|
139
139
|
implementation: str = "cpython"
|
|
140
|
+
managed_by: str | None = None
|
|
140
141
|
metadata: dict = attribute(default_factory=dict)
|
|
141
142
|
shadowed: bool = False
|
|
142
143
|
_implementation_version: tuple[int, int, int, str, int] | None = attribute(default=None, private=True)
|
|
@@ -180,6 +181,7 @@ class PythonInstall(Prefab):
|
|
|
180
181
|
executable: str,
|
|
181
182
|
architecture: str = "64bit",
|
|
182
183
|
implementation: str = "cpython",
|
|
184
|
+
managed_by: str | None = None,
|
|
183
185
|
metadata: dict | None = None,
|
|
184
186
|
):
|
|
185
187
|
version_tuple = version_str_to_tuple(version)
|
|
@@ -190,16 +192,23 @@ class PythonInstall(Prefab):
|
|
|
190
192
|
executable=executable,
|
|
191
193
|
architecture=architecture,
|
|
192
194
|
implementation=implementation,
|
|
195
|
+
managed_by=managed_by,
|
|
193
196
|
metadata=metadata,
|
|
194
197
|
)
|
|
195
198
|
|
|
196
199
|
@classmethod
|
|
197
|
-
def from_json(cls, version, executable, architecture, implementation, metadata):
|
|
200
|
+
def from_json(cls, version, executable, architecture, implementation, metadata, managed_by=None):
|
|
198
201
|
if arch_ver := metadata.get(f"{implementation}_version"):
|
|
199
202
|
metadata[f"{implementation}_version"] = tuple(arch_ver)
|
|
200
203
|
|
|
204
|
+
# noinspection PyArgumentList
|
|
201
205
|
return cls(
|
|
202
|
-
tuple(version),
|
|
206
|
+
version=tuple(version),
|
|
207
|
+
executable=executable,
|
|
208
|
+
architecture=architecture,
|
|
209
|
+
implementation=implementation,
|
|
210
|
+
managed_by=managed_by,
|
|
211
|
+
metadata=metadata,
|
|
203
212
|
)
|
|
204
213
|
|
|
205
214
|
def get_pip_version(self) -> str | None:
|
|
@@ -229,7 +238,7 @@ def _python_exe_regex(basename: str = "python"):
|
|
|
229
238
|
return _laz.re.compile(rf"{basename}\d?\.?\d*")
|
|
230
239
|
|
|
231
240
|
|
|
232
|
-
def get_install_details(executable: str) -> PythonInstall | None:
|
|
241
|
+
def get_install_details(executable: str, managed_by=None) -> PythonInstall | None:
|
|
233
242
|
try:
|
|
234
243
|
source = details.get_source_code()
|
|
235
244
|
except FileNotFoundError:
|
|
@@ -270,7 +279,7 @@ def get_install_details(executable: str) -> PythonInstall | None:
|
|
|
270
279
|
except _laz.json.JSONDecodeError as e:
|
|
271
280
|
return None
|
|
272
281
|
|
|
273
|
-
return PythonInstall.from_json(**output)
|
|
282
|
+
return PythonInstall.from_json(**output, managed_by=managed_by)
|
|
274
283
|
|
|
275
284
|
|
|
276
285
|
def get_folder_pythons(
|
|
@@ -344,7 +353,8 @@ def _implementation_from_uv_dir(
|
|
|
344
353
|
executable=python_path,
|
|
345
354
|
architecture="32bit" if arch in {"i686", "armv7"} else "64bit",
|
|
346
355
|
implementation=implementation,
|
|
347
|
-
metadata=metadata
|
|
356
|
+
metadata=metadata,
|
|
357
|
+
managed_by="Astral UV",
|
|
348
358
|
)
|
|
349
359
|
except ValueError:
|
|
350
360
|
pass
|
|
@@ -354,6 +364,7 @@ def _implementation_from_uv_dir(
|
|
|
354
364
|
# Slow backup - ask python itself
|
|
355
365
|
if query_executables:
|
|
356
366
|
install = get_install_details(python_path)
|
|
367
|
+
install.managed_by = "Astral UV"
|
|
357
368
|
|
|
358
369
|
return install
|
|
359
370
|
|
|
@@ -48,13 +48,13 @@ def get_pyenv_pythons(
|
|
|
48
48
|
if path_base.startswith("pypy"):
|
|
49
49
|
executable = os.path.join(p.path, "pypy.exe")
|
|
50
50
|
if os.path.exists(executable):
|
|
51
|
-
yield get_install_details(executable)
|
|
51
|
+
yield get_install_details(executable, managed_by="pyenv")
|
|
52
52
|
continue
|
|
53
53
|
elif path_base.startswith("graalpy"):
|
|
54
54
|
# Graalpy exe in bin subfolder
|
|
55
55
|
executable = os.path.join(p.path, "bin", "graalpy.exe")
|
|
56
56
|
if os.path.exists(executable):
|
|
57
|
-
yield get_install_details(executable)
|
|
57
|
+
yield get_install_details(executable, managed_by="pyenv")
|
|
58
58
|
continue
|
|
59
59
|
|
|
60
60
|
# Regular CPython
|
|
@@ -76,6 +76,7 @@ def get_pyenv_pythons(
|
|
|
76
76
|
version=version,
|
|
77
77
|
executable=executable,
|
|
78
78
|
architecture=arch,
|
|
79
|
+
managed_by="pyenv",
|
|
79
80
|
)
|
|
80
81
|
except ValueError:
|
|
81
82
|
pass
|
|
@@ -86,6 +87,7 @@ def get_pyenv_pythons(
|
|
|
86
87
|
version=version,
|
|
87
88
|
executable=executable,
|
|
88
89
|
architecture="64bit",
|
|
90
|
+
managed_by="pyenv",
|
|
89
91
|
)
|
|
90
92
|
except ValueError:
|
|
91
93
|
pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: ducktools-pythonfinder
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.8
|
|
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
|
|
@@ -72,7 +72,7 @@ def test_mock_versions_folder():
|
|
|
72
72
|
|
|
73
73
|
python_versions = list(get_pyenv_pythons())
|
|
74
74
|
|
|
75
|
-
assert python_versions == [PythonInstall.from_str(version=out_ver, executable=out_executable)]
|
|
75
|
+
assert python_versions == [PythonInstall.from_str(version=out_ver, executable=out_executable, managed_by="pyenv")]
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
@pytest.mark.skipif(sys.platform != "win32", reason="Test for Windows only")
|
|
@@ -89,7 +89,7 @@ def test_fs_versions_win(fs):
|
|
|
89
89
|
|
|
90
90
|
versions = list(get_pyenv_pythons(tmpdir))
|
|
91
91
|
|
|
92
|
-
assert versions == [PythonInstall.from_str(version="3.12.1", executable=py_exe)]
|
|
92
|
+
assert versions == [PythonInstall.from_str(version="3.12.1", executable=py_exe, managed_by="pyenv")]
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
@pytest.mark.skipif(sys.platform != "win32", reason="Test for Windows only")
|
|
@@ -106,7 +106,9 @@ def test_32bit_version(fs):
|
|
|
106
106
|
|
|
107
107
|
versions = list(get_pyenv_pythons(tmpdir))
|
|
108
108
|
|
|
109
|
-
assert versions == [
|
|
109
|
+
assert versions == [
|
|
110
|
+
PythonInstall.from_str(version="3.12.1", executable=py_exe, architecture="32bit", managed_by="pyenv")
|
|
111
|
+
]
|
|
110
112
|
|
|
111
113
|
|
|
112
114
|
@pytest.mark.skipif(sys.platform != "win32", reason="Test for Windows only")
|
|
@@ -155,7 +157,7 @@ def test_fs_versions_nix(fs):
|
|
|
155
157
|
|
|
156
158
|
versions = list(get_pyenv_pythons(tmpdir))
|
|
157
159
|
|
|
158
|
-
assert versions == [PythonInstall.from_str(version="3.12.1", executable=py_exe)]
|
|
160
|
+
assert versions == [PythonInstall.from_str(version="3.12.1", executable=py_exe, managed_by="pyenv")]
|
|
159
161
|
|
|
160
162
|
|
|
161
163
|
@pytest.mark.skipif(sys.platform == "win32", reason="Test for non-Windows only")
|
|
@@ -235,6 +237,7 @@ def test_pypy_version(fs):
|
|
|
235
237
|
architecture="64bit",
|
|
236
238
|
implementation="pypy",
|
|
237
239
|
metadata={"pypy_version": (7, 3, 15, "final", 0)},
|
|
240
|
+
managed_by="pyenv",
|
|
238
241
|
)
|
|
239
242
|
|
|
240
243
|
assert versions == [out_version]
|
|
@@ -132,6 +132,7 @@ class TestUVReal:
|
|
|
132
132
|
assert len(pythons) == 1
|
|
133
133
|
assert pythons[0].version_str == "3.12.6"
|
|
134
134
|
assert pythons[0].implementation == "cpython"
|
|
135
|
+
assert pythons[0].managed_by == "Astral UV"
|
|
135
136
|
|
|
136
137
|
@pytest.mark.uv_python
|
|
137
138
|
def test_finds_installed_pypy(self, uv_pythondir):
|
|
@@ -145,6 +146,7 @@ class TestUVReal:
|
|
|
145
146
|
assert pythons[0].version >= (3, 10, 14)
|
|
146
147
|
assert pythons[0].implementation == "pypy"
|
|
147
148
|
assert pythons[0].implementation_version >= (7, 3, 17)
|
|
149
|
+
assert pythons[0].managed_by == "Astral UV"
|
|
148
150
|
|
|
149
151
|
|
|
150
152
|
def test_regex_matches():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/scripts/print_python_versions.py
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/src/ducktools/pythonfinder/__init__.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.6.6 → ducktools_pythonfinder-0.6.8}/tests/sources/python_versions.txt
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.6.6 → ducktools_pythonfinder-0.6.8}/tests/sources/release_file.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|