Commits

David Schneider  committed 8390004

add support for mixins

  • Participants
  • Parent commits aee2035

Comments (0)

Files changed (2)

             raise RPythonTypeError(
                 "Class %s inherits from non-RPython bases clases: %r"
                     % (name, offending_bases,))
-        # XXX allow mixins?
-        if len(bases) > 1:
+        offending_bases = cls.check_mixin_bases(name, bases)
+        if len(offending_bases) > 0:
             raise RPythonTypeError(
-                "Class %s inherits from more than one class: %r"
-                    % (name, bases,))
+                "Class %s inherits from more than one class (non mixin): %r"
+                    % (name, offending_bases,))
         result = type.__new__(cls, name, bases, dct)
         for key, value in dct.iteritems():
             if isinstance(value, attribute):
         f = lambda x: not isinstance(x, RPyType) and name != 'RPyObject'
         return filter(f, bases)
 
+    @staticmethod
+    def check_mixin_bases(name, bases):
+        def f(x):
+            if x is bases[0] or name == 'RPyObject':
+                return False
+            return not (hasattr(x, '_mixin_') and x._mixin_)
+        return filter(f, bases)
+
 
 class RPyObject(object):
     __metaclass__ = RPythonClass
 
     py.test.raises(r.RPythonTypeError, "class AD(A, D): pass")
 
+
+def test_mixins():
+    class A(r.RPyObject):
+        pass
+
+    class B(object):
+        _mixin_ = True
+
+    class C(r.RPyObject):
+        _mixin_ = True
+        a = r.attribute(int)
+
+    class AC(A, C):
+        pass
+
+    py.test.raises(r.RPythonTypeError, "class AB(A, B): pass")
+
+    assert hasattr(AC(), 'a')
+
+
 def test_default_value():
     class A(r.RPyObject):
         x = r.attribute(int, default_value=41)