Issue 32162: typing.Generic breaks init_subclass (original) (raw)

Created on 2017-11-28 22:27 by Ilya.Kulakov, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (9)
msg307182 - (view) Author: Ilya Kulakov (Ilya.Kulakov) * Date: 2017-11-28 22:27
When superclass inherits from Generic, attributes set for a subclass are incorrectly propagated to its superclass. Without Generic attribute access raises an exception: class X: def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) cls.attr = 42 class Y(X): pass Y.attr # 42 X.attr # AttributeError With Generic it does not: import typing T = typing.TypeVar('T') class X(typing.Generic[T]): def __init_subclass__(cls, **kwargs): super().__init_subclass__(**kwargs) cls.attr = 42 class Y(X): pass Y.attr # 42 X.attr # 42
msg307185 - (view) Author: Ilya Kulakov (Ilya.Kulakov) * Date: 2017-11-28 22:48
This issue is more server that I expected: it doesn't just propagate value to superclasses, but overrides them. The last subclass created by Python runtime will overwrite value for the whole chain.
msg307187 - (view) Author: Ilya Kulakov (Ilya.Kulakov) * Date: 2017-11-28 22:52
Current workaround is class X(typing.Generic[T] if typing.TYPE_CHECKING else object):
msg307189 - (view) Author: Ilya Kulakov (Ilya.Kulakov) * Date: 2017-11-28 23:08
Nah, that's a bad one: you cannot use Generic classes as intended by specifying types. It looks like it happens because cls._grog is not yet set properly by the time __init_subclass__ is called.
msg307192 - (view) Author: Ilya Kulakov (Ilya.Kulakov) * Date: 2017-11-28 23:54
That's a better workaround: class X(typing.Generic[T]): def __init_subclass__(cls, **kwargs): super(typing.GenericMeta, cls).__setattr__('_gorg', cls) super().__init_subclass__(**kwargs)
msg312309 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-02-18 13:07
FWIW, this is fixed in 3.7 by PEP 560, providing a separate fix for 3.6 is not easy, and you have a good workaround, so I propose to close this issue.
msg314824 - (view) Author: Will T (wrmsr) Date: 2018-04-02 20:08
I believe I'm experiencing a related bug in the new (3.7) version unfortunately. The current version of typing.Generic.__init_subclass__ isn't chaining to super(Generic, cls).__init_subclass__, meaning Generic's position in class bases can prevent subsequent bases from working properly. I can currently work around it with this unsightly hack but it's obviously suboptimal: _old_generic_init_subclass = object.__getattribute__(ta.Generic, '__init_subclass__').__func__ @classmethod # noqa def _new_generic_init_subclass(cls, *args, **kwargs): # noqa _old_generic_init_subclass(cls, *args, **kwargs) super(ta.Generic, cls).__init_subclass__(*args, **kwargs) ta.Generic.__init_subclass__ = _new_generic_init_subclass # noqa
msg314825 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-04-02 20:18
Thanks Will! I think this is actually a different (although very similar issue). It looks like it is easy to fix. Could you please open a separate issue (and mention it here)? Also could you please provide a typical example when this breaks so that I can add an appropriate test with the fix?
msg314829 - (view) Author: Will T (wrmsr) Date: 2018-04-02 22:03
Done: https://bugs.python.org/issue33207 - thanks for the quick response!
History
Date User Action Args
2022-04-11 14:58:54 admin set github: 76343
2018-04-02 22:03:02 wrmsr set messages: +
2018-04-02 20🔞40 levkivskyi set messages: +
2018-04-02 20:08:48 wrmsr set nosy: + wrmsrmessages: +
2018-02-18 13:07:43 levkivskyi set status: open -> closedresolution: fixedmessages: + stage: resolved
2017-12-01 22:23:06 levkivskyi set nosy: + levkivskyi
2017-11-28 23:54:31 Ilya.Kulakov set messages: +
2017-11-28 23:08:36 Ilya.Kulakov set messages: +
2017-11-28 22:52:50 Ilya.Kulakov set messages: +
2017-11-28 22:48:14 Ilya.Kulakov set messages: +
2017-11-28 22:27:43 Ilya.Kulakov create