Pyright cannot recognize the type of `SQLModel.__tablename__`
First Check
- [X] I added a very descriptive title to this issue.
- [X] I used the GitHub search to find a similar issue and didn't find it.
- [X] I searched the SQLModel documentation, with the integrated search.
- [X] I already searched in Google "How to X in SQLModel" and didn't find any information.
- [X] I already read and followed all the tutorial in the docs and didn't find an answer.
- [X] I already checked if it is not related to SQLModel but to Pydantic.
- [X] I already checked if it is not related to SQLModel but to SQLAlchemy.
Commit to Help
- [X] I commit to help with one of those options 👆
Example Code
from sqlmodel import SQLModel
reveal_type(SQLModel.__tablename__)
# mypy(0.910) output: Revealed type is "Union[builtins.str, def (*Any, **Any) -> builtins.str]"
# pyright(1.1.166) output: Type of "SQLModel.__tablename__" is "declared_attr"
class User(SQLModel, table=True): # pyright error: Instance variable "__name__" overrides class variable of same name in class "SQLModel"
__tablename__ = "users" # pyright error: Expression of type "Literal['users']" cannot be assigned to declared type "declared_attr"
name: str
Description
This will cause a type error when you declare __tablename__ with pyright as type checker. Like:
Expression of type "Literal['users']" cannot be assigned to declared type "declared_attr"
Operating System
Linux, macOS
Operating System Details
No response
SQLModel Version
0.0.4
Python Version
3.8.6
Additional Context
No response
this is my workaround to silence that type of errors (not my proudest hack but it work)
from sqlmodel import SQLModel
from sqlalchemy.orm import declared_attr
class User(SQLModel, table=True):
name: str
@declared_attr
def __tablename__(cls): # noqa: N805
return 'users'
inspired by the declared_attr documentation, tested with pyright 1.1.172 (Linux), python 3.9.7, sqlmodel 0.0.4
@Chedi Hi, of my own workaround is adding a # type: ignore after __tablename__ = "users".
With @Chedi 's workaround, I still get an error on Mypy: error: Signature of "__tablename__" incompatible with supertype "SQLModel".
Only # type: ignore works.
another really easy workaround is just specifying the type: __tablename__: str = 'poop'
another really easy workaround is just specifying the type:
__tablename__: str = 'poop'
Note that Pyright complains at this:
"__tablename__" incorrectly overrides property of same name in class "SQLModel" Pylance(reportIncompatibleMethodOverride)
To satisfy the type checker you need to use the declared_attr approach, eg:
class Lineitem(SQLModel, table=True):
@declared_attr
def __tablename__(cls):
return "invoice_lineitems"
This could be mentioned in the docs, and maybe in a future version a more intuitive approach could be used, such as putting it in a Meta as ormar does:
class Lineitem(SQLModel, table=True):
class Meta:
tablename: str = "invoice_lineitems"
I thought about making a request for this but I'm guessing there's already a lot on the roadmap.
Since I posted https://github.com/tiangolo/sqlmodel/issues/98#issuecomment-1146535179, I've started simply doing
__tablename__: str = "invoices_legacy" # type: ignore
I think this is by far the best solution for people still getting the "incorrect override" error for the line without type: ignore. As I said when I mentioned this in https://github.com/tiangolo/sqlmodel/issues/159,
I choose this last method because the others are far too verbose for something as simple as declaring the table name. This may seem hacky, but although I have to tell Pyright to ignore a number of things in sqlmodel, it's not half the file like I have to type: ignore with sqlalchemy.