Skip to content

prefer-immutable-module-constant

Module collection constants should use native immutable containers or declare dictionary bindings as Final.

Why

Tuple and frozenset protect collection membership. Final makes a dictionary's constant binding explicit without changing its runtime type or concrete dictionary API.

Fix

When the concrete list or set API is not part of the contract, use a tuple for ordered values or a frozenset for membership. Annotate dictionary constants with Final[dict[K, V]]. Final prevents reassignment in type-checked code but does not freeze dictionary contents. Use MappingProxyType when runtime write protection is required.

Examples

Before — flagged Conditional dictionary factory needs constant intent
settings.py
if voice_enabled:
TOOL_LABELS = dict.fromkeys(("call", "transfer"), "Voice")
After — preferred Conditional dictionary factory declares a Final binding
settings.py
from typing import Final
if voice_enabled:
TOOL_LABELS: Final[dict[str, str]] = dict.fromkeys(("call", "transfer"), "Voice")
Before — flagged Mutable collection exposed as a module constant
settings.py
ROLE_NAMES = ["admin", "member"]
After — preferred Immutable tuple used for a module constant
settings.py
ROLE_NAMES = ("admin", "member")
Before — flagged Dictionary exposed as a module constant
settings.py
ROLE_LABELS = {"admin": "Administrator"}
After — preferred Final dictionary binding used for keyed values
settings.py
from typing import Final
ROLE_LABELS: Final[dict[str, str]] = {"admin": "Administrator"}