Skip to content

Appendix: Uncategorized Topics#

These need to appear somewhere...

Annotated for Metadata#

Demonstration using Cyclopts

Annotated provides metadata for types, useful in documentation, validation, or frameworks:

# example_2.py
from typing import Annotated

UserID = Annotated[int, "Database primary key"]


def fetch_user(user_id: UserID) -> dict:
    return {"id": user_id, "name": "Alice"}

Metadata within Annotated helps convey additional context beyond type annotations.

Type Narrowing#

Perhaps a short chapter?

Type narrowing refines a variable's type within conditional checks:

Using isinstance#

# example_4.py


def process(value: int | str) -> None:
    if isinstance(value, int):
        print(value + 1)
    else:
        print(value.upper())

Using assertions#

# example_5.py
from typing import Optional


def greet(name: Optional[str]) -> None:
    assert name is not None, "Name cannot be None"
    print(f"Hello, {name}")

Type narrowing helps write precise, safe, and understandable code.

Type Guards (isinstance, custom type guards, assertions)#

Custom type guards offer explicit ways to narrow types more clearly:

Custom type guard functions (Python 3.10+)#

# example_6.py
from typing import TypeGuard


class Cat:
    def meow(self):
        print("Meow!")


def is_cat(animal: object) -> TypeGuard[Cat]:
    return hasattr(animal, "meow")


animal = Cat()
if is_cat(animal):
    animal.meow()  # Safe to call
## Meow!

Type guards enhance type narrowing accuracy, making code safer and cleaner.