pytorch/pytorch
Patterns and conventions
The repo's CLAUDE.md / AGENTS.md is the authoritative short list of conventions; this page expands on them and adds the codebase-wide patterns you'll see when reading PyTorch source.
Coding style (from CLAUDE.md)
- Minimize comments. Code should be self-documenting. Comments are for non-obvious global context — not for restating what the next line does.
- No trivial 1-2-LOC helpers. If it's used once, inline it.
- Clear abstractions. State management explicit. No dynamic
setattr/getattrin lieu of a class definition. - Match existing style. Look at the file you're editing.
- Assume PyTorch familiarity. Don't explain what
Tensoris. - When uncertain, choose the simpler implementation.
C++
- C++20. PyTorch builds with
-std=c++20. - Headers under c10 are header-only. Don't pull in heavy ATen headers from c10.
- Use
c10::intrusive_ptrfor refcounted shared types. Inheritc10::intrusive_ptr_target. - Use
c10::SmallVector/c10::ArrayRef/c10::optional. They are PyTorch's idiom;std::vector/std::span/std::optionalare also accepted now (PyTorch is C++20) but the existing code uses the c10 versions. TORCH_CHECK(cond, msg)for runtime checks. Throws ac10::Erroron failure.TORCH_INTERNAL_ASSERT(cond)for invariants that should never fail.c10::optionalis nowstd::optional. Both work; new code can use either.- Don't catch and swallow exceptions. Errors should surface.
Python
- Type hints are expected on new code. Old code is being incrementally annotated.
- Use
torch.Tensortypes in signatures, notAny. @torch.jit.unusedfor code that shouldn't be scripted.torch.fx.wrapto mark a function as opaque to FX tracing.- Use
torch._dynamo.config.patchfor temporary config changes (perCLAUDE.md's "Dynamo Config" section). Don't manually save/restore.
Error handling
- C++ ops use
TORCH_CHECKwith a clear message and the values involved. - Python user-facing errors should be
RuntimeError(notException) and reference the offending input where possible. - Don't
assertin production code paths.assertis stripped bypython -O. - For impossible-to-reach code,
TORCH_INTERNAL_ASSERT(C++) orraise RuntimeError("internal: ...")(Python).
Op authoring
The canonical guide is aten/src/ATen/native/README.md. The patterns:
- Schemas live in
native_functions.yaml. One source of truth. - Three variants per op:
op(functional),op_(in-place),op.out(out-variant taking explicit output). - Structured kernels for new pointwise/reduction ops. The shape rule (meta function) and the loop are separated.
- Backwards in
derivatives.yaml. Closed-form when possible; helper functions for complex cases live intools/autograd/templates/Functions.cpp. - OpInfo for testing.
torch/testing/_internal/common_methods_invocations.py. - Tagging. Mark
pointwise,inplace_view,data_dependent_output, etc., innative_functions.yaml.
Logging
Per CLAUDE.md:
- Two personas: local development and production. Code should support both.
- Production-friendly:
torch._logging.trace_structured. Artifact-shaped logs that are visible totlparse. No runtime cost when tracing is disabled. - Local development: optional file dumps. OK for true internal compiler exceptions where reproducibility matters.
- Error messages should mention both options to the user when relevant: "FX graph dump: foo.txt" + "Use tlparse to extract artifacts" (only if tracing enabled).
- Use
_get_unique_path()to avoid overwriting debug files.
Concurrency / GIL
- The GIL is held in most C++ paths. Released only via
pybind11::gil_scoped_releasein long-running native sections (training step, dataloader fetch). record_functionspans are GIL-friendly; they don't allocate.- Don't acquire the GIL twice. Use
pybind11::gil_scoped_acquirecarefully in callbacks.
Tensor-author idioms
- Prefer
c10::SmallVector<int64_t, N>overstd::vector<int64_t>for sizes/strides (typical N is 5). - Use
IntArrayReffor size/stride arguments. Cheap pass-by-reference. - Use
Tensor::contiguous()once at the top of a kernel if you need a contiguous view. - Use
TensorIteratorfor elementwise/reduction ops instead of hand-rolling loops.
Multiline string in B950 lint failures
Per CLAUDE.md's explicit guidance: if B950 line too long triggers on a multiline string, you can't add # noqa: B950 inside the string (it would change the content) or break the string (it would change the content). Instead put # noqa: B950 on the line with the closing triple-quote:
self.assertExpectedInline(
foo(),
"""
this line is too long...
""", # noqa: B950
)ghstack hygiene
Per CLAUDE.md:
- Don't amend ghstack commits unless asked. Leave changes uncommitted for review with
git diff. - Preserve
ghstack-source-idandPull-Request:trailers. - Submit with
ghstack(full stack) orghstack --no-stack(current commit only). ghstack -uto push only an updated commit message.- Never
git pushtogh/USERNAME/Nbranches.
Where to read next
CONTRIBUTING.md— the canonical rulebook.aten/src/ATen/native/README.md— op-author guide.- Testing — test idioms.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.