Correctly construct Meta class for multi-inherited Blocks

Conflicts:
	CHANGELOG.txt
	docs/releases/1.5.rst
	wagtail/wagtailcore/blocks/base.py
This commit is contained in:
Tim Heap 2016-04-07 14:54:42 +10:00 committed by Matt Westcott
parent 0011fc08a1
commit aaefb81b60
4 changed files with 47 additions and 7 deletions

View file

@ -4,7 +4,8 @@ Changelog
1.4.4 (xx.xx.2016)
~~~~~~~~~~~~~~~~~~
* The `wagtailuserbar` template tag now gracefully handles situations where the `request` object is not in the template context (Matt Westcott)
* Fix: The `wagtailuserbar` template tag now gracefully handles situations where the `request` object is not in the template context (Matt Westcott)
* Fix: Meta classes on StreamField blocks now handle multiple inheritance correctly (Tim Heap)
1.4.3 (04.04.2016)

View file

@ -13,4 +13,5 @@ What's changed
Bug fixes
~~~~~~~~~
* The ``wagtailuserbar`` template tag now gracefully handles situations where the ``request`` object is not in the template context (Matt Westcott)
* The ``wagtailuserbar`` template tag now gracefully handles situations where the ``request`` object is not in the template context (Matt Westcott)
* Meta classes on StreamField blocks now handle multiple inheritance correctly (Tim Heap)

View file

@ -30,9 +30,11 @@ class BaseBlock(type):
cls = super(BaseBlock, mcs).__new__(mcs, name, bases, attrs)
base_meta_class = getattr(cls, '_meta_class', None)
bases = tuple(cls for cls in [meta_class, base_meta_class] if cls) or ()
cls._meta_class = type(str(name + 'Meta'), bases + (object, ), {})
# Get all the Meta classes from all the bases
meta_class_bases = [meta_class] + [getattr(base, '_meta_class', None)
for base in bases]
meta_class_bases = tuple(filter(bool, meta_class_bases))
cls._meta_class = type(str(name + 'Meta'), meta_class_bases, {})
return cls
@ -43,7 +45,7 @@ class Block(six.with_metaclass(BaseBlock, object)):
TEMPLATE_VAR = 'value'
class Meta:
class Meta(object):
label = None
icon = "placeholder"
classname = None

View file

@ -454,7 +454,10 @@ class TestMeta(unittest.TestCase):
block = HeadingBlock(template='subheading.html')
self.assertEqual(block.meta.template, 'subheading.html')
def test_meta_multiple_inheritance(self):
def test_meta_nested_inheritance(self):
"""
Check that having a multi-level inheritance chain works
"""
class HeadingBlock(blocks.CharBlock):
class Meta:
template = 'heading.html'
@ -468,6 +471,39 @@ class TestMeta(unittest.TestCase):
self.assertEqual(block.meta.template, 'subheading.html')
self.assertEqual(block.meta.test, 'Foo')
def test_meta_multi_inheritance(self):
"""
Check that multi-inheritance and Meta classes work together
"""
class LeftBlock(blocks.CharBlock):
class Meta:
template = 'template.html'
clash = 'the band'
label = 'Left block'
class RightBlock(blocks.CharBlock):
class Meta:
default = 'hello'
clash = 'the album'
label = 'Right block'
class ChildBlock(LeftBlock, RightBlock):
class Meta:
label = 'Child block'
block = ChildBlock()
# These should be directly inherited from the LeftBlock/RightBlock
self.assertEqual(block.meta.template, 'template.html')
self.assertEqual(block.meta.default, 'hello')
# This should be inherited from the LeftBlock, solving the collision,
# as LeftBlock comes first
self.assertEqual(block.meta.clash, 'the band')
# This should come from ChildBlock itself, ignoring the label on
# LeftBlock/RightBlock
self.assertEqual(block.meta.label, 'Child block')
class TestStructBlock(SimpleTestCase):
def test_initialisation(self):