Skip to content

Commit

Permalink
Initial pass at converting off pydantic
Browse files Browse the repository at this point in the history
  • Loading branch information
matteius committed Jan 22, 2024
1 parent dc7bd85 commit 67e2454
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 172 deletions.
2 changes: 0 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ dynamic = ["version"]
requires-python = ">=3.8"
dependencies = [
"packaging>=22.0",
"pydantic>=1.10.7,<2",
]

[project.optional-dependencies]
Expand Down Expand Up @@ -136,7 +135,6 @@ unfixable = [

[tool.ruff.flake8-type-checking]
runtime-evaluated-base-classes = [
"pydantic.BaseModel",
"pythonfinder.models.common.FinderBaseModel",
"pythonfinder.models.mixins.PathEntry",
]
Expand Down
26 changes: 0 additions & 26 deletions src/pythonfinder/models/common.py

This file was deleted.

61 changes: 31 additions & 30 deletions src/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 pydantic import BaseModel, Field, validator

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

if TYPE_CHECKING:
from pathlib import Path

from 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] | None = 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 path is set, use its name for the name field
if self.path and not self.name:
self.name = self.path.name

# Ensure children are properly set
self.children_ref = self.set_children(self.children_ref)

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 @@ -360,7 +361,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
67 changes: 26 additions & 41 deletions src/pythonfinder/models/path.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
from __future__ import annotations

import dataclasses
import errno
import operator
import os
import sys
from collections import ChainMap, 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,
)

from pydantic import Field, root_validator

from ..environment import (
ASDF_DATA_DIR,
ASDF_INSTALLED,
Expand All @@ -37,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 @@ -52,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 @@ -93,24 +81,21 @@ 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"] = [
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 = [
p
for p in ChainMap(
*(child.children_ref.values() for child in paths.values())
*(child.children_ref.values() for child in self.paths.values())
)
if p.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 67e2454

Please sign in to comment.