# order.py
class Order(Base):
__tablename__ = "Order"
id: Mapped[int] = mapped_column(primary_key=True)
items: Mapped[List["Item"]] = relationship(back_populates="order")
# item.py
class Item(Base):
__tablename__ = "Item"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
order_id: Mapped[int] = mapped_column(ForeignKey("Order.id"))
order: Mapped["Order"] = relationship(back_populates="items")
I'm using sqlalchemy 2.0.23 and not using plugins for mypy or flake8.
Neither module should need to import the other since I'm using string relationships like "Item" in the Order class and "Order" in the relationship in the Item class.
flake8 reports an F821 error on both files because of the undefined name.
mypy reports a similar error on both.
I can configure flake8 to ignore the F821. I'm not sure how I'd do similar in mypy. But these are important rules that shouldn't be turned off to get SQLAlchemy classes through linters.
I want to keep my classes in separate files. Is there a way to correctly define them so that linters like these won't complain? Adding imports to both files quiets these linters, but results in a circular import problem so the code won't run.
mypy
and flake8
are correct here, these warnings shouldn't be ignored. To resolve the circular import problem, you can use "typechecking-only import", i.e. an import
statement wrapped in if TYPE_CHECKING
block (TYPE_CHECKING
constant is explained here) . Here's how it may look like:
# order.py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .item import Item
class Order(Base):
__tablename__ = "Order"
id: Mapped[int] = mapped_column(primary_key=True)
items: Mapped[List["Item"]] = relationship(back_populates="order")
and
# item.py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .order import Order
class Item(Base):
__tablename__ = "Item"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
order_id: Mapped[int] = mapped_column(ForeignKey("Order.id"))
order: Mapped["Order"] = relationship(back_populates="items")