Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .config/ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ ignore = [
"N999", # Ignoring this since we are using jinja templates in the directory path which will eventually turn into a valid module name. # TODO: make a task in downstream templates to remove this
"S101", # We do not use the -o optimize flag, so it's fine to use `assert` in the main code. It's especially helpful for static typing
"SIM102", # Nested if statements can be better analyzed by coverage detectors than compound statements
"SIM103", # Explicit if/else branches let the coverage checker track both paths, unlike evaluating an expression
"SIM108", # Explicit if/else branches let the coverage checker track both paths, unlike a ternary
"SIM110", # Explicit if statements and loops let the coverage checker track both paths, unlike using `any` or `all` with a generator expression
"SIM114", # Using `or` statements to simplify this would confuse the coverage checker
"SIM401", # using dictionary getters to simplify this would inhibit the coverage checker from tracking both paths
"TD002", # Adding author names to TODOs erodes shared ownership of codebase. Git history provides information about who originally created the TODO if that information is vitally needed
"TD003", # Up to the author's judgement whether a TODO requires a link to an issue or not
"TID252", # Sometimes it makes sense to use relative imports, that's a judgement call for us, not ruff
Expand Down
8 changes: 6 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ This project is a Copier template used to generate other copier templates. It is
- Comments should be used very rarely. Code should generally express its intent.
- Never write a one-line docstring — either the name is sufficient or the behavior warrants a full explanation.
- Don't sort or remove imports manually — pre-commit handles it.
- Always include type hints in Python
- Respect the pyrefly unused-call-result check; assign unneeded return values to `_`
- Prefer keyword-only parameters (unless a very clear single-argument function): use `*` in Python signatures and destructured options objects in TypeScript.
- When disabling a linting rule with an inline directive, provide a comment at the end of the line (or on the line above for tools that don't allow extra text after an inline directive) describing the reasoning for disabling the rule.
- Avoid telling the type checker what a type is rather than letting it prove it. This includes type assertions (`as SomeType` in TypeScript, `cast()` in Python) and variable annotations that override inference. Prefer approaches that let the type checker verify the type itself: `isinstance`/`instanceof` narrowing, restructuring code so the correct type flows naturally, or using discriminated unions. When there is genuinely no alternative, add a comment explaining why the workaround is necessary and why it is safe.
- Avoid `||` (TypeScript) or `or` (Python) in `if`/`elif` conditions, and avoid `x in ['a', 'b']`-style membership tests in implementation code — coverage tools treat these as a single branch, silently masking untested paths and producing false 100% branch coverage. Use separate `if`/`elif` branches instead so each condition is independently covered.

### Python

- Always include type hints.
- Respect the pyrefly unused-call-result check; assign unneeded return values to `_`
- Prefer explicit `if`/`else` (or a `for` loop with `if`/`return`) over one-line forms that collapse branches: a ternary, `d.get(key, default)`, returning a boolean expression `return b > 5`/`return bool(b)`, or `any()`/`all()` over a generator in place of a loop. `coverage.py` tracks branches as line-to-line arcs, so a single-line expression hides the untaken path.
- When filtering logic combines multiple `and`-joined guards (e.g. a null check alongside a value check), prefer a loop with explicit `if`/`continue` branches over a single-line comprehension. A compound boolean filter on one line hides individual branches from line coverage — each guard condition should be its own statement so missing test cases are surfaced.

## Testing
Expand Down