Skip to content

Commit

Permalink
MetaAdminPageConfig: factorize ColsConfig and FieldsetsConfig inherit…
Browse files Browse the repository at this point in the history
…ance management with TabsConfig's one
  • Loading branch information
yohanboniface committed Mar 17, 2012
1 parent 638162b commit 95af5d4
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 44 deletions.
103 changes: 60 additions & 43 deletions admin_tabs/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,50 +169,67 @@ class MetaAdminPageConfig(type):
"""
def __new__(mcs, name, base, dct):
it = type.__new__(mcs, name, base, dct)
# Make the FieldsetsConfig attributes overwrittable and inheritable
# TODO: reverse mro like its done in tabs
for cls in it.mro():
if not hasattr(cls, "FieldsetsConfig"): continue
for attr in dir(cls.FieldsetsConfig):
if attr.startswith("_"): continue
if hasattr(it.FieldsetsConfig, attr): continue # do not override
setattr(it.FieldsetsConfig, attr, getattr(cls.FieldsetsConfig, attr))
# Make the ColsConfig attributes overwrittable and inheritable
# TODO: reverse mro like its done in tabs
for cls in it.mro():
if not hasattr(cls, "ColsConfig"): continue
for attr in dir(cls.ColsConfig):
if attr.startswith("_"): continue
if hasattr(it.ColsConfig, attr): continue # do not override
setattr(it.ColsConfig, attr, getattr(cls.ColsConfig, attr))

def _manage_config_class_inheritance(config_class_name):
"""
Manage the ihneritance of the config classes (TabsConfig, ColsConfig
and FieldsetsConfig):
- inherit attributes from parent when not setted in current class
- remove parent attribute when setted to None in current class
- merge with parent ones if setted also in current class
:param config_class_name: could be "TabsConfig", "ColsConfig" or
"FieldsetsConfig"
"""
_final_attrs = {} # Attrs that will be finally added to the created class
reverse_mro = list(it.mro())
reverse_mro.reverse()
for cls in reverse_mro:
if not hasattr(cls, config_class_name): continue
# config_class will be cls.TabsConfig, cls.ColsConfig or
# cls.FieldsetsConfig, according to the given config_class_name
# param
config_class = getattr(cls, config_class_name)
for attr_name in dir(config_class):
# Lets look for the Config attribute of the current inner class
attr = getattr(config_class, attr_name)
# We keep Config instances AND attr_name already in _final_attrs
# because they can be overwritten by None
if not isinstance(attr, Config) and not attr_name in _final_attrs: continue
# Setting some attr to None remove an attr that was setted in a
# parent class
if attr is None and attr_name in _final_attrs:
del _final_attrs[attr_name]
delattr(config_class, attr_name)
else:
# Merge with parent's attr if exists
if attr_name in _final_attrs:
config = Config(**_final_attrs[attr_name]) # Copy it
config.update(attr)
attr = config
_final_attrs[attr_name] = attr

# Add selected Config attributes in the created class
# final_class_config is the it.TabsConfig, it.ColsConfig or
# it.FieldsetsConfig, according to the given config_class_name param
# (Do not confuse with the cls.X ones: `it` is current created class,
# `cls` are the parent classes from which we inherit attributes)
final_class_config = getattr(it, config_class_name)
for attr_name, attr in _final_attrs.iteritems():
setattr(final_class_config, attr_name, attr)
return _final_attrs

# --- Make the TabsConfig attributes overwrittable and inheritable
reverse_mro = list(it.mro())
reverse_mro.reverse()
_final_attrs = {} # Attrs that will be finally added to the created class
for cls in reverse_mro:
if not hasattr(cls, "TabsConfig"): continue
for attr_name in dir(cls.TabsConfig):
attr = getattr(cls.TabsConfig, attr_name)
# We keep Config instances AND attr_name already in _final_attrs
# because they can be overwritten by None
if not isinstance(attr, Config) and not attr_name in _final_attrs: continue
# Setting some attr to None remove an attr that was setted in a
# parent class
if attr is None and attr_name in _final_attrs:
del _final_attrs[attr_name]
delattr(cls.TabsConfig, attr_name)
else:
# Merge with parent's attr if it exists
if attr_name in _final_attrs:
config = Config(**_final_attrs[attr_name]) # Copy it
config.update(attr)
attr = config
_final_attrs[attr_name] = attr
# Add selected tabs in the created class
for attr_name, attr in _final_attrs.iteritems():
setattr(it.TabsConfig, attr_name, attr)

# Define a default tabs order if user as not provided one
_manage_config_class_inheritance("TabsConfig")

# --- Make the ColsConfig attributes overwrittable and inheritable
_manage_config_class_inheritance("ColsConfig")

# --- Make the FieldsetsConfig attributes overwrittable and inheritable
_manage_config_class_inheritance("FieldsetsConfig")

# --- Define a default tabs order if user as not provided one
if not hasattr(it.TabsConfig, 'tabs_order'):
tabs_order = [attr for attr in dir(it.TabsConfig) if not attr.startswith('_')]
tabs_order.sort(key=lambda attr: getattr(it.TabsConfig, attr).creation_counter)
Expand Down
53 changes: 52 additions & 1 deletion admin_tabs/tests/metaadminpageconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
__all__ = [
"TabsConfigsInheritanceTests",
"TabsConfigOrderTests",
"ColsConfigIneritanceTests"
"ColsConfigIneritanceTests",
"FieldsetsConfigIneritanceTests"
]

class TabsConfigsInheritanceTests(TestCase):
Expand Down Expand Up @@ -187,3 +188,53 @@ class ColsConfig:
self.assertEqual(ABC.ColsConfig.c_col["name"], "c_col")
self.failIf(hasattr(ABC.ColsConfig, "d_col"))


class FieldsetsConfigIneritanceTests(TestCase):

def test_should_inherit_from_parent(self):
"""
When a PageConfig inherit from another, it must inherit the fieldsets of its
parent.
"""

class A(TabbedPageConfig):

class FieldsetsConfig:
a_fieldset = Config(name='a_fieldset')

class AB(A):

class FieldsetsConfig:
b_fieldset = Config(name="b_fieldset")

class AD(A):

class FieldsetsConfig:
d_fieldset = Config(name="d_fieldset")

class ABC(AB):

class FieldsetsConfig:
c_fieldset = Config(name="c_fieldset")

# A must have only its attribute
self.failUnless(hasattr(A.FieldsetsConfig, "a_fieldset"))
self.assertEqual(A.FieldsetsConfig.a_fieldset["name"], "a_fieldset")
self.failIf(hasattr(A.FieldsetsConfig, "b_fieldset"))

# AB must have its attribute and A's one
self.failUnless(hasattr(AB.FieldsetsConfig, "b_fieldset"))
self.failUnless(hasattr(AB.FieldsetsConfig, "a_fieldset"))
self.assertEqual(AB.FieldsetsConfig.a_fieldset["name"], "a_fieldset")
self.assertEqual(AB.FieldsetsConfig.b_fieldset["name"], "b_fieldset")
self.failIf(hasattr(AB.FieldsetsConfig, "c_fieldset"))
self.failIf(hasattr(AB.FieldsetsConfig, "d_fieldset"))

# ABC must have its attribute, AB's one and A's one
self.failUnless(hasattr(ABC.FieldsetsConfig, "c_fieldset"))
self.failUnless(hasattr(ABC.FieldsetsConfig, "b_fieldset"))
self.failUnless(hasattr(ABC.FieldsetsConfig, "a_fieldset"))
self.assertEqual(ABC.FieldsetsConfig.a_fieldset["name"], "a_fieldset")
self.assertEqual(ABC.FieldsetsConfig.b_fieldset["name"], "b_fieldset")
self.assertEqual(ABC.FieldsetsConfig.c_fieldset["name"], "c_fieldset")
self.failIf(hasattr(ABC.FieldsetsConfig, "d_fieldset"))

0 comments on commit 95af5d4

Please sign in to comment.