Metadata-Version: 2.4
Name: supercargo
Version: 0.6.0
Summary: Native Python annotations for Supercargo type-safe metadata
Author: Supercargo
Author-email: support@supercargo.dev
Requires-Python: >=3.9,<4.0
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Project-URL: Homepage, https://supercargo.dev
Description-Content-Type: text/markdown

# Supercargo Python SDK

The official Python SDK for [Supercargo](https://supercargo.dev), providing native decorators and `typing.Annotated` metadata bindings for Pydantic and standard Python dataclasses to define type-safe Data Contracts, governance metadata, and schema constraints.

## Installation

```bash
pip install supercargo
```

---

## Defining Data Contracts

Decorate your Pydantic models (or dataclasses) with `@supercargo.contract` and attach metadata to fields using `typing.Annotated` with `supercargo.field(...)`.

### Example

```python
from typing import Annotated
from pydantic import BaseModel, Field
import supercargo
from supercargo import ValidationPolicy

@supercargo.contract(
    urn="urn:supercargo:contract:user_signup:v1",
    version="1.0.0",
    owner_team="identity-team",
    data_asset="users_v1",
    validation_policy=ValidationPolicy.STRICT,
)
class UserSignup(BaseModel):
    # Federated entity anchor with UUID semantic hint and PII metadata
    user_id: Annotated[str, supercargo.field(
        as_type="UUID",
        pii=True,
        context_id="user_salt",
        identity_domain="urn:supercargo:identity_domain:user",
        rank=1,
        entity_ref="urn:supercargo:entity:identity-team:user",
    )] = Field(alias="userId")

    # String with regex constraint and min length (using Pydantic Field or supercargo.field)
    email: Annotated[str, Field(pattern=r"^\S+@\S+$", min_length=1), supercargo.field(pii=True)]

    # Numerical constraint
    age: Annotated[int, Field(gt=18, lt=120)]

    # Standard boolean field
    is_active: bool = Field(alias="isActive")
```

---

## Decorator & Field Options Reference

### `@supercargo.contract(...)`

| Option | Type | Description |
| :--- | :--- | :--- |
| `urn` | `str` | Canonical URN for the contract. |
| `version` | `str` | Semantic version string. |
| `owner_team` / `ownerTeam` | `str` | Owning team name. |
| `data_asset` / `dataAsset` | `str` | Associated data asset or topic name. |
| `validation_policy` | `ValidationPolicy` \| `str` | Validation policy enum (`STRICT`, `LENIENT`, `MUTATE`). |

### `supercargo.field(...)`

| Option | Type | Description |
| :--- | :--- | :--- |
| `as_type` | `str` | Semantic data type hint (`UUID`, `TIMESTAMP`, `EMAIL`, etc.). |
| `pii` | `bool` \| `str` | Marks field as containing PII. |
| `context_id` | `str` | Salt / hashing context for pseudonymization. |
| `identity_domain` | `str` | Identity Domain URN for cross-system joining. |
| `rank` | `int` | Identity domain priority rank (1 = Primary). |
| `entity_ref` / `entity` | `str` | Entity reference URN for federated identity anchoring. |
| `not_empty` | `bool` | Enforces non-empty constraint. |
| `min_length` | `int` | Minimum string length. |
| `max_length` | `int` | Maximum string length. |
| `pattern` | `str` | Regular expression pattern. |
| `greater_than` / `gt` | `int` \| `float` | Numerical lower bound (exclusive). |
| `greater_than_or_equal` / `ge` | `int` \| `float` | Numerical lower bound (inclusive). |
| `less_than` / `lt` | `int` \| `float` | Numerical upper bound (exclusive). |
| `less_than_or_equal` / `le` | `int` \| `float` | Numerical upper bound (inclusive). |

---

## Testing & Validation Harness

Use `assert_validates` in your pytest test suite to verify constraint compliance:

```python
from supercargo import assert_validates

def test_user_signup_validation():
    # Assert validation failure when age is below minimum
    assert_validates(
        factory_callable=lambda: UserSignup(
            userId="550e8400-e29b-41d4-a716-446655440000",
            email="alice@example.com",
            age=15,
            isActive=True,
        ),
        expected_errors=["greaterThan", "gt"],
    )
```

