A powerful Python refactoring tool that converts camelCase codebases to pythonic naming conventions while intelligently preserving external library calls.
- Smart Environment Detection - Automatically distinguishes between internal and external modules
- Aggressive Refactoring - Converts entire codebases while preserving external library APIs
- File & Directory Renaming - Renames files and directories to match pythonic conventions
- Ignores non-code directories.
- Gitignore Integration - Respects .gitignore patterns and includes sensible defaults
- PascalCase Preservation - Keeps class names and type imports in PascalCase
- LibCST-Powered - Uses concrete syntax trees for accurate code transformation
- Dry Run Support - Preview changes before applying them
# Install the tool
pip install snake-shift
# Preview changes to a single file
snake-shift my_file.py --dry-run
# Refactor code and rename files in a directory
snake-shift src/ --rename-files
# Just refactor code without renaming files
snake-shift project/ --dry-runBefore:
# myModule.py
import pandas as pd
from myPackage.dataUtils import processData
class myClass:
def myMethod(self, inputData):
df = pd.DataFrame(inputData)
processedData = processData(df.dropna())
return processedDataAfter:
# my_module.py
import pandas as pd
from my_package.data_utils import process_data
class MyClass:
def my_method(self, input_data):
df = pd.DataFrame(input_data) # External library preserved!
processed_data = process_data(df.dropna())
return processed_dataUnlike other tools that use hardcoded library lists, snake-shift intelligently detects external modules by:
- Checking if modules are installed in your Python environment
- Identifying standard library modules
- Recognizing common external packages even when not installed
- Treating unknown modules as internal (local code)
- Classes ?
PascalCase(MyClass) - Functions & Variables ?
snake_case(my_function, my_var) - PascalCase Imports ? Preserved (Dict, Path, MyClass)
- External Library Calls ? Untouched (pd.DataFrame, np.zeros)
With --rename-files:
-
myModule.py$\to$ my_module.py -
dataUtils/$\to$ data_utils/
pip install snake-shiftOr install from source:
git clone https://github.com/simondoesstuff/snake_shift.git
pip install -e .snake-shift [OPTIONS] PATHOptions:
--dry-run, -n- Show changes without writing to files--rename-files, -r- Also rename files and directories--stdout- Print refactored code to stdout (single files only)--verbose, -v- Show detailed output during processing--help- Show help message
Examples:
# Preview all changes to a project
snake-shift my_project/ --rename-files --dry-run
# Refactor a single file
snake-shift utils.py
# Refactor directory with file renaming
snake-shift src/ --rename-files --verbose
# Output refactored code to stdout
snake-shift my_script.py --stdoutfrom snake_shift import refactor_source, refactor_directory
# Refactor source code string
code = """
def myFunction(inputData):
return inputData.lower()
"""
refactored = refactor_source(code)
print(refactored)
# Output: def my_function(input_data):\n return input_data.lower()
# Refactor entire directory
from pathlib import Path
refactor_directory(
Path("my_project/"),
rename_files=True,
dry_run=False
)- Variable names:
myVar$\to$ my_var - Function names:
myFunction$\to$ my_function - Class names:
myClass$\to$ MyClass - Module imports:
from myPackage.myModule$\to$ from my_package.my_module - File names:
myModule.py$\to$ my_module.py - Directory names:
myPackage/$\to$ my_package/
- Library calls:
pd.DataFrame()stayspd.DataFrame() - Standard library:
os.path.join()staysos.path.join() - PascalCase imports:
from typing import DictstaysDict - External attributes:
model.fit()staysmodel.fit()
Contributions are welcome!
# run tests with,
uv run pytest
# or just set up the environment,
uv sync
# or if you don't have UV,
pip install -r requirements.txt
pytest # testsMIT Licence