reassigned-constants
LintSurfaces a module-level constant reassigned despite its UPPER_SNAKE_CASE casing.
PEP 8 writes a module constant in SCREAMING_CASE, so a public module-level name that binds a fixed value yet reads as max_retries tells every caller "mutable state" when nothing ever writes it again.
SCREAMING_CASE, when nothing in the module reassigns it.The condition reads inertness through the same classifier the notebook banding gate consumes, which is what keeps the lint quiet where pylint's equivalent drowns in noise. A call-produced global (logger = get_logger(__name__), app = build()) is effectful, so it never flags, and a leading underscore marks deliberate module-private state (_cache = {}), the dunder __version__ riding the same exemption. A single-character name is spared too, its lone-capital SCREAMING form reading as a matrix by linear-algebra convention and its lowercase form usually a mathematical scalar. What remains is public data with no reassignment anywhere in the module, exactly the shape the SCREAMING_CASE convention exists for. The lint reports without an auto-fix and names the SCREAMING_CASE form in its help line, because renaming a module constant breaks importers outside the file. Notebooks are skipped whole, a cell's top-level assignments being working variables rather than module constants.
| Key | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | true | Toggle the rule on or off |
allow-pattern | regex | "" | Constant names exempted from the lint |
The allow-pattern regex is empty by default, exempting nothing beyond the structural carve-outs. A project carrying old-style PascalCase aliases (Vector = list[float]) sets it to spare them, whereas a TypeAlias-annotated target skips the gate without any configuration.
max_retries binds an inert literal nothing in the module reassigns, so it reads as a constant whose casing never says so. The lint reports it without rewriting and names the MAX_RETRIES form in its help line, because renaming a module constant breaks importers outside the file.
max_retries = 5
Word-boundary case folding turns maxRetries into MAX_RETRIES for the help line, where a naive uppercasing would produce MAXRETRIES. The same fold covers a PascalCase MaxRetries.
The scan descends into a top-level if, so default_encoding behind a platform guard draws the DEFAULT_ENCODING rename. Only a def, a class, or an if TYPE_CHECKING: block ends the descent.
An annotated assignment carrying a value reads the same as a bare one, so timeout: int = 30 draws the TIMEOUT rename. A bare annotation with no value binds nothing and stays silent.
A project carrying old-style PascalCase aliases sets allow-pattern = "^[A-Z][a-z]", so Vector = list[float] passes while the unmatched timeout still draws the TIMEOUT rename. The pattern is empty by default, exempting nothing.
max_retries: int declares a type without a value, so there is no constant to classify and the lint stays silent.
The scan does not descend into a def, so a local max_retries is a working variable rather than a module constant and stays silent.
counter is written twice, so it is mutable state rather than a constant, and the lint leaves it to its lowercase name. This is the mirror of reassigned-constants, which flags a SCREAMING_CASE name that a later write contradicts.
MAX_RETRIES already reads as a constant, so the lint leaves it alone. This is the shape every flagged case suggests renaming to.
Bindings under if TYPE_CHECKING: carry type-only semantics distinct from runtime configuration, so json_type never flags.
A TypeAlias annotation marks the target a type rather than a constant, so Vector skips the gate structurally. An old-style bare alias without the annotation is spared through the allow-pattern instead.
logger and app bind the result of a call, so evaluating them runs code rather than reading a fixed value. The shared inert-value classifier keeps the lint quiet on these effectful globals, exactly the split that spares pylint's noise.
Chained assignment (first = second = 1), tuple unpacking (first, second = 1, 2), and attribute targets (config.timeout = 30) all fall outside the single-name shape the rule reads, so each line passes silently whatever the casing of its names.
A lone letter at module scope usually names a mathematical scalar, and its SCREAMING form is a single capital, which linear algebra reads as a matrix. So x and n stay silent, where the suggestion would mislead more than help.
A leading underscore marks deliberate module-private state, so _cache and the dunder __version__ both drop out ahead of the casing gate.
Surfaces a module-level constant reassigned despite its UPPER_SNAKE_CASE casing.
Surfaces single-use local bindings that could inline cleanly.
For per-line opt-outs, the Suppression chapter covers the # prose: ignore[miscased-constants] directive.