From 2fa6b9eae07e2385e2acbf2e40093a21fb3a10c4 Mon Sep 17 00:00:00 2001 From: "Eric V. Smith" Date: Mon, 26 Feb 2018 20:38:33 -0500 Subject: bpo-32960: For dataclasses, disallow inheriting frozen from non-frozen classes and vice-versa, (GH-5919) This restriction will be relaxed at a future date. --- Lib/dataclasses.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'Lib/dataclasses.py') diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index db92b10960..54478fec93 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -623,14 +623,21 @@ def _process_class(cls, repr, eq, order, unsafe_hash, init, frozen): else: setattr(cls, f.name, f.default) + # We're inheriting from a frozen dataclass, but we're not frozen. + if cls.__setattr__ is _frozen_setattr and not frozen: + raise TypeError('cannot inherit non-frozen dataclass from a ' + 'frozen one') + + # We're inheriting from a non-frozen dataclass, but we're frozen. + if (hasattr(cls, _MARKER) and cls.__setattr__ is not _frozen_setattr + and frozen): + raise TypeError('cannot inherit frozen dataclass from a ' + 'non-frozen one') + # Remember all of the fields on our class (including bases). This # marks this class as being a dataclass. setattr(cls, _MARKER, fields) - # We also need to check if a parent class is frozen: frozen has to - # be inherited down. - is_frozen = frozen or cls.__setattr__ is _frozen_setattr - # Was this class defined with an explicit __hash__? Note that if # __eq__ is defined in this class, then python will automatically # set __hash__ to None. This is a heuristic, as it's possible @@ -654,7 +661,7 @@ def _process_class(cls, repr, eq, order, unsafe_hash, init, frozen): if f._field_type in (_FIELD, _FIELD_INITVAR)] _set_new_attribute(cls, '__init__', _init_fn(flds, - is_frozen, + frozen, has_post_init, # The name to use for the "self" param # in __init__. Use "self" if possible. @@ -696,7 +703,7 @@ def _process_class(cls, repr, eq, order, unsafe_hash, init, frozen): f'in class {cls.__name__}. Consider using ' 'functools.total_ordering') - if is_frozen: + if frozen: for name, fn in [('__setattr__', _frozen_setattr), ('__delattr__', _frozen_delattr)]: if _set_new_attribute(cls, name, fn): -- cgit v1.2.1