Contributing
Development Setup
The dev dependency group includes the OTel SDK, pytest, pytest-cov, pre-commit, and Ruff.
Code Style
- Line length: 100 (ruff-enforced)
- Python: 3.12+ (use
X | Y, notOptional) - Ruff rules: E, W, F, I (isort), UP, B, SIM, TCH (with TC002/TC003 ignored for runtime imports)
- Double quotes for strings
Run the following commands:
Pre-commit runs both checks automatically on staged files. Continuous integration enforces linting using pre-commit run --all-files. Ruff is pinned to version 0.11.5 in .pre-commit-config.yaml, so running pre-commit run --all-files locally is the authoritative check. Running ruff directly is for convenience and might use a different version of Ruff.
Defer Heavy Imports
opentelemetry-sdk and related packages are expensive to import. Every opentelemetry.sdk.* import must be deferred inside the function that requires it and not at the module top level. Most SDK imports are located in providers.py (distributed across build_providers() and either the _build_*_exporter or _setup_log_provider helpers), but sampling.py and logging_bridge.py also import the SDK lazily inside their functions.
This keeps import nemo.lens cheap; this is important for consumers that might import nemo.lens solely to access the fallback implementations.
Use Type Hints
Public functions must contain type hints on parameters and return types. Use both typing and __future__.annotations for forward references. You can use TYPE_CHECKING guards for imports that are used only in type hints.
Avoid Redundant Comments
Prefer the following implementation:
Avoid adding comments that repeat the code:
Comments should explain why (non-obvious invariants, workarounds, design choices). For most code, good names make comments unnecessary.
Write Tests Before Implementing Changes
For every change that modifies behavior:
- Write a failing test.
- Run the test to confirm that it fails.
- Implement the change.
- Run the test to confirm that it passes.
- Run the full test suite to confirm that other functionality remains intact.
Refer to the Test documentation for fixture patterns and state-isolation requirements.
Changes to the Public API
The __all__ list in __init__.py defines the public API contract. Before adding or modifying any components in that list, address the following questions:
- Is the change part of the core value proposition or is it a one-off helper? Keep one-off helpers internal.
- Does the change have a corresponding test?
- Does the change have a docstring?
- Is there a corresponding page in the user guide, or does an existing page contain a description of this component?
- Is an update to
fallbacks.pyrequired? Signature changes tomanaged_span,trace_fn,span_cm,is_span_group_enabled, andsafe_set_span_attributesmust be mirrored.
Changes to fallbacks.py
Whenever a signature in helpers.py, state.py, or wherever else is mirrored in fallbacks.py changes, update fallbacks.py too, and add a test in test_fallbacks.py that exercises the new signature.
Changes to semconv
When adding an attribute name constant:
- Place the constant in the appropriate namespace, such as
dl.*or<project>.*(refer to the Semantic Conventions documentation). - Update the stability-marker comment block if the namespace is new.
- Ensure that the constant is used. Unused constants are considered dead code.
When bumping SEMCONV_VERSION:
- Review the upstream changelog for breaking changes.
- Update constants that were renamed or removed upstream.
- Describe these changes in the PR description so that downstream consumers are aware.
Changes that Affect Consumers
Megatron-LM, NeMo RL, and NeMo Gym all depend on NeMo Lens. Changes that break these consumer repositories are blocking:
- Renaming a public function causes a breaking change.
- Changing
managed_spanto require a new positional argument causes a breaking change. - Removing a span group causes a breaking change.
For such changes, coordinate with the consumer repos (feature branches, paired PRs). Prefer additive changes over breaking ones.
PR Checklist
- Tests are added and passing (
pytest -v). - The pull request title follows the conventional commits or semantic format (enforced by the
Validate PR Titlecontinuous integration check; for example,feat: ...,fix: ..., ordocs: ...). - Lint checks pass successfully (
pre-commit run --all-files). - Public API changes are mirrored in
fallbacks.py, if applicable. - Docstrings are updated for changed signatures.
- A user guide page is added or updated if the change is visible to users.
- The
__all__list is updated if exports changed. - A changelog entry is added, if a changelog exists.
Build the Documentation
The documentation source is located in docs/ and is built with Fern. Generate the local Python API reference and validate the site before opening a pull request:
Refer to Build the Documentation for local preview, authoring, versioning, and troubleshooting details.
Questions
Open an issue on the repository, or contact the NeMo ecosystem team.