Static type checking, part 1: SQLAlchemy 2.0 annotations #222

Closed
TriHard wants to merge 7 commits from TriHard/rDrama:type-checking into master

SQLAlchemy 2.0 introduced a new way to create a Declarative table. Instead of passing the database type toColumn, you provide the Python type as a PEP 484 type annotation wrapped in Mapped, and use mapped_column instead of Column. The database type will be inferred from the annotation:

class Base(DeclarativeBase):
    pass

class Value(Base):
    # Same as `foo = Column(Integer)`
    foo: Mapped[int]
    # Same as `bar = Column(String, default=None, nullable=True)`
    bar: Mapped[Optional[str]] = mapped_column(default=None)
    # Same as `baz = relationship("Other")`
    baz: Mapped["Other"] = relationship()

This new style allows the above constructs to be fully type-checked by static type checkers like Mypy and Pyright, making the code much easier to understand:

value: Value # Obtained from a DB query
x = value.foo # x: int
y = value.bar # y: str | None
z = value.baz # z: Other

In the old style, all of these would have the type Any.

SQLAlchemy 2.0 introduced [a new way to create a Declarative table.](https://docs.sqlalchemy.org/en/20/changelog/whatsnew_20.html#orm-declarative-models) Instead of passing the database type to`Column`, you provide the Python type as a [PEP 484](https://peps.python.org/pep-0484/) type annotation wrapped in `Mapped`, and use `mapped_column` instead of `Column`. The database type will be inferred from the annotation: ```py class Base(DeclarativeBase): pass class Value(Base): # Same as `foo = Column(Integer)` foo: Mapped[int] # Same as `bar = Column(String, default=None, nullable=True)` bar: Mapped[Optional[str]] = mapped_column(default=None) # Same as `baz = relationship("Other")` baz: Mapped["Other"] = relationship() ``` This new style allows the above constructs to be fully type-checked by static type checkers like [Mypy](https://github.com/python/mypy) and [Pyright](https://github.com/microsoft/pyright), making the code much easier to understand: ```py value: Value # Obtained from a DB query x = value.foo # x: int y = value.bar # y: str | None z = value.baz # z: Other ``` In the old style, all of these would have the type `Any`.
TriHard added 7 commits 2024-02-17 17:09:38 +00:00

typing is cringe

typing is cringe
Aevann closed this pull request 2024-02-17 17:55:38 +00:00

Pull request closed

Sign in to join this conversation.
There is no content yet.