# Snake Shift
[](https://github.com/simondoesstuff/snake_shift)
[](https://python.org)
[](LICENSE)
A powerful Python refactoring tool that converts camelCase _codebases_ to pythonic naming conventions while intelligently preserving external library calls.
## Features
- **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
## Quick Start
```bash
# 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-run
```
## Before & After
**Before:**
```python
# 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 processedData
```
**After:**
```python
# 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_data
```
## How It Works
### 1. Environment-Based Module Detection
Unlike 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)
### 2. Pythonic Convention Application
- **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)
### 3. File System Organization
With `--rename-files`:
- `myModule.py` ? `my_module.py`
- `dataUtils/` ? `data_utils/`
- `MyClass.py` ? `MyClass.py` (PascalCase preserved)
## Installation
```bash
pip install snake-shift
```
Or install from source:
```bash
git clone https://github.com/simondoesstuff/snake_shift.git
pip install -e .
```
## Usage
### Command Line Interface
```bash
snake-shift [OPTIONS] PATH
```
**Options:**
- `--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:**
```bash
# 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 --stdout
```
### Python API
```python
from 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
)
```
## What Gets Refactored
### Internal Code (Your Code)
- 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/`
### External Code (Preserved)
- Library calls: `pd.DataFrame()` stays `pd.DataFrame()`
- Standard library: `os.path.join()` stays `os.path.join()`
- PascalCase imports: `from typing import Dict` stays `Dict`
- External attributes: `model.fit()` stays `model.fit()`
## Contributing
Contributions are welcome!
### Building
```bash
# 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 # tests
```
## License
MIT Licence
## Acknowledgments
- Built with [LibCST](https://libcst.readthedocs.io/) for accurate Python code transformation
- CLI powered by [Typer](https://typer.tiangolo.com/)
- Inspired by the need for better Python refactoring tools that understand modern codebases
Raw data
{
"_id": null,
"home_page": null,
"name": "snake-shift",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "camelcase, code-formatting, python, refactoring, snake-case",
"author": null,
"author_email": "Simon Walker <simon@simonwalker.tech>",
"download_url": "https://files.pythonhosted.org/packages/d0/16/2be29a5671f626beb19c1a813d6e15341b1afb17750411ecb0ed9bcff349/snake_shift-1.0.2.tar.gz",
"platform": null,
"description": "# Snake Shift\n\n[](https://github.com/simondoesstuff/snake_shift)\n[](https://python.org)\n[](LICENSE)\n\nA powerful Python refactoring tool that converts camelCase _codebases_ to pythonic naming conventions while intelligently preserving external library calls.\n\n## Features\n\n- **Smart Environment Detection** - Automatically distinguishes between internal and external modules\n- **Aggressive Refactoring** - Converts entire codebases while preserving external library APIs\n- **File & Directory Renaming** - Renames files and directories to match pythonic conventions\n - Ignores non-code directories.\n- **Gitignore Integration** - Respects .gitignore patterns and includes sensible defaults\n- **PascalCase Preservation** - Keeps class names and type imports in PascalCase\n- **LibCST-Powered** - Uses concrete syntax trees for accurate code transformation\n- **Dry Run Support** - Preview changes before applying them\n\n## Quick Start\n\n```bash\n# Install the tool\npip install snake-shift\n\n# Preview changes to a single file\nsnake-shift my_file.py --dry-run\n\n# Refactor code and rename files in a directory\nsnake-shift src/ --rename-files\n\n# Just refactor code without renaming files\nsnake-shift project/ --dry-run\n```\n\n## Before & After\n\n**Before:**\n\n```python\n# myModule.py\nimport pandas as pd\nfrom myPackage.dataUtils import processData\n\nclass myClass:\n def myMethod(self, inputData):\n df = pd.DataFrame(inputData)\n processedData = processData(df.dropna())\n return processedData\n```\n\n**After:**\n\n```python\n# my_module.py\nimport pandas as pd\nfrom my_package.data_utils import process_data\n\nclass MyClass:\n def my_method(self, input_data):\n df = pd.DataFrame(input_data) # External library preserved!\n processed_data = process_data(df.dropna())\n return processed_data\n```\n\n## How It Works\n\n### 1. Environment-Based Module Detection\n\nUnlike other tools that use hardcoded library lists, snake-shift intelligently detects external modules by:\n\n- Checking if modules are installed in your Python environment\n- Identifying standard library modules\n- Recognizing common external packages even when not installed\n- Treating unknown modules as internal (local code)\n\n### 2. Pythonic Convention Application\n\n- **Classes** ? `PascalCase` (MyClass)\n- **Functions & Variables** ? `snake_case` (my_function, my_var)\n- **PascalCase Imports** ? Preserved (Dict, Path, MyClass)\n- **External Library Calls** ? Untouched (pd.DataFrame, np.zeros)\n\n### 3. File System Organization\n\nWith `--rename-files`:\n\n- `myModule.py` ? `my_module.py`\n- `dataUtils/` ? `data_utils/`\n- `MyClass.py` ? `MyClass.py` (PascalCase preserved)\n\n## Installation\n\n```bash\npip install snake-shift\n```\n\nOr install from source:\n\n```bash\ngit clone https://github.com/simondoesstuff/snake_shift.git\npip install -e .\n```\n\n## Usage\n\n### Command Line Interface\n\n```bash\nsnake-shift [OPTIONS] PATH\n```\n\n**Options:**\n\n- `--dry-run, -n` - Show changes without writing to files\n- `--rename-files, -r` - Also rename files and directories\n- `--stdout` - Print refactored code to stdout (single files only)\n- `--verbose, -v` - Show detailed output during processing\n- `--help` - Show help message\n\n**Examples:**\n\n```bash\n# Preview all changes to a project\nsnake-shift my_project/ --rename-files --dry-run\n\n# Refactor a single file\nsnake-shift utils.py\n\n# Refactor directory with file renaming\nsnake-shift src/ --rename-files --verbose\n\n# Output refactored code to stdout\nsnake-shift my_script.py --stdout\n```\n\n### Python API\n\n```python\nfrom snake_shift import refactor_source, refactor_directory\n\n# Refactor source code string\ncode = \"\"\"\ndef myFunction(inputData):\n return inputData.lower()\n\"\"\"\nrefactored = refactor_source(code)\nprint(refactored)\n# Output: def my_function(input_data):\\n return input_data.lower()\n\n# Refactor entire directory\nfrom pathlib import Path\nrefactor_directory(\n Path(\"my_project/\"),\n rename_files=True,\n dry_run=False\n)\n```\n\n## What Gets Refactored\n\n### Internal Code (Your Code)\n\n- Variable names: `myVar` $\\to$ `my_var`\n- Function names: `myFunction` $\\to$ `my_function`\n- Class names: `myClass` $\\to$ `MyClass`\n- Module imports: `from myPackage.myModule` $\\to$ `from my_package.my_module`\n- File names: `myModule.py` $\\to$ `my_module.py`\n- Directory names: `myPackage/` $\\to$ `my_package/`\n\n### External Code (Preserved)\n\n- Library calls: `pd.DataFrame()` stays `pd.DataFrame()`\n- Standard library: `os.path.join()` stays `os.path.join()`\n- PascalCase imports: `from typing import Dict` stays `Dict`\n- External attributes: `model.fit()` stays `model.fit()`\n\n## Contributing\n\nContributions are welcome!\n\n### Building\n\n```bash\n# run tests with,\nuv run pytest\n\n# or just set up the environment,\nuv sync\n\n# or if you don't have UV,\npip install -r requirements.txt\npytest # tests\n```\n\n## License\n\nMIT Licence\n\n## Acknowledgments\n\n- Built with [LibCST](https://libcst.readthedocs.io/) for accurate Python code transformation\n- CLI powered by [Typer](https://typer.tiangolo.com/)\n- Inspired by the need for better Python refactoring tools that understand modern codebases\n",
"bugtrack_url": null,
"license": null,
"summary": "Smart codebase refactor from camelCase to pythonic snake_case",
"version": "1.0.2",
"project_urls": {
"Homepage": "https://github.com/simondoesstuff/snake_shift",
"Issues": "https://github.com/simondoesstuff/snake_shift/issues",
"Repository": "https://github.com/simondoesstuff/snake_shift"
},
"split_keywords": [
"camelcase",
" code-formatting",
" python",
" refactoring",
" snake-case"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "45dd555f6a81493fa41daf4ea127b5b4d406bfbdac1d75d2f0b5314e03e882bd",
"md5": "906ed1d1b9a848edff951d1667e56a01",
"sha256": "77ad1dc51b12a4b7348bc969487c62f7a6aa088f1fbee1ddb561afdbaf19a08c"
},
"downloads": -1,
"filename": "snake_shift-1.0.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "906ed1d1b9a848edff951d1667e56a01",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 15621,
"upload_time": "2025-09-02T00:22:51",
"upload_time_iso_8601": "2025-09-02T00:22:51.404423Z",
"url": "https://files.pythonhosted.org/packages/45/dd/555f6a81493fa41daf4ea127b5b4d406bfbdac1d75d2f0b5314e03e882bd/snake_shift-1.0.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "d0162be29a5671f626beb19c1a813d6e15341b1afb17750411ecb0ed9bcff349",
"md5": "1a90c1afcb77eb0524efb8121003b386",
"sha256": "ae94880cea64181d54a32cedb14ae7910160a126c39062ad3a641b9ec2de81dd"
},
"downloads": -1,
"filename": "snake_shift-1.0.2.tar.gz",
"has_sig": false,
"md5_digest": "1a90c1afcb77eb0524efb8121003b386",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 92462,
"upload_time": "2025-09-02T00:22:52",
"upload_time_iso_8601": "2025-09-02T00:22:52.867606Z",
"url": "https://files.pythonhosted.org/packages/d0/16/2be29a5671f626beb19c1a813d6e15341b1afb17750411ecb0ed9bcff349/snake_shift-1.0.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-02 00:22:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "simondoesstuff",
"github_project": "snake_shift",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [],
"lcname": "snake-shift"
}