summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Euresti <david@dropbox.com>2017-01-03 20:54:36 -0800
committerClaudiu Popa <pcmanticore@gmail.com>2017-01-22 14:48:48 +0200
commit096ad490f89c568ca0da8f15dd74457da9be377b (patch)
tree516235186ef426d6c6dff91644e715f0230dfa87
parenta1fc66a981a8d25467ed720af973aa7168343915 (diff)
downloadastroid-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--ChangeLog2
-rw-r--r--astroid/tests/unittest_inference.py16
-rw-r--r--astroid/tree/scoped_nodes.py25
3 files changed, 43 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 1baa403c..558b3857 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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