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
- Uses sheridan-iceberg to extract the public API surface at two points in git history
- Diffs those two surfaces to find what was added or removed
- 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 changes1— 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-msgfirst
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.toml → pyproject.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 eventhead.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 suggestfeat(parser):on mismatch
What it does not do
diffracthas no AST logic of its own. It delegates all API surface extraction tosheridan-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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6a63dbffb284a240675ebb9b6f0915da28eccbfb1eeee580ea10be8716f6348
|
|
| MD5 |
1d37e4198f1a50b0e854ebdeff4a8d75
|
|
| BLAKE2b-256 |
8b0fad61fa345eb698d79a22a121cc53ac7a6246af139ef77f5e250001295125
|
Provenance
The following attestation bundles were made for sheridan_diffract-1.0.1.tar.gz:
Publisher:
publish.yaml on andrewasheridan/diffract
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sheridan_diffract-1.0.1.tar.gz -
Subject digest:
c6a63dbffb284a240675ebb9b6f0915da28eccbfb1eeee580ea10be8716f6348 - Sigstore transparency entry: 1177410112
- Sigstore integration time:
-
Permalink:
andrewasheridan/diffract@18f8a9ef68d27fbf56120957eedfafe9b98a11d3 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/andrewasheridan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@18f8a9ef68d27fbf56120957eedfafe9b98a11d3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sheridan_diffract-1.0.1-py3-none-any.whl.
File metadata
- Download URL: sheridan_diffract-1.0.1-py3-none-any.whl
- Upload date:
- Size: 17.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e64717faa95c2b853203303666947701ed369df64335c0f803eef8999ae91aa1
|
|
| MD5 |
a3af28ad9987a39c4574fac14b33147a
|
|
| BLAKE2b-256 |
08cb724d4e7df5ed6e697a346a617c9f9c58b0ff5e1b2c6b92299bde982caff6
|
Provenance
The following attestation bundles were made for sheridan_diffract-1.0.1-py3-none-any.whl:
Publisher:
publish.yaml on andrewasheridan/diffract
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sheridan_diffract-1.0.1-py3-none-any.whl -
Subject digest:
e64717faa95c2b853203303666947701ed369df64335c0f803eef8999ae91aa1 - Sigstore transparency entry: 1177410183
- Sigstore integration time:
-
Permalink:
andrewasheridan/diffract@18f8a9ef68d27fbf56120957eedfafe9b98a11d3 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/andrewasheridan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yaml@18f8a9ef68d27fbf56120957eedfafe9b98a11d3 -
Trigger Event:
push
-
Statement type: