Skip to content

Commit fbb2b01

Browse files
committed
refactor: replace _AutoNamedFieldsMetaclass with __set_name__
_AutoNamedFieldsMetaclass was a hand-rolled way of capturing each Field's name as it is defined on an XBlock. Since Python 3.6, __set_name__ is part of the built-in Descriptor interface, providing a more elegant way of achieving the same thing.
1 parent abb10af commit fbb2b01

2 files changed

Lines changed: 8 additions & 42 deletions

File tree

xblock/core.py

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -38,47 +38,7 @@
3838
UNSET = object()
3939

4040

41-
class _AutoNamedFieldsMetaclass(type):
42-
"""
43-
Builds classes such that their Field attributes know their own names.
44-
45-
This allows XBlock API users to define fields without name redundancy, e.g. like this:
46-
47-
class MyBlock(XBlock):
48-
my_field = Field(...)
49-
50-
rather than this:
51-
52-
class MyBlock(XBlock):
53-
my_field = Field(name="my_field", ...)
54-
"""
55-
def __new__(mcs, name, bases, attrs):
56-
"""
57-
Ensure __name__ is set on all Field attributes, both on the new class and on its bases.
58-
"""
59-
def needs_name(obj):
60-
"""
61-
Is this object a Field that hasn't had its name assigned yet?
62-
"""
63-
return isinstance(obj, Field) and not obj.__name__
64-
65-
# Iterate over the attrs before they're bound to the class
66-
# so that we don't accidentally trigger any __get__ methods
67-
for attr_name, attr in attrs.items():
68-
if needs_name(attr):
69-
attr.__name__ = attr_name
70-
71-
# Iterate over all of the base classes, so that we can add
72-
# names to any mixins that don't include this metaclass, but that
73-
# do include Fields
74-
for base in bases:
75-
for attr_name, attr in inspect.getmembers(base, predicate=needs_name):
76-
attr.__name__ = attr_name
77-
78-
return super().__new__(mcs, name, bases, attrs)
79-
80-
81-
class Blocklike(metaclass=_AutoNamedFieldsMetaclass):
41+
class Blocklike:
8242
"""
8343
Shared base for XBlocks and XBlockAsides, providing these common capabilities:
8444
@@ -645,7 +605,7 @@ class XBlockMixin(Blocklike):
645605
"""
646606

647607

648-
class _HasChildrenMetaclass(_AutoNamedFieldsMetaclass):
608+
class _HasChildrenMetaclass(type):
649609
"""
650610
Adds a ``children`` XBlock ReferenceList field to classes where ``has_children == True``.
651611
"""

xblock/fields.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,12 @@ def __init__(self, help=None, default=UNSET, scope=Scope.content, # pylint:disa
331331
self.xml_node = xml_node
332332
self.force_export = force_export
333333

334+
def __set_name__(self, owner: type, name: str):
335+
"""
336+
Automatically record the name of this Field as it is defined on a class.
337+
"""
338+
self.__name__ = name
339+
334340
@property
335341
def default(self):
336342
"""Returns the static value that this defaults to."""

0 commit comments

Comments
 (0)