SLD7xx - Naming¶
SLD701: Names must not contain vague words (helper, util,
manager, etc.).
SLD702: Module-level names (functions, classes, top-level assignments)
must not shadow names from builtins, the typing module, or any
stdlib module:
# Bad
def list(): # shadows builtin 'list'
...
def sys(): # shadows stdlib module 'sys'
...
def Optional(): # shadows typing.Optional
...
Imports of these names are fine — only definitions are flagged.
SLD703: Flags any pair of names bound in the same scope (module,
function, class, lambda, or comprehension) whose identifiers differ by
exactly one inserted, deleted, or substituted letter. The classic
node / nodes and code / codes pairs are confusable at a
glance and obscure intent — use distinct names instead.
The single carve-out is single-letter names bound only as iteration
targets: for i, thing in items: is fine, including pairings like
for i in xs: ... for j in ys: ... where i and j co-occur in
the same scope. Multi-letter loop variables are not exempt; rewrite
for node in nodes: as for n in nodes: or rename one of the names.
The differing character must be a letter (a-z, A-Z) for the rule to
fire — names that differ only in digits or punctuation
(SLD304 / SLD305, foo_1 / foo_2, foo / _foo)
are intentionally allowed.
Dunder names (the __name__ form, such as __init__, __add__,
or __all__) are never flagged: they are mandated by Python and a
user cannot rename them to disambiguate, so pairs like __add__ /
__and__ are exempt.
# Bad
nodes = collect()
for node in nodes: # 'node' vs 'nodes' — confusable
process(node)
def fn(foo, fooo): # 'foo' vs 'fooo' — confusable
return foo
mosh = 1
mish = 2 # 'mosh' vs 'mish' — one substitution
moshe = 1
mosh = 2 # 'moshe' vs 'mosh' — one insertion
# Good
nodes = collect()
for n in nodes: # single-letter loop var — exempt
process(n)
def fn(first, second):
return first
# Good (digit-only differences are allowed)
SLD304 = "..."
SLD305 = "..."
SLD704: Flags any function or method whose name starts with is_
(optionally prefixed with leading underscores, e.g. _is_ready) but
whose return annotation is not bool (or TypeGuard[...] /
TypeIs[...], which are bool-valued by definition). The is_
prefix is a strong convention for boolean predicates – naming a
function is_open and then returning a string, an integer, or
None lies to every caller and breaks idioms like
if is_open(x):.
Functions with no return annotation are not flagged: with no claim
about the return type there is no claim to contradict. To force the
issue, add an explicit annotation. Names that merely happen to start
with the letters is (isolate, island, issue) are not
matched – only the is_ prefix triggers the rule.
# Bad
def is_ready() -> str:
return "yes"
def is_count() -> int:
return 0
class Job:
def is_open(self) -> str | None:
...
# Good
def is_ready() -> bool:
return True
from typing import TypeGuard
def is_str(x: object) -> TypeGuard[str]:
return isinstance(x, str)
# Good (no annotation -- nothing to contradict)
def is_ready():
return True