Skip to main content

shikumi-contrace

shikumi-contrace is a library for describing contracts about software behavior as referenceable Python assets.

Keeping contracts separate from implementations and tests makes the following information explicit.

  • What is the subject of a contract
  • What behavior is promised
  • Which tests address which clauses
  • Which implementation corresponds to which contract subject
  • What dependencies exist between contracts
contract
   ↑
   │ upholds / violates
   │
 test ───── binds ───── implementation

Contracts are written as ordinary Python code and can be referenced by people, LLMs, and tools.

shikumi-contrace is not a library that generates tests from contracts. Tests are written normally, with declarations that state which contracts they address.

Installation

The current version is 0.1.0.

pip install shikumi-contrace

To use the pytest integration:

pip install "shikumi-contrace[pytest]"

Example

Boundary types

# contract/ports/reservation.py

from dataclasses import dataclass


@dataclass(frozen=True)
class Reservation:
    sku: str
    quantity: int
# contract/inventory.py

from typing import Protocol

from .ports.reservation import Reservation


class Inventory(Protocol):
    def reserve(self, sku: str, quantity: int) -> Reservation: ...

Contract

# contract/inventory_contract.py

from shikumi_contrace import (
    INV,
    POST,
    PRE,
    REJECTED,
    kind,
    member,
    on_violation,
    subject,
)

from .inventory import Inventory


class InventoryContract:
    subject @= Inventory

    class StockUnchangedOnFailure:
        """A failed reservation does not change stock."""

        kind @= INV

    class reserve:
        member @= Inventory.reserve

        class QuantityMustBePositive:
            """Reservation quantity must be greater than zero."""

            kind @= PRE
            on_violation @= REJECTED

        class ReservationIsReturned:
            """A successful reservation returns a reservation handle."""

            kind @= POST

Implementation

# inventory_service.py

from contract.ports.reservation import Reservation


class InventoryService:
    def __init__(self, stock: dict[str, int]) -> None:
        self.stock = dict(stock)

    def reserve(self, sku: str, quantity: int) -> Reservation:
        if quantity <= 0:
            raise ValueError("quantity must be positive")

        available = self.stock.get(sku, 0)

        if quantity > available:
            raise ValueError("insufficient stock")

        self.stock[sku] = available - quantity

        return Reservation(
            sku=sku,
            quantity=quantity,
        )

Tests

# test_inventory.py

import pytest

from shikumi_contrace import (
    Phase,
    binds,
    upholds,
    violates,
)

from contract.inventory import Inventory
from contract.inventory_contract import InventoryContract as Contract
from inventory_service import InventoryService


@binds[Inventory](InventoryService)
class TestReserve:
    @upholds(Contract.reserve.ReservationIsReturned)
    def test_returns_reservation(self):
        with Phase.PREPARE:
            inventory = InventoryService(
                stock={"book": 10},
            )

        with Phase.MAIN:
            reservation = inventory.reserve(
                "book",
                2,
            )

        with Phase.VERIFY:
            assert reservation.sku == "book"
            assert reservation.quantity == 2

    @violates(Contract.reserve.QuantityMustBePositive)
    @upholds(Contract.StockUnchangedOnFailure)
    def test_rejects_zero_quantity(self):
        with Phase.PREPARE:
            inventory = InventoryService(
                stock={"book": 10},
            )
            before = dict(inventory.stock)

        with Phase.MAIN:
            with pytest.raises(ValueError):
                inventory.reserve(
                    "book",
                    0,
                )

        with Phase.VERIFY:
            assert inventory.stock == before

Vocabulary

Contract declarations

Vocabulary Use Example
subject Specify the contract subject subject @= Inventory
member Specify a member of the subject member @= Inventory.reserve
kind Specify the kind of a clause kind @= PRE
on_violation Describe the handling of a PRE violation on_violation @= REJECTED
depends_on Describe a dependency on another contract asset depends_on @= OtherClause

Clause kinds

Vocabulary Meaning
PRE A condition that holds before an operation
POST A condition that holds after an operation
INV A condition maintained across operations

Violation handling

Vocabulary Meaning
REJECTED A violating call is not accepted as a normal success
OUT_OF_SCOPE Behavior on violation is outside the promise of that clause

REJECTED does not prescribe how rejection is represented. An exception, result type, HTTP response, or another implementation-appropriate form can be used.

OUT_OF_SCOPE means that the clause makes no promise about behavior when the condition is violated.

These words do not build a complete trust-boundary model, but they can be used to express concisely how far a condition is trusted and how far behavior on violation is included in the contract.

Test relations

Vocabulary Use
@upholds(...) The test addresses behavior that satisfies a clause
@violates(...) The test addresses a violation of a clause
@binds[Subject](Implementation) Record the correspondence between a subject and an implementation

Phase is re-exported as an alias of metamk.Mk.

with Phase.PREPARE:
    ...

with Phase.MAIN:
    ...

with Phase.VERIFY:
    ...

Contract dependencies

Dependencies between contracts can be expressed with depends_on.

class ReservationCanBeCancelled:
    depends_on @= InventoryContract.reserve.ReservationIsReturned

In this case, a change or retirement of ReservationIsReturned also makes ReservationCanBeCancelled something to re-evaluate.

Multiple dependencies can be declared.

class Something:
    depends_on @= ContractA
    depends_on @= ContractB

Dependencies are treated as an acyclic structure.

Generic subjects

A generic Protocol can also be used as a subject.

from typing import Protocol, TypeVar

T = TypeVar("T")


class Repository(Protocol[T]):
    def get(self, key: str) -> T: ...
@binds[Repository[User]](UserRepository)
class TestUserRepository: ...

The type checker uses Repository[User], while at runtime the origin Repository is used as the subject identity.

Contract assets and ports

A contract can consist of multiple modules.

contract/
├── __init__.py
├── inventory.py
├── inventory_contract.py
└── ports/
    ├── __init__.py
    └── reservation.py

Types that cross the contract boundary are placed under ports/.

Kind Use
dataclass Data that crosses the boundary
Protocol Behavior at the boundary
enum Values shared by the contract
type alias Type expressions used by the contract

Keeping contract and ports together lets the types needed by the contract remain part of the same asset when the implementation is replaced.

Open vocabulary

Custom vocabulary can be defined in addition to the standard vocabulary.

CUSTOM = define.kind("custom")

Custom vocabulary can also be added for violation handling.

CUSTOM_POLICY = define.violation("custom")

The standard vocabulary provides common contract expressions, while domain-specific expressions can be added as needed.

Reading contract information

Information recorded on contracts can be read at runtime.

clauses = clauses_of(InventoryContract)

Clauses without a recorded test relation can also be retrieved.

missing = untested_clauses(InventoryContract)

untested_clauses() returns clauses for which contrace has no recorded test relation.

It does not decide whether a test is required from the clause kind or the value of on_violation.

Validation

Structural issues in contract assets and relations can be validated.

  • contract structure
  • placement of ports
  • cycles in contract dependency
  • placement of metadata

Validation returns diagnostics for declared structures and relations.

Design meaning and validity can be judged by people, LLMs, and other tooling from the information recorded in the contract.

pytest integration

pytest integration is optional.

pytest_plugins = [
    "shikumi_contrace.pytest",
]

With the plugin enabled, pytest can use contract relations for display and validation.

pytest --contrace-check

Normal pytest features such as fixtures, parametrize, and markers remain available.

Documentation

This README introduces the basic usage and main concepts.

For detailed semantics, structural rules, and validation behavior, see the following documents.

License

MIT License. See LICENSE for details.

Metadata

Release files for shikumi-contrace 0.1.0

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

Source distribution (sdist)

Source distribution for shikumi-contrace 0.1.0
File Size Uploaded
shikumi_contrace-0.1.0.tar.gz 144.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for shikumi-contrace 0.1.0
File Interpreter ABI Platform
shikumi_contrace-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 170.2 kB

Release files / shikumi_contrace-0.1.0.tar.gz

Download URL shikumi_contrace-0.1.0.tar.gz
Size 144.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a4e524b0af88efac78781241d251da9f161132fd96b653396b2b7367016bc963
BLAKE2b-256 checksum
How to use checksums
330e2578468dc7e9a0ae678d1c44cb1c943de96e6eb09a538b9512109c716ee0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / shikumi_contrace-0.1.0-py3-none-any.whl

Download URL shikumi_contrace-0.1.0-py3-none-any.whl
Size 26.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cfaea35c917db9f62b65b70005368e08b96a2892eb2def687d00d13d0505353a
BLAKE2b-256 checksum
How to use checksums
26c8b23966091fa6f668bdac7864aa928d8506ed0a8aedb0ca6f2bdf518b6ddd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

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