Skip to content

Commit

Permalink
Try changes from sarugaku/pythonfinder#157
Browse files Browse the repository at this point in the history
  • Loading branch information
matteius committed Jan 22, 2024
1 parent 2bd7eab commit 4de1487
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 203 deletions.
26 changes: 0 additions & 26 deletions pipenv/vendor/pythonfinder/models/common.py

This file was deleted.

104 changes: 44 additions & 60 deletions pipenv/vendor/pythonfinder/models/mixins.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
from __future__ import annotations

import dataclasses
import os
from collections import defaultdict
from pathlib import Path
from dataclasses import field
from typing import (
TYPE_CHECKING,
Any,
Dict,
Generator,
Iterator,
Optional,
)

from pipenv.vendor.pydantic import BaseModel, Field, validator

from ..exceptions import InvalidPythonVersion
from ..utils import (
KNOWN_EXTS,
Expand All @@ -25,33 +22,33 @@
)

if TYPE_CHECKING:
from pathlib import Path

from pipenv.vendor.pythonfinder.models.python import PythonVersion


class PathEntry(BaseModel):
is_root: bool = Field(default=False, order=False)
name: Optional[str] = None
path: Optional[Path] = None
children_ref: Optional[Any] = Field(default_factory=lambda: dict())
only_python: Optional[bool] = False
py_version_ref: Optional[Any] = None
pythons_ref: Optional[Dict[Any, Any]] = defaultdict(lambda: None)
is_dir_ref: Optional[bool] = None
is_executable_ref: Optional[bool] = None
is_python_ref: Optional[bool] = None

class Config:
validate_assignment = True
arbitrary_types_allowed = True
allow_mutation = True
include_private_attributes = True

@validator("children", pre=True, always=True, check_fields=False)
def set_children(cls, v, values, **kwargs):
path = values.get("path")
if path:
values["name"] = path.name
return v or cls()._gen_children()
@dataclasses.dataclass(unsafe_hash=True)
class PathEntry:
is_root: bool = False
name: str | None = None
path: Path | None = None
children_ref: dict[str, Any] = field(default_factory=dict)
only_python: bool | None = False
py_version_ref: Any | None = None
pythons_ref: dict[str, Any] | None = field(
default_factory=lambda: defaultdict(lambda: None)
)
is_dir_ref: bool | None = None
is_executable_ref: bool | None = None
is_python_ref: bool | None = None

def __post_init__(self):
if not self.children_ref:
self._gen_children()

def set_children(self, children):
# If children are not provided, generate them
return children or self._gen_children()

def __str__(self) -> str:
return f"{self.path.as_posix()}"
Expand Down Expand Up @@ -316,39 +313,26 @@ def _filter_children(self) -> Iterator[Path]:
children = self.path.iterdir()
return children

def _gen_children(self) -> Iterator:
pass_name = self.name != self.path.name
pass_args = {"is_root": False, "only_python": self.only_python}
if pass_name:
if self.name is not None and isinstance(self.name, str):
pass_args["name"] = self.name
elif self.path is not None and isinstance(self.path.name, str):
pass_args["name"] = self.path.name

if not self.is_dir:
yield (self.path.as_posix(), self)
elif self.is_root:
for child in self._filter_children():
if self.only_python:
try:
entry = PathEntry.create(path=child, **pass_args)
except (InvalidPythonVersion, ValueError):
continue
else:
try:
entry = PathEntry.create(path=child, **pass_args)
except (InvalidPythonVersion, ValueError):
continue
yield (child.as_posix(), entry)
return
def _gen_children(self):
if self.is_dir and self.is_root and self.path is not None:
# Assuming _filter_children returns an iterator over child paths
for child_path in self._filter_children():
pass_name = self.name != self.path.name
pass_args = {"is_root": False, "only_python": self.only_python}
if pass_name:
if self.name is not None and isinstance(self.name, str):
pass_args["name"] = self.name
elif self.path is not None and isinstance(self.path.name, str):
pass_args["name"] = self.path.name

try:
entry = PathEntry.create(path=child_path, **pass_args)
self.children_ref[child_path.as_posix()] = entry
except (InvalidPythonVersion, ValueError):
continue # Or handle as needed

@property
def children(self) -> dict[str, PathEntry]:
children = getattr(self, "children_ref", {})
if not children:
for child_key, child_val in self._gen_children():
children[child_key] = child_val
self.children_ref = children
return self.children_ref

@classmethod
Expand All @@ -360,7 +344,7 @@ def create(
pythons: dict[str, PythonVersion] | None = None,
name: str | None = None,
) -> PathEntry:
"""Helper method for creating new :class:`pythonfinder.models.PathEntry` instances.
"""Helper method for creating new :class:`PathEntry` instances.
:param str path: Path to the specified location.
:param bool is_root: Whether this is a root from the environment PATH variable, defaults to False
Expand Down
81 changes: 31 additions & 50 deletions pipenv/vendor/pythonfinder/models/path.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,22 @@
from __future__ import annotations

import dataclasses
import errno
import operator
import os
import sys
from collections import ChainMap, defaultdict
from collections import defaultdict
from dataclasses import field
from functools import cached_property
from itertools import chain
from pathlib import Path
from typing import (
Any,
DefaultDict,
Dict,
Generator,
Iterator,
List,
Optional,
Tuple,
Union,
)

if sys.version_info >= (3, 8):
from functools import cached_property
else:
from pipenv.patched.pip._vendor.pyparsing.core import cached_property
from pipenv.vendor.pydantic import Field, root_validator

from ..environment import (
ASDF_DATA_DIR,
ASDF_INSTALLED,
Expand All @@ -40,7 +32,6 @@
parse_pyenv_version_order,
split_version_and_name,
)
from .common import FinderBaseModel
from .mixins import PathEntry
from .python import PythonFinder

Expand All @@ -55,38 +46,32 @@ def exists_and_is_accessible(path):
raise


class SystemPath(FinderBaseModel):
@dataclasses.dataclass(unsafe_hash=True)
class SystemPath:
global_search: bool = True
paths: Dict[str, Union[PythonFinder, PathEntry]] = Field(
paths: dict[str, PythonFinder | PathEntry] = field(
default_factory=lambda: defaultdict(PathEntry)
)
executables_tracking: List[PathEntry] = Field(default_factory=lambda: list())
python_executables_tracking: Dict[str, PathEntry] = Field(
default_factory=lambda: dict()
executables_tracking: list[PathEntry] = field(default_factory=list)
python_executables_tracking: dict[str, PathEntry] = field(
default_factory=dict, init=False
)
path_order: List[str] = Field(default_factory=lambda: list())
python_version_dict: Dict[Tuple, Any] = Field(
path_order: list[str] = field(default_factory=list)
python_version_dict: dict[tuple, Any] = field(
default_factory=lambda: defaultdict(list)
)
version_dict_tracking: Dict[Tuple, List[PathEntry]] = Field(
version_dict_tracking: dict[tuple, list[PathEntry]] = field(
default_factory=lambda: defaultdict(list)
)
only_python: bool = False
pyenv_finder: Optional[PythonFinder] = None
asdf_finder: Optional[PythonFinder] = None
pyenv_finder: PythonFinder | None = None
asdf_finder: PythonFinder | None = None
system: bool = False
ignore_unsupported: bool = False
finders_dict: Dict[str, PythonFinder] = Field(default_factory=lambda: dict())

class Config:
validate_assignment = True
arbitrary_types_allowed = True
allow_mutation = True
include_private_attributes = True
keep_untouched = (cached_property,)
finders_dict: dict[str, PythonFinder] = field(default_factory=dict)

def __init__(self, **data):
super().__init__(**data)
def __post_init__(self):
# Initialize python_executables_tracking
python_executables = {}
for child in self.paths.values():
if child.pythons:
Expand All @@ -96,24 +81,20 @@ def __init__(self, **data):
python_executables.update(dict(finder.pythons))
self.python_executables_tracking = python_executables

@root_validator(pre=True)
def set_defaults(cls, values):
values["python_version_dict"] = defaultdict(list)
values["pyenv_finder"] = None
values["asdf_finder"] = None
values["path_order"] = []
values["_finders"] = {}
values["paths"] = defaultdict(PathEntry)
paths = values.get("paths")
if paths:
values["executables"] = [
p
for p in ChainMap(
*(child.children_ref.values() for child in paths.values())
)
if p.is_executable
self.python_version_dict = defaultdict(list)
self.pyenv_finder = self.pyenv_finder or None
self.asdf_finder = self.asdf_finder or None
self.path_order = self.path_order or []
self.finders_dict = self.finders_dict or {}

# The part with 'paths' seems to be setting up 'executables'
if self.paths:
self.executables_tracking = [
child
for path_entry in self.paths.values()
for child in path_entry.children_ref.values()
if child.is_executable
]
return values

def _register_finder(self, finder_name, finder):
if finder_name not in self.finders_dict:
Expand Down
Loading

0 comments on commit 4de1487

Please sign in to comment.