The Magic Removal Tool.
Constantipy is a CLI tool that automatically refactors "magic" literals (strings, numbers, bytes) in your Python codebase into named constants.
It scans your project, identifies repeated literals, names them intelligently (e.g., "SELECT *" → STR_SELECT_SQL), and refactors your code to import them from a central constants.py or define them locally.
- Zero Runtime Dependencies: Runs on standard library only.
- Smart Naming Heuristics:
- Auto-detects SQL (
STR_SELECT_SQL), URLs (HTTPS_GOOGLE_COM_URL), and Regex patterns. - Splits CamelCase (
FieldState→STR_FIELD_STATE).
- Auto-detects SQL (
- Scope Detection:
- Global: Strings used in multiple files are moved to
constants.py. - Local: Strings used in only one file are defined at the top of that file (keeps your global constants file clean).
- Global: Strings used in multiple files are moved to
- Safety First:
- Ignores f-strings (
f"Hello {name}") to prevent breaking interpolation. - Ignores docstrings.
- Checks for variable name collisions before generating constants.
- Ignores structural numbers (0, 1, 2, -1) by default.
- Ignores f-strings (
- Granular Control:
- Ignore specific values (
--ignore-str desc,--ignore-num 404). - Ignore specific types (
--no-ints,--no-floats). - Ignore specific function calls (like
logging.debug).
- Ignore specific values (
pip install constantipyBefore Constantipy:
# db_utils.py
import time
import logging
def fetch_users(retries=3):
# Magic String (SQL)
query = "SELECT * FROM users WHERE active = 1"
if retries > 0:
# Magic String inside logging (can be ignored via config)
logging.debug("Attempting connection...")
# Magic Number
time.sleep(60)
return "Success"After running constantipy apply:
# db_utils.py
import time
import logging
from constants import STR_SELECT_SQL, STR_SUCCESS, INT_60
def fetch_users(retries=3):
# Magic String (SQL)
query = STR_SELECT_SQL
if retries > 0:
# Magic String inside logging (can be ignored via config)
logging.debug("Attempting connection...")
# Magic Number
time.sleep(INT_60)
return STR_SUCCESSScan the codebase and preview or apply changes
constantipyconstantipy --applyGenerate a JSON report, review/edit it manually, and then apply the refactoring.
constantipy report > report.jsonconstantipy validate < report.jsonconstantipy refactor --apply < report.jsonYou can fine-tune the extraction process using command-line flags:
| Flag | Description | Default |
|---|---|---|
--apply |
Apply detected changes to files (direct mode only) | False |
--constants-file |
File name for storing global constants | constants.py |
--exclude |
Directories to exclude | None |
--extra-constants |
Additional Python files to scan for constants | None |
--ignore-call |
Ignore specific function calls during scanning | None |
--min-count |
Minimum occurrences for a constant to be considered | 2 |
--min-length |
Minimum length for string literals | 4 |
--naming {generic,derived} |
Strategy for naming generated constants | derived |
--no-local-scope |
Force all constants to be global (ignore local scope) | False |
--path |
Path to scan or refactor (default: current directory) | . |
| Flag | Description |
|---|---|
--ignore-num X |
Explicitly ignore number X (e.g. --ignore-num 42) |
--ignore-str S |
Explicitly ignore string S (e.g. --ignore-str "foo") |
--include-num X |
Explicitly extract number X (overrides default ignore) |
--no-bytes |
Skip bytes scanning |
--no-floats |
Skip float scanning |
--no-ints |
Skip integer scanning |
--no-numbers |
Disable ALL magic number extraction |
Constantipy modifies your source code.
While it contains safety checks (AST parsing, collision detection), automated refactoring always carries risk.
- Always commit your changes to git before running with
--apply. - Run your test suite immediately after applying.
MIT