Skip to content

build: generate CUDA dependency metadata from one source#655

Open
binaryaaron wants to merge 4 commits into
mainfrom
binaryaaron/cuda13/dependency-manifest
Open

build: generate CUDA dependency metadata from one source#655
binaryaaron wants to merge 4 commits into
mainfrom
binaryaaron/cuda13/dependency-manifest

Conversation

@binaryaaron

@binaryaaron binaryaaron commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

this is one of three stacked prs (#656, #657) for our overdue multiple-versions-of-cuda support. This one is the core mechanism for generating the deps all from one place and handles instructions and docs for new installation methods.

  • Define CPU and CUDA runtime extras, conflicts, package sources, and indexes in cuda_deps.toml.
  • Generate the corresponding marked pyproject.toml sections from that single source of truth.

Validation

- uv run --offline --script tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml --check
- uv lock --check

Summary by CodeRabbit

  • New Features

    • Introduced a single, tool-managed configuration for CPU/CUDA runtime extras (including CPU and CUDA 12.9 variants) and automatic generation of the related dependency and package-source metadata.
    • Added a check mode so generated metadata and the lockfile stay in sync.
  • Documentation

    • Updated contributor instructions to use the new CPU/CUDA runtime-extras workflow and clarified required lockfile/verification steps.
  • Quality & Tests

    • Expanded automated tests to validate generation, safe application to the project file, drift detection, and error handling.

Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

The PR adds cuda_deps.toml as the CPU/CUDA dependency source of truth, introduces tools/gen_cuda_deps.py to generate pyproject.toml metadata, adds generator tests, and updates lock-check workflows and contributor guidance.

CUDA Metadata Generation

Layer / File(s) Summary
Dependency configuration and validation contract
cuda_deps.toml, tools/gen_cuda_deps.py
Defines dependency variants, extras, indexes, sources, and validated configuration models.
Fragment generation and pyproject update
tools/gen_cuda_deps.py
Generates requirements and UV mappings, updates marked sections in pyproject.toml, and provides CLI check/update behavior.
Generated metadata and generator coverage
pyproject.toml, tests/test_gen_cuda_deps.py
Stores generated CPU/CUDA metadata and tests rendering, splicing, marker replacement, CLI behavior, and validation errors.
Lock consistency workflow and contributor guidance
.mise/tasks/quality.toml, .agents/skills/uv-build/SKILL.md, CONTRIBUTING.md
Checks generated CUDA metadata before uv.lock drift and documents the regeneration workflow.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested labels: feature, test

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: generating CUDA dependency metadata from a single source of truth.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch binaryaaron/cuda13/dependency-manifest

Comment @coderabbitai help to get the list of available commands.

Comment thread tools/gen_cuda_deps.py
return spec.as_pepstr(self)
raise TypeError(f"Unsupported dependency entry {dependency!r}")

def applies(self, dependency: DependencyEntry) -> bool:
@coderabbitai coderabbitai Bot added feature New feature or request test Test-only addition or change labels Jul 16, 2026
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.92697% with 29 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
tools/gen_cuda_deps.py 94.92% 28 Missing ⚠️
tests/test_gen_cuda_deps.py 99.37% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR moves the CPU and CUDA runtime extras, uv sources, and package indexes out of hand-maintained pyproject.toml sections into a single cuda_deps.toml source of truth, and introduces tools/gen_cuda_deps.py to generate and check those sections deterministically.

  • cuda_deps.toml defines shared dep groups, per-extra CPU/CUDA overrides, NVIDIA library routing metadata, and package index templates; the generator materialises these into three guarded blocks in pyproject.toml.
  • tools/gen_cuda_deps.py validates the TOML config with Pydantic, renders PEP 508 strings with template substitution, splices the generated sections idempotently into pyproject.toml using tomlkit, and wraps them in BEGIN/END GENERATED markers so the --check mode can detect drift.
  • The mise run lock-check task is extended to run the generator in --check mode before re-generating uv.lock, and documentation across AGENTS.md, CONTRIBUTING.md, and the uv-build skill is updated accordingly.

Confidence Score: 5/5

Safe to merge; the generator is fully deterministic, the generated pyproject.toml sections are consistent with cuda_deps.toml, and the previous thread issues are all resolved in this revision.

The core generation logic is correct and well-tested: idempotency, stale-marker replacement, drift detection, and a dozen error-path validations are all covered. The pyproject.toml changes are purely reformatting of existing entries plus the addition of more precise platform markers on torchao and triton sources, which are stricter and correct. No functional regressions were identified.

No files require special attention; the two inline comments flag minor future-proofing concerns in tools/gen_cuda_deps.py that do not affect current correctness.

Important Files Changed

Filename Overview
tools/gen_cuda_deps.py 970-line code-generation script; previous thread concerns (dataclass+Pydantic, dead GenStatus.error, structlog dep, unconditional write) are all addressed in this revision. Minor fragility in line-exact marker search is mitigated by comprehensive tests.
cuda_deps.toml New source-of-truth TOML; defines cpu/cu129 extras, shared deps, NVIDIA library routing, and indexes correctly. conflict_extras contains only "cpu" which is validated as a managed extra.
tests/test_gen_cuda_deps.py 369-line test suite covering generation, idempotency, stale-marker replacement, drift detection, CLI check/update round-trip, and a dozen error-path validations.
pyproject.toml Generated sections wrapped in BEGIN/END markers; content is consistent with cuda_deps.toml. New torch/torchao/triton source markers are more restrictive (linux-only) and align correctly with the dependency markers.
.mise/tasks/quality.toml lock-check task updated to run gen_cuda_deps.py --check before uv lock; --offline --frozen flags prevent network activity and lock mutations.
AGENTS.md Single paragraph added guiding contributors never to hand-edit generated blocks and describing the correct workflow.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cuda_deps.toml] -->|load_cuda_deps_config| B[CudaDepsConfig Pydantic model]
    B -->|build_cuda_pyproject_fragment| C[CudaPyprojectFragment]
    C -->|apply_cuda_fragment_to_pyproject| D{pyproject.toml current content}
    D -->|_update_optional_dependencies| E[splice cpu / cu129 extras]
    D -->|_update_uv_sections| F[splice conflicts / sources / index]
    E & F --> G[tomlkit.dumps]
    G -->|_mark_generated_sections| H[add BEGIN/END markers]
    H --> I[pyproject.toml with generated sections]
    I -->|--check flag| J{current == updated?}
    J -->|yes| K[GenStatus.ok exit 0]
    J -->|no| L[GenStatus.changed exit 1]
    I -->|normal mode| M[write_text GenStatus.ok]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[cuda_deps.toml] -->|load_cuda_deps_config| B[CudaDepsConfig Pydantic model]
    B -->|build_cuda_pyproject_fragment| C[CudaPyprojectFragment]
    C -->|apply_cuda_fragment_to_pyproject| D{pyproject.toml current content}
    D -->|_update_optional_dependencies| E[splice cpu / cu129 extras]
    D -->|_update_uv_sections| F[splice conflicts / sources / index]
    E & F --> G[tomlkit.dumps]
    G -->|_mark_generated_sections| H[add BEGIN/END markers]
    H --> I[pyproject.toml with generated sections]
    I -->|--check flag| J{current == updated?}
    J -->|yes| K[GenStatus.ok exit 0]
    J -->|no| L[GenStatus.changed exit 1]
    I -->|normal mode| M[write_text GenStatus.ok]
Loading

Reviews (3): Last reviewed commit: "docs: fix stale pyproject.toml editing g..." | Re-trigger Greptile

Comment thread tools/gen_cuda_deps.py Outdated
Comment on lines +224 to +236
@dataclass(frozen=True)
class NvidiaCudaLibrarySpec(StrictModel):
"""NVIDIA CUDA package source routing metadata."""

name: str = Field(description="NVIDIA CUDA library package stem without the nvidia- prefix.")
nvidia_package_suffix: str | None = Field(
default=None,
description="Optional package suffix override. Defaults to the CUDA variant suffix.",
)
index: str | None = Field(
default=None,
description="Optional literal uv index name or template. Defaults to the variant PyTorch index.",
)

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.

P2 @dataclass(frozen=True) applied to a Pydantic BaseModel subclass

NvidiaCudaLibrarySpec combines Python's standard @dataclass(frozen=True) with Pydantic's BaseModel, which is non-standard. Because Pydantic v2 generates __init__ directly into each model class's __dict__, the @dataclass decorator skips its own __init__ — but it still writes __setattr__/__delattr__ that raise FrozenInstanceError, bypassing Pydantic's own immutability machinery. The correct approach for frozen Pydantic models is model_config = ConfigDict(frozen=True), which is already available through StrictModel's configuration. This combination may break silently across Pydantic minor releases if that internal __init__ placement changes.

Comment thread tools/gen_cuda_deps.py Outdated
Comment thread tools/gen_cuda_deps.py Outdated
Comment thread tools/gen_cuda_deps.py
Comment on lines +913 to +926
def _update_pyproject(
pyproject_path: Path,
check: bool,
generated: CudaPyprojectFragment,
) -> GenerationResult:
current = pyproject_path.read_text(encoding="utf-8")
updated = apply_cuda_fragment_to_pyproject(current, generated)
if check:
return _check_pyproject(pyproject_path, current, updated)
pyproject_path.write_text(updated, encoding="utf-8")
return GenerationResult(
status=GenStatus.ok,
message=f"Updated generated CUDA dependency sections in {pyproject_path}",
)

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.

P2 Non-check mode always writes and always reports "Updated"

_update_pyproject unconditionally calls pyproject_path.write_text(updated, ...) and returns "Updated generated CUDA dependency sections" even when current == updated. This means running the generator when the file is already up-to-date still modifies the mtime, can create a spurious git diff, and produces a misleading success message. A pre-check if current == updated: return GenerationResult(status=GenStatus.ok, message="... already up to date") before the write would prevent this.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b4bffca5-fd31-4a5a-8bfe-d35cea816d23

📥 Commits

Reviewing files that changed from the base of the PR and between 1a33099 and ae95473.

📒 Files selected for processing (7)
  • .agents/skills/uv-build/SKILL.md
  • .mise/tasks/quality.toml
  • CONTRIBUTING.md
  • cuda_deps.toml
  • pyproject.toml
  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
📜 Review details
⏰ Context from checks skipped due to timeout. (4)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • CONTRIBUTING.md
  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
**/*.{md,markdown}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown}: Bold is acceptable only in markdown tables where it's the conventional way to mark header-like cells in the body
Use ## headers to segment markdown sections instead of bold text
Use -- (em-dash) instead of - (hyphen) for asides in markdown

Files:

  • CONTRIBUTING.md
**/*.md

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Do not use decorative bold in Markdown body text, list items, or docstrings; use single backticks for code identifiers, paths, and commands.

Use the repository's MkDocs Material Markdown conventions, including supported admonitions, content tabs, fenced code blocks, Mermaid diagrams, task lists, footnotes, definition lists, and emoji where appropriate.

Files:

  • CONTRIBUTING.md
**/*

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

**/*: Every source file requires the SPDX copyright and license header appropriate to its file format.
End files with a newline, remove trailing whitespace, use one space between sentences, and keep code, comments, and docstrings within 120 characters.

**/*: Never move a published release tag; if release code changes, create and validate the next release candidate instead.
A stable release tag must point to the exact tested commit SHA, not a later main commit.
Before publishing a release, verify the wheel, package import, CLI, dependency set, GitHub release, PyPI artifacts, and immutable container image tag.
All contributions must include a DCO Signed-off-by trailer, and commits must also have a verified cryptographic signature.
Commits merged to main must follow Conventional Commits syntax with a lowercase valid type, optional scope, description of at most 100 characters, and ! for breaking changes.
Before submitting a pull request, all existing tests must pass; new features require tests and bug fixes require regression tests.
Use the repository's mise tasks for development, testing, formatting, checking, documentation, and release operations instead of deprecated Makefile task commands.

Files:

  • CONTRIBUTING.md
  • cuda_deps.toml
  • pyproject.toml
  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • CONTRIBUTING.md
  • cuda_deps.toml
  • pyproject.toml
  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{py,sh,yaml,yml,md}: All source files with .py, .sh, .yaml, .yml, or .md extensions must include SPDX copyright headers.
Use the repository's pinned mise tasks and formatting checks rather than relying on locally installed tool versions.

Files:

  • CONTRIBUTING.md
  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
.agents/skills/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

Store skills in canonical location .agents/skills/ with each skill containing a SKILL.md file and optional references/

Files:

  • .agents/skills/uv-build/SKILL.md
**/*.toml

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Use spaces around =, comment dependency pins inline, and follow the prescribed pyproject.toml section order.

Files:

  • cuda_deps.toml
  • pyproject.toml
cuda_deps.toml

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Changes to cuda_deps.toml require regenerated CUDA metadata and lockfile validation via mise run lock-check.

Files:

  • cuda_deps.toml
.mise/tasks/**/*.toml

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Keep declarative Mise tasks under .mise/tasks/, provide descriptions for public tasks, and add usage metadata where arguments need validation or help.

Files:

  • .mise/tasks/quality.toml
.mise/tasks/*

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Keep shared shell helpers in .mise/tasks/_lib.sh and make that file non-executable.

Files:

  • .mise/tasks/quality.toml
pyproject.toml

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

Configure package metadata, dependencies, extras (cpu/cu129/engine), and uv configuration in pyproject.toml

Keep generated CUDA metadata and the uv lockfile synchronized when changing pyproject.toml or cuda_deps.toml; validate drift with mise run lock-check.

Files:

  • pyproject.toml

⚙️ CodeRabbit configuration file

Treat pyproject.toml as high-risk. Check package metadata, uv indexes, dependency groups, optional extras, Python version bounds, hatch config, ty config, script entry points, dependency consistency, and whether changes require regenerating uv.lock.

Files:

  • pyproject.toml
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Place durable implementation guidance in function and class docstrings for public contracts and source comments for local invariants
Target Python 3.11–3.13 with modern syntax (X | Y, list[str], Self). Python 3.14+ is not supported

**/*.py: Use American English spelling in Python code, documentation, and messages.
Use Field(description=...) for every Pydantic model field.
Use assignment-style Field() by default; use Annotated only for additional metadata such as validators, constrained aliases, or discriminated unions.
Use @dataclass(frozen=True) for immutable value objects and validators; use mutable dataclasses only for builders, accumulators, and pipeline state.
Use field(default_factory=list) instead of mutable list defaults.
Use StrEnum for string-valued configuration or serialization enums and plain Enum for internal constants.
Obtain loggers with observability.get_logger(__name__); do not call logging.getLogger() or structlog.get_logger() directly.
Use .runtime, .user, and .system category loggers appropriately.
Do not use print() for operational library output; use the approved logger, click.echo(), or sys.stdout.write() where appropriate.
Use extra={} for machine-queryable logging data and f-strings only for human-readable context.
Raise errors from the custom Safe Synthesizer error hierarchy, using the documented dual inheritance for user and internal errors.
Keep shared package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Prefer X | Y, built-in collection generics, and Self over Optional, Union, and legacy typing collections.
Use collection ABCs for function arguments and concrete collection types for return values.
Use Protocol for structural subtyping and avoid Any when object, generics, or protocols are suitable.
Use TYPE_CHECKING guards for heavy imports such as pandas, torch, and transformers.
...

Files:

  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
**/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit marker instead of the deprecated unit_test marker for test identification

Files:

  • tests/test_gen_cuda_deps.py
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Mirror source code directory structure in tests directory (e.g., tests/training/, tests/generation/ parallel to source structure)

Files:

  • tests/test_gen_cuda_deps.py
tests/**/*.py

📄 CodeRabbit inference engine (tests/TESTING.md)

tests/**/*.py: Auto-mark tests based on file path: tests under /e2e/ get e2e marker, tests under /smoke/ get smoke marker, all others get unit marker (only if no category marker already present)
Every test should have exactly one category marker: unit, smoke, or e2e
Use pytest.mark.requires_gpu modifier on tests that need CUDA hardware
Use pytest.mark.vllm on tests using vLLM generation backend and ensure each vLLM test file runs in its own process for GPU memory isolation
Use pytest.mark.slow on long-running tests
Use pytest.mark.smollm2 for SmolLM2 Hub download tests to enable process isolation
Use pytest.mark.noautouse to skip autouse fixtures for specific tests
Use load_test_dataset(filename) helper to load test datasets from tests/stub_datasets/ as HuggingFace Dataset objects
Use load_test_dataframe(filename) helper to load test data files from tests/stub_datasets/ as pandas DataFrames
Convert pandas columns to nullable dtypes (pd.Int64Dtype(), pd.BooleanDtype()) before assigning np.nan values
Use fake.seed_instance(seed) and random.seed(seed) together for Faker-based test data reproducibility
When sharing methods across multiple test files, define them in conftest.py and import them using relative imports (e.g., from .conftest import train_with_sdk); note that importing from other test files like tests/cli/helpers.py does not work
Use fixture_mock_processor or fixture_mock_processor_without_valid_records for mocking ParsedResponse objects with valid_records, invalid_records, errors, and prompt_number fields
Use pytest.importorskip to gate tests on optional dependencies that require specific extras (e.g., sentence_transformers, vllm)
Run vLLM tests with separate pytest invocations (one per file) using -n 0 (single process) for GPU memory isolation, or use staged mise tasks for CI visibility
Print statements are allowed in tests (ruff T201 is suppressed for tests/ directory) and should...

Files:

  • tests/test_gen_cuda_deps.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/test_gen_cuda_deps.py
tests/test_*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Name test files test_*.py, classes Test*, and functions test_<module>_<expected_behavior>.

Files:

  • tests/test_gen_cuda_deps.py
tools/**

⚙️ CodeRabbit configuration file

Review tools as developer and CI infrastructure. Check that scripts use uv or Makefile wrappers instead of ad hoc python/pip commands, preserve read-only behavior for check targets, fail with clear messages, avoid hidden network or filesystem side effects, and stay consistent with STYLE_GUIDE.md and CONTRIBUTING.md. Tooling may use print() when it is a standalone script or intentional CLI output.

Files:

  • tools/gen_cuda_deps.py
🧠 Learnings (1)
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/test_gen_cuda_deps.py
🪛 LanguageTool
.agents/skills/uv-build/SKILL.md

[grammar] ~70-~70: Use a hyphen to join words.
Context: ...ock`. Pre-commit verifies the lock is up to date. The generated CPU/CUDA sections of...

(QB_NEW_EN_HYPHEN)

🔇 Additional comments (7)
cuda_deps.toml (1)

1-59: LGTM!

Also applies to: 64-112

tools/gen_cuda_deps.py (1)

1-4: LGTM!

Also applies to: 6-13, 22-223, 238-983

pyproject.toml (1)

113-244: LGTM!

Also applies to: 252-331

tests/test_gen_cuda_deps.py (1)

1-3: LGTM!

Also applies to: 9-149, 155-340

.mise/tasks/quality.toml (1)

24-25: LGTM!

Also applies to: 27-29

.agents/skills/uv-build/SKILL.md (1)

64-74: LGTM!

CONTRIBUTING.md (1)

596-596: LGTM!

Comment thread .mise/tasks/quality.toml Outdated
Comment thread cuda_deps.toml
Comment thread tools/gen_cuda_deps.py Outdated
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
# /// script
# requires-python = ">=3.11"

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- tools/gen_cuda_deps.py ---\n'
sed -n '1,220p' tools/gen_cuda_deps.py

printf '\n--- version constraints ---\n'
rg -n --hidden --glob '!**/.git/**' 'requires-python|3\.14|3\.13|3\.11' pyproject.toml tools README.md CONTRIBUTING.md STYLE_GUIDE.md .github || true

Repository: NVIDIA-NeMo/Safe-Synthesizer

Length of output: 257


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' tools/gen_cuda_deps.py
printf '\n---\n'
rg -n --hidden --glob '!**/.git/**' '^requires-python|python = "' pyproject.toml tools/*.py .github CONTRIBUTING.md STYLE_GUIDE.md README.md || true

Repository: NVIDIA-NeMo/Safe-Synthesizer

Length of output: 9211


🏁 Script executed:

#!/bin/bash
set -euo pipefail

nl -ba tools/gen_cuda_deps.py | sed -n '1,120p'

Repository: NVIDIA-NeMo/Safe-Synthesizer

Length of output: 206


Cap tools/gen_cuda_deps.py at Python 3.13.
tools/gen_cuda_deps.py:5 is a standalone uv run --script entry, so requires-python = ">=3.11" still allows 3.14+. Tighten it to >=3.11,<3.14 to match the supported runtime window.

Source: Coding guidelines

Comment thread tools/gen_cuda_deps.py
Comment on lines +14 to +16
"""Generate CPU and CUDA dependency metadata in pyproject.toml."""

import tomllib

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- tools/gen_cuda_deps.py ---\n'
cat -n tools/gen_cuda_deps.py | sed -n '1,40p'

printf '\n--- tests/test_gen_cuda_deps.py ---\n'
cat -n tests/test_gen_cuda_deps.py | sed -n '1,40p'

Repository: NVIDIA-NeMo/Safe-Synthesizer

Length of output: 257


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- tools/gen_cuda_deps.py ---'
sed -n '1,40p' tools/gen_cuda_deps.py | cat -n

echo
echo '--- tests/test_gen_cuda_deps.py ---'
sed -n '1,40p' tests/test_gen_cuda_deps.py | cat -n

Repository: NVIDIA-NeMo/Safe-Synthesizer

Length of output: 3126


Add from __future__ import annotations to both new modules.

  • tools/gen_cuda_deps.py
  • tests/test_gen_cuda_deps.py
📍 Affects 2 files
  • tools/gen_cuda_deps.py#L14-L16 (this comment)
  • tests/test_gen_cuda_deps.py#L4-L7

Source: Coding guidelines

Comment thread tools/gen_cuda_deps.py Outdated
Addresses PR #655 review comments: scope CPU torch/torchaudio/torchvision
sources to Linux, skip rewriting an unchanged pyproject.toml, drop unused
structlog dependency and dead GenStatus.error, use Pydantic's frozen model
config instead of mixing in @DataClass, match the script's Python range to
the repo, and run the lock-check generator call offline.

Also simplifies tools/gen_cuda_deps.py: drop the PEP 723 inline-script
metadata block in favor of running against the repo venv, fix a marker
duplication bug in the generated-block stripping logic (surfaced while
dropping that block), fold single-caller helpers into their only callers
(_render_template, GeneratedBlocks' position finders), derive the uv source
marker from sys_platform/arch instead of hand-duplicating it in
cuda_deps.toml, and move CudaVariantUvRouter's index-resolution methods onto
CudaVariantContext to remove multi-hop reaches through it. Reworks the test
fixtures to use structural TOML mutation instead of brittle string-replace
against a shared blob, and extracts duplicated expected-output constants.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 16e068a0-3deb-47ca-bcc3-03870e2efcf0

📥 Commits

Reviewing files that changed from the base of the PR and between ae95473 and cff9c9c.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock, !uv.lock
📒 Files selected for processing (5)
  • .mise/tasks/quality.toml
  • cuda_deps.toml
  • pyproject.toml
  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • .mise/tasks/quality.toml
  • pyproject.toml
  • cuda_deps.toml
📜 Review details
⏰ Context from checks skipped due to timeout. (8)
  • GitHub Check: Unit Tests (3.12)
  • GitHub Check: Unit Tests (3.11)
  • GitHub Check: Unit Tests (3.13)
  • GitHub Check: Smoke Tests
  • GitHub Check: End-user Wheel Install
  • GitHub Check: Greptile Review
  • GitHub Check: Analyze (Python)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{md,markdown,py}

📄 CodeRabbit inference engine (.cursor/rules/agent-markdown-style.mdc)

**/*.{md,markdown,py}: Avoid decorative bold (**text**) in list items, body text, and docstrings; use structural cues (headers, list markers, colons, backticks) for emphasis instead
Use backticks for code identifiers, paths, and CLI commands in markdown and docstrings

Files:

  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Place durable implementation guidance in function and class docstrings for public contracts and source comments for local invariants
Target Python 3.11–3.13 with modern syntax (X | Y, list[str], Self). Python 3.14+ is not supported

**/*.py: Use American English spelling in Python code, documentation, and messages.
Use Field(description=...) for every Pydantic model field.
Use assignment-style Field() by default; use Annotated only for additional metadata such as validators, constrained aliases, or discriminated unions.
Use @dataclass(frozen=True) for immutable value objects and validators; use mutable dataclasses only for builders, accumulators, and pipeline state.
Use field(default_factory=list) instead of mutable list defaults.
Use StrEnum for string-valued configuration or serialization enums and plain Enum for internal constants.
Obtain loggers with observability.get_logger(__name__); do not call logging.getLogger() or structlog.get_logger() directly.
Use .runtime, .user, and .system category loggers appropriately.
Do not use print() for operational library output; use the approved logger, click.echo(), or sys.stdout.write() where appropriate.
Use extra={} for machine-queryable logging data and f-strings only for human-readable context.
Raise errors from the custom Safe Synthesizer error hierarchy, using the documented dual inheritance for user and internal errors.
Keep shared package code compatible with Python 3.11; do not use Python 3.12-only syntax such as PEP 695 type statements or bracketed generic parameters.
Prefer X | Y, built-in collection generics, and Self over Optional, Union, and legacy typing collections.
Use collection ABCs for function arguments and concrete collection types for return values.
Use Protocol for structural subtyping and avoid Any when object, generics, or protocols are suitable.
Use TYPE_CHECKING guards for heavy imports such as pandas, torch, and transformers.
...

Files:

  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
**/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use the unit marker instead of the deprecated unit_test marker for test identification

Files:

  • tests/test_gen_cuda_deps.py
tests/**

📄 CodeRabbit inference engine (.cursor/rules/repo-navigation.mdc)

tests/**: Mirror src/ directory structure in tests/ directory for test organization
Auto-mark tests by directory: tests/e2e/e2e, tests/smoke/smoke, otherwise default to unit

Mirror source code directory structure in tests directory (e.g., tests/training/, tests/generation/ parallel to source structure)

Files:

  • tests/test_gen_cuda_deps.py
tests/**/*.py

📄 CodeRabbit inference engine (tests/TESTING.md)

tests/**/*.py: Auto-mark tests based on file path: tests under /e2e/ get e2e marker, tests under /smoke/ get smoke marker, all others get unit marker (only if no category marker already present)
Every test should have exactly one category marker: unit, smoke, or e2e
Use pytest.mark.requires_gpu modifier on tests that need CUDA hardware
Use pytest.mark.vllm on tests using vLLM generation backend and ensure each vLLM test file runs in its own process for GPU memory isolation
Use pytest.mark.slow on long-running tests
Use pytest.mark.smollm2 for SmolLM2 Hub download tests to enable process isolation
Use pytest.mark.noautouse to skip autouse fixtures for specific tests
Use load_test_dataset(filename) helper to load test datasets from tests/stub_datasets/ as HuggingFace Dataset objects
Use load_test_dataframe(filename) helper to load test data files from tests/stub_datasets/ as pandas DataFrames
Convert pandas columns to nullable dtypes (pd.Int64Dtype(), pd.BooleanDtype()) before assigning np.nan values
Use fake.seed_instance(seed) and random.seed(seed) together for Faker-based test data reproducibility
When sharing methods across multiple test files, define them in conftest.py and import them using relative imports (e.g., from .conftest import train_with_sdk); note that importing from other test files like tests/cli/helpers.py does not work
Use fixture_mock_processor or fixture_mock_processor_without_valid_records for mocking ParsedResponse objects with valid_records, invalid_records, errors, and prompt_number fields
Use pytest.importorskip to gate tests on optional dependencies that require specific extras (e.g., sentence_transformers, vllm)
Run vLLM tests with separate pytest invocations (one per file) using -n 0 (single process) for GPU memory isolation, or use staged mise tasks for CI visibility
Print statements are allowed in tests (ruff T201 is suppressed for tests/ directory) and should...

Files:

  • tests/test_gen_cuda_deps.py

⚙️ CodeRabbit configuration file

Review tests against tests/TESTING.md. Check marker usage, fixture naming, tmp_path usage, determinism, and GPU/vLLM process-isolation requirements. Flag slop tests that only check that code runs, assert result is not None when stronger invariants exist, over-mock internal implementation details, patch around the bug instead of reproducing it, or add broad snapshot/golden churn without a clear contract. Flag change detector tests that fail on harmless refactors, formatting, record ordering, incidental wording, or private implementation details without demonstrating a behavior regression. Prefer existing fixtures or focused new fixtures for repeated setup; keep tests DRY when reasonable without making the behavior under test opaque. print() is allowed in tests.

Files:

  • tests/test_gen_cuda_deps.py
tests/test_*.py

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

Name test files test_*.py, classes Test*, and functions test_<module>_<expected_behavior>.

Files:

  • tests/test_gen_cuda_deps.py
**/*

📄 CodeRabbit inference engine (STYLE_GUIDE.md)

**/*: Every source file requires the SPDX copyright and license header appropriate to its file format.
End files with a newline, remove trailing whitespace, use one space between sentences, and keep code, comments, and docstrings within 120 characters.

**/*: Commits merged to main must use Conventional Commits format: <type>(<scope>): <description> or <type>: <description>, with a valid lowercase type and a description of at most 100 characters.
All contributions must include a DCO Signed-off-by trailer, and commits must also have a verified cryptographic signature.
Branches other than main must follow the lowercase <author>/<description> convention, optionally including an issue ID and one of the approved type prefixes.
Before submitting a pull request, run the repository's formatting, quality checks, and tests (mise run format, mise run check, and mise run test).

Files:

  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py

⚙️ CodeRabbit configuration file

**/*: Review as a senior maintainer for NeMo Safe Synthesizer. Prioritize issues that can change behavior, break user workflows, weaken privacy guarantees, hide failures, make tests unreliable, or create maintenance risk. Avoid generic style commentary unless it points to a concrete project convention that automated tools will not catch.
Comment only when the finding is actionable and tied to changed code. For each finding, state the impact, the condition that triggers it, and the smallest practical fix. Prefer one precise comment over broad advice. Do not ask for refactors outside the PR scope unless the changed code creates the problem.
Review type guidance: - Potential issue: use for correctness bugs, data loss, privacy leaks,
security risks, broken public APIs, invalid config behavior, missing
validation, hidden failures, nondeterministic tests, or CI breakage.

  • Refactor suggestion: use for local maintainability problems introduced
    by the diff when they have clear future cost, such as duplicated setup,
    unclear boundaries, over-mocking, avoidable complexity, or opaque test
    helpers.
  • Nitpick: avoid in chill mode. Do not emit formatting, import-order,
    wording, or style-only comments unless automated tools cannot catch the
    issue and it affects maintainability.

Severity guidance: - Critical: security/privacy leaks, data loss, training/test/holdout
contamination, or broken release/package/core pipeline execution.

  • Major: incorrect generation/training/evaluation behavior, broken
    CLI/SDK public API, invalid config defaults or validators, or GPU/vLLM
    cleanup and process-isolation bugs likely to fail CI or production
    runs.
  • Minor: localized bugs, missing focused tests for changed behavior, or
    bad test patterns that weaken regression coverage.
  • Trivial: small cleanup with no behavior impact. Usually suppress in
    chill mode.
  • Info: context only. Avoid unless it helps reviewers understand risk.
    Safe-Synthesizer-specific review focus: - Data ...

Files:

  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
**/*.{py,sh,yaml,yml,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

All Python, shell, YAML, YML, and Markdown source files must include SPDX copyright headers, except files listed in .copyrightignore.

Files:

  • tests/test_gen_cuda_deps.py
  • tools/gen_cuda_deps.py
tools/**

⚙️ CodeRabbit configuration file

Review tools as developer and CI infrastructure. Check that scripts use uv or Makefile wrappers instead of ad hoc python/pip commands, preserve read-only behavior for check targets, fail with clear messages, avoid hidden network or filesystem side effects, and stay consistent with STYLE_GUIDE.md and CONTRIBUTING.md. Tooling may use print() when it is a standalone script or intentional CLI output.

Files:

  • tools/gen_cuda_deps.py
🧠 Learnings (1)
📚 Learning: 2026-05-27T22:20:37.354Z
Learnt from: kendrickb-nvidia
Repo: NVIDIA-NeMo/Safe-Synthesizer PR: 520
File: tests/generation/test_vllm_backend.py:556-587
Timestamp: 2026-05-27T22:20:37.354Z
Learning: In NVIDIA-NeMo/Safe-Synthesizer, `tests/conftest.py`’s `pytest_collection_modifyitems` hook applies pytest category markers automatically based on each test file’s path: tests under `/e2e/` get `pytest.mark.e2e`, tests under `/smoke/` get `pytest.mark.smoke`, and all other tests get `pytest.mark.unit`. Therefore, when reviewing pytest tests outside `tests/e2e/` and `tests/smoke/`, do not flag missing explicit `pytest.mark.unit` decorators on test classes/functions as an issue (the hook will add them during collection). If a new test directory/category is introduced, ensure the hook is updated so it’s categorized correctly.

Applied to files:

  • tests/test_gen_cuda_deps.py
🔇 Additional comments (2)
tools/gen_cuda_deps.py (1)

1-42: LGTM!

Also applies to: 171-223, 252-540, 761-783, 899-937

tests/test_gen_cuda_deps.py (1)

33-204: LGTM!

Also applies to: 235-369

Comment on lines +216 to +232
def test_apply_cuda_fragment_to_pyproject_replaces_stale_marker_text(tmp_path: Path, generator: ModuleType) -> None:
"""Regenerating over a header written by an older script version must replace it, not leave a stray copy."""
config_path = tmp_path / "cuda_deps.toml"
config_path.write_text(CUDA_DEPS, encoding="utf-8")
generated = generator.build_cuda_pyproject_fragment(generator.load_cuda_deps_config(config_path))
updated = generator.apply_cuda_fragment_to_pyproject(PYPROJECT, generated)

stale = updated.replace(
"# Regenerate with: uv run --frozen tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml",
"# Regenerate with: uv run --script tools/gen_cuda_deps.py cuda_deps.toml --pyproject pyproject.toml",
)
assert stale != updated

reapplied = generator.apply_cuda_fragment_to_pyproject(stale, generated)

assert reapplied == updated
assert reapplied.count("Regenerate with") == 3

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Exercise a stale header with a different line count.

This replacement preserves the current header shape, so it cannot detect the fixed-length stripping bug. Add or remove a header comment line before reapplying the fragment and assert exact convergence.

Comment thread tools/gen_cuda_deps.py
Comment on lines +64 to +116
runtime_start = self._find_assignment(self.extras[0])
conflicts_start = self._find_assignment("conflicts")
yield GeneratedBlock(
label="RUNTIME EXTRAS",
start=runtime_start,
end=self._find_array_end(self._find_assignment(self.extras[-1])),
detail=f"# Generated extras in this block: {', '.join(self.extras)}.",
)
yield GeneratedBlock(
label="UV CONFLICTS",
start=conflicts_start,
end=self._find_array_end(conflicts_start),
detail="# Generated uv section: tool.uv.conflicts.",
)
yield GeneratedBlock(
label="UV SOURCES AND INDEXES",
start=self._find_section("[tool.uv.sources]"),
end=self._last_generated_index_line(),
detail="# Generated uv sections: tool.uv.sources and tool.uv.index.",
)

def reversed(self) -> list[GeneratedBlock]:
return sorted(self, key=lambda block: block.start, reverse=True)

def _find_assignment(self, key: str) -> int:
assignment = f"{key} = ["
for index, line in enumerate(self.lines):
if line == assignment:
return index
raise ValueError(f"pyproject.toml: missing generated assignment {assignment!r}")

def _find_section(self, section: str) -> int:
for index, line in enumerate(self.lines):
if line == section:
return index
raise ValueError(f"pyproject.toml: missing generated section {section!r}")

def _last_generated_index_line(self) -> int:
index_start = self._find_section("[[tool.uv.index]]")
next_section = self._find_next_non_index_section(index_start + 1)
return next_section - 1 if next_section is not None else len(self.lines) - 1

def _find_next_non_index_section(self, start_index: int) -> int | None:
for index in range(start_index, len(self.lines)):
if self.lines[index].startswith("[") and self.lines[index] != "[[tool.uv.index]]":
return index
return None

def _find_array_end(self, start_index: int) -> int:
for index in range(start_index + 1, len(self.lines)):
if self.lines[index] == "]":
return index
raise ValueError(f"pyproject.toml: missing closing bracket for generated assignment at line {start_index + 1}")

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Scope assignment searches to their owning TOML tables.

_find_assignment() scans the entire document, so an earlier unrelated cpu = [ or conflicts = [ is selected. Marker insertion—and later removal—can then modify unrelated configuration. Restrict searches to [project.optional-dependencies] and [tool.uv], with a collision regression test.

Comment thread tools/gen_cuda_deps.py
Comment on lines +224 to +229
def effective_source_marker(self, renderer: "TemplateRenderer") -> str | None:
"""Marker for the generated uv source entry: an explicit override, else the requirement's own markers."""
if self.source_marker is not None:
return renderer.template(self.source_marker)
markers = list(self.pep_markers(renderer))
return " and ".join(markers) if markers else None

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the rendered source marker before returning it.

Templated source_marker values bypass validation at Lines 201–203, and this method returns the rendered value directly. An invalid rendered marker therefore reaches generated tool.uv.sources. Parse it with Marker(rendered) before returning.

Proposed fix
     if self.source_marker is not None:
-        return renderer.template(self.source_marker)
+        rendered = renderer.template(self.source_marker)
+        Marker(rendered)
+        return rendered

As per path instructions, invalid configuration and missing validation must be treated as potential issues.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def effective_source_marker(self, renderer: "TemplateRenderer") -> str | None:
"""Marker for the generated uv source entry: an explicit override, else the requirement's own markers."""
if self.source_marker is not None:
return renderer.template(self.source_marker)
markers = list(self.pep_markers(renderer))
return " and ".join(markers) if markers else None
def effective_source_marker(self, renderer: "TemplateRenderer") -> str | None:
"""Marker for the generated uv source entry: an explicit override, else the requirement's own markers."""
if self.source_marker is not None:
rendered = renderer.template(self.source_marker)
Marker(rendered)
return rendered
markers = list(self.pep_markers(renderer))
return " and ".join(markers) if markers else None

Source: Path instructions

Comment thread tools/gen_cuda_deps.py
Comment on lines +702 to +719
def _strip_generated_markers(lines: list[str]) -> list[str]:
# Header length is fixed by _insert_generated_marker (GENERATED_MARKER_BODY plus one
# detail line), so skip by position rather than matching comment text: matching text
# would silently miss stale headers left over from a previous version of that text.
header_length = len(GENERATED_MARKER_BODY) + 1
stripped = []
skip_remaining = 0
for line in lines:
if skip_remaining:
skip_remaining -= 1
continue
if line.startswith(GENERATED_BEGIN_PREFIX):
skip_remaining = header_length
continue
if line.startswith(GENERATED_END_PREFIX):
continue
stripped.append(line)
return stripped

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Handle stale generated headers without assuming their historical length.

  • tools/gen_cuda_deps.py#L702-L719: strip the consecutive header comments instead of skipping the current fixed count.
  • tests/test_gen_cuda_deps.py#L216-L232: add a stale header with an extra or missing comment line and assert exact convergence.
📍 Affects 2 files
  • tools/gen_cuda_deps.py#L702-L719 (this comment)
  • tests/test_gen_cuda_deps.py#L216-L232

…tion

pyproject.toml's CPU/CUDA sections are now generated from cuda_deps.toml,
but AGENTS.md never mentioned this, docs/developer-guide/docker.md still
told contributors to hand-edit pyproject.toml for a new variant, and
.agents/skills/uv-build/SKILL.md contradicted its own generated-section
warning with a stale "edit extras manually in pyproject.toml" convention
and a --script invocation that no longer works now that the generator
dropped its inline PEP 723 metadata.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:build-dist area:dev-ex Affects build or dev experience area:docs area:tests feature New feature or request test Test-only addition or change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant