{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Data Contracts with PyCharter\n",
        "\n",
        "Parse, build, and work with data contracts: schema, metadata, ownership, governance, coercion, and validation rules.\n",
        "\n",
        "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/optophi/pycharter/blob/main/docs/notebooks/03_contracts.ipynb)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 1. Parse Contract from Dictionary\n",
        "\n",
        "Parse a contract from a Python dict (schema + metadata + ownership + governance)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from pycharter import parse_contract\n",
        "\n",
        "contract_dict = {\n",
        "    \"json_schema\": {\n",
        "        \"type\": \"object\",\n",
        "        \"version\": \"1.0.0\",\n",
        "        \"properties\": {\n",
        "            \"id\": {\"type\": \"string\"},\n",
        "            \"name\": {\"type\": \"string\", \"minLength\": 1},\n",
        "            \"email\": {\"type\": \"string\", \"format\": \"email\"},\n",
        "            \"age\": {\"type\": \"integer\", \"minimum\": 0},\n",
        "        },\n",
        "        \"required\": [\"id\", \"name\", \"email\"],\n",
        "    },\n",
        "    \"metadata\": {\n",
        "        \"version\": \"1.0.0\",\n",
        "        \"description\": \"User data contract\",\n",
        "        \"ownership\": {\"owner\": \"data-team\", \"team\": \"engineering\"},\n",
        "        \"governance_rules\": {\"data_retention\": {\"days\": 365}, \"pii_fields\": [\"email\"]},\n",
        "    },\n",
        "}\n",
        "\n",
        "contract = parse_contract(contract_dict)\n",
        "print(\"Schema properties:\", list(contract.schema.get(\"properties\", {}).keys()))\n",
        "print(\"Required:\", contract.schema.get(\"required\"))\n",
        "print(\"Owner:\", contract.ownership.get(\"owner\") if contract.ownership else \"N/A\")\n",
        "gov = contract.governance_rules or {}\n",
        "print(\"Retention (days):\", gov.get(\"data_retention\", {}).get(\"days\", \"N/A\"))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2. Parse Contract from File\n",
        "\n",
        "Load a contract from a YAML or JSON file."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from pycharter import parse_contract_file\n",
        "\n",
        "# contract = parse_contract_file(\"contracts/user.yaml\")\n",
        "print(\"parse_contract_file('path.yaml') or parse_contract_file('path.json') supported\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 3. Build Contract from Artifacts\n",
        "\n",
        "Build a consolidated contract from separate schema, metadata, ownership, governance, coercion, and validation artifacts.\n",
        "\n",
        "**Note:** The contract contains RAW schema + separate rules. Rules are NOT merged into the schema. The `Validator` class handles merging internally during validation."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "from pycharter import build_contract, ContractArtifacts\n",
        "\n",
        "schema = {\n",
        "    \"type\": \"object\",\n",
        "    \"version\": \"2.0.0\",\n",
        "    \"properties\": {\n",
        "        \"product_id\": {\"type\": \"string\"},\n",
        "        \"name\": {\"type\": \"string\"},\n",
        "        \"price\": {\"type\": \"number\", \"minimum\": 0},\n",
        "    },\n",
        "    \"required\": [\"product_id\", \"name\", \"price\"],\n",
        "}\n",
        "metadata = {\"version\": \"2.0.0\", \"description\": \"Product catalog\", \"domain\": \"commerce\"}\n",
        "ownership = {\"owner\": \"product-team\", \"team\": \"catalog\"}\n",
        "governance_rules = {\"data_retention\": {\"days\": 730}, \"classification\": \"internal\"}\n",
        "coercion_rules = {\"rules\": {\"price\": \"coerce_to_float\"}}\n",
        "validation_rules = {\"rules\": {\"price\": {\"min_value\": {\"threshold\": 0}}}}\n",
        "\n",
        "artifacts = ContractArtifacts(\n",
        "    schema=schema,\n",
        "    metadata=metadata,\n",
        "    ownership=ownership,\n",
        "    governance_rules=governance_rules,\n",
        "    coercion_rules=coercion_rules,\n",
        "    validation_rules=validation_rules,\n",
        ")\n",
        "contract = build_contract(artifacts)\n",
        "\n",
        "print(\"Contract keys:\", list(contract.model_dump().keys()))\n",
        "print(\"Schema is RAW (no coercion in properties):\", \"coercion\" not in contract.json_schema[\"properties\"][\"price\"])\n",
        "print(\"Coercion rules (separate):\", contract.coercion_rules)\n",
        "print(\"Validation rules (separate):\", contract.validation_rules)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 4. Contract with PyCharter Extensions\n",
        "\n",
        "Use `coercion` and `validations` in schema properties for runtime behavior."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "contract_dict = {\n",
        "    \"json_schema\": {\n",
        "        \"type\": \"object\",\n",
        "        \"version\": \"1.0.0\",\n",
        "        \"properties\": {\n",
        "            \"user_id\": {\"type\": \"string\", \"coercion\": \"coerce_to_string\"},\n",
        "            \"age\": {\n",
        "                \"type\": \"integer\",\n",
        "                \"coercion\": \"coerce_to_integer\",\n",
        "                \"validations\": {\"min_value\": {\"threshold\": 0}, \"max_value\": {\"threshold\": 150}},\n",
        "            },\n",
        "            \"email\": {\n",
        "                \"type\": \"string\",\n",
        "                \"format\": \"email\",\n",
        "                \"validations\": {\"regex\": {\"pattern\": r\"^[\\\\w.-]+@[\\\\w.-]+\\\\.\\\\w+$\"}},\n",
        "            },\n",
        "        },\n",
        "        \"required\": [\"user_id\", \"email\"],\n",
        "    },\n",
        "}\n",
        "\n",
        "contract = parse_contract(contract_dict)\n",
        "for name, prop in contract.schema.get(\"properties\", {}).items():\n",
        "    c = prop.get(\"coercion\", \"none\")\n",
        "    v = list(prop.get(\"validations\", {}).keys()) or \"none\"\n",
        "    print(f\"  {name}: coercion={c}, validations={v}\")"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.10.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}
