Skip to content

Commit 2e99557

Browse files
authored
Merge branch 'main' into u/xiaoxuan/fix-rewrite-ref-one-of
2 parents 884b6e9 + 298c295 commit 2e99557

114 files changed

Lines changed: 5062 additions & 250 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 0 additions & 15 deletions
This file was deleted.

.github/workflows/governance.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
name: PR Governance
3+
4+
on:
5+
pull_request_target:
6+
types: [
7+
opened,
8+
synchronize,
9+
reopened,
10+
ready_for_review,
11+
review_requested,
12+
review_request_removed,
13+
assigned,
14+
unassigned
15+
]
16+
pull_request_review:
17+
types: [submitted, dismissed]
18+
19+
jobs:
20+
governance:
21+
name: Reviews
22+
# skip for draft PRs
23+
if: github.event.pull_request.draft == false
24+
permissions:
25+
statuses: write
26+
contents: read
27+
pull-requests: read
28+
# Use the reusable workflow defined in the central governance repository
29+
# zizmor: ignore[ref-confusion]
30+
uses: Universal-Commerce-Protocol/.github/.github/workflows/reusable-governance.yml@main
31+
secrets:
32+
# Required: An org-level Read token to read team memberships
33+
ORG_READ_TOKEN: ${{ secrets.ORG_READ_TOKEN }}

.github/workflows/linter.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ jobs:
2424
pre-commit:
2525
runs-on: ubuntu-latest
2626
steps:
27-
- uses: actions/checkout@v4
28-
- uses: actions/setup-python@v5
27+
- uses: actions/checkout@v5
28+
- uses: actions/setup-python@v6
2929
with:
3030
python-version: '3.x'
3131
- uses: pre-commit/action@v3.0.1
32+
env:
33+
# workaround for pre-commit/action not being updated to node24
34+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ jobs:
1818
contents: read
1919
steps:
2020
- name: Checkout code
21-
uses: actions/checkout@v4
21+
uses: actions/checkout@v5
2222

2323
# Installs uv (and manages Python automatically)
2424
- name: Install uv
25-
uses: astral-sh/setup-uv@v5
25+
uses: astral-sh/setup-uv@v8.2.0
2626
with:
2727
enable-cache: true
2828

README.md

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,103 @@
2222
<b>Official Python library for the Universal Commerce Protocol (UCP).</b>
2323
</p>
2424

25+
<p align="center">
26+
<a href="https://pypi.org/project/ucp-sdk/"><img src="https://img.shields.io/pypi/v/ucp-sdk" alt="PyPI version"></a>
27+
<a href="https://pypi.org/project/ucp-sdk/"><img src="https://img.shields.io/pypi/pyversions/ucp-sdk" alt="Python versions"></a>
28+
<a href="https://github.com/Universal-Commerce-Protocol/python-sdk/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Universal-Commerce-Protocol/python-sdk" alt="License"></a>
29+
</p>
30+
2531
## Overview
2632

2733
This repository contains the Python SDK for the
2834
[Universal Commerce Protocol (UCP)](https://ucp.dev). It provides Pydantic
2935
models for UCP schemas, making it easy to build UCP-compliant applications in
3036
Python.
3137

38+
### UCP Version Compatibility
39+
40+
Each version of the Python SDK is generated against a specific version of the
41+
UCP schema:
42+
43+
| SDK Version | UCP Schema Version |
44+
| ----------------- | ------------------ |
45+
| **`0.4.x`** | **`2026-04-08`** |
46+
| `0.3.x` | `2026-01-23` |
47+
| `0.2.x` / `0.1.x` | `2026-01-11` |
48+
3249
## Installation
3350

34-
For now, you can install the SDK using the following commands:
51+
To use this SDK in your own project, install it from PyPI:
3552

3653
```bash
37-
# Clone the repository
38-
git clone https://github.com/Universal-Commerce-Protocol/python-sdk.git
54+
pip install ucp-sdk
55+
```
3956

40-
# Navigate to the directory
41-
cd python-sdk
57+
Or, if you are managing your project with [uv](https://docs.astral.sh/uv/):
4258

43-
# Install dependencies
44-
uv sync
59+
```bash
60+
uv add ucp-sdk
61+
```
62+
63+
## Usage
64+
65+
The example below parses a UCP checkout response and reads typed fields:
66+
67+
```python
68+
from ucp_sdk.models.schemas.shopping.checkout import Checkout
69+
70+
# Parse a UCP checkout response
71+
checkout = Checkout.model_validate(checkout_data)
72+
73+
# Access typed fields
74+
print(checkout.status) # "incomplete" | "ready_for_complete" | ...
75+
print(checkout.currency) # ISO 4217 currency code
76+
for item in checkout.line_items:
77+
print(f"{item.item.title}: {item.quantity}")
78+
```
79+
80+
### Available model packages
81+
82+
| Package | Description |
83+
| --------------------------------------- | --------------------------------------------------- |
84+
| `ucp_sdk.models.schemas.shopping` | Checkout, cart, catalog, order, payment models |
85+
| `ucp_sdk.models.schemas.shopping.types` | Line items, totals, buyer, fulfillment, signals |
86+
| `ucp_sdk.models.schemas.transports` | REST, MCP, and embedded protocol bindings |
87+
| `ucp_sdk.models.schemas` | Service definitions, capabilities, payment handlers |
88+
89+
### Validation
90+
91+
All models support Pydantic validation and serialization:
92+
93+
```python
94+
from pydantic import ValidationError
95+
from ucp_sdk.models.schemas.shopping.checkout import Checkout
96+
97+
# Validate data against UCP schemas
98+
try:
99+
checkout = Checkout.model_validate(checkout_data)
100+
# Serialize to JSON-compatible dict
101+
checkout_dict = checkout.model_dump(exclude_none=True)
102+
except ValidationError as e:
103+
print(e.errors())
45104
```
46105

47106
## Development
48107

49108
### Prerequisites
50109

51-
This project uses `uv` for dependency management.
110+
This project uses [`uv`](https://docs.astral.sh/uv/) for dependency management.
111+
112+
### Setup
113+
114+
```bash
115+
# Clone the repository
116+
git clone https://github.com/Universal-Commerce-Protocol/python-sdk.git
117+
cd python-sdk
118+
119+
# Install dependencies
120+
uv sync
121+
```
52122

53123
### Generating Pydantic Models
54124

@@ -63,7 +133,7 @@ uv sync
63133
```
64134

65135
Where `<version>` is the version of the UCP specification to use (for example,
66-
"2026-01-23").
136+
"2026-04-08").
67137

68138
If no version is specified, the `main` branch of the
69139
[UCP repo](https://github.com/Universal-Commerce-Protocol/ucp) will be used.

generate_models.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
#!/bin/bash
2+
# Copyright 2026 UCP Authors
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
216
# Generate Pydantic models from UCP JSON Schemas
317

418
# Ensure we are in the script's directory

preprocess_schemas.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,12 +306,18 @@ def eval_prop_inclusion(name, data, op, base_required):
306306
include = False
307307
elif marker == "required":
308308
is_required = True
309+
elif marker == "optional":
310+
# A simple string "optional" marker overrides the base schema's required list for all operations.
311+
is_required = False
309312
elif isinstance(marker, dict):
310313
val = marker.get(op)
311314
if val == "omit" or val is None:
312315
include = False
313316
elif val == "required":
314317
is_required = True
318+
elif val == "optional":
319+
# Override base schema's required list when a field is explicitly marked optional for a specific operation.
320+
is_required = False
315321

316322
return include, is_required
317323

@@ -337,7 +343,7 @@ def update_variant_identity(variant_schema, op, stem):
337343
def rewrite_refs_to_variants(root, op, file_path, variant_needs):
338344
"""
339345
Walks a schema tree and updates external links to point to variant files.
340-
Example: product.json -> product_create_request.json
346+
Example: product.json -> product_create_request.json.
341347
"""
342348
for node in iter_nodes(root):
343349
if isinstance(node, dict) and "$ref" in node:
@@ -516,7 +522,7 @@ def main():
516522
1. Pass 1: Local flattening (allOf) and discovery of needed variants
517523
2. metadata normalization: unifies ucp properties
518524
3. Pass 2: Transitive propagation (ensuring matched variants for linked schemas)
519-
4. Pass 3: Variant file generation (*_request.json)
525+
4. Pass 3: Variant file generation (*_request.json).
520526
"""
521527
target_dir = Path(
522528
sys.argv[1] if len(sys.argv) > 1 else "ucp/source/schemas"

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "ucp-sdk"
3-
version = "0.3.0"
3+
version = "0.4.0"
44
description = "UCP Python SDK"
55
readme = "README.md"
66
license = {file = "LICENSE"}
@@ -68,6 +68,9 @@ indent-style = "space"
6868
skip-magic-trailing-comma = false
6969
line-ending = "auto"
7070

71+
[tool.ruff.lint.per-file-ignores]
72+
"src/ucp_sdk/models/schemas/**/*.py" = ["E501", "D"]
73+
7174
[tool.ruff.lint]
7275
select = ["E", "F", "W", "B", "C4", "SIM", "N", "UP", "D", "PTH", "T20"]
7376
ignore = ["D212", "D200"]

0 commit comments

Comments
 (0)