Claude Code Plugins

Community-maintained marketplace

Feedback

Python Rope Refactor

@brian-yu/python-rope-refactor
21
0

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; only fallback if rope fails/dynamic imports.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name Python Rope Refactor
description 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; only fallback if rope fails/dynamic imports.

Python Rope Refactor

Default policy (rope-first)

When the user asks for mechanical Python refactors like move module, rename module, or rename class/function/symbol, default to running rope via scripts/rope_refactor.py rather than manually editing imports/usages.

Workflow:

  • run with --dry-run
  • review output; then run with --apply
  • review git diff
  • run relevant checks (tests/mypy/pyright)

Only 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.

Quick start

  1. Ensure you are in the repo you want to refactor.
  2. Create/activate a venv and install rope:
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install 'rope>=1.14,<2'

Version check: `rope.__version__` may not exist. Use one of:
- `python scripts/rope_refactor.py version`
- `python -c "from importlib.metadata import version; print(version('rope'))"`


(Recommended) Pin rope: this skill is tested with rope 1.14.x and rope APIs can differ across versions.

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):

python 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):

  • After --apply, run rg for the old symbol/module name(s) to confirm no leftovers.
  • If leftovers exist, widen scanning and rerun:
    • use --scan-roots <top-level-package> (e.g. --scan-roots responsesapi)
    • or omit --scan-roots/--auto-scan-roots to scan the whole project root (slow but complete)
  1. Run a dry-run first:
python scripts/rope_refactor.py --help
python scripts/rope_refactor.py move-module --help
  1. Apply, then review:
python scripts/rope_refactor.py ... --apply
git diff

Common refactors

Move a module (file) to another package

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).

python scripts/rope_refactor.py \
  move-module \
  --project-root . \
  --auto-project-root \
  --src pkg/old_mod.py \
  --dest-package pkg.newpkg \
  --dry-run

python scripts/rope_refactor.py \
  move-module \
  --project-root . \
  --auto-project-root \
  --src pkg/old_mod.py \
  --dest-package pkg.newpkg \
  --apply

Rename a module (file) within a package

Example: rename pkg/foo.py to pkg/bar.py (module name foo -> bar).

python scripts/rope_refactor.py \
  rename-module \
  --project-root . \
  --auto-project-root \
  --src pkg/foo.py \
  --new-name bar \
  --dry-run

python scripts/rope_refactor.py \
  rename-module \
  --project-root . \
  --auto-project-root \
  --src pkg/foo.py \
  --new-name bar \
  --apply

Rename a symbol (class/function/variable)

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):

python 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:

python 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

python 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 function/method

Extract a line range into a new function:

python 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:

python 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

Inline a variable at a specific definition site using --symbol targeting:

python scripts/rope_refactor.py \
  inline-variable \
  --project-root . \
  --auto-project-root \
  --file pkg/mod.py \
  --symbol TEMP \
  --context any \
  --dry-run

Organize imports

python scripts/rope_refactor.py \
  organize-imports \
  --project-root . \
  --auto-project-root \
  --roots pkg \
  --dry-run

Batch (JSON-driven)

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

python scripts/rope_refactor.py \
  batch \
  --project-root . \
  --auto-project-root \
  --map /tmp/rope_ops.json \
  --dry-run

Safety rules and gotchas

  • Prefer --dry-run first; always review git diff after --apply.
  • Rope can miss dynamic imports and string-based references:
    • importlib.import_module("pkg.old_mod")
    • framework config like "pkg.mod:Class"
  • Consider leaving a temporary compatibility re-export after big moves (optional):
# old_mod.py
from pkg.newpkg.old_mod import SomeName
__all__ = ["SomeName"]

When to fall back to non-rope edits

If rope fails due to version/API differences or code is too dynamic:

  • do the filesystem move/rename
  • do a targeted rg search + update imports manually
  • run tests / mypy / pyright to confirm