Skip to content

Commit f905bd8

Browse files
committed
Fix for issues #91 and #96: newobject breaks multiple inheritance in v0.13
Also add related tests (currently failing) for multiple inheritance from other future types
1 parent 17be3ae commit f905bd8

File tree

6 files changed

+138
-2
lines changed

6 files changed

+138
-2
lines changed

future/tests/test_bytes.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,31 @@ def test_mod(self):
600600
with self.assertRaises(TypeError):
601601
bytes(b'%r' % 'abc')
602602

603+
def test_multiple_inheritance(self):
604+
"""
605+
Issue #96 (for newbytes instead of newobject)
606+
"""
607+
import collections
608+
609+
class Base(bytes):
610+
pass
611+
612+
class Foo(Base, collections.Container):
613+
def __contains__(self, item):
614+
return False
615+
616+
def test_with_metaclass_and_bytes(self):
617+
"""
618+
Issue #91 (for newdict instead of newobject)
619+
"""
620+
from future.utils import with_metaclass
621+
622+
class MetaClass(type):
623+
pass
624+
625+
class TestClass(with_metaclass(MetaClass, bytes)):
626+
pass
627+
603628

604629
if __name__ == '__main__':
605630
unittest.main()

future/tests/test_dict.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,32 @@ def test_braces_create_newdict_object(self):
106106
d = self.d1
107107
self.assertTrue(type(d) == dict)
108108

109+
def test_multiple_inheritance(self):
110+
"""
111+
Issue #96 (for newdict instead of newobject)
112+
"""
113+
import collections
114+
115+
class Base(dict):
116+
pass
117+
118+
class Foo(Base, collections.Container):
119+
def __contains__(self, item):
120+
return False
121+
122+
def test_with_metaclass_and_dict(self):
123+
"""
124+
Issue #91 (for newdict instead of newobject)
125+
"""
126+
from future.utils import with_metaclass
127+
128+
class MetaClass(type):
129+
pass
130+
131+
class TestClass(with_metaclass(MetaClass, dict)):
132+
pass
133+
134+
109135

110136
if __name__ == '__main__':
111137
unittest.main()

future/tests/test_int.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,31 @@ class myint(int):
10381038
self.assertRaises(TypeError, myint.from_bytes, mytype(0), 'big')
10391039
# self.assertRaises(TypeError, int.from_bytes, mytype(0), 'big', True)
10401040

1041+
def test_multiple_inheritance(self):
1042+
"""
1043+
Issue #96 (for newint instead of newobject)
1044+
"""
1045+
import collections
1046+
1047+
class Base(int):
1048+
pass
1049+
1050+
class Foo(Base, collections.Container):
1051+
def __add__(self, other):
1052+
return 0
1053+
1054+
def test_with_metaclass_and_int(self):
1055+
"""
1056+
Issue #91 (for newint instead of newobject)
1057+
"""
1058+
from future.utils import with_metaclass
1059+
1060+
class MetaClass(type):
1061+
pass
1062+
1063+
class TestClass(with_metaclass(MetaClass, int)):
1064+
pass
1065+
10411066

10421067
if __name__ == "__main__":
10431068
unittest.main()

future/tests/test_object.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from future import utils
88
from future.builtins import object, str, next, int, super
99
from future.utils import implements_iterator, python_2_unicode_compatible
10-
from future.tests.base import unittest
10+
from future.tests.base import unittest, expectedFailurePY2
1111

1212

1313
class TestNewObject(unittest.TestCase):
@@ -162,6 +162,7 @@ class C(A):
162162
self.assertFalse(isinstance(b, C))
163163
self.assertTrue(isinstance(c, C))
164164

165+
@expectedFailurePY2
165166
def test_types_isinstance_newobject(self):
166167
a = list()
167168
b = dict()
@@ -204,6 +205,31 @@ def __int__(self):
204205
if utils.PY2:
205206
self.assertEqual(long(a), 0)
206207

208+
def test_multiple_inheritance(self):
209+
"""
210+
Issue #96
211+
"""
212+
import collections
213+
214+
class Base(object):
215+
pass
216+
217+
class Foo(Base, collections.Container):
218+
def __contains__(self, item):
219+
return False
220+
221+
def test_with_metaclass_and_object(self):
222+
"""
223+
Issue #91
224+
"""
225+
from future.utils import with_metaclass
226+
227+
class MetaClass(type):
228+
pass
229+
230+
class TestClass(with_metaclass(MetaClass, object)):
231+
pass
232+
207233

208234
if __name__ == '__main__':
209235
unittest.main()

future/tests/test_str.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,31 @@ def test_maketrans_translate(self):
524524
self.assertRaises(TypeError, 'hello'.translate)
525525
self.assertRaises(TypeError, 'abababc'.translate, 'abc', 'xyz')
526526

527+
def test_multiple_inheritance(self):
528+
"""
529+
Issue #96 (for newstr instead of newobject)
530+
"""
531+
import collections
532+
533+
class Base(str):
534+
pass
535+
536+
class Foo(Base, collections.Container):
537+
def __contains__(self, item):
538+
return False
539+
540+
def test_with_metaclass_and_str(self):
541+
"""
542+
Issue #91 (for newstr instead of newobject)
543+
"""
544+
from future.utils import with_metaclass
545+
546+
class MetaClass(type):
547+
pass
548+
549+
class TestClass(with_metaclass(MetaClass, str)):
550+
pass
551+
527552

528553
if __name__ == '__main__':
529554
unittest.main()

future/types/newobject.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,17 @@ def __instancecheck__(cls, instance):
5353
else:
5454
return issubclass(instance.__class__, cls)
5555

56+
# We no longer define a metaclass for newobject because this breaks multiple
57+
# inheritance and custom metaclass use with this exception:
5658

57-
class newobject(with_metaclass(BaseNewObject, _builtin_object)):
59+
# TypeError: Error when calling the metaclass bases
60+
# metaclass conflict: the metaclass of a derived class must be a
61+
# (non-strict) subclass of the metaclasses of all its bases
62+
63+
# See issues #91 and #96.
64+
65+
66+
class newobject(object):
5867
"""
5968
A magical object class that provides Python 2 compatibility methods::
6069
next

0 commit comments

Comments
 (0)