Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Rewrite `ConfigurationMeta.__new__` to make gpyconf support configura…

…tion inheritance which was broken until now.
  • Loading branch information...
commit 6664ddab8bd923dbf7d92a6b9f0aff9c805e62c4 1 parent a3b3a4c
@jonashaag authored
Showing with 56 additions and 16 deletions.
  1. +37 −0 examples/unittests/inheritance.py
  2. +19 −16 src/gpyconf.py
View
37 examples/unittests/inheritance.py
@@ -0,0 +1,37 @@
+import unittest
+
+import math
+from gpyconf import Configuration
+from gpyconf.fields import IntegerField, CharField, FloatField
+
+class ConfigurationSuperclass(Configuration):
+ field1_from_superclass = IntegerField()
+
+class ConfigurationSuperclass2(ConfigurationSuperclass):
+ field1_from_superclass2 = CharField()
+
+class InheritedConfiguration(ConfigurationSuperclass2):
+ field1_from_subclass = FloatField()
+
+
+class InheritanceTest(unittest.TestCase):
+ def runTest(self):
+ self.config = InheritedConfiguration()
+ self.assert_('field1_from_superclass' in self.config.fields)
+ self.assert_('field1_from_superclass2' in self.config.fields)
+ self.assert_('field1_from_subclass' in self.config.fields)
+
+ self.config.field1_from_superclass = 42
+ self.config.field1_from_superclass2 = 'hello world'
+ self.config.field1_from_subclass = round(math.pi, 10)
+
+ self.config.save()
+ del self.config
+
+ self.config = InheritedConfiguration()
+ self.assertEqual(self.config.field1_from_superclass, 42)
+ self.assertEqual(self.config.field1_from_superclass2, 'hello world')
+ self.assertEqual(self.config.field1_from_subclass, round(math.pi, 10))
+
+if __name__ == '__main__':
+ unittest.main()
View
35 src/gpyconf.py
@@ -48,23 +48,27 @@ def __init__(self, *args, **kwargs):
class ConfigurationMeta(type):
""" Metaclass for the :class:`Configuration` class """
- def __init__(self, name, bases, dict):
- def sort_by_creation_counter(field1, field2):
- return field1[1].creation_counter - field2[1].creation_counter
+ def __new__(cls, name, bases, class_dict):
+ super_new = super(ConfigurationMeta, cls).__new__
+ parents = tuple(base for base in bases
+ if isinstance(base, ConfigurationMeta))
+ if not parents:
+ # This isn't a subclass of ConfigurationMeta, don't do anything special
+ return super_new(cls, name, bases, class_dict)
- self.fields = dicts.FieldsDict()
+ class_fields = class_dict['fields'] = dicts.FieldsDict()
- _fields = [(name, field) for name, field in dict.iteritems()
- if isinstance(field, fields.Field)]
- _fields.sort(cmp=sort_by_creation_counter)
+ for superclass in parents:
+ for name, field in superclass.fields.iteritems():
+ class_fields[name] = field
+ field.field_var = name
- for name, instance in _fields:
- instance.field_var = name
- # let the field know what variable name it got
- self.fields[name] = instance
- delattr(self, name)
- # delete the attribute (we don't need it anymore; fields are
- # handled by ``fields`` dict and __getattr__, __setattr__ stuff)
+ for name, obj in class_dict.items():
+ if isinstance(obj, fields.Field):
+ class_fields[name] = class_dict.pop(name)
+ obj.field_var = name
+
+ return super_new(cls, name, bases, class_dict)
class Configuration(MVCComponent):
@@ -95,9 +99,8 @@ def callback(sender_instance, field_instance, new_field_value):
...
"""
__metaclass__ = ConfigurationMeta
+ fields = dict()
- #: a :class:`dict` mapping all attribute names to field instances
- fields = None
frontend_instance = None
initially_read = False
logger = None
Please sign in to comment.
Something went wrong with that request. Please try again.