Rope-first workflow for ANY mechanical Python rename/move (functions/methods/classes/variables/modules/packages), updating imports/references via scripts/rope_refactor.py; use even for small renames;...
When the user asks for mechanical Python refactors like move module, rename module, or rename class/function/symbol, default to running rope via uv run scripts/rope_refactor.py rather than manually editing imports/usages.
Workflow:
--dry-run--applygit diffOnly fall back to manual edits when rope fails or the code uses dynamic/string-based imports.
Use this skill when you need reliable, mechanical Python refactors (especially in larger codebases) and want imports/usages updated automatically.
This skill provides a small CLI wrapper around rope refactorings with a safe workflow.
uv is installed.Tip: in large monorepos, prefer --auto-project-root (and optionally --auto-scan-roots) to avoid rope scanning the entire repo.
Example (paths can be relative to repo root; the tool will re-root them):
uv run scripts/rope_refactor.py \
rename-symbol \
--project-root . \
--auto-project-root \
--auto-scan-roots \
--file path/to/file.py \
--symbol OldName \
--context class \
--new-name NewName \
--dry-run
If roots are too narrow (missed references):
--apply, run rg for the old symbol/module name(s) to confirm no leftovers.--scan-roots <top-level-package> (e.g. --scan-roots responsesapi)--scan-roots/--auto-scan-roots to scan the whole project root (slow but complete)uv run scripts/rope_refactor.py --help
uv run scripts/rope_refactor.py move-module --help
uv run scripts/rope_refactor.py ... --apply
git diff
Example: move pkg/old_mod.py into the pkg/newpkg package.
Destination package must exist on disk and include __init__.py (rope requires a real package folder).
uv run scripts/rope_refactor.py \
move-module \
--project-root . \
--auto-project-root \
--src pkg/old_mod.py \
--dest-package pkg.newpkg \
--dry-run
uv run scripts/rope_refactor.py \
move-module \
--project-root . \
--auto-project-root \
--src pkg/old_mod.py \
--dest-package pkg.newpkg \
--apply
Example: rename pkg/foo.py to pkg/bar.py (module name foo -> bar).
uv run scripts/rope_refactor.py \
rename-module \
--project-root . \
--auto-project-root \
--src pkg/foo.py \
--new-name bar \
--dry-run
uv run scripts/rope_refactor.py \
rename-module \
--project-root . \
--auto-project-root \
--src pkg/foo.py \
--new-name bar \
--apply
Rope renames based on a precise cursor/offset into a file.
This wrapper lets you target the symbol precisely:
--offset (most precise)--pattern + optional --occurrence and --group--symbol + --context class|def|any (builds a safer pattern when --pattern is omitted)Example: rename a class OldName -> NewName using --symbol targeting (recommended):
uv run scripts/rope_refactor.py \
rename-symbol \
--project-root . \
--auto-project-root \
--file pkg/models.py \
--symbol OldName \
--context class \
--new-name NewName \
--dry-run
Example: rename a class OldName -> NewName using a pattern:
uv run scripts/rope_refactor.py \
rename-symbol \
--project-root . \
--auto-project-root \
--file pkg/models.py \
--new-name NewName \
--pattern 'class\\s+OldName\\b' \
--dry-run
uv run scripts/rope_refactor.py \
rename-symbol \
--project-root . \
--auto-project-root \
--file pkg/models.py \
--new-name NewName \
--pattern 'class\\s+OldName\\b' \
--apply
Extract a line range into a new function:
uv run scripts/rope_refactor.py \
extract-function \
--project-root . \
--auto-project-root \
--file pkg/mod.py \
--start-line 10 \
--end-line 25 \
--new-name helper_fn \
--dry-run
Extract a line range into a method:
uv run scripts/rope_refactor.py \
extract-method \
--project-root . \
--auto-project-root \
--file pkg/mod.py \
--start-line 10 \
--end-line 25 \
--new-name _helper \
--dry-run
Inline a variable at a specific definition site using --symbol targeting:
uv run scripts/rope_refactor.py \
inline-variable \
--project-root . \
--auto-project-root \
--file pkg/mod.py \
--symbol TEMP \
--context any \
--dry-run
uv run scripts/rope_refactor.py \
organize-imports \
--project-root . \
--auto-project-root \
--roots pkg \
--dry-run
Create a JSON file (list of ops or {"ops": [...]}), then run:
cat > /tmp/rope_ops.json <<'JSON'
[
{"op": "rename-module", "src": "pkg/foo.py", "new_name": "bar"},
{"op": "move-module", "src": "pkg/bar.py", "dest_package": "pkg.subpkg"},
{"op": "rename-symbol", "file": "pkg/subpkg/bar.py", "symbol": "OldClass", "context": "class", "new_name": "NewClass"},
{"op": "organize-imports", "roots": ["pkg"]}
]
JSON
uv run scripts/rope_refactor.py \
batch \
--project-root . \
--auto-project-root \
--map /tmp/rope_ops.json \
--dry-run
--dry-run first; always review git diff after --apply.importlib.import_module("pkg.old_mod")"pkg.mod:Class"# old_mod.py
from pkg.newpkg.old_mod import SomeName
__all__ = ["SomeName"]
If rope fails due to version/API differences or code is too dynamic:
rg search + update imports manually