diff --git a/python-annotations/README.md b/python-annotations/README.md new file mode 100644 index 0000000000..e65fcec5cc --- /dev/null +++ b/python-annotations/README.md @@ -0,0 +1,3 @@ +# Python 3.14 Preview: Lazy Annotations + +This folder contains sample code for the Real Python tutorial [Python 3.14 Preview: Lazy Annotations](https://realpython.com/python-annotations/). diff --git a/python-annotations/calculator.pyi b/python-annotations/calculator.pyi new file mode 100644 index 0000000000..4f17c5ceca --- /dev/null +++ b/python-annotations/calculator.pyi @@ -0,0 +1,9 @@ +type Number = int | float + +class Calculator: + history: list[Number] + + def __init__(self) -> None: ... + def add(self, a: Number, b: Number) -> Number: ... + +def add(a: Number, b: Number) -> Number: ... diff --git a/python-annotations/fib.py b/python-annotations/fib.py new file mode 100644 index 0000000000..0188692cb4 --- /dev/null +++ b/python-annotations/fib.py @@ -0,0 +1,9 @@ +from typing import Annotated + + +def fib(n: int) -> int: + return n if n < 2 else fib(n - 2) + fib(n - 1) + + +def increment(x: Annotated[int, fib(35)]) -> int: + return x + 1 diff --git a/python-annotations/forward_references_future.py b/python-annotations/forward_references_future.py new file mode 100644 index 0000000000..db7a905741 --- /dev/null +++ b/python-annotations/forward_references_future.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass +class LinkedList: + head: Node + + +@dataclass +class Node: + value: Any + next: Optional[Node] = None diff --git a/python-annotations/forward_references_strings.py b/python-annotations/forward_references_strings.py new file mode 100644 index 0000000000..948ca7b36e --- /dev/null +++ b/python-annotations/forward_references_strings.py @@ -0,0 +1,13 @@ +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass +class LinkedList: + head: "Node" + + +@dataclass +class Node: + value: Any + next: Optional["Node"] = None diff --git a/python-annotations/linked_list.py b/python-annotations/linked_list.py new file mode 100644 index 0000000000..4438ec1e8f --- /dev/null +++ b/python-annotations/linked_list.py @@ -0,0 +1,13 @@ +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass +class LinkedList: + head: Node # noqa + + +@dataclass +class Node: + value: Any + next: Optional[Node] = None # noqa diff --git a/python-annotations/models.py b/python-annotations/models.py new file mode 100644 index 0000000000..f2cf065bd1 --- /dev/null +++ b/python-annotations/models.py @@ -0,0 +1,12 @@ +from dataclasses import dataclass + +from validators import validate_email + + +@dataclass +class User: + email: str + password: str + + def __post_init__(self): + validate_email(self) diff --git a/python-annotations/requirements.txt b/python-annotations/requirements.txt new file mode 100644 index 0000000000..fd315a17ed --- /dev/null +++ b/python-annotations/requirements.txt @@ -0,0 +1,10 @@ +annotated-types==0.7.0 +dnspython==2.7.0 +email_validator==2.2.0 +idna==3.10 +polars==1.31.0 +pydantic==2.11.7 +pydantic_core==2.33.2 +typeguard==4.4.4 +typing-inspection==0.4.1 +typing_extensions==4.14.1 diff --git a/python-annotations/rtti.py b/python-annotations/rtti.py new file mode 100644 index 0000000000..58950a53b3 --- /dev/null +++ b/python-annotations/rtti.py @@ -0,0 +1,6 @@ +from typeguard import typechecked + + +@typechecked +def add(a: int, b: int) -> int: + return a + b diff --git a/python-annotations/validators.py b/python-annotations/validators.py new file mode 100644 index 0000000000..43bb0cc6ec --- /dev/null +++ b/python-annotations/validators.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from models import User + + +def validate_email(user: User): + if user.email is None: + raise ValueError("email is required")