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
{{ message }}
Repository navigation
Handling mixins that reference fields that they do not contain #5837
$ ../py37/bin/mypy --python-executable ../py27/bin/python test.py
test.py:12: error: "Mixin" has no attribute "var1"
I understand the issue, there's nothing in Mixin class that states that var1 will be available.
My question is is there a way to tell mypy somehow that this attribute will be available?
I did not have much luck with using abstract classes and Protocol.
I also had a suggestion to use stub file, but that doesn't look like be perfect solution either, since I might need to define types outside of the module and keep them in sync. And this pattern is used in multiple places not just one.
Is there a way how this could be expressed in mypy? If the code needs to be slightly refactored without changing how it works I suppose that might also be acceptable.
That actually will work, and probably will do it this way, but if there was a way to define some parent class that only mypy would see would be perfect. So I would need to define these fields only once.
That actually seems to work rather well, at least for the code so far. I used TYPE_CHECKING from typing instead of MYPY, is there any disadvantage to use that instead?
Actually looks like this still has an issue. When I'm now checking for classes that includes mixins I'm getting error similar to this: test.py:21: error: Cannot determine consistent method resolution order (MRO) for "B"
Yeah, if I place mixin first then things work and I no longer even need to make type checking a special case, just have the base class a parent of mixin by default. Seems like that is the correct way of using mixins. My only concern is that this is an existing code base and I'm wondering if this could break something this way.
fromtypingimportType, TYPE_CHECKING, TypeVarT=TypeVar('T')
defwith_typehint(baseclass: Type[T]) ->Type[T]:
""" Useful function to make mixins with baseclass typehint ``` class ReadonlyMixin(with_typehint(BaseAdmin))): ... ``` """ifTYPE_CHECKING:
returnbaseclassreturnobject
Example:
classReadOnlyInlineMixin(with_typehint(BaseModelAdmin)):
defget_readonly_fields(self,
request: WSGIRequest,
obj: Optional[Model] =None) ->List[str]:
ifself.readonly_fieldsisNone:
readonly_fields= []
else:
readonly_fields=self.readonly_fields# self get is typed by baseclassreturnself._get_readonly_fields(request, obj) +list(readonly_fields)
defhas_change_permission(self,
request: WSGIRequest,
obj: Optional[Model] =None) ->bool:
return (
request.methodin ['GET', 'HEAD']
andsuper().has_change_permission(request, obj) # super is typed by baseclass
)
>>>ReadOnlyAdminMixin.__mro__
(<class'custom.django.admin.mixins.ReadOnlyAdminMixin'>, <class'object'>)
Not sure why it's failing with QuerySet, but also with Model and Field based classes. Most other classes seem to work fine, just not those (maybe something in the metaclasses Django uses?).
If anyone has feedback as to why the other ways aren't working I'd be happy to hear about it (CPYthon 3.8.0, Mypy: 0.780), but this solution worked and is also more succinct that the others.
Reacted by λ🏺, Keith, Lorenzo, Erik Körner, Trung Nguyen, Dan Jacob, John Torres, DenisK, Rigel Di Scala, GeonHee Lee and 2 more
choose 1. u can specify needed field with their typehints as classvariables of Mixin class. It's will be more pythonic(more explicit)
choose 2. u can inherit protocol (Typing.Protocol) of class which Mixin extended,
but this will not work if master class of mixin class inherit sqlalchemy Model :(
Activity
msullivan commentedon Oct 25, 2018
How about (for python 2.7; in python 3.6 or greater you'd use a variable type annotation):
(The
if MYPYstuff isn't strictly necessary, but it keeps the runtime behavior from changing.)I had hoped it would work to declare
var1as anabstractpropertyofMixin, but mypy doesn't seem able to figure out they are compatible.takeda commentedon Oct 25, 2018
That actually will work, and probably will do it this way, but if there was a way to define some parent class that only mypy would see would be perfect. So I would need to define these fields only once.
JelleZijlstra commentedon Oct 25, 2018
You can probably do that with something like:
takeda commentedon Oct 26, 2018
That actually seems to work rather well, at least for the code so far. I used TYPE_CHECKING from typing instead of MYPY, is there any disadvantage to use that instead?
gvanrossum commentedon Oct 26, 2018
You should use
typing.TYPE_CHECKING. UsingMYPYis only needed when you are stuck with a very old version oftyping.py.takeda commentedon Oct 26, 2018
Awesome, thank you all for your help.
takeda commentedon Oct 26, 2018
Actually looks like this still has an issue. When I'm now checking for classes that includes mixins I'm getting error similar to this:
test.py:21: error: Cannot determine consistent method resolution order (MRO) for "B"gvanrossum commentedon Oct 26, 2018
takeda commentedon Oct 26, 2018
This is how the code looks now after the change:
gvanrossum commentedon Oct 26, 2018
takeda commentedon Oct 26, 2018
Yeah, if I place mixin first then things work and I no longer even need to make type checking a special case, just have the base class a parent of mixin by default. Seems like that is the correct way of using mixins. My only concern is that this is an existing code base and I'm wondering if this could break something this way.
gvanrossum commentedon Oct 26, 2018
I don't think we can help you with that...
bot: Split into multiple compartmentalized ABC mixins
Handle missing attribute in mixin properly in type-check
leonardoramirezr commentedon Jul 9, 2020
Try with:
Example:
jaredlockhart commentedon Jul 21, 2020
@leonardon473 trying your proposal results in:
Unsupported dynamic base class "with_typehint" mypy(error)using:
Python 3.8.2
mypy==0.770
The closest reference I find to that error is here:
#6372
which suggests that mypy does not accept dynamically generated base classes?
Also mypy complained that
return objectis an unreachable statement.jsatt commentedon Jul 28, 2020
An alternate solution for future folks which this doesn't work:
I was having a similar problem making a QuerySet Mixin for Django.
Resulted in
"Mixin" has no attribute "filter"So I tried the solution above:
And got
Invalid base class "_Base"Not sure why it's failing with QuerySet, but also with Model and Field based classes. Most other classes seem to work fine, just not those (maybe something in the metaclasses Django uses?).
I finally got it to work by type hinting
self,If anyone has feedback as to why the other ways aren't working I'd be happy to hear about it (CPYthon 3.8.0, Mypy: 0.780), but this solution worked and is also more succinct that the others.
BakinSergey commentedon Aug 18, 2023
choose 1. u can specify needed field with their typehints as classvariables of Mixin class. It's will be more pythonic(more explicit)
choose 2. u can inherit protocol (Typing.Protocol) of class which Mixin extended,
but this will not work if master class of mixin class inherit sqlalchemy Model :(