Skip to content

Commit 74518e7

Browse files
Use experimental TypeForm
This updates typing for events and PropertyKey to use TypeForm. This is still experimental, but without it these interfaces either don't work at all or don't work under some common cases.
1 parent d12a7f8 commit 74518e7

File tree

8 files changed

+453
-463
lines changed

8 files changed

+453
-463
lines changed

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ private static void writePyproject(
183183
reportUnusedVariable = false
184184
reportUnnecessaryComparison = false
185185
reportUnusedClass = false
186+
enableExperimentalFeatures = true
186187
187188
[tool.ruff]
188189
target-version = "py312"

packages/smithy-core/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ dependencies = []
99
[dependency-groups]
1010
dev = [
1111
"freezegun>=1.5.1",
12+
"typing_extensions>=4.13.0"
1213
]
1314

1415
[build-system]

packages/smithy-core/src/smithy_core/aio/interfaces/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from .eventstream import EventPublisher, EventReceiver
1212

1313
if TYPE_CHECKING:
14+
from typing_extensions import TypeForm
15+
1416
from ...deserializers import DeserializeableShape, ShapeDeserializer
1517
from ...schemas import APIOperation
1618
from ...serializers import SerializeableShape
@@ -162,7 +164,7 @@ def create_event_publisher[
162164
*,
163165
operation: "APIOperation[OperationInput, OperationOutput]",
164166
request: I,
165-
event_type: type[Event],
167+
event_type: "TypeForm[Event]",
166168
context: TypedProperties,
167169
) -> EventPublisher[Event]:
168170
"""Creates an event publisher for a protocol event stream.
@@ -184,7 +186,7 @@ def create_event_receiver[
184186
operation: "APIOperation[OperationInput, OperationOutput]",
185187
request: I,
186188
response: O,
187-
event_type: type[Event],
189+
event_type: "TypeForm[Event]",
188190
event_deserializer: Callable[["ShapeDeserializer"], Event],
189191
context: TypedProperties,
190192
) -> EventReceiver[Event]:

packages/smithy-core/src/smithy_core/interfaces/__init__.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
# SPDX-License-Identifier: Apache-2.0
33
from asyncio import iscoroutinefunction
44
from collections.abc import ItemsView, Iterator, KeysView, ValuesView
5-
from typing import (
6-
Any,
7-
Protocol,
8-
TypeGuard,
9-
overload,
10-
runtime_checkable,
11-
)
5+
from typing import TYPE_CHECKING, Any, Protocol, TypeGuard, overload, runtime_checkable
6+
7+
if TYPE_CHECKING:
8+
from typing_extensions import TypeForm
129

1310

1411
class URI(Protocol):
@@ -122,26 +119,18 @@ class PropertyKey[T](Protocol):
122119
123120
For a concrete implementation, see :py:class:`smithy_core.types.PropertyKey`.
124121
125-
Note that unions and other special types cannot easily be used here due to being
126-
incompatible with ``type[T]``. PEP747 proposes a fix to this case, but it has not
127-
yet been accepted. In the meantime, there is a workaround. The PropertyKey must
128-
be assigned to an explicitly typed variable, and the ``value_type`` parameter of
129-
the constructor must have a ``# type: ignore`` comment, like so:
130-
131122
.. code-block:: python
132123
133124
UNION_PROPERTY: PropertyKey[str | int] = PropertyKey(
134125
key="union",
135-
value_type=str | int, # type: ignore
126+
value_type=str | int,
136127
)
137-
138-
Type checkers will be able to use such a property as expected.
139128
"""
140129

141130
key: str
142131
"""The string key used to access the value."""
143132

144-
value_type: type[T]
133+
value_type: "TypeForm[T]"
145134
"""The type of the associated value in the properties bag."""
146135

147136
def __str__(self) -> str:

packages/smithy-core/src/smithy_core/types.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from datetime import datetime
1010
from email.utils import format_datetime, parsedate_to_datetime
1111
from enum import Enum
12-
from typing import Any, overload
12+
from typing import TYPE_CHECKING, Any, overload
1313

1414
from .exceptions import ExpectationNotMetError
1515
from .interfaces import PropertyKey as _PropertyKey
@@ -22,6 +22,9 @@
2222
serialize_rfc3339,
2323
)
2424

25+
if TYPE_CHECKING:
26+
from typing_extensions import TypeForm
27+
2528
_GREEDY_LABEL_RE = re.compile(r"\{(\w+)\+\}")
2629

2730
type Document = (
@@ -163,29 +166,21 @@ def format(self, *args: object, **kwargs: str) -> str:
163166
class PropertyKey[T](_PropertyKey[T]):
164167
"""A typed property key.
165168
166-
Note that unions and other special types cannot easily be used here due to being
167-
incompatible with ``type[T]``. PEP747 proposes a fix to this case, but it has not
168-
yet been accepted. In the meantime, there is a workaround. The PropertyKey must
169-
be assigned to an explicitly typed variable, and the ``value_type`` parameter of
170-
the constructor must have a ``# type: ignore`` comment, like so:
171-
172169
.. code-block:: python
173170
174171
UNION_PROPERTY: PropertyKey[str | int] = PropertyKey(
175172
key="union",
176-
value_type=str | int, # type: ignore
173+
value_type=str | int,
177174
)
178-
179-
Type checkers will be able to use such a property as expected.
180175
"""
181176

182177
key: str
183178
"""The string key used to access the value."""
184179

185-
value_type: type[T]
180+
value_type: "TypeForm[T]"
186181
"""The type of the associated value in the property bag."""
187182

188-
def __init__(self, *, key: str, value_type: type[T]) -> None:
183+
def __init__(self, *, key: str, value_type: "TypeForm[T]") -> None:
189184
# Intern the key to speed up dict access
190185
object.__setattr__(self, "key", sys.intern(key))
191186
object.__setattr__(self, "value_type", value_type)

packages/smithy-core/tests/unit/test_types.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
# pyright: reportPrivateUsage=false
55
from datetime import UTC, datetime
6-
from typing import Any, assert_type, cast
6+
from typing import Any, assert_type
77

88
import pytest
99
from smithy_core.exceptions import ExpectationNotMetError
@@ -323,12 +323,9 @@ def test_properties_typed_pop() -> None:
323323

324324
def test_union_property() -> None:
325325
properties = TypedProperties()
326-
union = cast(
327-
PropertyKey[str | int],
328-
PropertyKey(
329-
key="union",
330-
value_type=str | int, # type: ignore
331-
),
326+
union = PropertyKey(
327+
key="union",
328+
value_type=str | int,
332329
)
333330

334331
properties[union] = "foo"

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ aws_sdk_signers = {workspace = true }
3434

3535
[tool.pyright]
3636
typeCheckingMode = "strict"
37+
enableExperimentalFeatures = true
3738

3839
[tool.pytest.ini_options]
3940
asyncio_mode = "auto" # makes pytest run async tests without having to be marked with the @pytest.mark.asyncio decorator

0 commit comments

Comments
 (0)