Here, are a few ideas for new rules for discussion.
1. Unnecessary mapped_column()
What it does
Checks for redundant i.e. empty mapped_column() calls in SQLAlchemy models. Empty mapped_column() calls do not carry any additional information and can be removed.
Example
from sqlalchemy import orm
class MyModel(Base):
__tablename__ = "my_model"
id: orm.Mapped[int] = orm.mapped_column(primary_key=True)
count: orm.Mapped[int | None] = orm.mapped_column()
Use instead:
from sqlalchemy import orm
class MyModel(Base):
__tablename__ = "my_model"
id: orm.Mapped[int] = orm.mapped_column(primary_key=True)
count: orm.Mapped[int | None]
2. filter_by vs. filter vs. where
What it does
Checks for use of filter_by calls in SQLAlchemy queries.
Why is this bad?
Using where or filter (where is preferred in SQLAlchemy2) has many advantages for static code analysis (and refactoring tools).
Example
import sqlalchemy as sa
query = sa.select(MyModel).filter_by(x=3)
Use instead:
import sqlalchemy as sa
query = sa.select(MyModel).where(MyModel.x == 3)
3. Missing type annotation
What it does
Checks for existence of Mapped type annotations in SQLAlchemy models.
Why is this bad?
If Mapped type annotations are missing, type checkers wills treat the corresponding field as type Any.
Example
import sqlalchemy as sa
from sqlalchemy import orm
class MyModel(Base):
__tablename__ = "my_model"
id: orm.Mapped[int] = orm.mapped_column(primary_key=True)
count = orm.mapped_column(sa.Integer)
m = MyModel()
reveal_type(m.count) # note: Revealed type is "Any"
Use instead:
from sqlalchemy import orm
class MyModel(Base):
__tablename__ = "my_model"
id: orm.Mapped[int] = orm.mapped_column(primary_key=True)
count: orm.Mapped[int | None]
m = MyModel()
reveal_type(m.count) # note: Revealed type is "Union[builtins.int, None]"
4. Consistency filter vs. where
There could be a could about consistently using filter or where, but where is preferred in the new SQLAlchemy2 style.
Here, are a few ideas for new rules for discussion.
1. Unnecessary
mapped_column()What it does
Checks for redundant i.e. empty
mapped_column()calls in SQLAlchemy models. Emptymapped_column()calls do not carry any additional information and can be removed.Example
Use instead:
2.
filter_byvs.filtervs.whereWhat it does
Checks for use of
filter_bycalls in SQLAlchemy queries.Why is this bad?
Using
whereorfilter(whereis preferred in SQLAlchemy2) has many advantages for static code analysis (and refactoring tools).Example
Use instead:
3. Missing type annotation
What it does
Checks for existence of
Mappedtype annotations in SQLAlchemy models.Why is this bad?
If
Mappedtype annotations are missing, type checkers wills treat the corresponding field as typeAny.Example
Use instead:
4. Consistency
filtervs.whereThere could be a could about consistently using
filterorwhere, butwhereis preferred in the new SQLAlchemy2 style.