Skip to main content

A short description of your project

Project description

sheridan-diffract

Detects how a Python package's public API changed between two git commits and classifies that change as a conventional commit type.

Most semver tools trust the developer to classify their own changes correctly. diffract verifies that classification against the actual diff — catching the common case where someone writes fix: but actually removed a public function.

How it works

  1. Uses sheridan-iceberg to extract the public API surface at two points in git history
  2. Diffs those two surfaces to find what was added or removed
  3. Maps the diff to a conventional commit classification:
Change Commit type
Public name removed feat! (breaking)
Public name added feat
Only internal/private changes refactor
No changes detected fix

Installation

pip install sheridan-diffract

Usage

CLI

# Compare the last two commits (default)
diffract

# Compare specific refs
diffract HEAD~3 HEAD

# Custom source directory (default: src/)
diffract --src lib/

# Emit JSON for CI consumption
diffract --json

# Exit non-zero if a breaking change is detected (for CI gates)
diffract --exit-code

Exit codes with --exit-code:

  • 0 — no API surface changes
  • 1 — breaking change (public name removed)
  • 2 — non-breaking API change (public name added)
  • 3 — error (git or surface extraction failure)

Example output:

Detected: feat!  (breaking change)

Removed public names:
  sheridan.diffract.enums:
    - OldHelper

Suggested commit prefix: feat!:
Detected: fix

No public API changes detected.

Suggested commit prefix: fix:

Scopes are passed through to the suggestion — if your commit message includes (parser), the suggested prefix will too:

Suggested commit prefix: feat(parser):

Python API

from sheridan.diffract import check

result = check(base_ref="v1.2.0", head_ref="HEAD")
print(result.commit_type)   # e.g. "feat!"
print(result.summary)       # human-readable description
print(result.diff.removed)  # tuple of NameChange objects
print(result.diff.added)

# JSON-serialisable dict for CI output
import json
print(json.dumps(result.to_dict(), indent=2))

To compare HEAD against the staging area (what the next commit will contain) — the same comparison the pre-commit hook uses:

from sheridan.diffract import check_staged

result = check_staged()
print(result.commit_type)  # reflects what is staged, not the last commit

Validate commit messages with pre-commit

diffract ships a commit-msg hook that rejects commits whose conventional commit type doesn't match the detected API change — catching fix: when you actually removed a public name.

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/sheridan/diffract
    rev: v<VERSION>
    hooks:
      - id: diffract-validate
  • make sure to pre-commit install --hook-type commit-msg first

The hook compares HEAD against the git staging area (not HEAD~1 → HEAD), so it correctly detects what is about to be committed rather than what was committed last. Explicit BASE/HEAD refs can be added to override this (see the GitHub Actions example below).

Scopes are preserved in all output — if you write fix(parser): …, the mismatch message will show fix(parser): as written and feat(parser): as the suggested replacement:

diffract: commit type mismatch
  written:  fix(parser):
  detected: feat(parser):

Non-conventional commit types (docs:, chore:, test:, etc.) are never blocked.

Configuration

If your source code isn't in src/, tell diffract once in a config file rather than repeating it on every command:

diffract.toml (takes precedence):

src = "python/src"

pyproject.toml:

[tool.diffract]
src = "python/src"

Priority: explicit --src flag → diffract.tomlpyproject.toml → default (src/).

As a GitHub Actions check

Validate the PR title against detected API changes — the CI equivalent of the pre-commit hook. The refs to diff are the PR branch HEAD versus the target branch HEAD:

# .github/workflows/diffract.yml
name: diffract

on:
  pull_request:
    types: [opened, synchronize, reopened, edited]  # 'edited' catches title-only changes

jobs:
  api-change-check:
    name: Validate PR title against API changes
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # required to access both commit SHAs

      - name: Install diffract
        run: pip install sheridan-diffract

      - name: Validate PR title type matches API change
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
        run: |
          printf '%s' "$PR_TITLE" > /tmp/pr-title.txt
          diffract \
            ${{ github.event.pull_request.base.sha }} \
            ${{ github.event.pull_request.head.sha }} \
            --validate-msg-file /tmp/pr-title.txt
  • base.sha — HEAD of the target branch (e.g. main) at the time of the PR event
  • head.sha — HEAD of the PR branch
  • Non-conventional title prefixes (docs:, chore:, test:, etc.) are never blocked
  • Scopes are passed through: a title of feat(parser): … will suggest feat(parser): on mismatch

What it does not do

  • diffract has no AST logic of its own. It delegates all API surface extraction to sheridan-iceberg.
  • It compares public names only (additions and removals). Signature changes (argument renames, return type changes) are not currently detected — iceberg returns name lists, not signatures.
  • It does not modify commits or rewrite history. It only reports.

Development

task install        # install all dependencies
task check          # lint + format + typecheck + tests (must all pass)
task test           # pytest with coverage (≥90% required)

See CONTRIBUTING.md for the full workflow.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sheridan_diffract-1.0.1.tar.gz (37.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sheridan_diffract-1.0.1-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

Details for the file sheridan_diffract-1.0.1.tar.gz.

File metadata

  • Download URL: sheridan_diffract-1.0.1.tar.gz
  • Upload date:
  • Size: 37.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sheridan_diffract-1.0.1.tar.gz
Algorithm Hash digest
SHA256 c6a63dbffb284a240675ebb9b6f0915da28eccbfb1eeee580ea10be8716f6348
MD5 1d37e4198f1a50b0e854ebdeff4a8d75
BLAKE2b-256 8b0fad61fa345eb698d79a22a121cc53ac7a6246af139ef77f5e250001295125

See more details on using hashes here.

Provenance

The following attestation bundles were made for sheridan_diffract-1.0.1.tar.gz:

Publisher: publish.yaml on andrewasheridan/diffract

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sheridan_diffract-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for sheridan_diffract-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e64717faa95c2b853203303666947701ed369df64335c0f803eef8999ae91aa1
MD5 a3af28ad9987a39c4574fac14b33147a
BLAKE2b-256 08cb724d4e7df5ed6e697a346a617c9f9c58b0ff5e1b2c6b92299bde982caff6

See more details on using hashes here.

Provenance

The following attestation bundles were made for sheridan_diffract-1.0.1-py3-none-any.whl:

Publisher: publish.yaml on andrewasheridan/diffract

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page