Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/ucp_sdk/models/schemas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
# generated by datamodel-codegen
# pylint: disable=all
# pyformat: disable

132 changes: 116 additions & 16 deletions src/ucp_sdk/models/schemas/capability.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,114 @@ class UcpCapability(RootModel[Any]):
"""


class Extends(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends1Item(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")


class Extends1(RootModel[list[Extends1Item]]):
model_config = ConfigDict(
frozen=True,
)
root: list[Extends1Item] = Field(..., min_length=1)
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends2(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends3Item(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")


class Extends3(RootModel[list[Extends3Item]]):
model_config = ConfigDict(
frozen=True,
)
root: list[Extends3Item] = Field(..., min_length=1)
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends4(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends5Item(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")


class Extends5(RootModel[list[Extends5Item]]):
model_config = ConfigDict(
frozen=True,
)
root: list[Extends5Item] = Field(..., min_length=1)
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends6(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


class Extends7Item(RootModel[str]):
model_config = ConfigDict(
frozen=True,
)
root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")


class Extends7(RootModel[list[Extends7Item]]):
model_config = ConfigDict(
frozen=True,
)
root: list[Extends7Item] = Field(..., min_length=1)
"""
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


Comment on lines +36 to +143
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication in the newly added Extends* classes. For example, Extends, Extends2, Extends4, and Extends6 are identical. Similarly, Extends1, Extends3, Extends5, and Extends7 are identical, and their item types (Extends*Item) are also identical.

While this code is auto-generated, this duplication harms maintainability and readability. It would be better to define base types and reuse them, possibly through aliasing.

For example:

class ExtendsStr(RootModel[str]):
    model_config = ConfigDict(frozen=True)
    root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")

class ExtendsListItem(RootModel[str]):
    model_config = ConfigDict(frozen=True)
    root: str = Field(..., pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$")

class ExtendsList(RootModel[list[ExtendsListItem]]):
    model_config = ConfigDict(frozen=True)
    root: list[ExtendsListItem] = Field(..., min_length=1)

# Aliases for other Extends classes
Extends = ExtendsStr
Extends1 = ExtendsList
# ...and so on

Consider adjusting the code generation process, perhaps in preprocess_schemas.py, to consolidate these redundant definitions. This would make the generated code much cleaner.

class Version(RootModel[Any]):
model_config = ConfigDict(
frozen=True,
Expand Down Expand Up @@ -64,11 +172,9 @@ class Base(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
extends: str | None = Field(
None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$"
)
extends: Extends | Extends1 | None = None
"""
Parent capability this extends. Present for extensions, absent for root capabilities.
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


Expand Down Expand Up @@ -100,11 +206,9 @@ class PlatformSchema(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
extends: str | None = Field(
None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$"
)
extends: Extends2 | Extends3 | None = None
"""
Parent capability this extends. Present for extensions, absent for root capabilities.
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


Expand Down Expand Up @@ -136,11 +240,9 @@ class BusinessSchema(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
extends: str | None = Field(
None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$"
)
extends: Extends4 | Extends5 | None = None
"""
Parent capability this extends. Present for extensions, absent for root capabilities.
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""


Expand Down Expand Up @@ -172,9 +274,7 @@ class ResponseSchema(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
extends: str | None = Field(
None, pattern="^[a-z][a-z0-9]*(?:\\.[a-z][a-z0-9_]*)+$"
)
extends: Extends6 | Extends7 | None = None
"""
Parent capability this extends. Present for extensions, absent for root capabilities.
Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.
"""
26 changes: 26 additions & 0 deletions src/ucp_sdk/models/schemas/payment_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

from pydantic import AnyUrl, BaseModel, ConfigDict, Field, RootModel

from .shopping.types import available_payment_instrument


class PaymentHandler(RootModel[Any]):
model_config = ConfigDict(
Expand Down Expand Up @@ -64,6 +66,12 @@ class Base(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
available_instruments: (
list[available_payment_instrument.AvailablePaymentInstrument] | None
) = Field(None, min_length=1)
"""
Instrument types this handler supports, with optional constraints. When absent, every instrument should be considered available.
"""


class PlatformSchema(BaseModel):
Expand Down Expand Up @@ -94,6 +102,12 @@ class PlatformSchema(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
available_instruments: (
list[available_payment_instrument.AvailablePaymentInstrument] | None
) = Field(None, min_length=1)
"""
Instrument types this handler supports, with optional constraints. When absent, every instrument should be considered available.
"""


class BusinessSchema(BaseModel):
Expand Down Expand Up @@ -124,6 +138,12 @@ class BusinessSchema(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
available_instruments: (
list[available_payment_instrument.AvailablePaymentInstrument] | None
) = Field(None, min_length=1)
"""
Instrument types this handler supports, with optional constraints. When absent, every instrument should be considered available.
"""


class ResponseSchema(BaseModel):
Expand Down Expand Up @@ -154,3 +174,9 @@ class ResponseSchema(BaseModel):
"""
Entity-specific configuration. Structure defined by each entity's schema.
"""
available_instruments: (
list[available_payment_instrument.AvailablePaymentInstrument] | None
) = Field(None, min_length=1)
"""
Instrument types this handler supports, with optional constraints. When absent, every instrument should be considered available.
"""
28 changes: 16 additions & 12 deletions src/ucp_sdk/models/schemas/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ class Config(BaseModel):
)
delegate: list[str] | None = None
"""
Delegations the business allows. At service-level, declares available delegations. In checkout responses, confirms accepted delegations for this session.
Delegations the business allows. At service-level, declares available delegations. In UCP responses, confirms accepted delegations for this session.
"""
color_scheme: list[Literal["light", "dark"]] | None = None
"""
Color schemes the business supports. Hosts use ec_color_scheme query parameter to request a scheme from this list.
"""


Expand Down Expand Up @@ -90,7 +94,7 @@ class Base(BaseModel):

class PlatformSchema(BaseModel):
"""
Full service declaration for platform-level discovery. Different transports require different fields.
Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST and MCP additionally require `schema` and `endpoint`; A2A requires `endpoint`; embedded requires `schema`.
"""

model_config = ConfigDict(
Expand Down Expand Up @@ -126,9 +130,9 @@ class PlatformSchema(BaseModel):
"""


class PlatformSchema5(BaseModel):
class PlatformSchema7(BaseModel):
"""
Full service declaration for platform-level discovery. Different transports require different fields.
Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST and MCP additionally require `schema` and `endpoint`; A2A requires `endpoint`; embedded requires `schema`.
"""

model_config = ConfigDict(
Expand Down Expand Up @@ -164,9 +168,9 @@ class PlatformSchema5(BaseModel):
"""


class PlatformSchema6(BaseModel):
class PlatformSchema8(BaseModel):
"""
Full service declaration for platform-level discovery. Different transports require different fields.
Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST and MCP additionally require `schema` and `endpoint`; A2A requires `endpoint`; embedded requires `schema`.
"""

model_config = ConfigDict(
Expand Down Expand Up @@ -202,9 +206,9 @@ class PlatformSchema6(BaseModel):
"""


class PlatformSchema7(BaseModel):
class PlatformSchema9(BaseModel):
"""
Full service declaration for platform-level discovery. Different transports require different fields.
Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST and MCP additionally require `schema` and `endpoint`; A2A requires `endpoint`; embedded requires `schema`.
"""

model_config = ConfigDict(
Expand Down Expand Up @@ -240,19 +244,19 @@ class PlatformSchema7(BaseModel):
"""


class PlatformSchema3(
class PlatformSchema5(
RootModel[
PlatformSchema | PlatformSchema5 | PlatformSchema6 | PlatformSchema7
PlatformSchema | PlatformSchema7 | PlatformSchema8 | PlatformSchema9
]
):
model_config = ConfigDict(
frozen=True,
)
root: (
PlatformSchema | PlatformSchema5 | PlatformSchema6 | PlatformSchema7
PlatformSchema | PlatformSchema7 | PlatformSchema8 | PlatformSchema9
) = Field(..., title="Service (Platform Schema)")
"""
Full service declaration for platform-level discovery. Different transports require different fields.
Full service declaration for platform-level discovery. All transports require `version`, `spec`, and `transport`. REST and MCP additionally require `schema` and `endpoint`; A2A requires `endpoint`; embedded requires `schema`.
"""


Expand Down
1 change: 1 addition & 0 deletions src/ucp_sdk/models/schemas/shopping/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
# generated by datamodel-codegen
# pylint: disable=all
# pyformat: disable

Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@

from pydantic import BaseModel, ConfigDict, Field, RootModel

from .checkout import Checkout as Checkout_1


class Ap2MandateExtension(RootModel[Any]):
model_config = ConfigDict(
Expand Down Expand Up @@ -91,24 +89,6 @@ class Ap2WithCheckoutMandate(BaseModel):
"""


class Ap2(BaseModel):
"""
AP2 extension data including merchant authorization.
"""

model_config = ConfigDict(
extra="allow",
)
merchant_authorization: MerchantAuthorization | None = None
"""
Merchant's signature proving checkout terms are authentic.
"""
checkout_mandate: CheckoutMandate | None = None
"""
SD-JWT+kb proving user authorized this checkout.
"""


class ErrorCode(
RootModel[
Literal[
Expand Down Expand Up @@ -137,17 +117,3 @@ class ErrorCode(
"""
Error codes specific to AP2 mandate verification.
"""


class Checkout(Checkout_1):
"""
Checkout extended with AP2 mandate support.
"""

model_config = ConfigDict(
extra="allow",
)
ap2: Ap2 | None = None
"""
AP2 extension data including merchant authorization.
"""
18 changes: 18 additions & 0 deletions src/ucp_sdk/models/schemas/shopping/ap2_mandate/dev/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2026 UCP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# generated by datamodel-codegen
# pylint: disable=all
# pyformat: disable

Loading