Skip to content

Commit ab2f007

Browse files
authored
Merge pull request #63 from DavidCEllis/additional-folder-names
Add MacOS managed by folders
2 parents ef7f788 + 7488902 commit ab2f007

File tree

9 files changed

+93
-16
lines changed

9 files changed

+93
-16
lines changed

src/ducktools/pythonfinder/__main__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
# SOFTWARE.
2323
from __future__ import annotations
2424

25-
2625
import sys
2726
import os
2827

src/ducktools/pythonfinder/darwin/__init__.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,55 @@
2020
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2121
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
# SOFTWARE.
23+
from __future__ import annotations
2324

24-
"""Currently just copied from linux"""
25+
import itertools
26+
try:
27+
from _collections_abc import Iterator
28+
except ImportError:
29+
from collections.abc import Iterator
2530

26-
from ..linux import get_python_installs, get_path_pythons, get_pyenv_pythons
31+
from .. import linux
32+
from ..shared import get_uv_pythons, DetailFinder,PythonInstall
33+
34+
35+
# This is the difference from the linux methods
36+
KNOWN_MANAGED_PATHS = {
37+
**linux.KNOWN_MANAGED_PATHS,
38+
"/opt/homebrew": "Homebrew", # ARM Apple
39+
"/usr/local/opt": "Homebrew", # x86_64 Apple
40+
"/Applications/Xcode.app": "Xcode",
41+
"/Library/Developer/CommandLineTools": "Xcode", # Xcode commandline tools
42+
"/Library/Frameworks/Python.framework": "python.org",
43+
}
44+
45+
46+
def get_path_pythons(
47+
*,
48+
finder: DetailFinder | None = None,
49+
known_paths: dict[str, str] | None = None,
50+
) -> Iterator[PythonInstall]:
51+
52+
known_paths = KNOWN_MANAGED_PATHS if known_paths is None else known_paths
53+
54+
return linux.get_path_pythons(finder=finder, known_paths=known_paths)
55+
56+
57+
def get_python_installs(
58+
*,
59+
finder: DetailFinder | None = None,
60+
) -> Iterator[PythonInstall]:
61+
listed_pythons = set()
62+
63+
finder = DetailFinder() if finder is None else finder
64+
65+
chain_commands = [
66+
linux.get_pyenv_pythons(finder=finder),
67+
get_uv_pythons(finder=finder),
68+
get_path_pythons(finder=finder),
69+
]
70+
with finder:
71+
for py in itertools.chain.from_iterable(chain_commands):
72+
if py.executable not in listed_pythons:
73+
yield py
74+
listed_pythons.add(py.executable)

src/ducktools/pythonfinder/linux/__init__.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
import os
2626
import os.path
2727
import itertools
28-
from _collections_abc import Iterator
28+
29+
try:
30+
from _collections_abc import Iterator
31+
except ImportError:
32+
from collections.abc import Iterator
2933

3034
from ..shared import (
3135
DetailFinder,
@@ -45,7 +49,12 @@
4549
}
4650

4751

48-
def get_path_pythons(*, finder: DetailFinder | None = None) -> Iterator[PythonInstall]:
52+
def get_path_pythons(
53+
*,
54+
finder: DetailFinder | None = None,
55+
known_paths: dict[str, str] | None = None,
56+
) -> Iterator[PythonInstall]:
57+
4958
exe_names = set()
5059

5160
path_folders = os.environ.get("PATH", "").split(":")
@@ -55,6 +64,7 @@ def get_path_pythons(*, finder: DetailFinder | None = None) -> Iterator[PythonIn
5564
excluded_folders = [pyenv_root, uv_root]
5665

5766
finder = DetailFinder() if finder is None else finder
67+
known_paths = KNOWN_MANAGED_PATHS if known_paths is None else known_paths
5868

5969
for fld in path_folders:
6070
# Don't retrieve pyenv installs
@@ -71,8 +81,10 @@ def get_path_pythons(*, finder: DetailFinder | None = None) -> Iterator[PythonIn
7181
continue
7282

7383
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
84+
for path, manager in known_paths.items():
85+
if os.path.commonpath((path, install.executable)) == path:
86+
install.managed_by = manager
87+
break
7688

7789
name = os.path.basename(install.executable)
7890
if name in exe_names:

src/ducktools/pythonfinder/linux/pyenv_search.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@
2020
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2121
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
# SOFTWARE.
23-
from __future__ import annotations
24-
2523
"""
2624
Discover python installs that have been created with pyenv
2725
"""
2826

27+
from __future__ import annotations
28+
2929
import os
3030
import os.path
31-
from _collections_abc import Iterator
31+
32+
try:
33+
from _collections_abc import Iterator
34+
except ImportError:
35+
from collections.abc import Iterator
3236

3337
from ducktools.lazyimporter import LazyImporter, FromImport, ModuleImport
3438

src/ducktools/pythonfinder/shared.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
import os
2727
import os.path
2828

29-
from _collections_abc import Iterator
29+
try:
30+
from _collections_abc import Iterator
31+
except ImportError:
32+
from collections.abc import Iterator
3033

3134
from ducktools.classbuilder.prefab import Prefab, attribute, as_dict
3235
from ducktools.lazyimporter import LazyImporter, ModuleImport, FromImport

src/ducktools/pythonfinder/venv.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import os
3131
import sys
3232

33-
3433
from ducktools.classbuilder.prefab import Prefab, attribute
3534
from ducktools.lazyimporter import LazyImporter, FromImport, ModuleImport
3635

src/ducktools/pythonfinder/win32/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222
# SOFTWARE.
2323
from __future__ import annotations
2424

25-
from _collections_abc import Iterator
2625
import itertools
2726

27+
try:
28+
from _collections_abc import Iterator
29+
except ImportError:
30+
from collections.abc import Iterator
31+
2832
from ..shared import PythonInstall, get_uv_pythons, DetailFinder
2933
from .pyenv_search import get_pyenv_pythons
3034
from .registry_search import get_registered_pythons

src/ducktools/pythonfinder/win32/pyenv_search.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@
2424

2525
import os
2626
import os.path
27-
from _collections_abc import Iterator
27+
28+
try:
29+
from _collections_abc import Iterator
30+
except ImportError:
31+
from collections.abc import Iterator
2832

2933
from ..shared import PythonInstall, DetailFinder
3034

src/ducktools/pythonfinder/win32/registry_search.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,20 @@
2020
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2121
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
# SOFTWARE.
23-
from __future__ import annotations
23+
24+
# This is an overly broad ignore as linux mypy errors
25+
# mypy: disable-error-code="attr-defined"
2426

2527
"""
2628
Search the Windows registry to find python installs
2729
2830
Based on PEP 514 registry entries.
2931
"""
3032

33+
from __future__ import annotations
34+
3135
import os.path
32-
import winreg # noqa # pycharm seems to think winreg doesn't exist in python3.12
36+
import winreg
3337
from _collections_abc import Iterator
3438

3539
from ..shared import DetailFinder, PythonInstall, version_str_to_tuple

0 commit comments

Comments
 (0)