summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-10-26 12:30:08 +0000
committerClaudiu Popa <pcmanticore@gmail.com>2015-10-26 12:30:08 +0000
commit8a0343728bc9b578d533ef5aa21e1412a8951ce6 (patch)
tree0bfe86d443ed10dc9a5b41d83d8e1ab6b240dd69
parent033a215bb1d1a7f4b954ef99667e41d9e6fed92b (diff)
downloadastroid-8a0343728bc9b578d533ef5aa21e1412a8951ce6.tar.gz
Class.getattr('__mro__') returns the actual MRO.
Also, Class.getattr('__bases__') returns actual bases. It previously didn't work correctly, because it was putting the entire ancestors into the Tuple object and it put those classes into the wrong attribute. Closes issue #128.
-rw-r--r--ChangeLog3
-rw-r--r--astroid/scoped_nodes.py14
-rw-r--r--astroid/tests/unittest_scoped_nodes.py23
3 files changed, 34 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 88e4aa2..6b93e83 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,9 @@ Change log for the astroid package (used to be astng)
=====================================================
--
+
+ * Class.getattr('__mro__') returns the actual MRO. Closes issue #128.
+
* The logilab-common dependency is not needed anymore as the needed code
was integrated into astroid.
diff --git a/astroid/scoped_nodes.py b/astroid/scoped_nodes.py
index 31fc2f8..e6e3324 100644
--- a/astroid/scoped_nodes.py
+++ b/astroid/scoped_nodes.py
@@ -1359,14 +1359,16 @@ class ClassDef(mixins.FilterStmtsMixin, LocalsDictNodeNG,
if name in self.special_attributes:
if name == '__module__':
return [node_classes.const_factory(self.root().qname())] + values
- # FIXME: do we really need the actual list of ancestors?
- # returning [Tuple()] + values don't break any test
- # this is ticket http://www.logilab.org/ticket/52785
- # XXX need proper meta class handling + MRO implementation
- if name == '__bases__' or (name == '__mro__' and self.newstyle):
+ if name == '__bases__':
node = node_classes.Tuple()
- node.items = self.ancestors(recurs=True, context=context)
+ elts = list(self._inferred_bases(context))
+ node.postinit(elts=elts)
return [node] + values
+ if name == '__mro__' and self.newstyle:
+ mro = self.mro()
+ node = node_classes.Tuple()
+ node.postinit(elts=mro)
+ return [node]
return std_special_attributes(self, name)
# don't modify the list in self.locals!
values = list(values)
diff --git a/astroid/tests/unittest_scoped_nodes.py b/astroid/tests/unittest_scoped_nodes.py
index bf090da..8e82290 100644
--- a/astroid/tests/unittest_scoped_nodes.py
+++ b/astroid/tests/unittest_scoped_nodes.py
@@ -584,6 +584,29 @@ class ClassNodeTest(ModuleLoader, unittest.TestCase):
self.assertEqual(len(cls.getattr('__dict__')), 1)
self.assertEqual(len(cls.getattr('__mro__')), 1)
+ def test__mro__attribute(self):
+ node = test_utils.extract_node('''
+ class A(object): pass
+ class B(object): pass
+ class C(A, B): pass
+ ''')
+ mro = node.getattr('__mro__')[0]
+ self.assertIsInstance(mro, nodes.Tuple)
+ self.assertEqual(mro.elts, node.mro())
+
+ def test__bases__attribute(self):
+ node = test_utils.extract_node('''
+ class A(object): pass
+ class B(object): pass
+ class C(A, B): pass
+ class D(C): pass
+ ''')
+ bases = node.getattr('__bases__')[0]
+ self.assertIsInstance(bases, nodes.Tuple)
+ self.assertEqual(len(bases.elts), 1)
+ self.assertIsInstance(bases.elts[0], nodes.ClassDef)
+ self.assertEqual(bases.elts[0].name, 'C')
+
def test_cls_special_attributes_2(self):
astroid = builder.parse('''
class A: pass