Skip to content

Pyright cannot recognize the type of SQLModel.__tablename__ #98

Description

@Ma233

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the SQLModel documentation, with the integrated search.
  • I already searched in Google "How to X in SQLModel" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to SQLModel but to Pydantic.
  • I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • 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

Activity

  1. Chedi commented on Sep 30, 2021

    @Chedi

    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

  2. Ma233 commented on Oct 7, 2021

    @Ma233
    Author

    @Chedi Hi, of my own workaround is adding a # type: ignore after __tablename__ = "users".

  3. mudassirkhan19 commented on Oct 28, 2021

    @mudassirkhan19

    With @Chedi 's workaround, I still get an error on Mypy: error: Signature of "__tablename__" incompatible with supertype "SQLModel".
    Only # type: ignore works.

  4. indivisible commented on Dec 17, 2021

    @indivisible

    another really easy workaround is just specifying the type: __tablename__: str = 'poop'

  5. cassieopea commented on Jun 4, 2022

    @cassieopea

    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.

  6. cassieopea commented on Jun 21, 2022

    @cassieopea

    Since I posted #98 (comment), 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 #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.

  7. anton-fomin commented on Feb 8, 2025

    @anton-fomin

    It seems

        __tablename__: ClassVar[str] = "users"
    

    Solves this for both pyright and mypy

    Updated
    Works only with basic type checking mode. Does not work in standard

  8. chriscarrollsmith commented on May 3, 2025

    @chriscarrollsmith

    I tried all the fixes in this thread, and I'm sorry to report that you'll need # type: ignore to fix this with Pylance in "standard" type checking mode, because none of the other suggestions work.

  9. madduck commented on Jun 30, 2025

    @madduck

    I use

    __tablename__ = typing.cast(declared_attr, "Users")

    and be done with it.

  10. youhogeon-meritz commented on Sep 3, 2025

    @youhogeon-meritz

    It works on pyright strict mode . But not graceful.

    __tablename__: ClassVar[Any] = "my_table"
    
  11. madduck commented on Sep 3, 2025

    @madduck
    __tablename__: ClassVar[Any] = "my_table"
    

    I can confirm this works for pyright and mypy.

  12. marcoshevaristo commented on Dec 28, 2025

    @marcoshevaristo

    Since I posted #98 (comment), 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 #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.

    I can confirm this works.

  13. added 4 commits that reference this issue on Mar 18, 2026
    f738f67
    6b0eadd
    98c37a4
    24d66f7
  14. locked and limited conversation to collaborators on May 18, 2026
  15. converted this issue into a discussion #1932 on May 18, 2026
  16. added a commit that references this issue on Jun 10, 2026
    415c8fc
  17. added a commit that references this issue on Sep 21, 2026
    ac37dba
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions