Skip to content

Commit 3c92360

Browse files
Refactor _is_uv_a_dep to mirror _deps.py patterns with proper types
Replace lazy import approach with architecture-compliant helpers that mirror get_project_deps()/get_dep_groups() using only _file and _types layers (permitted by import-linter). Uses TOMLDocument type, Dependency model, and packaging.requirements.Requirement for proper parsing. Agent-Logs-Url: https://github.com/usethis-python/usethis-python/sessions/99da146b-5070-472d-a959-ddb17f09c237 Co-authored-by: nathanjmcdougall <18602289+nathanjmcdougall@users.noreply.github.com>
1 parent 674995e commit 3c92360

1 file changed

Lines changed: 71 additions & 29 deletions

File tree

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
"""Check whether the uv CLI is available."""
22

3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING
6+
37
from packaging.requirements import InvalidRequirement, Requirement
48

59
from usethis._backend.uv.call import call_uv_subprocess
610
from usethis._backend.uv.errors import UVSubprocessFailedError
7-
from usethis._file.pyproject_toml.errors import PyprojectTOMLError
811
from usethis._file.pyproject_toml.io_ import PyprojectTOMLManager
12+
from usethis._types.deps import Dependency
13+
14+
if TYPE_CHECKING:
15+
from tomlkit import TOMLDocument
916

1017

1118
def is_uv_available() -> bool:
@@ -19,41 +26,76 @@ def is_uv_available() -> bool:
1926

2027

2128
def _is_uv_a_dep() -> bool:
22-
"""Check if uv is declared as a project dependency or in a dependency group."""
29+
"""Check if uv is declared as a project dependency or in a dependency group.
30+
31+
Note: we cannot use the higher-level ``get_project_deps`` /
32+
``get_dep_groups`` helpers from ``usethis._deps`` because the
33+
``_backend`` layer must not import from the ``_deps`` layer
34+
(enforced by import-linter). The logic below mirrors those
35+
functions using only ``_file`` and ``_types`` which are
36+
permitted.
37+
"""
38+
uv_dep = Dependency(name="uv")
39+
2340
try:
24-
content = PyprojectTOMLManager().get()
25-
except (FileNotFoundError, PyprojectTOMLError):
41+
pyproject = PyprojectTOMLManager().get()
42+
except Exception:
2643
return False
2744

28-
# Gather all requirement strings from both sources
29-
req_strs: list[str] = []
45+
all_deps = _get_project_deps(pyproject) + _get_dep_group_deps(pyproject)
46+
return any(dep.name == uv_dep.name for dep in all_deps)
47+
3048

31-
# Collect from project dependencies
49+
def _get_project_deps(pyproject: TOMLDocument) -> list[Dependency]:
50+
"""Extract dependencies from the [project.dependencies] section."""
3251
try:
33-
project_section = content["project"]
34-
if isinstance(project_section, dict):
35-
deps = project_section["dependencies"]
36-
if isinstance(deps, list):
37-
req_strs.extend(s for s in deps if isinstance(s, str))
38-
except (KeyError, TypeError):
39-
pass
40-
41-
# Collect from dependency groups
52+
project_section = pyproject["project"]
53+
except KeyError:
54+
return []
55+
56+
if not isinstance(project_section, dict):
57+
return []
58+
4259
try:
43-
groups = content["dependency-groups"]
44-
if isinstance(groups, dict):
45-
for group_deps in groups.values():
46-
if isinstance(group_deps, list):
47-
req_strs.extend(s for s in group_deps if isinstance(s, str))
48-
except (KeyError, TypeError):
49-
pass
50-
51-
# Check if any requirement is for 'uv'
52-
for req_str in req_strs:
60+
dep_section = project_section["dependencies"]
61+
except KeyError:
62+
return []
63+
64+
if not isinstance(dep_section, list):
65+
return []
66+
67+
deps: list[Dependency] = []
68+
for item in dep_section:
69+
if not isinstance(item, str):
70+
continue
5371
try:
54-
if Requirement(req_str).name == "uv":
55-
return True
72+
req = Requirement(item)
5673
except InvalidRequirement:
5774
continue
75+
deps.append(Dependency(name=req.name, extras=frozenset(req.extras)))
76+
return deps
77+
5878

59-
return False
79+
def _get_dep_group_deps(pyproject: TOMLDocument) -> list[Dependency]:
80+
"""Extract dependencies from all [dependency-groups] sections."""
81+
try:
82+
groups_section = pyproject["dependency-groups"]
83+
except KeyError:
84+
return []
85+
86+
if not isinstance(groups_section, dict):
87+
return []
88+
89+
deps: list[Dependency] = []
90+
for group_items in groups_section.values():
91+
if not isinstance(group_items, list):
92+
continue
93+
for item in group_items:
94+
if not isinstance(item, str):
95+
continue
96+
try:
97+
req = Requirement(item)
98+
except InvalidRequirement:
99+
continue
100+
deps.append(Dependency(name=req.name, extras=frozenset(req.extras)))
101+
return deps

0 commit comments

Comments
 (0)