Skip to main content

PyRef2

PyPI version

PyRef2 is based on the core idea behind PyRef: automatically detecting refactorings in Python code. It extends that idea with a typed Python 3.13 codebase, direct Git revision analysis, structured JSON and Markdown reporting, hierarchical change summaries, and explicit functional-change detection for both refactoring-related and standalone behavior changes.

Use it when you need a fast, review-friendly report for questions like:

  • What was renamed, moved, extracted, inlined, or signature-changed between two revisions?
  • Did any of those findings also change method/class behavior?
  • Were there behavior changes that are not simple rename/move operations?

It is designed for CI checks, release reviews, and repository archaeology.

Install and run in 60 seconds

Install from PyPI:

python -m pip install pyref2

Or with uv:

uv tool install pyref2

Then run:

pyref2 analyze-revisions --repo path/to/repo origin/main..HEAD --format markdown

What you get:

  • machine-readable JSON findings (default)
  • optional Markdown report grouped by change type and scope
  • per-finding functional-change status
  • condensed method-level code diffs when a functional change is detected

How to read the output

  • No Functional Change means PyRef2 did not find structural behavior signals for the compared entity.
  • Functional Change Detected means at least one behavior signal changed and the report includes reasons.
  • Markdown reports group findings into module-level changes, class-wise changes, mixed-scope method changes, and other refactorings.

Architecture overview

PyRef2 uses a small layered pipeline so each stage stays testable and replaceable:

  • Parsing layer (core/ast_analysis.py): converts Python source into typed entities (ModuleEntity, ClassEntity, MethodEntity).
  • Diff layer (core/diff_engine.py): matches entities between revisions and produces a structural ModuleDiff.
  • Detection layer (core/detectors/): runs focused heuristic detectors (rename/extract/inline/move/signature changes).
  • Service layer (service.py): orchestrates parse → diff → detect and returns sorted findings.
  • Interface layer (cli/commands.py): exposes analyze-files and emits schema-versioned JSON output.

How functional changes are detected

PyRef2 reports functional-change status using static structural checks for move-related and non-move findings.

Method-level checks

For method comparisons, PyRef2 marks Functional Change Detected when any of these differ between before/after revisions:

  • body_signature: normalized AST statement signatures for the method body
  • params: method parameter tuple
  • called_names: set of called symbol names detected in the method body

If none of those differ, status is No Functional Change.

These method-level checks are used by:

  • Move Method
  • Rename Method
  • Modify Method (same name, same scope, same module, but behavior changed)
  • Change Method Signature
  • Extract Method (assesses whether the source caller changed)
  • Inline Method (assesses whether the destination caller changed)

Class-level checks

For class moves, PyRef2 combines class-level and member-level signals:

  • class bases changed
  • class method-name set changed
  • any contained matched method is marked Functional Change Detected

If none of the above is true, class status is No Functional Change.

For class signature changes (for example, base-class changes), PyRef2 reports Functional Change Detected with reasons when the class signature differs.

Reporting behavior

  • Move-related and non-move behavior findings include a functional-change status in JSON and Markdown.
  • In Markdown, same-name method entries are suppressed unless status is Functional Change Detected.
  • Class entries can include child method changes used to justify class-level status.
  • When status is Functional Change Detected, Markdown includes a condensed unified code diff scoped to the relevant method.

Current limitations

This is a static heuristic, not dynamic execution equivalence. It does not guarantee runtime equivalence in all cases. In particular, behavior can still change through effects not captured by the current signals (for example, external state interactions or semantics-preserving AST rewrites that alter call-name sets).

Quickstart

uv sync --extra dev
uv run pyref2 analyze-files --before path/to/old.py --after path/to/new.py
uv run pyref2 analyze-tree --before-root path/to/revision-A --after-root path/to/revision-B
uv run pyref2 analyze-revisions --repo path/to/repo origin/main..HEAD
uv run pyref2 analyze-revisions --format markdown --repo path/to/repo origin/main..HEAD

Git revision analysis

Use analyze-revisions to compare repository states directly from Git without exporting trees by hand.

  • Pass a standard Git double-dot range: uv run pyref2 analyze-revisions --repo path/to/repo origin/main..HEAD
  • main..feature means: analyze the total effect between the tree at main and the tree at feature, which matches the common feature-branch review workflow.
  • Add --format markdown to get a developer-oriented report grouped by refactoring type.

Tree test fixtures

Whole-tree regression tests live under tests/source_trees/ and use this layout:

  • <test-name>/revision-A/
  • <test-name>/revision-B/

This keeps it easy to add a new before/after source tree pair whenever a bug needs a permanent fixture.

Documentation conventions

  • Use Google-style docstrings for public Python modules, classes, and functions.

Metadata

Release files for pyref2 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyref2 0.1.1
File Size Uploaded
pyref2-0.1.1.tar.gz 14.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyref2 0.1.1
File Interpreter ABI Platform
pyref2-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 35.2 kB

Release files / pyref2-0.1.1.tar.gz

Download URL pyref2-0.1.1.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f05bd6b35c95cdc13b11654760c81494fa89e7738a2289c3b0680bde2418e1aa
BLAKE2b-256 checksum
How to use checksums
aee179d7bfbbb704e8ef58025f6a772214681ed7971633ff7f53a4dfc116a09a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / pyref2-0.1.1-py3-none-any.whl

Download URL pyref2-0.1.1-py3-none-any.whl
Size 20.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2b2d37493986db8c579f719eb3be05496759dfcf8e794716efe761472f38db05
BLAKE2b-256 checksum
How to use checksums
bf179bbed00c62d3445ea0573ea5dd697685f8ace03964cdcd703f8011e74ef9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page