-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Invalid base class" raised when Base Class is a class field #3587
Comments
Probably because bases are processed in an early stage of type checking
(when not everything is sorted out) since otherwise class attributes may
not be found. But Types.Base in your example is itself a class attribute.
So it's essentially circular. (It can be fixed by adding more passes but it
may not be easy.)
|
@gvanrossum Thanks for taking a look! I suspected this one would be near impossible to fix but wanted to report it anyway 😄 |
I would say that in some sense mypy is actually right here (while the error might be clearer). There is a distinction between type aliases and variables with types Except at class scope, everything that appears there is automatically a variable, not an alias (there is an explicit code for this in |
Hm, I didn't realize there was this exception. It makes some sense and I think I've seen code using it, having a base class that delegates certain things to another class and allowing a subclass to override the delegate class. I don't know if that case is more common than Roy's example (the latter looks a lot like abuse of a class as a namespace). |
That's my use case that got me to run into this bug. It would be nice for this to work. Maybe one way to address #3587 (comment) is to detect when the class attribute that is being subclassed is marked as a Work aroundTurn the class attribute pointing at another class into an inner class, like class Foo:
pass
class Types:
class FooShadow(Foo): pass
class WorksAgain(Types.FooShadow):
pass (Mypy 0.620 has no output for the above code.) |
I tried this workaround when creating a stub for flask-sqlalchemy: stub: class SQLAlchemy:
def __init__(self):
...
class Model:
pass real code: db = SQLAlchemy()
class User(db.Model):
pass However, I still get "Invalid base class" when subclassing |
This seems to work (mypy passes, code runs) for me after following the instructions here to separate the model classes from the flask-sqlalchemy Model: Any = declarative_base(cls=ModelBase)
class MyModel(Model):
__tablename__ = 'foo'
... |
I found this issue while looking for my own way to solve flask-sqlalchemy stubs headache, and while @gnmerritt's method seems like the easiest way out, I'm still wondering if there does exist a way to solve the use-class-from-instance-attribute version of the problem: db = SQLAlchemy()
class User(db.Model):
pass Or, put as a self-contained example: class A():
pass
class B:
def __init__(self):
self.sub = A
myB = B()
class C(myB.sub): # Name 'myB.sub' is not defined
pass (any variations, such as assigning |
Repro:
Results in:
What's odd is that mypy recognizes
Base
andTypes.Base
as having identical types yet acceptsBase
as a base class but notTypes.Base
The text was updated successfully, but these errors were encountered: