Skip to content

Use pathlib in toolshed and ci helper scripts (part 7 of #2410) - #2496

Open
LeSingh1 wants to merge 3 commits into
NVIDIA:mainfrom
LeSingh1:pathlib/toolshed-ci
Open

Use pathlib in toolshed and ci helper scripts (part 7 of #2410)#2496
LeSingh1 wants to merge 3 commits into
NVIDIA:mainfrom
LeSingh1:pathlib/toolshed-ci

Conversation

@LeSingh1

Copy link
Copy Markdown
Contributor

Path joining and filesystem predicates in the helper scripts, plus glob.globPath.glob in dump_cutile_b64.py.

os.path.isfile stays in check_generated_file_seals.py: that guard skips anything that is not a readable regular file, and Path.is_file() raises on EACCES/ENAMETOOLONG where os.path.isfile returns False. os.path.abspath stays where sys.path needs a str.

Not covered by the cuda_pathfinder CI job, so I verified locally instead: ci/tools/tests/test_check_release_notes.py passes (42 tests), and both pre-commit hooks produce output identical to the pre-change scripts when run over every tracked .py file.

Part 7 of #2410.

Parts 5 and 6 (cuda_core and cuda_bindings, largely build_hooks.py) are not ready — I have no way to run a wheel build here, and given the Path.is_file() divergence noted on #2410 I would rather not ship unverifiable build-system path changes.

Part 7 of the series proposed in NVIDIA#2410.
Path joining and filesystem predicates in the toolshed and ci/tools helper
scripts now go through pathlib. glob.glob in dump_cutile_b64.py becomes
Path.glob, with the mtime key reading Path.stat().
Kept on os.path, with a comment where it is not obvious:
- os.path.abspath in build_static_bitcode_input.py, since sys.path wants a str
and Path.absolute() does not normalize.
- os.path.isfile in check_generated_file_seals.py. That guard exists to skip
anything that is not a readable regular file, and Path.is_file() is not a
drop-in: it propagates OSError for errnos outside pathlib's ignore list
(EACCES, ENAMETOOLONG) where os.path.isfile returns False.
- os.path.normpath in check_spdx.py, which already carries its own comment.
The plan on NVIDIA#2410 also listed a root conftest.py; there is no such file. The
three conftest.py files live under cuda_pathfinder, cuda_core and
cuda_bindings, and none of them use os.path.
Verified locally: ci/tools/tests/test_check_release_notes.py passes (42
tests), and check_spdx.py and check_generated_file_seals.py produce output
identical to the pre-change scripts when run over every tracked .py file.
Signed-off-by: LeSingh1 <sshaurya914@gmail.com>
@copy-pr-bot

Copy link
Copy Markdown
Contributor

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actionsgithub-actionsBot added the CI/CD CI/CD infrastructure label Aug 4, 2026
Comment threadci/tools/check_release_notes.py Outdated

def notes_path(package: str, version: str) -> str:
return os.path.join(package, "docs", "source", "release", f"{version}-notes.rst")
return str(Path(package, "docs", "source", "release", f"{version}-notes.rst"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can treat all functions in these toolshed helper scripts as private. (They are generally not imported from third-party code). So we can change the return type on this to Path and prevent more conversions back and forth.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. repo_root is now a Path end to end — load_backport_branch, check_release_notes and validate_backport_decision all take Path, and --repo-root parses with type=Path. That removed the Path(repo_root) re-wrap inside the functions and 19 str(tmp_path) conversions in the tests. The five main() argv lists keep str() since those are command-line strings, which argparse converts back to Path.

Comment on lines 145 to 147
# os.path.isfile, not Path.is_file: this skips anything that is not a
# readable regular file, and Path.is_file raises on e.g. EACCES.
if not os.path.isfile(filepath):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned elsewhere, let's not worry about this behavioral difference. Update to Path.is_file

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4385757 (pushed before I saw the review, flagging so the thread is not left hanging): the checker uses Path(filepath).is_file() and the comment about the os.path.isfile behavioural difference is gone. Also swept the rest of the PR for the same pattern — toolshed/build_static_bitcode_input.py still had one os.path.abspath, now Path.resolve().

Per review: treat these helper scripts as private, so notes_path can return
Path and drop the str/Path round-trip at its call site. Accept the behavioral
change from os.path.isfile to Path.is_file in check_generated_file_seals.
@LeSingh1

Copy link
Copy Markdown
ContributorAuthor

Both addressed.

notes_path returns Path now, so check_release_notes does Path(repo_root) / path instead of the Path(repo_root, str(Path(...))) round-trip you were pointing at. The Path then flows unconverted into the problem tuples and out through the f-strings, so I widened three annotations from list[tuple[str, str]] to list[tuple[str | Path, str]] — that list also carries literal <tag> / <component> / <backport-git-tag> placeholders, so the union is honest rather than a workaround.

check_generated_file_seals.main uses Path.is_file(), the comment defending os.path.isfile is gone, and import os went with it — that was the file's last os use.

Left alone deliberately: validate_generated_file_seal still takes the raw string, because it interpolates {filepath!r} in about ten user-facing messages and a Path would print PosixPath('foo.pyx') into pre-commit output — that would add ten str() calls, not remove conversions. repo_root: str stays because argparse hands it over as a string.

ci/tools/tests/test_check_release_notes.py passes (42), including the ::warning file=... assertion that pins the rendered path, so it renders byte-identically. I also ran both scripts by hand against real repo files.

Follow-up to mdboom's review.
- repo_root is now a Path end to end: load_backport_branch, check_release_notes
and validate_backport_decision take Path, and --repo-root parses with
type=Path. That removes the Path(repo_root) re-wrap inside the functions and
the 19 str(tmp_path) conversions the tests needed to call them. The five
main() argv lists keep str(): those are command-line strings, which argparse
then turns back into a Path.
- build_static_bitcode_input: the last os.path use (os.path.abspath) becomes
Path.resolve(); the os import is now unused and is dropped.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CDCI/CD infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@LeSingh1@mdboom