Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collapse member schemas #252

Merged
merged 4 commits into from
May 27, 2024
Merged
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
16 changes: 8 additions & 8 deletions python-packages/smithy-core/smithy_core/documents.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .shapes import ShapeID, ShapeType
from .utils import expect_type

_DOCUMENT = Schema(id=ShapeID("smithy.api#Document"), type=ShapeType.DOCUMENT)
_DOCUMENT = Schema(id=ShapeID("smithy.api#Document"), shape_type=ShapeType.DOCUMENT)


type DocumentValue = (
Expand Down Expand Up @@ -95,7 +95,7 @@ def __init__(
self._value = value

if self._schema is not _DOCUMENT:
self._type = self._schema.type
self._type = self._schema.shape_type
elif isinstance(self._raw_value, Sequence):
self._type = ShapeType.LIST
else:
Expand Down Expand Up @@ -196,7 +196,7 @@ def as_list(self) -> list["Document"]:

def _wrap_list(self, value: Sequence[DocumentValue]) -> list["Document"]:
schema = self._schema
if schema.type is ShapeType.LIST:
if schema.shape_type is ShapeType.LIST:
schema = self._schema.members["member"].expect_member_target()
return [Document(e, schema=schema) for e in value]

Expand All @@ -212,9 +212,9 @@ def as_map(self) -> dict[str, "Document"]:
)

def _wrap_map(self, value: Mapping[str, DocumentValue]) -> dict[str, "Document"]:
if self._schema.type is not ShapeType.STRUCTURE:
if self._schema.shape_type is not ShapeType.STRUCTURE:
member_schema = self._schema
if self._schema.type is ShapeType.MAP:
if self._schema.shape_type is ShapeType.MAP:
member_schema = self._schema.members["value"].expect_member_target()
return {k: Document(v, schema=member_schema) for k, v in value.items()}

Expand Down Expand Up @@ -278,16 +278,16 @@ def __setitem__(
if isinstance(key, str):
if not isinstance(value, Document):
schema = self._schema
if schema.type is ShapeType.STRUCTURE:
if schema.shape_type is ShapeType.STRUCTURE:
schema = schema.members[key].expect_member_target()
elif schema.type is ShapeType.MAP:
elif schema.shape_type is ShapeType.MAP:
schema = schema.members["value"].expect_member_target()
value = Document(value, schema=schema)
self.as_map()[key] = value
else:
if not isinstance(value, Document):
schema = self._schema
if schema.type is ShapeType.LIST:
if schema.shape_type is ShapeType.LIST:
schema = schema.members["member"].expect_member_target()
value = Document(value, schema=schema)
self.as_list()[key] = value
Expand Down
42 changes: 21 additions & 21 deletions python-packages/smithy-core/smithy_core/prelude.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,67 +8,67 @@

BLOB = Schema(
id=ShapeID("smithy.api#Blob"),
type=ShapeType.BLOB,
shape_type=ShapeType.BLOB,
)

BOOLEAN = Schema(
id=ShapeID("smithy.api#Boolean"),
type=ShapeType.BOOLEAN,
shape_type=ShapeType.BOOLEAN,
)

STRING = Schema(
id=ShapeID("smithy.api#String"),
type=ShapeType.STRING,
shape_type=ShapeType.STRING,
)

TIMESTAMP = Schema(
id=ShapeID("smithy.api#Timestamp"),
type=ShapeType.TIMESTAMP,
shape_type=ShapeType.TIMESTAMP,
)

BYTE = Schema(
id=ShapeID("smithy.api#Byte"),
type=ShapeType.BYTE,
shape_type=ShapeType.BYTE,
)

SHORT = Schema(
id=ShapeID("smithy.api#Short"),
type=ShapeType.SHORT,
shape_type=ShapeType.SHORT,
)

INTEGER = Schema(
id=ShapeID("smithy.api#Integer"),
type=ShapeType.INTEGER,
shape_type=ShapeType.INTEGER,
)

LONG = Schema(
id=ShapeID("smithy.api#Long"),
type=ShapeType.LONG,
shape_type=ShapeType.LONG,
)

FLOAT = Schema(
id=ShapeID("smithy.api#Float"),
type=ShapeType.FLOAT,
shape_type=ShapeType.FLOAT,
)

DOUBLE = Schema(
id=ShapeID("smithy.api#Double"),
type=ShapeType.DOUBLE,
shape_type=ShapeType.DOUBLE,
)

BIG_INTEGER = Schema(
id=ShapeID("smithy.api#BigInteger"),
type=ShapeType.BIG_INTEGER,
shape_type=ShapeType.BIG_INTEGER,
)

BIG_DECIMAL = Schema(
id=ShapeID("smithy.api#BigDecimal"),
type=ShapeType.BIG_DECIMAL,
shape_type=ShapeType.BIG_DECIMAL,
)

DOCUMENT = Schema(
id=ShapeID("smithy.api#Document"),
type=ShapeType.DOCUMENT,
shape_type=ShapeType.DOCUMENT,
)


Expand All @@ -77,48 +77,48 @@

PRIMITIVE_BOOLEAN = Schema(
id=ShapeID("smithy.api#PrimitiveBoolean"),
type=ShapeType.BOOLEAN,
shape_type=ShapeType.BOOLEAN,
traits=[Trait(id=_DEFAULT, value=False)],
)

PRIMITIVE_BYTE = Schema(
id=ShapeID("smithy.api#PrimitiveByte"),
type=ShapeType.BYTE,
shape_type=ShapeType.BYTE,
traits=[Trait(id=_DEFAULT, value=0)],
)

PRIMITIVE_SHORT = Schema(
id=ShapeID("smithy.api#PrimitiveShort"),
type=ShapeType.SHORT,
shape_type=ShapeType.SHORT,
traits=[Trait(id=_DEFAULT, value=0)],
)

PRIMITIVE_INTEGER = Schema(
id=ShapeID("smithy.api#PrimitiveInteger"),
type=ShapeType.INTEGER,
shape_type=ShapeType.INTEGER,
traits=[Trait(id=_DEFAULT, value=0)],
)

PRIMITIVE_LONG = Schema(
id=ShapeID("smithy.api#PrimitiveLong"),
type=ShapeType.LONG,
shape_type=ShapeType.LONG,
traits=[Trait(id=_DEFAULT, value=0)],
)

PRIMITIVE_FLOAT = Schema(
id=ShapeID("smithy.api#PrimitiveFloat"),
type=ShapeType.FLOAT,
shape_type=ShapeType.FLOAT,
traits=[Trait(id=_DEFAULT, value=0.0)],
)

PRIMITIVE_DOUBLE = Schema(
id=ShapeID("smithy.api#PrimitiveDouble"),
type=ShapeType.DOUBLE,
shape_type=ShapeType.DOUBLE,
traits=[Trait(id=_DEFAULT, value=0.0)],
)

UNIT = Schema(
id=ShapeID("smithy.api#Unit"),
type=ShapeType.DOUBLE,
shape_type=ShapeType.DOUBLE,
traits=[Trait(id=ShapeID("smithy.api#UnitTypeTrait"))],
)
60 changes: 46 additions & 14 deletions python-packages/smithy-core/smithy_core/schemas.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from collections.abc import Mapping
from dataclasses import dataclass, field
from dataclasses import dataclass, field, replace
from typing import TYPE_CHECKING, NotRequired, Required, Self, TypedDict

from .exceptions import ExpectationNotMetException, SmithyException
Expand All @@ -14,7 +14,7 @@ class Schema:
"""Describes a shape, its traits, and its members."""

id: ShapeID
type: ShapeType
shape_type: ShapeType
traits: dict[ShapeID, "Trait"] = field(default_factory=dict)
members: dict[str, "Schema"] = field(default_factory=dict)
member_target: "Schema | None" = None
Expand All @@ -24,7 +24,7 @@ def __init__(
self,
*,
id: ShapeID,
type: ShapeType,
shape_type: ShapeType,
traits: list["Trait"] | dict[ShapeID, "Trait"] | None = None,
members: list["Schema"] | dict[str, "Schema"] | None = None,
member_target: "Schema | None" = None,
Expand All @@ -33,7 +33,7 @@ def __init__(
"""Initialize a schema.

:param id: The ID of the shape.
:param type: The type of the shape.
:param shape_type: The type of the shape.
:param traits: Traits applied to the shape, which describe additional metadata.
:param members: Members of the shape. These correspond to list contents,
dataclass properties, map keys/values, and union variants.
Expand All @@ -56,7 +56,7 @@ def __init__(

# setattr is required because the class is frozen
object.__setattr__(self, "id", id)
object.__setattr__(self, "type", type)
object.__setattr__(self, "shape_type", shape_type)

if traits:
if isinstance(traits, list):
Expand Down Expand Up @@ -126,14 +126,14 @@ def collection(
cls,
*,
id: ShapeID,
type: ShapeType = ShapeType.STRUCTURE,
shape_type: ShapeType = ShapeType.STRUCTURE,
traits: list["Trait"] | None = None,
members: Mapping[str, "MemberSchema"] | None = None,
) -> Self:
"""Create a schema for a collection shape.

:param id: The ID of the shape.
:param type: The type of the shape. Defaults to STRUCTURE.
:param shape_type: The type of the shape. Defaults to STRUCTURE.
:param traits: Traits applied to the shape, which describe additional metadata.
:param members: Members of the shape. These correspond to list contents, dataclass
properties, map keys/values, and union variants. In contrast to the main
Expand All @@ -143,22 +143,54 @@ def collection(
struct_members: dict[str, "Schema"] = {}
if members:
for i, k in enumerate(members.keys()):
member_traits = members[k].get("traits")
struct_members[k] = cls(
struct_members[k] = cls.member(
id=id.with_member(k),
type=ShapeType.MEMBER,
traits=member_traits,
member_target=members[k]["target"],
member_index=i,
target=members[k]["target"],
index=i,
member_traits=members[k].get("traits"),
)

result = cls(
id=id,
type=type,
shape_type=shape_type,
traits=traits,
members=struct_members,
)
return result

@classmethod
def member(
cls,
id: ShapeID,
target: Self,
index: int,
member_traits: list["Trait"] | None = None,
) -> Self:
"""Create a schema for a member shape.

Member schemas are largely copies of the schemas they target to make it easier
to use them. They contain all the members of the target and all of the traits of
the target. Any traits provided to this method, will override traits of the same
type on the member schema.

:param id: The member's id.
JordonPhillips marked this conversation as resolved.
Show resolved Hide resolved
:param target: The schema the member is targeting.
:param index: The member's index.
"""
id.expect_member()
if target.member_target is not None:
raise ExpectationNotMetException("Member targets must not be members.")
resolved_traits = target.traits.copy()
if member_traits:
resolved_traits.update({t.id: t for t in member_traits})
return replace(
target,
id=id,
traits=resolved_traits,
member_target=target,
member_index=index,
)


class MemberSchema(TypedDict):
"""A simplified schema for members.
Expand Down
3 changes: 1 addition & 2 deletions python-packages/smithy-core/smithy_core/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,8 @@ class ShapeType(Enum):
STRUCTURE = 18
UNION = 19

MEMBER = 20

# We won't acutally be using these, probably
# MEMBER = 20
# SERVICE = 21
# RESOURCE = 22
# OPERATION = 23
Loading
Loading