Metadata-Version: 2.4
Name: pyseam
Version: 0.1.0
Summary: Semantic Python refactoring and symbol search CLI
Keywords: find,search,references,rename,refactor,inline,symbols,jedi,cli,python
Author: artificiadrian
Author-email: artificiadrian <36929853+artificiadrian@users.noreply.github.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Code Generators
Requires-Dist: click>=8.1
Requires-Dist: jedi>=0.20,<0.21
Requires-Dist: pyflakes>=3.4.0
Requires-Python: >=3.12
Project-URL: Repository, https://github.com/artificiadrian/pyseam
Project-URL: Issues, https://github.com/artificiadrian/pyseam/issues
Description-Content-Type: text/markdown

# pyseam

[![CI](https://img.shields.io/github/actions/workflow/status/artificiadrian/pyseam/ci.yml?branch=main&label=ci)](https://github.com/artificiadrian/pyseam/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/pyseam)](https://pypi.org/project/pyseam/)
[![Python versions](https://img.shields.io/pypi/pyversions/pyseam)](https://pypi.org/project/pyseam/)
[![License](https://img.shields.io/github/license/artificiadrian/pyseam)](https://github.com/artificiadrian/pyseam/blob/main/LICENSE)

Find and safely refactor Python symbols from the command line. pyseam resolves
names through scopes and imports with [jedi](https://jedi.readthedocs.io/), so it
sees the same symbols your interpreter does: every real use, without the false
matches and misses that `grep` and `sed` produce.

It does two things, both first-class:

- **Search.** Find where a symbol is defined and every place it is used, and
  inspect what sits under any position.
- **Refactor.** Rename a symbol, module, or package and rewrite every reference
  and import across the project, or inline a single-use variable. Changes are
  dry-run by default: review the diff, then re-run with `--apply`.

## What you can do

| Command | What it does |
| --- | --- |
| `pyseam find NAME [--refs]` | Locate a symbol's definition; with `--refs`, list every reference across the project (for a module, its import sites). |
| `pyseam describe FILE:LINE:COL \| NAME` | Report the kind, type, and full name of the symbol at a position or name. Use it to confirm the cursor before a rename. |
| `pyseam rename TARGET NEW_NAME [--apply]` | Rename a symbol (by name or `FILE:LINE:COL`) or a module/package (by path), updating every reference and import. |
| `pyseam inline FILE:LINE:COL \| NAME [--apply]` | Replace a single-use variable with its value and delete the assignment. |

pyseam runs project-wide from anywhere in a git repository, and refuses rather than
corrupts: it will not write a result that fails to parse, collides with an
existing name, or shadows a builtin, and it warns you where jedi cannot guarantee
completeness. Exit codes are scriptable: `0` ok, `2` nothing to do, `1` error.

## Install

### CLI

Install the command with [uv](https://docs.astral.sh/uv/):

```bash
uv tool install pyseam                                         # from PyPI
uv tool install git+https://github.com/artificiadrian/pyseam.git   # from GitHub
uv tool install .                                                # from a local clone
```

The distribution is `pyseam`; the installed command is `pyseam`. Confirm with
`pyseam --version`.

### Claude Code plugin

This repository is also a Claude Code plugin marketplace. The plugin provides the
`use-pyseam` skill, which directs Claude to use pyseam for semantic Python
refactors rather than editing across files by hand.

Install pyseam as a tool (above) first, then:

```
/plugin marketplace add artificiadrian/pyseam
/plugin install pyseam@pyseam
/reload-plugins                                  # skills are not loaded automatically
```

The skill is then available as `/pyseam:use-pyseam`. To test against a local
checkout, add the marketplace by path: `/plugin marketplace add ./path/to/pyseam`.
The plugin documents how to use pyseam; it does not bundle the binary, so the CLI
must be on `PATH`.

## Examples

Find where a symbol lives, then every place it is used:

```bash
pyseam find load_config            # definition, e.g. app/core.py:12:5
pyseam find load_config --refs     # definition and all references
```

Confirm what is under a position, or address an ambiguous name precisely:

```bash
pyseam describe app/core.py:12:5   # kind, type, full name
```

Rename a symbol by name; pyseam resolves it to its definition and rewrites every
reference:

```bash
pyseam rename load_config read_config            # dry-run; prints the diff
pyseam rename load_config read_config --apply    # applies it
```

Rename a module or package by path; imports are rewritten across the project:

```bash
pyseam rename app/core/money.py currency --apply   # module: file and imports
pyseam rename app/core newpkg --apply              # package: directory and imports
```

Inline a single-use variable back into its use site:

```bash
pyseam inline app/core.py:40:5 --apply
```

## Learn more

- `pyseam docs` prints the full guide from the installed binary (so it matches your
  version): commands, the position/name/path forms, interpreter resolution, exit
  codes, and caveats.
- `pyseam <command> --help` lists the complete flags for a command.

## Limitations

pyseam rewrites references that jedi can resolve statically, which is the bulk of a
real codebase. It cannot see a symbol named inside a *string* (`mock.patch`
targets, `getattr` keys, string and forward-reference annotations, dotted paths in
configuration), and jedi has a tail it under-resolves (duck-typed attribute
access, method overrides in sibling classes, rare comprehension cases). `rename
--apply` prints a reminder listing what to check; review the dry-run diff and run
your test suite, and grep for the old name (including non-`.py` files) to catch
string references.
