Skip to content

prefer-immutable-module-constant

Nonempty uppercase module collections allow top-level membership or keys to change at runtime.

Why

A constant-looking collection can expose process-wide top-level mutation even when callers intend it as a read-only lookup table.

Fix

When the concrete collection API is not part of the contract, use a tuple for ordered values, a frozenset for membership, or a Mapping-typed immutable mapping for keyed values. Recursively freeze nested values when needed.

Examples

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 Read-only mapping used for keyed values
settings.py
from collections.abc import Mapping
from types import MappingProxyType
ROLE_LABELS: Mapping[str, str] = MappingProxyType({"admin": "Administrator"})