You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Simpler repro (without the typeshed/sqlalchemy stuff):
deffunc(): passBase=func()
classC(Base): pass# errors on this line
Errors (mypy -s x.py):
x.py:3: error: Invalid type "x.Base"
x.py:3: error: Invalid base class
(Update: used def func... instead if import.)
Reacted by Dan Loewenherz, David Gang, Mickaël, Dean Stamler, Eric Arellano, Leah Einhorn, Utkarsh Upadhyay, James Adams, quapka, 김동현(DongHyeon Kim)/MP and 3 more
The reason this doesn't work is that the type of Base is not yet inferred during semantic analysis, and that's when we process base classes. You can add an annotation as a workaround:
from typing import Any
def func(): pass
Base = func() # type: Any
class C(Base): pass # now works
Reacted by James Cooke, Utkarsh Upadhyay, mikedanylov, Janrey Licas, huyl and Misha Tomilov
I seem to have hit a very similar bug that's a bit more convoluted (involving Optional and importing), but probably has a related base cause. It happened to me originally with sqlalchemy's declarative_base() as well, but this was my attempt to find a simple reproduction (Python 3.6):
file1.py:
fromtypingimportAnyBase: Any
file2.py:
fromtypingimportOptionalfrom .file1importBaseclassSubClass(Base):
passdefoptional_return_func() ->Optional[SubClass]:
returnSubClass()
defshould_fail() ->int:
test_var=optional_return_func()
reveal_type(test_var)
ifnottest_var:
return1return'not an int'
When I run mypy on this, the result is error: Revealed type is 'builtins.None'
The expected result should be Revealed type is 'Union[file2.SubClass, builtins.None]' along with an Incompatible return value type error, but since mypy is certain that test_var is None, it considers the final line that returns a string unreachable.
Hope that makes sense, let me know if any more information would be helpful.
@JukkaL sorry for the ping, but I just wanted to check and see if you think the issue I described above is similar enough that leaving it as part of this one is good, or if I should open a new, separate issue for it.
@Deimos The builtins.None issue seems to be fixed on github master -- can you verify that it works for you? It's unrelated to the original issue, but no need to create an issue if it already works.
Oh, yes, it does seem to be fixed using current github master. That's great, thanks (and sorry for bothering you about something that was already fixed).
But what would you expect? Except for a few trivial edge cases, when the base class is computed dynamically, mypy is unable to understand the structure of your class. That's why it gives an error when you use a dynamic base class -- if you shut it up using Any, literally "Any"thing can happen. :-)
[I changed the issue topic because it has nothing to do with sqlalchemy.]
If mypy can't parse it, it is unhelpful to say it's a type error
Reacted by Max Kühn, Kovalev Vasily, Sergey Shepelev, Jan Neumann, Aidar, Pavel Perestoronin, Dustin Martin, Ramiro, Siddhartha Gandhi and Justin Furuness
In case others are interested in the Django type checking issues I mentioned here and they find this thread, I'd like to point to this plugin for mypy: https://github.com/mkurnikov/django-stubs I haven't started using it yet, but it should solve a lot of Django type checking issues.
Note the workaround from Guido above does not work when wrapped in a function in general:
deffoo():
fromtypingimportTYPE_CHECKINGdefmake_base(): passifTYPE_CHECKING:
base=objectelse:
base=make_base()
classC(base): # !! Variable "base" is not valid as a typedeffoo(self): passc=C()
c.foo()
c.bar() # Error again
Simpler:
ifTrue: # worksbase=objectclassC(base):
passdeff():
base=objectclassC(base): # Variable "base" is not valid as a type / Invalid base class "base"pass
For anyone who comes across this via the original report, a simple way to address sqlalchemy/mypy issues is to also import DeclarativeMeta.
from sqalalchemy.ext.declarative import declarative_base, DeclarativeMeta
Base: DeclarativeMeta = declarative_base()
...
Reacted by 依云, junpet, Kevin L., Rich Fromm, Michael Bayer, Adrian, Lucas Mitsuo Taniguti, Johnny Wezel, Carlos Eduardo Moreira dos Santos, Alan R and 31 more
Reacted by Nemesis7, Andrei Chenchik, Tristan Schrader, Tim McFadden, Janrey Licas, Carlos Vicente, Martin Winkel, Cintia, Víctor Auñón, Marcin Wrochna and 13 more
Thanks @micahjsmith, just ran into this for the first time (on a 2-yo project, no clue why it was never reporting before). Base: Declarative = ... is way better than Base = ... # type: ignore
Activity
gvanrossum commentedon Nov 24, 2016
Simpler repro (without the typeshed/sqlalchemy stuff):
Errors (
mypy -s x.py):(Update: used
def func...instead ifimport.)JukkaL commentedon Nov 24, 2016
The reason this doesn't work is that the type of
Baseis not yet inferred during semantic analysis, and that's when we process base classes. You can add an annotation as a workaround:gvanrossum commentedon Nov 24, 2016
Should we close this then or update the docs somewhere? Maybe the error message could also be better.
JukkaL commentedon Nov 24, 2016
I think that we should at least see if we can make the error message better.
snakescott commentedon Nov 24, 2016
improved error message would be helpful. I did discover
# type: Anyas a workaround but it is good to be aware this is a known issue.Is there a github issue I should be tracking for the semantic analysis improvement, or just watch the release notes?
JukkaL commentedon Jan 16, 2017
Let's use this issue to track both the error message and the underlying semantic analysis issue for now.
Deimos commentedon Jan 19, 2017
I seem to have hit a very similar bug that's a bit more convoluted (involving
Optionaland importing), but probably has a related base cause. It happened to me originally with sqlalchemy'sdeclarative_base()as well, but this was my attempt to find a simple reproduction (Python 3.6):file1.py:
file2.py:
When I run mypy on this, the result is
error: Revealed type is 'builtins.None'The expected result should be
Revealed type is 'Union[file2.SubClass, builtins.None]'along with anIncompatible return value typeerror, but since mypy is certain thattest_varisNone, it considers the final line that returns a string unreachable.Hope that makes sense, let me know if any more information would be helpful.
Deimos commentedon Jan 30, 2017
@JukkaL sorry for the ping, but I just wanted to check and see if you think the issue I described above is similar enough that leaving it as part of this one is good, or if I should open a new, separate issue for it.
JukkaL commentedon Jan 31, 2017
@Deimos The
builtins.Noneissue seems to be fixed on github master -- can you verify that it works for you? It's unrelated to the original issue, but no need to create an issue if it already works.Deimos commentedon Jan 31, 2017
Oh, yes, it does seem to be fixed using current github master. That's great, thanks (and sorry for bothering you about something that was already fixed).
libre-man commentedon Jul 9, 2017
But if I add a
Anyannotation the problem is that it thinks the class can be anything, so doing stuff likedoes not yield an error which makes anything using this class (
Ain this case) not typesafe anymore.[-]MyPy not handling sqlalchemy declarative_base correctly[/-][+]Dynamic base classes are not handled[/+]gvanrossum commentedon Jul 10, 2017
But what would you expect? Except for a few trivial edge cases, when the base class is computed dynamically, mypy is unable to understand the structure of your class. That's why it gives an error when you use a dynamic base class -- if you shut it up using
Any, literally "Any"thing can happen. :-)[I changed the issue topic because it has nothing to do with sqlalchemy.]
20 remaining items
Correct Mypy "invalid base class" error
revmischa commentedon Jun 18, 2019
If mypy can't parse it, it is unhelpful to say it's a type error
w0rp commentedon Jun 18, 2019
In case others are interested in the Django type checking issues I mentioned here and they find this thread, I'd like to point to this plugin for mypy: https://github.com/mkurnikov/django-stubs I haven't started using it yet, but it should solve a lot of Django type checking issues.
blueyed commentedon Nov 7, 2019
@dms-cat
Is this inside of a function?
Note the workaround from Guido above does not work when wrapped in a function in general:
Simpler:
(0.750+dev.a94e649de794ecd169a5bcc42274e5205ffbb1fb)
bot: Split into multiple compartmentalized ABC mixins
micahjsmith commentedon Oct 3, 2020
For anyone who comes across this via the original report, a simple way to address sqlalchemy/mypy issues is to also import DeclarativeMeta.
kevlarr commentedon Dec 9, 2020
Thanks @micahjsmith, just ran into this for the first time (on a 2-yo project, no clue why it was never reporting before).
Base: Declarative = ...is way better thanBase = ... # type: ignoreabap: fix mypy typing error
abap: fix mypy typing error
abap: fix mypy typing error
abap: fix mypy typing error
abap: fix mypy typing error
abap: fix mypy typing error
Mypy workaround