ducktools-pythonfinder 0.7.0__tar.gz → 0.7.1__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.0/src/ducktools_pythonfinder.egg-info → ducktools_pythonfinder-0.7.1}/PKG-INFO +1 -1
- ducktools_pythonfinder-0.7.1/src/ducktools/pythonfinder/_version.py +2 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/venv.py +91 -22
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1/src/ducktools_pythonfinder.egg-info}/PKG-INFO +1 -1
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_venv_finder.py +7 -0
- ducktools_pythonfinder-0.7.0/src/ducktools/pythonfinder/_version.py +0 -2
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/.gitignore +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/LICENSE +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/MANIFEST.in +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/README.md +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/pyproject.toml +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/scripts/build_zipapp.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/scripts/detail_this_python.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/scripts/print_python_versions.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/setup.cfg +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/__main__.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/darwin/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/details_script.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/linux/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/linux/pyenv_search.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/pythonorg_search.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/shared.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/win32/__init__.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/win32/pyenv_search.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/win32/registry_search.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools_pythonfinder.egg-info/SOURCES.txt +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools_pythonfinder.egg-info/dependency_links.txt +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools_pythonfinder.egg-info/entry_points.txt +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools_pythonfinder.egg-info/requires.txt +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools_pythonfinder.egg-info/top_level.txt +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/conftest.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/sources/python_versions.txt +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/sources/release.json +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/sources/release_file.json +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_details_script.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_foldersearch.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_orgsearch.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_pyenv.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_shared.py +0 -0
- {ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/test_uv_finder.py +0 -0
{ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/venv.py
RENAMED
|
@@ -55,6 +55,10 @@ VIRTUALENV_PY_VER_RE = (
|
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
class InvalidVEnvError(Exception):
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
58
62
|
class PythonPackage(Prefab):
|
|
59
63
|
name: str
|
|
60
64
|
version: str
|
|
@@ -133,20 +137,18 @@ class PythonVEnv(Prefab):
|
|
|
133
137
|
|
|
134
138
|
return packages
|
|
135
139
|
|
|
140
|
+
@classmethod
|
|
141
|
+
def from_cfg(cls, cfg_path):
|
|
142
|
+
"""
|
|
143
|
+
Get a PythonVEnv instance from the path to a config file
|
|
136
144
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if recursive:
|
|
141
|
-
glob_call = _laz.Path(base_dir).glob(f"**/{VENV_CONFIG_NAME}")
|
|
142
|
-
else:
|
|
143
|
-
glob_call = _laz.Path(base_dir).glob(f"*/{VENV_CONFIG_NAME}")
|
|
144
|
-
|
|
145
|
-
for conf in glob_call:
|
|
145
|
+
:param cfg_path:
|
|
146
|
+
:return:
|
|
147
|
+
"""
|
|
146
148
|
parent_path, version_str = None, None
|
|
147
|
-
venv_base =
|
|
149
|
+
venv_base = cfg_path.parent
|
|
148
150
|
|
|
149
|
-
with
|
|
151
|
+
with cfg_path.open() as f:
|
|
150
152
|
for line in f:
|
|
151
153
|
key, value = (item.strip() for item in line.split("="))
|
|
152
154
|
|
|
@@ -160,14 +162,13 @@ def get_python_venvs(base_dir=None, recursive=True):
|
|
|
160
162
|
break
|
|
161
163
|
else:
|
|
162
164
|
# Not a valid venv, ignore
|
|
163
|
-
|
|
165
|
+
raise InvalidVEnvError(f"Path and version not defined in {cfg_path}")
|
|
164
166
|
|
|
165
167
|
if sys.platform == "win32":
|
|
166
168
|
venv_exe = os.path.join(venv_base, "Scripts", "python.exe")
|
|
167
169
|
else:
|
|
168
170
|
venv_exe = os.path.join(venv_base, "bin", "python")
|
|
169
171
|
|
|
170
|
-
version_tuple = None
|
|
171
172
|
try:
|
|
172
173
|
version_tuple = version_str_to_tuple(version_str)
|
|
173
174
|
except ValueError: # pragma: no cover
|
|
@@ -182,15 +183,83 @@ def get_python_venvs(base_dir=None, recursive=True):
|
|
|
182
183
|
releaselevel,
|
|
183
184
|
int(serial if serial != "" else 0),
|
|
184
185
|
)
|
|
186
|
+
else:
|
|
187
|
+
raise InvalidVEnvError(
|
|
188
|
+
f"Could not determine version from venv version string {version_str}"
|
|
189
|
+
)
|
|
185
190
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
return cls(
|
|
192
|
+
folder=venv_base,
|
|
193
|
+
executable=venv_exe,
|
|
194
|
+
version=version_tuple,
|
|
195
|
+
parent_path=parent_path
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def get_python_venvs(base_dir=None, recursive=False, search_parent_folders=False):
|
|
200
|
+
"""
|
|
201
|
+
Yield discoverable python virtual environment information
|
|
193
202
|
|
|
203
|
+
If recursive=True then search_parent_folders is ignored.
|
|
194
204
|
|
|
195
|
-
|
|
196
|
-
|
|
205
|
+
If you're in a project directory and are looking for a potential venv
|
|
206
|
+
search_parent_folders=True will search parents and yield installs discovered.
|
|
207
|
+
|
|
208
|
+
If you're in a folder of source trees and want to find venvs inside any subfolders
|
|
209
|
+
then use recursive=True.
|
|
210
|
+
|
|
211
|
+
:param base_dir: Base directory to search venvs
|
|
212
|
+
:param recursive: Also check subfolders of the base directory
|
|
213
|
+
:param search_parent_folders: Also search parent folders
|
|
214
|
+
:yield: PythonVEnv details.
|
|
215
|
+
"""
|
|
216
|
+
base_dir = _laz.Path.cwd() if base_dir is None else _laz.Path(base_dir)
|
|
217
|
+
|
|
218
|
+
search_folders = [base_dir]
|
|
219
|
+
|
|
220
|
+
# Recursive searches don't also search parent folders.
|
|
221
|
+
if recursive:
|
|
222
|
+
pattern = f"**/{VENV_CONFIG_NAME}"
|
|
223
|
+
else:
|
|
224
|
+
pattern = f"*/{VENV_CONFIG_NAME}"
|
|
225
|
+
if search_parent_folders:
|
|
226
|
+
search_folders.extend(base_dir.parents)
|
|
227
|
+
|
|
228
|
+
for f in search_folders:
|
|
229
|
+
try:
|
|
230
|
+
for conf in f.glob(pattern):
|
|
231
|
+
try:
|
|
232
|
+
env = PythonVEnv.from_cfg(conf)
|
|
233
|
+
except InvalidVEnvError:
|
|
234
|
+
continue
|
|
235
|
+
|
|
236
|
+
yield env
|
|
237
|
+
except OSError as e:
|
|
238
|
+
# MacOS can error on searching up folders with an invalid argument
|
|
239
|
+
# On Python 3.11 or earlier.
|
|
240
|
+
if e.errno == 22:
|
|
241
|
+
continue
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def list_python_venvs(
|
|
245
|
+
base_dir=None,
|
|
246
|
+
recursive=False,
|
|
247
|
+
search_parent_folders=False,
|
|
248
|
+
) -> list[PythonVEnv]:
|
|
249
|
+
"""
|
|
250
|
+
Get a list of discoverable python virtual environment information
|
|
251
|
+
|
|
252
|
+
If recursive=True then search_parent_folders is ignored.
|
|
253
|
+
|
|
254
|
+
:param base_dir: Base directory to search venvs
|
|
255
|
+
:param recursive: Also check subfolders of the base directory
|
|
256
|
+
:param search_parent_folders: Also search parent folders
|
|
257
|
+
:returns: List of Python VEnv details.
|
|
258
|
+
"""
|
|
259
|
+
return list(
|
|
260
|
+
get_python_venvs(
|
|
261
|
+
base_dir=base_dir,
|
|
262
|
+
recursive=recursive,
|
|
263
|
+
search_parent_folders=search_parent_folders,
|
|
264
|
+
)
|
|
265
|
+
)
|
|
@@ -76,6 +76,13 @@ def test_local_found(with_venvs):
|
|
|
76
76
|
assert os.path.samefile(venvs[0].folder, os.path.join(with_venvs, ".venv"))
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def test_found_in_parent(with_venvs):
|
|
80
|
+
venvs = list_python_venvs(base_dir=os.path.join(with_venvs, "subfolder"), search_parent_folders=True)
|
|
81
|
+
|
|
82
|
+
assert os.path.samefile(venvs[0].folder, os.path.join(with_venvs, "subfolder/.venv"))
|
|
83
|
+
assert os.path.samefile(venvs[1].folder, os.path.join(with_venvs, ".venv"))
|
|
84
|
+
|
|
85
|
+
|
|
79
86
|
def test_all_found(with_venvs):
|
|
80
87
|
venvs = sorted(
|
|
81
88
|
list_python_venvs(base_dir=with_venvs, recursive=True),
|
|
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.0 → ducktools_pythonfinder-0.7.1}/scripts/print_python_versions.py
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/__init__.py
RENAMED
|
File without changes
|
{ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/src/ducktools/pythonfinder/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/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
|
|
File without changes
|
{ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/tests/sources/python_versions.txt
RENAMED
|
File without changes
|
|
File without changes
|
{ducktools_pythonfinder-0.7.0 → ducktools_pythonfinder-0.7.1}/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
|