python.global_mutable_state
Correctness
High
Detects module-level mutable variables (lists, dicts, sets) not marked as Final or using constant naming convention.
Why It Matters
Section titled “Why It Matters”Global mutable state causes problems that only show up in production:
- Race conditions — Multiple threads modify the same data concurrently
- Request leakage — In web apps, data from one request leaks into another
- Test pollution — Tests affect each other through shared state
- Debugging nightmare — State changes from anywhere, hard to trace
Single-threaded development hides these bugs. Production with concurrent workers reveals them.
Example
Section titled “Example”# ❌ Beforecache = {} # Module-level mutable dict
def get_user(user_id): if user_id not in cache: cache[user_id] = fetch_user(user_id) return cache[user_id]In a multi-worker web server, this cache is duplicated per process and has no thread safety.
# ✅ Afterfrom threading import Lock
class UserCache: def __init__(self): self._cache = {} self._lock = Lock()
def get(self, user_id): with self._lock: if user_id not in self._cache: self._cache[user_id] = fetch_user(user_id) return self._cache[user_id]
# Or use a proper caching libraryfrom functools import lru_cache
@lru_cache(maxsize=1000)def get_user(user_id): return fetch_user(user_id)What Unfault Detects
Section titled “What Unfault Detects”- Module-level
{},[],set()assignments - Module-level variables that get mutated elsewhere
- Excludes
CONSTANT_CASEnames (assumed intentional) - Excludes
Finalannotated variables
Auto-Fix
Section titled “Auto-Fix”Unfault suggests encapsulating mutable state in classes with proper synchronization.