11

mypy reports an error in the following code:

import enum
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Enum

Base = declarative_base()

class MyEnum(enum.Enum):
    A = 1
    B = 2

class MyTable(Base):
    __tablename__ = 'my_table'

    col = Column(Enum(MyEnum), nullable=False)

c = MyTable(col=MyEnum.A)

Following is the error:

a.py:16: error: Incompatible type for "col" of "MyTable" (got "MyEnum", expected "str")

How do I make this error go away without adding a "type: ignore" ? I could also replace MyEnum.A with MyEnum.A.name to make the error go away. But this doesn't look clean and is also not suggested in sqlalchemy documentation.

1
  • I can't reproduce your error on my setup. When using your example in a fresh virtualenv, I get this error: error: Variable "Base" is not valid as a type. Did you bypass this error somehow? Could you explicit the versions of Python, mypy, sqlalchemy and sqlalchemy-stubs you're using? Commented Aug 8, 2021 at 23:57

3 Answers 3

6

I don't know what exactly makes this error go away but on my setup after some refactoring and mypy configuring this error disappeared.

I installed sqlalchemy-stubs

pip install sqlalchemy-stubs

and created setup.cfg file:

[mypy]
files = **/*.py
plugins =
  sqlalchemy.ext.mypy.plugin
import enum

from sqlalchemy import Column, Enum
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class MyEnum(enum.Enum):
    """My enum."""

    ONE = 1
    TWO = 2


class MyTable(Base):
    """My table."""

    __tablename__ = 'my_table'

    col = Column(Enum(MyEnum), nullable=False)


table = MyTable(col=MyEnum.ONE)
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! One minor thing though, is that currently the setup is a bit different (plugin name is now sqlmypy). See github.com/dropbox/sqlalchemy-stubs
It worked for me without specifying the plugin
4

You have to introduce them yourself in your script. The dynamically created Base class is of type DeclarativeMeta. If you type annotate the variable Base, mypy does not show the error any more.

from sqlalchemy.orm.decl_api import DeclarativeMeta
Base: DeclarativeMeta = declarative_base()

Now the Base variable is properly type annotated. I think that the DeclarativeMeta class is not to be exposed in the API, so I'm not sure how sustainable this solution will be.

1 Comment

sqlalchemy has first-party mypy support as an optional install via pip install sqlalchemy[mypy] since version 1.4
3

You have to import the base class:

SQLAlchemy <v2:

from sqlalchemy.orm.decl_api import DeclarativeMeta
Base: DeclarativeMeta = declarative_base()

see https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/basic_use.html

Or SQLAlchemy v2+:

from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
    pass

See: https://docs.sqlalchemy.org/en/20/orm/mapping_styles.html#mapped-class-essential-components

NB the first method also works for v2, but the latter is probably preferable, and certainly easier to understand as it follows Python's normal inheritance system..

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.