Remove SerializerMetaclass, unnecessary since Python 3.6

This is minimal supported version so we can confidently assume the interpreter
will call the __init_subclass__ hook that allow us to alter subclasses.

https://docs.python.org/3/reference/datamodel.html#customizing-class-creation
This commit is contained in:
Nicholas Guriev 2022-05-31 15:05:25 +03:00
parent e5fb9af0ea
commit d0cf41994c
No known key found for this signature in database
GPG Key ID: 05DAA87D248DF095

View File

@ -275,44 +275,6 @@ class BaseSerializer(Field):
# Serializer & ListSerializer classes # Serializer & ListSerializer classes
# ----------------------------------- # -----------------------------------
class SerializerMetaclass(type):
"""
This metaclass sets a dictionary named `_declared_fields` on the class.
Any instances of `Field` included as attributes on either the class
or on any of its superclasses will be include in the
`_declared_fields` dictionary.
"""
@classmethod
def _get_declared_fields(cls, bases, attrs):
fields = [(field_name, attrs.pop(field_name))
for field_name, obj in list(attrs.items())
if isinstance(obj, Field)]
fields.sort(key=lambda x: x[1]._creation_counter)
# Ensures a base class field doesn't override cls attrs, and maintains
# field precedence when inheriting multiple parents. e.g. if there is a
# class C(A, B), and A and B both define 'field', use 'field' from A.
known = set(attrs)
def visit(name):
known.add(name)
return name
base_fields = [
(visit(name), f)
for base in bases if hasattr(base, '_declared_fields')
for name, f in base._declared_fields.items() if name not in known
]
return OrderedDict(base_fields + fields)
def __new__(cls, name, bases, attrs):
attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs)
return super().__new__(cls, name, bases, attrs)
def as_serializer_error(exc): def as_serializer_error(exc):
assert isinstance(exc, (ValidationError, DjangoValidationError)) assert isinstance(exc, (ValidationError, DjangoValidationError))
@ -339,11 +301,46 @@ def as_serializer_error(exc):
} }
class Serializer(BaseSerializer, metaclass=SerializerMetaclass): class Serializer(BaseSerializer):
default_error_messages = { default_error_messages = {
'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.') 'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.')
} }
# Fields are expected to be declared in user's subclasses. This main class
# has got none.
_declared_fields = OrderedDict()
def __init_subclass__(cls):
"""
Collect any `Field` attributes (including ones from superclasses) to
the internal `_declared_fields` dictionary and remove the attributes
from class namespace.
"""
fields = [(field_name, obj)
for field_name, obj in vars(cls).items()
if isinstance(obj, Field)]
for field_name, _ in fields:
delattr(cls, field_name)
fields.sort(key=lambda x: x[1]._creation_counter)
# Ensures a base class field doesn't override cls attrs, and maintains
# field precedence when inheriting multiple parents. e.g. if there is a
# class C(A, B), and A and B both define 'field', use 'field' from A.
known = set(vars(cls))
def visit(name):
known.add(name)
return name
base_fields = [
(visit(name), f)
for base in cls.__bases__ if hasattr(base, '_declared_fields')
for name, f in base._declared_fields.items() if name not in known
]
cls._declared_fields = OrderedDict(base_fields + fields)
@cached_property @cached_property
def fields(self): def fields(self):
""" """