blob: a6bc9253dbbd7a651351e82917edb0628f85ce55 [file] [edit]
# Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
# Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
import types
import unittest
import six
from six.moves import builtins
import astroid
from astroid import builder
from astroid import exceptions
from astroid.interpreter import util as interpreterutil
from astroid import manager
from astroid import nodes
from astroid import test_utils
from astroid import util
class TestHelpers(unittest.TestCase):
def setUp(self):
builtins_name = builtins.__name__
astroid_manager = manager.AstroidManager()
self.builtins = astroid_manager.astroid_cache[builtins_name]
self.manager = manager.AstroidManager()
def _look_up_in_builtins(self, obj_name):
return self.builtins.getattr(obj_name)[0]
def test_object_type(self):
pairs = [
('1', self._look_up_in_builtins('int')),
('[]', self._look_up_in_builtins('list')),
('{1, 2, 3}', self._look_up_in_builtins('set')),
('{1:2, 4:3}', self._look_up_in_builtins('dict')),
('type', self._look_up_in_builtins('type')),
('object', self._look_up_in_builtins('type')),
('object()', self._look_up_in_builtins('object')),
('lambda: None', self._look_up_in_builtins(types.FunctionType.__name__)),
('len', self._look_up_in_builtins(types.BuiltinFunctionType.__name__)),
('None', self._look_up_in_builtins(type(None).__name__)),
('import sys\nsys#@', self._look_up_in_builtins(types.ModuleType.__name__)),
]
for code, expected in pairs:
node = astroid.extract_node(code)
objtype = interpreterutil.object_type(node)
self.assertIs(objtype, expected)
def test_object_type_classes_and_functions(self):
ast_nodes = astroid.extract_node('''
def generator():
yield
class A(object):
def test(self):
self #@
@classmethod
def cls_method(cls): pass
@staticmethod
def static_method(): pass
A #@
A() #@
A.test #@
A().test #@
A.cls_method #@
A().cls_method #@
A.static_method #@
A().static_method #@
generator() #@
''')
from_self = interpreterutil.object_type(ast_nodes[0])
cls = next(ast_nodes[1].infer())
self.assertIs(from_self, cls)
cls_type = interpreterutil.object_type(ast_nodes[1])
self.assertIs(cls_type, self._look_up_in_builtins('type'))
instance_type = interpreterutil.object_type(ast_nodes[2])
cls = next(ast_nodes[2].infer())._proxied
self.assertIs(instance_type, cls)
expected_method_types = [
(ast_nodes[3], types.MethodType.__name__ if six.PY2 else types.FunctionType.__name__),
(ast_nodes[4], types.MethodType.__name__),
(ast_nodes[5], types.MethodType.__name__),
(ast_nodes[6], types.MethodType.__name__),
(ast_nodes[7], types.FunctionType.__name__),
(ast_nodes[8], types.FunctionType.__name__),
(ast_nodes[9], types.GeneratorType.__name__),
]
for node, expected in expected_method_types:
node_type = interpreterutil.object_type(node)
expected_type = self._look_up_in_builtins(expected)
self.assertIs(node_type, expected_type)
@test_utils.require_version(minver='3.0')
def test_object_type_metaclasses(self):
module = builder.parse('''
import abc
class Meta(metaclass=abc.ABCMeta):
pass
meta_instance = Meta()
''')
meta_type = interpreterutil.object_type(module['Meta'])
self.assertIs(meta_type, module['Meta'].metaclass())
meta_instance = next(module['meta_instance'].infer())
instance_type = interpreterutil.object_type(meta_instance)
self.assertIs(instance_type, module['Meta'])
@test_utils.require_version(minver='3.0')
def test_object_type_most_derived(self):
node = astroid.extract_node('''
class A(type):
def __new__(*args, **kwargs):
return type.__new__(*args, **kwargs)
class B(object): pass
class C(object, metaclass=A): pass
# The most derived metaclass of D is A rather than type.
class D(B , C): #@
pass
''')
metaclass = node.metaclass()
self.assertEqual(metaclass.name, 'A')
obj_type = interpreterutil.object_type(node)
self.assertEqual(metaclass, obj_type)
def test_inference_errors(self):
node = astroid.extract_node('''
from unknown import Unknown
u = Unknown #@
''')
self.assertEqual(interpreterutil.object_type(node), util.Uninferable)
def test_object_type_too_many_types(self):
node = astroid.extract_node('''
from unknown import Unknown
def test(x):
if x:
return lambda: None
else:
return 1
test(Unknown) #@
''')
self.assertEqual(interpreterutil.object_type(node), util.Uninferable)
def test_is_subtype(self):
ast_nodes = astroid.extract_node('''
class int_subclass(int):
pass
class A(object): pass #@
class B(A): pass #@
class C(A): pass #@
int_subclass() #@
''')
cls_a = ast_nodes[0]
cls_b = ast_nodes[1]
cls_c = ast_nodes[2]
int_subclass = ast_nodes[3]
int_subclass = interpreterutil.object_type(next(int_subclass.infer()))
base_int = self._look_up_in_builtins('int')
self.assertTrue(interpreterutil.is_subtype(int_subclass, base_int))
self.assertTrue(interpreterutil.is_supertype(base_int, int_subclass))
self.assertTrue(interpreterutil.is_supertype(cls_a, cls_b))
self.assertTrue(interpreterutil.is_supertype(cls_a, cls_c))
self.assertTrue(interpreterutil.is_subtype(cls_b, cls_a))
self.assertTrue(interpreterutil.is_subtype(cls_c, cls_a))
self.assertFalse(interpreterutil.is_subtype(cls_a, cls_b))
self.assertFalse(interpreterutil.is_subtype(cls_a, cls_b))
@test_utils.require_version(maxver='3.0')
def test_is_subtype_supertype_old_style_classes(self):
cls_a, cls_b = astroid.extract_node('''
class A: #@
pass
class B(A): #@
pass
''')
self.assertFalse(interpreterutil.is_subtype(cls_a, cls_b))
self.assertFalse(interpreterutil.is_subtype(cls_b, cls_a))
self.assertFalse(interpreterutil.is_supertype(cls_a, cls_b))
self.assertFalse(interpreterutil.is_supertype(cls_b, cls_a))
def test_is_subtype_supertype_mro_error(self):
cls_e, cls_f = astroid.extract_node('''
class A(object): pass
class B(A): pass
class C(A): pass
class D(B, C): pass
class E(C, B): pass #@
class F(D, E): pass #@
''')
self.assertFalse(interpreterutil.is_subtype(cls_e, cls_f))
self.assertFalse(interpreterutil.is_subtype(cls_e, cls_f))
with self.assertRaises(exceptions._NonDeducibleTypeHierarchy):
interpreterutil.is_subtype(cls_f, cls_e)
self.assertFalse(interpreterutil.is_supertype(cls_f, cls_e))
def test_is_subtype_supertype_unknown_bases(self):
cls_a, cls_b = astroid.extract_node('''
from unknown import Unknown
class A(Unknown): pass #@
class B(A): pass #@
''')
with self.assertRaises(exceptions._NonDeducibleTypeHierarchy):
interpreterutil.is_subtype(cls_a, cls_b)
with self.assertRaises(exceptions._NonDeducibleTypeHierarchy):
interpreterutil.is_supertype(cls_a, cls_b)
def test_is_subtype_supertype_unrelated_classes(self):
cls_a, cls_b = astroid.extract_node('''
class A(object): pass #@
class B(object): pass #@
''')
self.assertFalse(interpreterutil.is_subtype(cls_a, cls_b))
self.assertFalse(interpreterutil.is_subtype(cls_b, cls_a))
self.assertFalse(interpreterutil.is_supertype(cls_a, cls_b))
self.assertFalse(interpreterutil.is_supertype(cls_b, cls_a))
def test_is_subtype_supertype_classes_no_type_ancestor(self):
cls_a = astroid.extract_node('''
class A(object): #@
pass
''')
builtin_type = self._look_up_in_builtins('type')
self.assertFalse(interpreterutil.is_supertype(builtin_type, cls_a))
self.assertFalse(interpreterutil.is_subtype(cls_a, builtin_type))
def test_is_subtype_supertype_classes_metaclasses(self):
cls_a = astroid.extract_node('''
class A(type): #@
pass
''')
builtin_type = self._look_up_in_builtins('type')
self.assertTrue(interpreterutil.is_supertype(builtin_type, cls_a))
self.assertTrue(interpreterutil.is_subtype(cls_a, builtin_type))
@test_utils.require_version(maxver='3.0')
def test_old_style_class(self):
cls = astroid.extract_node('''class A: pass''')
builtin_type = self._look_up_in_builtins('type')
self.assertEqual(interpreterutil.object_type(cls), builtin_type)
if __name__ == '__main__':
unittest.main()