This post is to cover a comprehensive, intuitive set of advanced typing primitives that show up in modern Python (≥3.9). These types enable:
– Type safety without runtime overhead
– Better IDE autocomplete
– Self-documenting APIs
– Generic/reusable code
To read below codes, need to know Type hints are ignored by Python’s interpreter — they exist only for static analysis, IDEs, and documentation, i.e. Python itself completely ignores all your type hints (Callable, Awaitable, list[int], etc.) and executes the code normally.
In developing or engineering a good system, the right workflow is Write code with type hints, Use Pyright or MyPy frequently, then Run your SDK, then can optionally Add type checking to CI/CD.
This guide covers advanced typing concepts used in professional SDKs. │ │
│ │ These types enable: │ │
│ │ - Type safety without runtime overhead │ │
│ │ - Better IDE autocomplete │ │
│ │ - Self-documenting APIs │ │
│ │ - Generic/reusable code │ │
│ │ │ │
│ │ Author: Educational reference for SDK development │ │
│ │ """ │ │
│ │ │ │
│ │ from typing import ( │ │
│ │ Callable, Awaitable, TypeVar, Generic, Protocol, Union, Optional, │ │
│ │ Literal, TypeAlias, ParamSpec, Concatenate, TypedDict, NotRequired, │ │
│ │ Any, cast, overload, TYPE_CHECKING │ │
│ │ ) │ │
│ │ from collections.abc import Awaitable as AbcAwaitable, Callable as AbcCallable │ │
│ │ from dataclasses import dataclass │ │
│ │ from abc import ABC, abstractmethod │ │
│ │ import asyncio │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 1: Callable - Function Type Signatures │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Callable[<parameter_types>, <return_type>] │ │
│ │ # Describes the signature of a function/method │ │
│ │ │ │
│ │ # Example 1: Simple function │ │
│ │ def greet(name: str) -> str: │ │
│ │ return f"Hello, {name}" │ │
│ │ │ │
│ │ # Type hint: "a function that takes str and returns str" │ │
│ │ SimpleFunction: TypeAlias = Callable[[str], str] │ │
│ │ my_func: SimpleFunction = greet # ✓ Valid │ │
│ │ │ │
│ │ │ │
│ │ # Example 2: Multiple parameters │ │
│ │ def add(a: int, b: int) -> int: │ │
│ │ return a + b │ │
│ │ │ │
│ │ BinaryOperation: TypeAlias = Callable[[int, int], int] │ │
│ │ operation: BinaryOperation = add # ✓ Valid │ │
│ │ │ │
│ │ │ │
│ │ # Example 3: No parameters │ │
│ │ def get_timestamp() -> float: │ │
│ │ import time │ │
│ │ return time.time() │ │
│ │ │ │
│ │ NoArgsFunction: TypeAlias = Callable[[], float] │ │
│ │ timestamp_fn: NoArgsFunction = get_timestamp # ✓ Valid │ │
│ │ │ │
│ │ │ │
│ │ # Example 4: Callback pattern (common in SDKs) │ │
│ │ @dataclass │ │
│ │ class Event: │ │
│ │ name: str │ │
│ │ data: dict │ │
│ │ │ │
│ │ EventHandler: TypeAlias = Callable[[Event], None] │ │
│ │ │ │
│ │ def on_calculation(event: Event) -> None: │ │
│ │ print(f"Calculation event: {event.name}") │ │
│ │ │ │
│ │ handlers: list[EventHandler] = [on_calculation] │ │
│ │ │ │
│ │ # Usage: │ │
│ │ event = Event(name="add", data={"result": 42}) │ │
│ │ for handler in handlers: │ │
│ │ handler(event) # Type-safe callback │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 2: Awaitable - Async/Promise Types │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Awaitable[T] - Something that can be awaited (returns T) │ │
│ │ # Includes: coroutines, Tasks, Futures │ │
│ │ │ │
│ │ # Example 1: Simple async function │ │
│ │ async def fetch_data() -> str: │ │
│ │ await asyncio.sleep(0.1) │ │
│ │ return "data"
# Example 2: Async callback pattern (like calculator SDK hooks) │ │
│ │ @dataclass │ │
│ │ class HookContext: │ │
│ │ operation: str │ │
│ │ params: dict │ │
│ │ │ │
│ │ @dataclass │ │
│ │ class HookResult: │ │
│ │ allow: bool │ │
│ │ message: str = "" │ │
│ │ │ │
│ │ # AsyncHook: takes context, returns awaitable result │ │
│ │ AsyncHook: TypeAlias = Callable[[HookContext], Awaitable[HookResult]] │ │
│ │ │ │
│ │ async def validate_input(ctx: HookContext) -> HookResult: │ │
│ │ """Example async hook""" │ │
│ │ if ctx.operation == "divide" and ctx.params.get("b") == 0: │ │
│ │ return HookResult(allow=False, message="Cannot divide by zero") │ │
│ │ return HookResult(allow=True) │ │
│ │ │ │
│ │ # Usage: │ │
│ │ my_hook: AsyncHook = validate_input # ✓ Type matches │ │
│ │ │ │
│ │ async def run_hooks(hook: AsyncHook, context: HookContext): │ │
│ │ result = await hook(context) # ✓ Can await the result │ │
│ │ print(f"Hook result: {result.allow}") │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 3: TypeVar - Generic Type Parameters │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # TypeVar creates placeholders for types that will be determined later │ │
│ │ # Used for generic functions/classes │ │
│ │ │ │
│ │ T = TypeVar('T') # Unconstrained - can be any type │ │
│ │ TNumber = TypeVar('TNumber', int, float) # Constrained to int or float │ │
│ │ │ │
│ │ │ │
│ │ # Example 1: Generic function │ │
│ │ def first_element(items: list[T]) -> T: │ │
│ │ """Returns first element, preserving type""" │ │
│ │ return items[0] │ │
│ │ │ │
│ │ # Type inference works: │ │
│ │ nums: list[int] = [1, 2, 3] │ │
│ │ result1: int = first_element(nums) # ✓ Inferred as int │ │
│ │ │ │
│ │ names: list[str] = ["Alice", "Bob"] │ │
│ │ result2: str = first_element(names) # ✓ Inferred as str │ │
│ │ │ │
│ │ │ │
│ │ # Example 2: Generic class │ │
│ │ class Box(Generic[T]): │ │
│ │ """A container that holds any type""" │ │
│ │ │ │
│ │ def __init__(self, value: T): │ │
│ │ self.value = value │ │
│ │ │ │
│ │ def get(self) -> T: │ │
│ │ return self.value │ │
│ │ │ │
│ │ int_box: Box[int] = Box(42) │ │
│ │ x: int = int_box.get() # ✓ Type checker knows it's int │ │
│ │ │ │
│ │ str_box: Box[str] = Box("hello") │ │
│ │ y: str = str_box.get() # ✓ Type checker knows it's str │ │
│ │ │ │
│ │ │ │
│ │ # Example 3: Bounded TypeVar (like OpenAI SDK) │ │
│ │ class Agent: │ │
│ │ name: str │ │
│ │ │ │
│ │ class SpecializedAgent(Agent): │ │
│ │ specialization: str │ │
│ │ │ │
│ │ TAgent = TypeVar('TAgent', bound=Agent) # Must be Agent or subclass │ │
│ │ │ │
│ │ def process_agent(agent: TAgent) -> TAgent: │ │
│ │ """Returns same type as input""" │ │
│ │ print(agent.name) # ✓ Type checker knows 'name' exists │ │
│ │ return agent │ │
│ │ │ │
│ │ # Works with subclasses: │ │
│ │ special = SpecializedAgent() │ │
│ │ result: SpecializedAgent = process_agent(special) # ✓ Preserves type │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 4: Protocol - Structural Subtyping (Duck Typing) │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Protocol defines interface without inheritance │ │
│ │ # "If it walks like a duck and quacks like a duck..." │ │
│ │ │ │
│ │ class Drawable(Protocol): │ │
│ │ """Anything with a draw() method""" │ │
│ │ def draw(self) -> str: │ │
│ │ ... │ │
│ │ │ │
│ │ class Circle: │ │
│ │ def draw(self) -> str: │ │
│ │ return "○" │ │
│ │ │ │
│ │ class Square: │ │
│ │ def draw(self) -> str: │ │
│ │ return "□" │ │
│ │ │ │
│ │ def render(shape: Drawable) -> str: │ │
│ │ """Accepts ANY object with draw() method""" │ │
│ │ return shape.draw() │ │
│ │ │ │
│ │ # Both work without inheriting from Drawable: │ │
│ │ print(render(Circle())) # ✓ Works │ │
│ │ print(render(Square())) # ✓ Works │ │
│ │ │ │
│ │ │ │
│ │ # Example: Session Protocol (like OpenAI SDK) │ │
│ │ class Session(Protocol): │ │
│ │ """Defines session interface""" │ │
│ │ async def get_items(self, limit: int | None = None) -> list[dict]: │ │
│ │ ... │ │
│ │ │ │
│ │ async def add_items(self, items: list[dict]) -> None: │ │
│ │ ... │ │
│ │ │ │
│ │ class MemorySession: │ │
│ │ """Implements Session protocol without inheriting""" │ │
│ │ def __init__(self): │ │
│ │ self.items: list[dict] = [] │ │
│ │ │ │
│ │ async def get_items(self, limit: int | None = None) -> list[dict]: │ │
│ │ return self.items[:limit] if limit else self.items │ │
│ │ │ │
│ │ async def add_items(self, items: list[dict]) -> None: │ │
│ │ self.items.extend(items) │ │
│ │ │ │
│ │ async def use_session(session: Session): │ │
│ │ """Works with ANY class matching Session protocol""" │ │
│ │ await session.add_items([{"msg": "hello"}]) │ │
│ │ items = await session.get_items() │ │
│ │ │ │
│ │ # Works even though MemorySession doesn't inherit from Session: │ │
│ │ # await use_session(MemorySession()) # ✓ Valid │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 5: Union and Optional │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Union[A, B] - "can be A or B" │ │
│ │ # Optional[T] - shorthand for Union[T, None] │ │
│ │ │ │
│ │ # Example 1: Union for multiple return types │ │
│ │ def parse_number(value: str) -> int | float | None: │ │
│ │ """Returns int, float, or None""" │ │
│ │ try: │ │
│ │ if '.' in value: │ │
│ │ return float(value) │ │
│ │ return int(value) │ │
│ │ except ValueError: │ │
│ │ return None │ │
│ │ │ │
│ │ result: int | float | None = parse_number("42") │ │
│ │ │ │
│ │ │ │
│ │ # Example 2: Optional for nullable values │ │
│ │ class User: │ │
│ │ def __init__(self, name: str, email: str | None = None): │ │
│ │ self.name = name │ │
│ │ self.email = email # Can be None │ │
│ │ │ │
│ │ def send_email(user: User) -> bool: │ │
│ │ if user.email is None: │ │
│ │ return False │ │
│ │ # Type narrowing: after check, type checker knows email is str │ │
│ │ print(f"Sending to {user.email}") │ │
│ │ return True │ │
│ │ │ │
│ │ │ │
│ │ # Example 3: Union with type guard │ │
│ │ def process_value(value: int | str) -> str: │ │
│ │ """Process different types differently""" │ │
│ │ if isinstance(value, int): │ │
│ │ # Type narrowed to int │ │
│ │ return f"Number: {value * 2}" │ │
│ │ else: │ │
│ │ # Type narrowed to str │ │
│ │ return f"Text: {value.upper()}" │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 6: Literal - Exact Value Types │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Literal restricts to specific values │ │
│ │ # Common for enums/modes without creating enum class │ │
│ │ │ │
│ │ Mode = Literal["read", "write", "append"] │ │
│ │ │ │
│ │ def open_file(path: str, mode: Mode) -> None: │ │
│ │ """mode must be exactly 'read', 'write', or 'append'""" │ │
│ │ print(f"Opening {path} in {mode} mode") │ │
│ │ │ │
│ │ open_file("data.txt", "read") # ✓ Valid │ │
│ │ # open_file("data.txt", "delete") # ✗ Type error │ │
│ │ │ │
│ │ │ │
│ │ # Example: Calculator SDK style │ │
│ │ OperationType = Literal["add", "subtract", "multiply", "divide"] │ │
│ │ │ │
│ │ def calculate(op: OperationType, a: float, b: float) -> float: │ │
│ │ if op == "add": │ │
│ │ return a + b │ │
│ │ elif op == "subtract": │ │
│ │ return a - b │ │
│ │ elif op == "multiply": │ │
│ │ return a * b │ │
│ │ else: # Type checker knows op must be "divide" here │ │
│ │ return a / b │ │
│ │ │ │
│ │ │ │
│ │ # Example: Result type discriminator │ │
│ │ ResultType = Literal["success", "error"] │ │
│ │ │ │
│ │ @dataclass │ │
│ │ class Result: │ │
│ │ type: ResultType │ │
│ │ value: Any = None │ │
│ │ error: str | None = None │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 7: TypeAlias - Readable Type Names │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Makes complex types readable and reusable │ │
│ │ │ │
│ │ # Before: Messy │ │
│ │ def process_handlers( │ │
│ │ handlers: dict[str, list[Callable[[dict[str, Any]], Awaitable[bool]]]] │ │
│ │ ) -> None: │ │
│ │ pass │ │
│ │ │ │
│ │ # After: Clean │ │
│ │ EventCallback: TypeAlias = Callable[[dict[str, Any]], Awaitable[bool]] │ │
│ │ HandlerRegistry: TypeAlias = dict[str, list[EventCallback]] │ │
│ │ │ │
│ │ def process_handlers_clean(handlers: HandlerRegistry) -> None: │ │
│ │ pass │ │
│ │ │ │
│ │ │ │
│ │ # Example: Complex nested types │ │
│ │ JsonValue: TypeAlias = str | int | float | bool | None | list['JsonValue'] | dict[str, 'JsonValue'] │ │
│ │ │ │
│ │ def parse_json(data: str) -> JsonValue: │ │
│ │ import json │ │
│ │ return json.loads(data) │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 8: ParamSpec - Preserve Function Signatures │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # ParamSpec preserves exact parameter signature when wrapping functions │ │
│ │ # Used for decorators │ │
│ │ │ │
│ │ P = ParamSpec('P') │ │
│ │ R = TypeVar('R') │ │
│ │ │ │
│ │ def log_calls(func: Callable[P, R]) -> Callable[P, R]: │ │
│ │ """Decorator that preserves exact function signature""" │ │
│ │ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: │ │
│ │ print(f"Calling {func.__name__}") │ │
│ │ return func(*args, **kwargs) │ │
│ │ return wrapper │ │
│ │ │ │
│ │ @log_calls │ │
│ │ def add_numbers(a: int, b: int) -> int: │ │
│ │ return a + b │ │
│ │ │ │
│ │ # Type checker knows exact signature is preserved: │ │
│ │ result: int = add_numbers(1, 2) # ✓ Valid │ │
│ │ # result = add_numbers("1", "2") # ✗ Type error │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 9: TypedDict - Structured Dictionaries │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # TypedDict provides type hints for dictionary keys/values │ │
│ │ │ │
│ │ class UserDict(TypedDict): │ │
│ │ """Typed dictionary for user data""" │ │
│ │ id: int │ │
│ │ name: str │ │
│ │ email: str │ │
│ │ age: NotRequired[int] # Optional key (Python 3.11+) │ │
│ │ │ │
│ │ def create_user(user: UserDict) -> None: │ │
│ │ print(f"User: {user['name']}") # ✓ Type checker knows 'name' exists │ │
│ │ # print(user['invalid']) # ✗ Type error │ │
│ │ │ │
│ │ user: UserDict = { │ │
│ │ "id": 1, │ │
│ │ "name": "Alice", │ │
│ │ "email": "alice@example.com" │ │
│ │ # age is optional │ │
│ │ } │ │
│ │ │ │
│ │ │ │
│ │ # Example: API Response │ │
│ │ class ApiResponse(TypedDict): │ │
│ │ status: Literal["success", "error"] │ │
│ │ data: dict[str, Any] │ │
│ │ message: NotRequired[str] │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 10: Overload - Multiple Function Signatures │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # @overload declares different signatures for same function │ │
│ │ # Helps type checker understand complex behaviors │ │
│ │ │ │
│ │ @overload │ │
│ │ def get_value(key: str) -> str: ... │ │
│ │ │ │
│ │ @overload │ │
│ │ def get_value(key: str, default: int) -> int: ... │ │
│ │ │ │
│ │ def get_value(key: str, default: str | int = "") -> str | int: │ │
│ │ """Returns string or int depending on default type""" │ │
│ │ # Implementation │ │
│ │ if isinstance(default, int): │ │
│ │ return default │ │
│ │ return default │ │
│ │ │ │
│ │ # Type checker infers correctly: │ │
│ │ v1: str = get_value("key") # ✓ Returns str │ │
│ │ v2: int = get_value("key", 42) # ✓ Returns int │ │
│ │ │ │
│ │ │ │
│ │ # Example: OpenAI SDK style handoff overloads │ │
│ │ class Agent: │ │
│ │ name: str │ │
│ │ │ │
│ │ @overload │ │
│ │ def handoff(agent: Agent) -> None: ... │ │
│ │ │ │
│ │ @overload │ │
│ │ def handoff(agent: Agent, data: dict[str, Any]) -> None: ... │ │
│ │ │ │
│ │ def handoff(agent: Agent, data: dict[str, Any] | None = None) -> None: │ │
│ │ """Handle agent handoff with optional data""" │ │
│ │ if data: │ │
│ │ print(f"Handoff to {agent.name} with data") │ │
│ │ else: │ │
│ │ print(f"Handoff to {agent.name}") │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 11: TYPE_CHECKING - Import-Time Only Types │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Avoid circular imports by importing types only during type checking │ │
│ │ │ │
│ │ if TYPE_CHECKING: │ │
│ │ # These imports only happen when type checker runs │ │
│ │ # Not imported at runtime │ │
│ │ from typing import Never │ │
│ │ from collections.abc import Sequence │ │
│ │ │ │
│ │ # Usage: forward references without runtime overhead │ │
│ │ def process_items(items: 'Sequence[int]') -> None: │ │
│ │ """Quotes prevent runtime evaluation""" │ │
│ │ pass │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 12: cast - Type Assertion │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Tell type checker "trust me, this is this type" │ │
│ │ # Use sparingly - no runtime checking │ │
│ │ │ │
│ │ def get_user_data() -> dict[str, Any]: │ │
│ │ return {"name": "Alice", "age": 30} │ │
│ │ │ │
│ │ # Type checker doesn't know the structure │ │
│ │ data = get_user_data() │ │
│ │ # name = data["name"].upper() # ✗ Type checker unsure │ │
│ │ │ │
│ │ # With cast: │ │
│ │ typed_data = cast(UserDict, data) │ │
│ │ name = typed_data["name"].upper() # ✓ Type checker trusts you │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SECTION 13: Generic Protocols - Advanced Pattern │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ # Combine Protocol + Generic for flexible interfaces │ │
│ │ │ │
│ │ T_co = TypeVar('T_co', covariant=True) # Covariant - allows subtype returns │ │
│ │ │ │
│ │ class Container(Protocol, Generic[T_co]): │ │
│ │ """Generic container protocol""" │ │
│ │ def get(self) -> T_co: │ │
│ │ ... │ │
│ │ │ │
│ │ class StringContainer: │ │
│ │ def get(self) -> str: │ │
│ │ return "hello" │ │
│ │ │ │
│ │ def use_container(container: Container[str]) -> str: │ │
│ │ return container.get() │ │
│ │ │ │
│ │ # Works without inheritance: │ │
│ │ use_container(StringContainer()) # ✓ Valid │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # PRACTICAL EXAMPLE: Complete SDK Hook System │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ class HookContextData(TypedDict): │ │
│ │ """Typed dict for hook context""" │ │
│ │ operation: str │ │
│ │ inputs: dict[str, float] │ │
│ │ session_id: str │ │
│ │ │ │
│ │ class HookResultData(TypedDict): │ │
│ │ """Typed dict for hook result""" │ │
│ │ type: Literal["allow", "deny", "modify"] │ │
│ │ message: NotRequired[str] │ │
│ │ modified_inputs: NotRequired[dict[str, float]] │ │
│ │ │ │
│ │ # Generic hook with context type parameter │ │
│ │ TContext = TypeVar('TContext') │ │
│ │ │ │
│ │ class Hook(Protocol[TContext]): │ │
│ │ """Generic hook protocol""" │ │
│ │ async def __call__(self, context: TContext) -> HookResultData: │ │
│ │ ... │ │
│ │ │ │
│ │ # Specific hook types │ │
│ │ CalculatorHook: TypeAlias = Callable[[HookContextData], Awaitable[HookResultData]] │ │
│ │ │ │
│ │ class HookRegistry: │ │
│ │ """Type-safe hook registry""" │ │
│ │ │ │
│ │ def __init__(self): │ │
│ │ self.hooks: dict[str, list[CalculatorHook]] = {} │ │
│ │ │ │
│ │ def register(self, event: str, hook: CalculatorHook) -> None: │ │
│ │ """Register a hook for an event""" │ │
│ │ if event not in self.hooks: │ │
│ │ self.hooks[event] = [] │ │
│ │ self.hooks[event].append(hook) │ │
│ │ │ │
│ │ async def execute(self, event: str, context: HookContextData) -> list[HookResultData]: │ │
│ │ """Execute all hooks for an event""" │ │
│ │ results: list[HookResultData] = [] │ │
│ │ │ │
│ │ for hook in self.hooks.get(event, []): │ │
│ │ result = await hook(context) │ │
│ │ results.append(result) │ │
│ │ │ │
│ │ return results │ │
│ │ │ │
│ │ │ │
│ │ # Usage example: │ │
│ │ async def validation_hook(ctx: HookContextData) -> HookResultData: │ │
│ │ """Validate inputs""" │ │
│ │ if ctx["operation"] == "divide" and ctx["inputs"].get("b") == 0: │ │
│ │ return {"type": "deny", "message": "Division by zero"} │ │
│ │ return {"type": "allow"} │ │
│ │ │ │
│ │ async def main(): │ │
│ │ registry = HookRegistry() │ │
│ │ registry.register("pre_calculate", validation_hook) │ │
│ │ │ │
│ │ context: HookContextData = { │ │
│ │ "operation": "divide", │ │
│ │ "inputs": {"a": 10.0, "b": 0.0}, │ │
│ │ "session_id": "test" │ │
│ │ } │ │
│ │ │ │
│ │ results = await registry.execute("pre_calculate", context) │ │
│ │ for result in results: │ │
│ │ print(f"Hook result: {result['type']}") │ │
│ │ │ │
│ │ │ │
│ │ # ============================================================================ │ │
│ │ # SUMMARY TABLE │ │
│ │ # ============================================================================ │ │
│ │ │ │
│ │ """ │ │
│ │ ┌─────────────────┬──────────────────────────────────────┬────────────────────────┐ │ │
│ │ │ Type │ Purpose │ Example │ │ │
│ │ ├─────────────────┼──────────────────────────────────────┼────────────────────────┤ │ │
│ │ │ Callable │ Function signature │ Callable[[int], str] │ │ │
│ │ │ Awaitable │ Async return type │ Awaitable[int] │ │ │
│ │ │ TypeVar │ Generic type parameter │ T = TypeVar('T') │ │ │
│ │ │ Generic │ Create generic classes │ class Box(Generic[T]) │ │ │
│ │ │ Protocol │ Structural interface (duck typing) │ class Drawable(Proto.) │ │ │
│ │ │ Union │ Multiple possible types │ int | str │ │ │
│ │ │ Optional │ Type or None │ Optional[str] │ │ │
│ │ │ Literal │ Exact value constraint │ Literal["a", "b"] │ │ │
│ │ │ TypeAlias │ Readable type names │ UserId: TypeAlias=int │ │ │
│ │ │ ParamSpec │ Preserve function signatures │ P = ParamSpec('P') │ │ │
│ │ │ TypedDict │ Typed dictionary structure │ class User(TypedDict) │ │ │
│ │ │ overload │ Multiple function signatures │ @overload def f() │ │ │
│ │ │ TYPE_CHECKING │ Import only during type checking │ if TYPE_CHECKING: │ │ │
│ │ │ cast │ Type assertion │ cast(str, value) │ │ │
│ │ │ NotRequired │ Optional TypedDict key │ age: NotRequired[int] │ │ │
│ │ └─────────────────┴──────────────────────────────────────┴────────────────────────┘ │ │
│ │ │ │
│ │ Common Patterns in Professional SDKs: │ │
│ │ 1. Callback hooks: Callable[[Context], Awaitable[Result]] │ │
│ │ 2. Generic containers: class Container(Generic[T]) │ │
│ │ 3. Session protocols: class Session(Protocol) │ │
│ │ 4. Type aliases for complex types │ │
│ │ 5. TypedDict for API responses/configs │ │
│ │ 6. Literal for mode/enum values │ │
│ │ 7. Union for multiple return types │ │
│ │ """ │ │
│ │ │ │
│ │ if __name__ == "__main__": │ │
│ │ print(__doc__) │ │
│ │ print("\nThis file demonstrates advanced Python typing concepts.") │ │
│ │ print("Run with a type checker (mypy, pyright) to see type safety in action.") │ │
│ │ │ │
│ │ # Run async examples │ │
│ │ asyncio.run(main()) │ │
│ │