Skip to content

Commit a25f7bf

Browse files
authored
Merge pull request #781 from dhellmann/linter-resolve-packages
feat(lint): add requirement resolution to lint-requirements command
2 parents 64aee9d + 0664d8d commit a25f7bf

File tree

1 file changed

+36
-3
lines changed

1 file changed

+36
-3
lines changed

src/fromager/commands/lint_requirements.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import click
66
from packaging.requirements import InvalidRequirement, Requirement
77

8-
from fromager import requirements_file
8+
from fromager import bootstrapper, context, progress, requirements_file
9+
from fromager.log import requirement_ctxvar
10+
from fromager.requirements_file import RequirementType
911

1012
logger = logging.getLogger(__name__)
1113

@@ -17,13 +19,17 @@
1719
required=True,
1820
type=click.Path(exists=False, path_type=pathlib.Path),
1921
)
20-
def lint_requirements(input_files_path: list[pathlib.Path]) -> None:
22+
@click.pass_obj
23+
def lint_requirements(
24+
wkctx: context.WorkContext, input_files_path: list[pathlib.Path]
25+
) -> None:
2126
"""
2227
Command to lint the constraints.txt and requirements.txt files
2328
This command takes a single wildcard path string for constraints.txt and requirements.txt.
2429
It checks the formatting of these files and reports issues if found. Files with names that
2530
end with constraints.txt (e.g. constraints.txt, global-constraints.txt, etc.) are not allowed
26-
to contain extra dependencies.
31+
to contain extra dependencies. Additionally, it resolves valid input requirements to ensure
32+
we can find a matching version of each package.
2733
"""
2834

2935
if len(input_files_path) == 0:
@@ -32,6 +38,15 @@ def lint_requirements(input_files_path: list[pathlib.Path]) -> None:
3238

3339
flag = True
3440

41+
# Create bootstrapper for requirement resolution
42+
bt = bootstrapper.Bootstrapper(
43+
ctx=wkctx,
44+
progressbar=progress.Progressbar(None),
45+
prev_graph=None,
46+
cache_wheel_server_url=None,
47+
sdist_only=True,
48+
)
49+
3550
for path in input_files_path:
3651
parsed_lines = requirements_file.parse_requirements_file(path)
3752
unique_entries: dict[str, Requirement] = {}
@@ -47,6 +62,24 @@ def lint_requirements(input_files_path: list[pathlib.Path]) -> None:
4762
raise InvalidRequirement(
4863
"Constraints files cannot contain extra dependencies"
4964
)
65+
66+
# Resolve the requirement to ensure it can be found
67+
# Skip resolution for constraints files as they should only specify versions
68+
if not path.name.endswith("constraints.txt"):
69+
token = requirement_ctxvar.set(requirement)
70+
try:
71+
_, version = bt.resolve_version(
72+
req=requirement,
73+
req_type=RequirementType.TOP_LEVEL,
74+
)
75+
logger.info(f"{requirement} resolves to {version}")
76+
except Exception as resolve_err:
77+
logger.error(
78+
f"{path}: {line}: Failed to resolve requirement: {resolve_err}"
79+
)
80+
flag = False
81+
finally:
82+
requirement_ctxvar.reset(token)
5083
except InvalidRequirement as err:
5184
logger.error(f"{path}: {line}: {err}")
5285
flag = False

0 commit comments

Comments
 (0)