Skip to content

Commit 2b46652

Browse files
docs: add docstrings and comments to complex functions
Add docstrings to functions and inline comments to non-obvious code patterns across various files. Only targets genuinely complex logic that would be hard for new contributors to understand. Closes: #1046 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Lalatendu Mohanty <lmohanty@redhat.com>
1 parent b8f4441 commit 2b46652

11 files changed

Lines changed: 110 additions & 5 deletions

src/fromager/bootstrapper.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,9 @@ def _look_for_existing_wheel(
10781078
if not wheel_filename:
10791079
return None, None
10801080

1081+
# Re-validate build tag from the actual wheel metadata because
1082+
# finders.find_wheel matches by filename prefix, which may not
1083+
# enforce an exact build tag match.
10811084
_, _, build_tag, _ = wheels.extract_info_from_wheel_file(req, wheel_filename)
10821085
if expected_build_tag and expected_build_tag != build_tag:
10831086
logger.info(
@@ -1181,7 +1184,15 @@ def _unpack_metadata_from_wheel(
11811184
return None
11821185

11831186
def _resolve_version_from_git_url(self, req: Requirement) -> tuple[str, Version]:
1184-
"Return path to the cloned git repository and the package version."
1187+
"""Resolve source path and version from a ``git+`` URL.
1188+
1189+
Strips the ``git+`` prefix, then checks for an ``@ref`` suffix in
1190+
the URL path. If the ref parses as a valid Python version, reuses
1191+
an existing clone when possible. Otherwise, clones to a temp
1192+
directory and extracts the version from package metadata. The clone
1193+
is moved to the standard work directory layout
1194+
(``<name>-<version>/<name>-<version>/``) once the version is known.
1195+
"""
11851196

11861197
if not req.url:
11871198
raise ValueError(f"unable to resolve from URL with no URL in {req}")

src/fromager/dependencies.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ def _filter_requirements(
8181
for r in requirements:
8282
if not isinstance(r, Requirement):
8383
r = Requirement(r)
84+
# Use the parent's extras for marker evaluation because PEP 508
85+
# markers like `extra == "foo"` refer to the parent's install extras.
8486
if requirements_file.evaluate_marker(req, r, req.extras):
8587
requires.add(r)
8688
else:
@@ -529,7 +531,14 @@ def get_build_backend_hook_caller(
529531
build_env: build_environment.BuildEnvironment,
530532
log_filename: str | None = None,
531533
) -> pyproject_hooks.BuildBackendHookCaller:
532-
"""Create pyproject_hooks build backend caller"""
534+
"""Create a ``BuildBackendHookCaller`` with merged environment variables.
535+
536+
The returned hook caller uses a custom runner that merges three sources
537+
of environment variables (in increasing priority):
538+
1. ``extra_environ`` passed by the hook caller itself
539+
2. ``override_environ`` from package-specific settings
540+
3. virtualenv variables from ``build_env``
541+
"""
533542

534543
def _run_hook_with_extra_environ(
535544
cmd: typing.Sequence[str],

src/fromager/dependency_graph.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ def _traverse_install_requirements(
169169
start_edges: list[DependencyEdge],
170170
visited: set[str],
171171
) -> typing.Iterable[DependencyEdge]:
172+
# Depth-first walk of install requirement edges, skipping nodes
173+
# already visited to avoid loops in the dependency graph.
172174
for edge in start_edges:
173175
if edge.key in visited:
174176
continue
@@ -220,6 +222,9 @@ def from_dict(
220222
graph_dict: dict[str, dict[str, typing.Any]],
221223
) -> DependencyGraph:
222224
graph = cls()
225+
# Stack-based DFS to reconstruct graph from serialized dict,
226+
# skipping nodes already visited to avoid processing shared
227+
# dependencies twice.
223228
stack = [ROOT]
224229
visited = set()
225230
while stack:

src/fromager/external_commands.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,14 @@ def run(
5858
log_filename: str | None = None,
5959
stdin: TextIOWrapper | None = None,
6060
) -> str:
61-
"""Call the subprocess while logging output"""
61+
"""Run a subprocess with optional network isolation and structured logging.
62+
63+
Captures output via a log file (when log_filename is set) or an in-memory
64+
pipe, then formats continuation lines with the current package prefix for
65+
greppability. On failure, raises ``NetworkIsolationError`` instead of
66+
``CalledProcessError`` when the output contains network-related error
67+
strings, so callers can distinguish network isolation failures.
68+
"""
6269
if extra_environ is None:
6370
extra_environ = {}
6471
env = os.environ.copy()

src/fromager/finders.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ def find_sdist(
4040
req: Requirement,
4141
dist_version: str,
4242
) -> pathlib.Path | None:
43+
"""Find an sdist archive in downloads_dir for the given requirement.
44+
45+
First checks for a plugin-provided exact filename. If no plugin match,
46+
tries four naming conventions (underscore-normalized, canonical, original,
47+
and dotted) with case-insensitive comparison to handle inconsistent
48+
sdist naming across the Python ecosystem. Case-insensitive globbing
49+
is not available before Python 3.12.
50+
"""
4351
sdist_file_name = overrides.find_and_invoke(
4452
req.name,
4553
"expected_source_archive_name",
@@ -95,6 +103,13 @@ def find_wheel(
95103
dist_version: str,
96104
build_tag: BuildTag = (),
97105
) -> pathlib.Path | None:
106+
"""Find a wheel file in downloads_dir for the given requirement.
107+
108+
Tries four naming conventions (PEP 427 transformed, canonical, original,
109+
and dotted), each suffixed with the build tag when present. Uses
110+
case-insensitive ``startswith`` matching rather than exact base comparison
111+
because wheel filenames include platform/Python tags after the version.
112+
"""
98113
filename_prefix = _dist_name_to_filename(req.name)
99114
canonical_name = canonicalize_name(req.name)
100115
# if build tag is 0 then we can ignore to handle non tagged wheels for backward compatibility
@@ -140,6 +155,15 @@ def find_source_dir(
140155
req: Requirement,
141156
dist_version: str,
142157
) -> pathlib.Path | None:
158+
"""Find the unpacked source directory for a requirement.
159+
160+
Tries three strategies in order:
161+
1. Plugin override providing the exact directory name
162+
2. Derive from the sdist archive name (strip extension), assuming the
163+
unpacked layout is ``<base>/<base>/`` (double-nested)
164+
3. Fall back to four naming conventions with case-insensitive matching,
165+
returning ``<match>/<match>/`` (same double-nested convention)
166+
"""
143167
sdir_name_func = overrides.find_override_method(
144168
req.name, "expected_source_directory_name"
145169
)

src/fromager/pyproject.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ def _default_build_system(self, doc: tomlkit.TOMLDocument) -> TomlDict:
9393
return build_system
9494

9595
def _update_build_requires(self, build_system: TomlDict) -> None:
96+
"""Merge, remove, and deduplicate build requirements.
97+
98+
Builds a map keyed by normalized package name (seeded with setuptools
99+
as a default), overlays existing requirements, removes unwanted ones,
100+
then applies update requirements. Only writes back if the resulting
101+
set differs from the original, ignoring order.
102+
"""
96103
old_requires = build_system[BUILD_REQUIRES]
97104
# always include setuptools
98105
req_map: dict[NormalizedName, list[Requirement]] = {

src/fromager/requirements_file.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ def evaluate_marker(
6565
if not extras:
6666
marker_envs = [default_env]
6767
else:
68+
# Evaluate once per extra because PEP 508 markers like `extra == "foo"`
69+
# can only match one extra value at a time.
6870
marker_envs = [default_env.copy() | {"extra": e} for e in extras]
6971

7072
for marker_env in marker_envs:

src/fromager/resolver.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,14 @@ def get_project_from_pypi(
222222
*,
223223
override_download_url: str | None = None,
224224
) -> Candidates:
225-
"""Return candidates created from the project name and extras."""
225+
"""Fetch and filter package candidates from a PyPI-compatible server.
226+
227+
Applies a multi-stage filtering pipeline to the project's package list:
228+
PEP 792 status check -> legacy filename rejection -> sdist/wheel type
229+
filter -> PEP 592 yanked check -> Python version compatibility ->
230+
platform tag matching (with ``ignore_platform`` fallback). Optionally
231+
substitutes ``override_download_url`` into each candidate's URL.
232+
"""
226233
found_candidates: set[str] = set()
227234
ignored_candidates: set[str] = set()
228235
logger.debug("%s: getting available versions from %s", project, sdist_server_url)
@@ -806,6 +813,10 @@ def cache_key(self) -> str:
806813
raise NotImplementedError("GenericProvider does not implement caching")
807814

808815
def find_candidates(self, identifier: typing.Any) -> Candidates:
816+
# Accepts three input formats from _version_source:
817+
# 1. Candidate objects (used directly)
818+
# 2. (url, Version) tuples
819+
# 3. (url, str) tuples (version parsed via _match_function)
809820
candidates: list[Candidate] = []
810821
version: Version | None
811822
for item in self._version_source(identifier):

src/fromager/sources.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,13 @@ def download_url(
295295
url: str,
296296
destination_filename: str | None = None,
297297
) -> pathlib.Path:
298+
"""Download a URL to destination_dir, returning the local path.
299+
300+
Returns immediately if the file already exists. Downloads to a ``.tmp``
301+
file first, then atomically renames on success to avoid leaving partial
302+
files. A nested function applies retry logic for transient network errors;
303+
the outer function ensures the temp file is cleaned up on any failure.
304+
"""
298305
basename = (
299306
destination_filename
300307
if destination_filename
@@ -500,6 +507,13 @@ def prepare_source(
500507
source_filename: pathlib.Path,
501508
version: Version,
502509
) -> pathlib.Path:
510+
"""Unpack and prepare source for building.
511+
512+
Git URL sources skip the plugin system and are prepared directly.
513+
Non-git sources go through ``find_and_invoke`` which may call a
514+
package-specific override. The plugin may return a ``Path`` or a
515+
``(Path, bool)`` tuple; both forms are handled.
516+
"""
503517
if req.url:
504518
logger.info(
505519
"preparing source cloned from %s into %s, ignoring any plugins",

src/fromager/vendor_rust.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def _cargo_shrink(crate_dir: pathlib.Path) -> None:
5656
for filename in crate_dir.glob(pattern):
5757
logger.debug("removing '%s'", filename.relative_to(crate_dir.parent))
5858
filename.unlink()
59-
filename.touch() # create empty file
59+
filename.touch() # keep empty placeholder so cargo doesn't error on missing files
6060
removed_files.append(str(filename.relative_to(crate_dir)))
6161

6262
# update checksums

0 commit comments

Comments
 (0)