Skip to content

set-attr-with-constant (B010)

Added in v0.0.111 · Related issues · View source

Derived from the flake8-bugbear linter.

Fix is always available.

What it does

Checks for uses of setattr that take a constant attribute value as an argument (e.g., setattr(obj, "foo", 42)).

Why is this bad?

setattr is used to set attributes dynamically. If the attribute is defined as a constant, it is no safer than a typical property access. When possible, prefer property access over setattr calls, as the former is more concise and idiomatic.

Example

setattr(obj, "foo", 42)

Use instead:

obj.foo = 42

Fix safety

The fix is marked as unsafe for attribute names that are not in NFKC (Normalization Form KC) normalization. Python normalizes identifiers using NFKC when using attribute access syntax (e.g., obj.attr = value), but does not normalize string arguments passed to setattr. Rewriting setattr(obj, "ſ", 1) to obj.ſ = 1 would be interpreted as obj.s = 1 at runtime, changing behavior.

Additionally, the fix is marked as unsafe if the expression contains comments, as the replacement may remove comments attached to the original setattr call.

For example, the long s character "ſ" normalizes to "s" under NFKC, so:

# This creates an attribute with the exact name "ſ"
setattr(obj, "ſ", 1)
getattr(obj, "ſ")  # Returns 1

# But this would normalize to "s" and set a different attribute
obj.ſ = 1  # This is interpreted as obj.s = 1, not obj.ſ = 1

Known issues

In some cases, a type checker may be able to analyze an assignment more thoroughly than a setattr call. Applying the fix in such cases may result in new type checking diagnostics, even if the runtime behavior of the code is unchanged.

References