summaryrefslogtreecommitdiff
path: root/tests/test_object_model.py
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2023-02-09 21:54:24 +0100
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2023-02-09 23:23:31 +0100
commitd4852be40cdf88d61d2c13fce22f1ec08fa23f3f (patch)
treeeeafa70f68063de0d87119e871807bd4f0af6c62 /tests/test_object_model.py
parentdc98a63a9fddf774e29ad340ff40cac3718faac3 (diff)
downloadastroid-git-d4852be40cdf88d61d2c13fce22f1ec08fa23f3f.tar.gz
[brain tests] Rename 'unittest' prefix to 'test'
Diffstat (limited to 'tests/test_object_model.py')
-rw-r--r--tests/test_object_model.py834
1 files changed, 834 insertions, 0 deletions
diff --git a/tests/test_object_model.py b/tests/test_object_model.py
new file mode 100644
index 00000000..8f41eda5
--- /dev/null
+++ b/tests/test_object_model.py
@@ -0,0 +1,834 @@
+# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
+# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
+# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
+
+import unittest
+import xml
+
+import pytest
+
+import astroid
+from astroid import bases, builder, nodes, objects, test_utils, util
+from astroid.const import PY311_PLUS
+from astroid.exceptions import InferenceError
+
+try:
+ import six # pylint: disable=unused-import
+
+ HAS_SIX = True
+except ImportError:
+ HAS_SIX = False
+
+
+class InstanceModelTest(unittest.TestCase):
+ def test_instance_special_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ class A:
+ "test"
+ def __init__(self):
+ self.a = 42
+ a = A()
+ a.__class__ #@
+ a.__module__ #@
+ a.__doc__ #@
+ a.__dict__ #@
+ """,
+ module_name="fake_module",
+ )
+ assert isinstance(ast_nodes, list)
+ cls = next(ast_nodes[0].infer())
+ self.assertIsInstance(cls, astroid.ClassDef)
+ self.assertEqual(cls.name, "A")
+
+ module = next(ast_nodes[1].infer())
+ self.assertIsInstance(module, astroid.Const)
+ self.assertEqual(module.value, "fake_module")
+
+ doc = next(ast_nodes[2].infer())
+ self.assertIsInstance(doc, astroid.Const)
+ self.assertEqual(doc.value, "test")
+
+ dunder_dict = next(ast_nodes[3].infer())
+ self.assertIsInstance(dunder_dict, astroid.Dict)
+ attr = next(dunder_dict.getitem(astroid.Const("a")).infer())
+ self.assertIsInstance(attr, astroid.Const)
+ self.assertEqual(attr.value, 42)
+
+ @pytest.mark.xfail(reason="Instance lookup cannot override object model")
+ def test_instance_local_attributes_overrides_object_model(self):
+ # The instance lookup needs to be changed in order for this to work.
+ ast_node = builder.extract_node(
+ """
+ class A:
+ @property
+ def __dict__(self):
+ return []
+ A().__dict__
+ """
+ )
+ inferred = next(ast_node.infer())
+ self.assertIsInstance(inferred, astroid.List)
+ self.assertEqual(inferred.elts, [])
+
+
+class BoundMethodModelTest(unittest.TestCase):
+ def test_bound_method_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ class A:
+ def test(self): pass
+ a = A()
+ a.test.__func__ #@
+ a.test.__self__ #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ func = next(ast_nodes[0].infer())
+ self.assertIsInstance(func, astroid.FunctionDef)
+ self.assertEqual(func.name, "test")
+
+ self_ = next(ast_nodes[1].infer())
+ self.assertIsInstance(self_, astroid.Instance)
+ self.assertEqual(self_.name, "A")
+
+
+class UnboundMethodModelTest(unittest.TestCase):
+ def test_unbound_method_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ class A:
+ def test(self): pass
+ t = A.test
+ t.__class__ #@
+ t.__func__ #@
+ t.__self__ #@
+ t.im_class #@
+ t.im_func #@
+ t.im_self #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ cls = next(ast_nodes[0].infer())
+ self.assertIsInstance(cls, astroid.ClassDef)
+ unbound_name = "function"
+
+ self.assertEqual(cls.name, unbound_name)
+
+ func = next(ast_nodes[1].infer())
+ self.assertIsInstance(func, astroid.FunctionDef)
+ self.assertEqual(func.name, "test")
+
+ self_ = next(ast_nodes[2].infer())
+ self.assertIsInstance(self_, astroid.Const)
+ self.assertIsNone(self_.value)
+
+ self.assertEqual(cls.name, next(ast_nodes[3].infer()).name)
+ self.assertEqual(func, next(ast_nodes[4].infer()))
+ self.assertIsNone(next(ast_nodes[5].infer()).value)
+
+
+class ClassModelTest(unittest.TestCase):
+ def test_priority_to_local_defined_values(self) -> None:
+ ast_node = builder.extract_node(
+ """
+ class A:
+ __doc__ = "first"
+ A.__doc__ #@
+ """
+ )
+ inferred = next(ast_node.infer())
+ self.assertIsInstance(inferred, astroid.Const)
+ self.assertEqual(inferred.value, "first")
+
+ def test_class_model_correct_mro_subclasses_proxied(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ class A(object):
+ pass
+ A.mro #@
+ A.__subclasses__ #@
+ """
+ )
+ for node in ast_nodes:
+ inferred = next(node.infer())
+ self.assertIsInstance(inferred, astroid.BoundMethod)
+ self.assertIsInstance(inferred._proxied, astroid.FunctionDef)
+ self.assertIsInstance(inferred.bound, astroid.ClassDef)
+ self.assertEqual(inferred.bound.name, "type")
+
+ def test_class_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ class A(object):
+ "test"
+
+ class B(A): pass
+ class C(A): pass
+
+ A.__module__ #@
+ A.__name__ #@
+ A.__qualname__ #@
+ A.__doc__ #@
+ A.__mro__ #@
+ A.mro() #@
+ A.__bases__ #@
+ A.__class__ #@
+ A.__dict__ #@
+ A.__subclasses__() #@
+ """,
+ module_name="fake_module",
+ )
+ assert isinstance(ast_nodes, list)
+ module = next(ast_nodes[0].infer())
+ self.assertIsInstance(module, astroid.Const)
+ self.assertEqual(module.value, "fake_module")
+
+ name = next(ast_nodes[1].infer())
+ self.assertIsInstance(name, astroid.Const)
+ self.assertEqual(name.value, "A")
+
+ qualname = next(ast_nodes[2].infer())
+ self.assertIsInstance(qualname, astroid.Const)
+ self.assertEqual(qualname.value, "fake_module.A")
+
+ doc = next(ast_nodes[3].infer())
+ self.assertIsInstance(doc, astroid.Const)
+ self.assertEqual(doc.value, "test")
+
+ mro = next(ast_nodes[4].infer())
+ self.assertIsInstance(mro, astroid.Tuple)
+ self.assertEqual([cls.name for cls in mro.elts], ["A", "object"])
+
+ called_mro = next(ast_nodes[5].infer())
+ self.assertEqual(called_mro.elts, mro.elts)
+
+ base_nodes = next(ast_nodes[6].infer())
+ self.assertIsInstance(base_nodes, astroid.Tuple)
+ self.assertEqual([cls.name for cls in base_nodes.elts], ["object"])
+
+ cls = next(ast_nodes[7].infer())
+ self.assertIsInstance(cls, astroid.ClassDef)
+ self.assertEqual(cls.name, "type")
+
+ cls_dict = next(ast_nodes[8].infer())
+ self.assertIsInstance(cls_dict, astroid.Dict)
+
+ subclasses = next(ast_nodes[9].infer())
+ self.assertIsInstance(subclasses, astroid.List)
+ self.assertEqual([cls.name for cls in subclasses.elts], ["B", "C"])
+
+
+class ModuleModelTest(unittest.TestCase):
+ def test_priority_to_local_defined_values(self) -> None:
+ ast_node = astroid.parse(
+ """
+ __file__ = "mine"
+ """
+ )
+ file_value = next(ast_node.igetattr("__file__"))
+ self.assertIsInstance(file_value, astroid.Const)
+ self.assertEqual(file_value.value, "mine")
+
+ def test__path__not_a_package(self) -> None:
+ ast_node = builder.extract_node(
+ """
+ import sys
+ sys.__path__ #@
+ """
+ )
+ with self.assertRaises(InferenceError):
+ next(ast_node.infer())
+
+ def test_module_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ import xml
+ xml.__path__ #@
+ xml.__name__ #@
+ xml.__doc__ #@
+ xml.__file__ #@
+ xml.__spec__ #@
+ xml.__loader__ #@
+ xml.__cached__ #@
+ xml.__package__ #@
+ xml.__dict__ #@
+ xml.__init__ #@
+ xml.__new__ #@
+
+ xml.__subclasshook__ #@
+ xml.__str__ #@
+ xml.__sizeof__ #@
+ xml.__repr__ #@
+ xml.__reduce__ #@
+
+ xml.__setattr__ #@
+ xml.__reduce_ex__ #@
+ xml.__lt__ #@
+ xml.__eq__ #@
+ xml.__gt__ #@
+ xml.__format__ #@
+ xml.__delattr___ #@
+ xml.__getattribute__ #@
+ xml.__hash__ #@
+ xml.__dir__ #@
+ xml.__call__ #@
+ xml.__closure__ #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ path = next(ast_nodes[0].infer())
+ self.assertIsInstance(path, astroid.List)
+ self.assertIsInstance(path.elts[0], astroid.Const)
+ self.assertEqual(path.elts[0].value, xml.__path__[0])
+
+ name = next(ast_nodes[1].infer())
+ self.assertIsInstance(name, astroid.Const)
+ self.assertEqual(name.value, "xml")
+
+ doc = next(ast_nodes[2].infer())
+ self.assertIsInstance(doc, astroid.Const)
+ self.assertEqual(doc.value, xml.__doc__)
+
+ file_ = next(ast_nodes[3].infer())
+ self.assertIsInstance(file_, astroid.Const)
+ self.assertEqual(file_.value, xml.__file__.replace(".pyc", ".py"))
+
+ for ast_node in ast_nodes[4:7]:
+ inferred = next(ast_node.infer())
+ self.assertIs(inferred, astroid.Uninferable)
+
+ package = next(ast_nodes[7].infer())
+ self.assertIsInstance(package, astroid.Const)
+ self.assertEqual(package.value, "xml")
+
+ dict_ = next(ast_nodes[8].infer())
+ self.assertIsInstance(dict_, astroid.Dict)
+
+ init_ = next(ast_nodes[9].infer())
+ assert isinstance(init_, bases.BoundMethod)
+ init_result = next(init_.infer_call_result(nodes.Call()))
+ assert isinstance(init_result, nodes.Const)
+ assert init_result.value is None
+
+ new_ = next(ast_nodes[10].infer())
+ assert isinstance(new_, bases.BoundMethod)
+
+ # The following nodes are just here for theoretical completeness,
+ # and they either return Uninferable or raise InferenceError.
+ for ast_node in ast_nodes[11:28]:
+ with pytest.raises(InferenceError):
+ next(ast_node.infer())
+
+
+class FunctionModelTest(unittest.TestCase):
+ def test_partial_descriptor_support(self) -> None:
+ bound, result = builder.extract_node(
+ """
+ class A(object): pass
+ def test(self): return 42
+ f = test.__get__(A(), A)
+ f #@
+ f() #@
+ """
+ )
+ bound = next(bound.infer())
+ self.assertIsInstance(bound, astroid.BoundMethod)
+ self.assertEqual(bound._proxied._proxied.name, "test")
+ result = next(result.infer())
+ self.assertIsInstance(result, astroid.Const)
+ self.assertEqual(result.value, 42)
+
+ def test___get__has_extra_params_defined(self) -> None:
+ node = builder.extract_node(
+ """
+ def test(self): return 42
+ test.__get__
+ """
+ )
+ inferred = next(node.infer())
+ self.assertIsInstance(inferred, astroid.BoundMethod)
+ args = inferred.args.args
+ self.assertEqual(len(args), 2)
+ self.assertEqual([arg.name for arg in args], ["self", "type"])
+
+ @test_utils.require_version(minver="3.8")
+ def test__get__and_positional_only_args(self):
+ node = builder.extract_node(
+ """
+ def test(self, a, b, /, c): return a + b + c
+ test.__get__(test)(1, 2, 3)
+ """
+ )
+ inferred = next(node.infer())
+ assert inferred is util.Uninferable
+
+ @pytest.mark.xfail(reason="Descriptors cannot infer what self is")
+ def test_descriptor_not_inferrring_self(self):
+ # We can't infer __get__(X, Y)() when the bounded function
+ # uses self, because of the tree's parent not being propagating good enough.
+ result = builder.extract_node(
+ """
+ class A(object):
+ x = 42
+ def test(self): return self.x
+ f = test.__get__(A(), A)
+ f() #@
+ """
+ )
+ result = next(result.infer())
+ self.assertIsInstance(result, astroid.Const)
+ self.assertEqual(result.value, 42)
+
+ def test_descriptors_binding_invalid(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ class A: pass
+ def test(self): return 42
+ test.__get__()() #@
+ test.__get__(2, 3, 4) #@
+ """
+ )
+ for node in ast_nodes:
+ with self.assertRaises(InferenceError):
+ next(node.infer())
+
+ def test_descriptor_error_regression(self) -> None:
+ """Make sure the following code does node cause an exception."""
+ node = builder.extract_node(
+ """
+ class MyClass:
+ text = "MyText"
+
+ def mymethod1(self):
+ return self.text
+
+ def mymethod2(self):
+ return self.mymethod1.__get__(self, MyClass)
+
+
+ cl = MyClass().mymethod2()()
+ cl #@
+ """
+ )
+ assert isinstance(node, nodes.NodeNG)
+ [const] = node.inferred()
+ assert const.value == "MyText"
+
+ def test_function_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ '''
+ def func(a=1, b=2):
+ """test"""
+ func.__name__ #@
+ func.__doc__ #@
+ func.__qualname__ #@
+ func.__module__ #@
+ func.__defaults__ #@
+ func.__dict__ #@
+ func.__globals__ #@
+ func.__code__ #@
+ func.__closure__ #@
+ func.__init__ #@
+ func.__new__ #@
+
+ func.__subclasshook__ #@
+ func.__str__ #@
+ func.__sizeof__ #@
+ func.__repr__ #@
+ func.__reduce__ #@
+
+ func.__reduce_ex__ #@
+ func.__lt__ #@
+ func.__eq__ #@
+ func.__gt__ #@
+ func.__format__ #@
+ func.__delattr___ #@
+ func.__getattribute__ #@
+ func.__hash__ #@
+ func.__dir__ #@
+ func.__class__ #@
+
+ func.__setattr__ #@
+ ''',
+ module_name="fake_module",
+ )
+ assert isinstance(ast_nodes, list)
+ name = next(ast_nodes[0].infer())
+ self.assertIsInstance(name, astroid.Const)
+ self.assertEqual(name.value, "func")
+
+ doc = next(ast_nodes[1].infer())
+ self.assertIsInstance(doc, astroid.Const)
+ self.assertEqual(doc.value, "test")
+
+ qualname = next(ast_nodes[2].infer())
+ self.assertIsInstance(qualname, astroid.Const)
+ self.assertEqual(qualname.value, "fake_module.func")
+
+ module = next(ast_nodes[3].infer())
+ self.assertIsInstance(module, astroid.Const)
+ self.assertEqual(module.value, "fake_module")
+
+ defaults = next(ast_nodes[4].infer())
+ self.assertIsInstance(defaults, astroid.Tuple)
+ self.assertEqual([default.value for default in defaults.elts], [1, 2])
+
+ dict_ = next(ast_nodes[5].infer())
+ self.assertIsInstance(dict_, astroid.Dict)
+
+ globals_ = next(ast_nodes[6].infer())
+ self.assertIsInstance(globals_, astroid.Dict)
+
+ for ast_node in ast_nodes[7:9]:
+ self.assertIs(next(ast_node.infer()), astroid.Uninferable)
+
+ init_ = next(ast_nodes[9].infer())
+ assert isinstance(init_, bases.BoundMethod)
+ init_result = next(init_.infer_call_result(nodes.Call()))
+ assert isinstance(init_result, nodes.Const)
+ assert init_result.value is None
+
+ new_ = next(ast_nodes[10].infer())
+ assert isinstance(new_, bases.BoundMethod)
+
+ # The following nodes are just here for theoretical completeness,
+ # and they either return Uninferable or raise InferenceError.
+ for ast_node in ast_nodes[11:26]:
+ inferred = next(ast_node.infer())
+ assert inferred is util.Uninferable
+
+ for ast_node in ast_nodes[26:27]:
+ with pytest.raises(InferenceError):
+ inferred = next(ast_node.infer())
+
+ def test_empty_return_annotation(self) -> None:
+ ast_node = builder.extract_node(
+ """
+ def test(): pass
+ test.__annotations__
+ """
+ )
+ annotations = next(ast_node.infer())
+ self.assertIsInstance(annotations, astroid.Dict)
+ self.assertEqual(len(annotations.items), 0)
+
+ def test_builtin_dunder_init_does_not_crash_when_accessing_annotations(
+ self,
+ ) -> None:
+ ast_node = builder.extract_node(
+ """
+ class Class:
+ @classmethod
+ def class_method(cls):
+ cls.__init__.__annotations__ #@
+ """
+ )
+ inferred = next(ast_node.infer())
+ self.assertIsInstance(inferred, astroid.Dict)
+ self.assertEqual(len(inferred.items), 0)
+
+ def test_annotations_kwdefaults(self) -> None:
+ ast_node = builder.extract_node(
+ """
+ def test(a: 1, *args: 2, f:4='lala', **kwarg:3)->2: pass
+ test.__annotations__ #@
+ test.__kwdefaults__ #@
+ """
+ )
+ annotations = next(ast_node[0].infer())
+ self.assertIsInstance(annotations, astroid.Dict)
+ self.assertIsInstance(
+ annotations.getitem(astroid.Const("return")), astroid.Const
+ )
+ self.assertEqual(annotations.getitem(astroid.Const("return")).value, 2)
+ self.assertIsInstance(annotations.getitem(astroid.Const("a")), astroid.Const)
+ self.assertEqual(annotations.getitem(astroid.Const("a")).value, 1)
+ self.assertEqual(annotations.getitem(astroid.Const("args")).value, 2)
+ self.assertEqual(annotations.getitem(astroid.Const("kwarg")).value, 3)
+
+ self.assertEqual(annotations.getitem(astroid.Const("f")).value, 4)
+
+ kwdefaults = next(ast_node[1].infer())
+ self.assertIsInstance(kwdefaults, astroid.Dict)
+ # self.assertEqual(kwdefaults.getitem('f').value, 'lala')
+
+ @test_utils.require_version(minver="3.8")
+ def test_annotation_positional_only(self):
+ ast_node = builder.extract_node(
+ """
+ def test(a: 1, b: 2, /, c: 3): pass
+ test.__annotations__ #@
+ """
+ )
+ annotations = next(ast_node.infer())
+ self.assertIsInstance(annotations, astroid.Dict)
+
+ self.assertIsInstance(annotations.getitem(astroid.Const("a")), astroid.Const)
+ self.assertEqual(annotations.getitem(astroid.Const("a")).value, 1)
+ self.assertEqual(annotations.getitem(astroid.Const("b")).value, 2)
+ self.assertEqual(annotations.getitem(astroid.Const("c")).value, 3)
+
+
+class TestContextManagerModel:
+ def test_model(self) -> None:
+ """We use a generator to test this model."""
+ ast_nodes = builder.extract_node(
+ """
+ def test():
+ "a"
+ yield
+
+ gen = test()
+ gen.__enter__ #@
+ gen.__exit__ #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+
+ enter = next(ast_nodes[0].infer())
+ assert isinstance(enter, astroid.BoundMethod)
+ # Test that the method is correctly bound
+ assert isinstance(enter.bound, bases.Generator)
+ assert enter.bound._proxied.qname() == "builtins.generator"
+ # Test that thet FunctionDef accepts no arguments except self
+ # NOTE: This probably shouldn't be double proxied, but this is a
+ # quirck of the current model implementations.
+ assert isinstance(enter._proxied._proxied, nodes.FunctionDef)
+ assert len(enter._proxied._proxied.args.args) == 1
+ assert enter._proxied._proxied.args.args[0].name == "self"
+
+ exit_node = next(ast_nodes[1].infer())
+ assert isinstance(exit_node, astroid.BoundMethod)
+ # Test that the FunctionDef accepts the arguments as defiend in the ObjectModel
+ assert isinstance(exit_node._proxied._proxied, nodes.FunctionDef)
+ assert len(exit_node._proxied._proxied.args.args) == 4
+ assert exit_node._proxied._proxied.args.args[0].name == "self"
+ assert exit_node._proxied._proxied.args.args[1].name == "exc_type"
+ assert exit_node._proxied._proxied.args.args[2].name == "exc_value"
+ assert exit_node._proxied._proxied.args.args[3].name == "traceback"
+
+
+class GeneratorModelTest(unittest.TestCase):
+ def test_model(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ def test():
+ "a"
+ yield
+
+ gen = test()
+ gen.__name__ #@
+ gen.__doc__ #@
+ gen.gi_code #@
+ gen.gi_frame #@
+ gen.send #@
+ gen.__enter__ #@
+ gen.__exit__ #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ name = next(ast_nodes[0].infer())
+ self.assertEqual(name.value, "test")
+
+ doc = next(ast_nodes[1].infer())
+ self.assertEqual(doc.value, "a")
+
+ gi_code = next(ast_nodes[2].infer())
+ self.assertIsInstance(gi_code, astroid.ClassDef)
+ self.assertEqual(gi_code.name, "gi_code")
+
+ gi_frame = next(ast_nodes[3].infer())
+ self.assertIsInstance(gi_frame, astroid.ClassDef)
+ self.assertEqual(gi_frame.name, "gi_frame")
+
+ send = next(ast_nodes[4].infer())
+ self.assertIsInstance(send, astroid.BoundMethod)
+
+ enter = next(ast_nodes[5].infer())
+ assert isinstance(enter, astroid.BoundMethod)
+
+ exit_node = next(ast_nodes[6].infer())
+ assert isinstance(exit_node, astroid.BoundMethod)
+
+
+class ExceptionModelTest(unittest.TestCase):
+ @staticmethod
+ def test_valueerror_py3() -> None:
+ ast_nodes = builder.extract_node(
+ """
+ try:
+ x[42]
+ except ValueError as err:
+ err.args #@
+ err.__traceback__ #@
+
+ err.message #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ args = next(ast_nodes[0].infer())
+ assert isinstance(args, astroid.Tuple)
+ tb = next(ast_nodes[1].infer())
+ # Python 3.11: If 'contextlib' is loaded, '__traceback__'
+ # could be set inside '__exit__' method in
+ # which case 'err.__traceback__' will be 'Uninferable'
+ try:
+ assert isinstance(tb, astroid.Instance)
+ assert tb.name == "traceback"
+ except AssertionError:
+ if PY311_PLUS:
+ assert tb == util.Uninferable
+ else:
+ raise
+
+ with pytest.raises(InferenceError):
+ next(ast_nodes[2].infer())
+
+ def test_syntax_error(self) -> None:
+ ast_node = builder.extract_node(
+ """
+ try:
+ x[42]
+ except SyntaxError as err:
+ err.text #@
+ """
+ )
+ inferred = next(ast_node.infer())
+ assert isinstance(inferred, astroid.Const)
+
+ @unittest.skipIf(HAS_SIX, "This test fails if the six library is installed")
+ def test_oserror(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ try:
+ raise OSError("a")
+ except OSError as err:
+ err.filename #@
+ err.filename2 #@
+ err.errno #@
+ """
+ )
+ expected_values = ["", "", 0]
+ for node, value in zip(ast_nodes, expected_values):
+ inferred = next(node.infer())
+ assert isinstance(inferred, astroid.Const)
+ assert inferred.value == value
+
+ def test_unicodedecodeerror(self) -> None:
+ code = """
+ try:
+ raise UnicodeDecodeError("utf-8", "blob", 0, 1, "reason")
+ except UnicodeDecodeError as error:
+ error.object[:1] #@
+ """
+ node = builder.extract_node(code)
+ inferred = next(node.infer())
+ assert isinstance(inferred, astroid.Const)
+
+ def test_import_error(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ try:
+ raise ImportError("a")
+ except ImportError as err:
+ err.name #@
+ err.path #@
+ """
+ )
+ for node in ast_nodes:
+ inferred = next(node.infer())
+ assert isinstance(inferred, astroid.Const)
+ assert inferred.value == ""
+
+ def test_exception_instance_correctly_instantiated(self) -> None:
+ ast_node = builder.extract_node(
+ """
+ try:
+ raise ImportError("a")
+ except ImportError as err:
+ err #@
+ """
+ )
+ inferred = next(ast_node.infer())
+ assert isinstance(inferred, astroid.Instance)
+ cls = next(inferred.igetattr("__class__"))
+ assert isinstance(cls, astroid.ClassDef)
+
+
+class DictObjectModelTest(unittest.TestCase):
+ def test__class__(self) -> None:
+ ast_node = builder.extract_node("{}.__class__")
+ inferred = next(ast_node.infer())
+ self.assertIsInstance(inferred, astroid.ClassDef)
+ self.assertEqual(inferred.name, "dict")
+
+ def test_attributes_inferred_as_methods(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ {}.values #@
+ {}.items #@
+ {}.keys #@
+ """
+ )
+ for node in ast_nodes:
+ inferred = next(node.infer())
+ self.assertIsInstance(inferred, astroid.BoundMethod)
+
+ def test_wrapper_objects_for_dict_methods_python3(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ {1:1, 2:3}.values() #@
+ {1:1, 2:3}.keys() #@
+ {1:1, 2:3}.items() #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ values = next(ast_nodes[0].infer())
+ self.assertIsInstance(values, objects.DictValues)
+ self.assertEqual([elt.value for elt in values.elts], [1, 3])
+ keys = next(ast_nodes[1].infer())
+ self.assertIsInstance(keys, objects.DictKeys)
+ self.assertEqual([elt.value for elt in keys.elts], [1, 2])
+ items = next(ast_nodes[2].infer())
+ self.assertIsInstance(items, objects.DictItems)
+
+
+class TestExceptionInstanceModel:
+ """Tests for ExceptionInstanceModel."""
+
+ def test_str_argument_not_required(self) -> None:
+ """Test that the first argument to an exception does not need to be a str."""
+ ast_node = builder.extract_node(
+ """
+ BaseException() #@
+ """
+ )
+ args: nodes.Tuple = next(ast_node.infer()).getattr("args")[0]
+ # BaseException doesn't have any required args, not even a string
+ assert not args.elts
+
+
+class LruCacheModelTest(unittest.TestCase):
+ def test_lru_cache(self) -> None:
+ ast_nodes = builder.extract_node(
+ """
+ import functools
+ class Foo(object):
+ @functools.lru_cache()
+ def foo():
+ pass
+ f = Foo()
+ f.foo.cache_clear #@
+ f.foo.__wrapped__ #@
+ f.foo.cache_info() #@
+ """
+ )
+ assert isinstance(ast_nodes, list)
+ cache_clear = next(ast_nodes[0].infer())
+ self.assertIsInstance(cache_clear, astroid.BoundMethod)
+ wrapped = next(ast_nodes[1].infer())
+ self.assertIsInstance(wrapped, astroid.FunctionDef)
+ self.assertEqual(wrapped.name, "foo")
+ cache_info = next(ast_nodes[2].infer())
+ self.assertIsInstance(cache_info, astroid.Instance)