diff options
author | David Euresti <david@dropbox.com> | 2017-01-03 20:54:36 -0800 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2017-01-22 14:48:48 +0200 |
commit | 096ad490f89c568ca0da8f15dd74457da9be377b (patch) | |
tree | 516235186ef426d6c6dff91644e715f0230dfa87 | |
parent | a1fc66a981a8d25467ed720af973aa7168343915 (diff) | |
download | astroid-git-096ad490f89c568ca0da8f15dd74457da9be377b.tar.gz |
Implement __getitem__ inference for classes (using the metaclass)
Essentially implement the getitem method in ClassDef which returns the correct value.
Fixes #348
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | astroid/tests/unittest_inference.py | 16 | ||||
-rw-r--r-- | astroid/tree/scoped_nodes.py | 25 |
3 files changed, 43 insertions, 0 deletions
@@ -7,6 +7,8 @@ Change log for the astroid package (used to be astng) Classes can support keyword arguments, which are passed when a class is constructed using ``__new__``. + * ClassDef now supports __getitem__ inference through the metaclass. + * getitem() method accepts nodes now, instead of Python objects. * Add support for explicit namespace packages, created with pkg_resources. diff --git a/astroid/tests/unittest_inference.py b/astroid/tests/unittest_inference.py index 497b286c..0d1ea266 100644 --- a/astroid/tests/unittest_inference.py +++ b/astroid/tests/unittest_inference.py @@ -2537,6 +2537,22 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): for node in ast_nodes: self.assertEqual(next(node.infer()), util.Uninferable) + def test_metaclass__getitem__(self): + ast_node = extract_node(''' + class Meta(type): + def __getitem__(cls, arg): + return 24 + import six + @six.add_metaclass(Meta) + class A(object): + pass + + A['Awesome'] #@ + ''') + inferred = next(ast_node.infer()) + self.assertIsInstance(inferred, nodes.Const) + self.assertEqual(inferred.value, 24) + def test_bin_op_classes(self): ast_node = extract_node(''' class Meta(type): diff --git a/astroid/tree/scoped_nodes.py b/astroid/tree/scoped_nodes.py index 257b13d9..31dfc9cd 100644 --- a/astroid/tree/scoped_nodes.py +++ b/astroid/tree/scoped_nodes.py @@ -34,6 +34,7 @@ from astroid.interpreter import objects from astroid.interpreter import objectmodel from astroid.interpreter import runtimeabc from astroid.interpreter.util import infer_stmts +from astroid.interpreter import dunder_lookup from astroid import manager from astroid.tree import base as treebase from astroid.tree import node_classes @@ -1671,6 +1672,30 @@ class ClassDef(QualifiedNameMixin, base.FilterStmtsMixin, pass return False + def getitem(self, index, context=None): + """Return the inference of a subscript. + + This is basically looking up the method in the metaclass and calling it. + """ + try: + methods = dunder_lookup.lookup(self, '__getitem__') + except (exceptions.AttributeInferenceError, + exceptions.NotSupportedError) as error: + util.reraise(exceptions.InferenceError(**vars(error))) + + method = methods[0] + + # Create a new callcontext for providing index as an argument. + if context: + new_context = context.clone() + else: + new_context = contextmod.InferenceContext() + + new_context.callcontext = contextmod.CallContext(args=[index]) + new_context.boundnode = self + + return next(method.infer_call_result(self, new_context)) + def methods(self): """return an iterator on all methods defined in the class and its ancestors |