""" 'tests.testdata.python3.data.fake_module_with_warnings' and 'tests.testdata.python3.data.fake_module_with_warnings' are fake modules to simulate issues in unittest below """ # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt from __future__ import annotations import logging import os import sys import types import unittest from typing import Any from unittest import mock import _io import pytest import tests.testdata.python3.data.fake_module_with_broken_getattr as fm_getattr import tests.testdata.python3.data.fake_module_with_warnings as fm from astroid.builder import AstroidBuilder from astroid.const import IS_PYPY from astroid.raw_building import ( attach_dummy_node, build_class, build_from_import, build_function, build_module, ) class RawBuildingTC(unittest.TestCase): def test_attach_dummy_node(self) -> None: node = build_module("MyModule") attach_dummy_node(node, "DummyNode") self.assertEqual(1, len(list(node.get_children()))) def test_build_module(self) -> None: node = build_module("MyModule") self.assertEqual(node.name, "MyModule") self.assertEqual(node.pure_python, False) self.assertEqual(node.package, False) self.assertEqual(node.parent, None) def test_build_class(self) -> None: node = build_class("MyClass") self.assertEqual(node.name, "MyClass") self.assertEqual(node.doc_node, None) def test_build_function(self) -> None: node = build_function("MyFunction") self.assertEqual(node.name, "MyFunction") self.assertEqual(node.doc_node, None) def test_build_function_args(self) -> None: args = ["myArgs1", "myArgs2"] node = build_function("MyFunction", args) self.assertEqual("myArgs1", node.args.args[0].name) self.assertEqual("myArgs2", node.args.args[1].name) self.assertEqual(2, len(node.args.args)) def test_build_function_defaults(self) -> None: defaults = ["defaults1", "defaults2"] node = build_function(name="MyFunction", args=None, defaults=defaults) self.assertEqual(2, len(node.args.defaults)) def test_build_function_posonlyargs(self) -> None: node = build_function(name="MyFunction", posonlyargs=["a", "b"]) self.assertEqual(2, len(node.args.posonlyargs)) def test_build_function_kwonlyargs(self) -> None: node = build_function(name="MyFunction", kwonlyargs=["a", "b"]) assert len(node.args.kwonlyargs) == 2 assert node.args.kwonlyargs[0].name == "a" assert node.args.kwonlyargs[1].name == "b" def test_build_from_import(self) -> None: names = ["exceptions, inference, inspector"] node = build_from_import("astroid", names) self.assertEqual(len(names), len(node.names)) @unittest.skipIf(IS_PYPY, "Only affects CPython") def test_io_is__io(self): # _io module calls itself io. This leads # to cyclic dependencies when astroid tries to resolve # what io.BufferedReader is. The code that handles this # is in astroid.raw_building.imported_member, which verifies # the true name of the module. builder = AstroidBuilder() module = builder.inspect_build(_io) buffered_reader = module.getattr("BufferedReader")[0] self.assertEqual(buffered_reader.root().name, "io") def test_build_function_deepinspect_deprecation(self) -> None: # Tests https://github.com/pylint-dev/astroid/issues/1717 # When astroid deep inspection of modules raises # attribute errors when getting all attributes # Create a mock module to simulate a Cython module m = types.ModuleType("test") # Attach a mock of pandas with the same behavior m.pd = fm # This should not raise an exception AstroidBuilder().module_build(m, "test") def test_module_object_with_broken_getattr(self) -> None: # Tests https://github.com/pylint-dev/astroid/issues/1958 # When astroid deep inspection of modules raises # errors when using hasattr(). # This should not raise an exception AstroidBuilder().inspect_build(fm_getattr, "test") @pytest.mark.skipif( "posix" not in sys.builtin_module_names, reason="Platform doesn't support posix" ) def test_build_module_getattr_catch_output( capsys: pytest.CaptureFixture[str], caplog: pytest.LogCaptureFixture, ) -> None: """Catch stdout and stderr in module __getattr__ calls when building a module. Usually raised by DeprecationWarning or FutureWarning. """ caplog.set_level(logging.INFO) original_sys = sys.modules original_module = sys.modules["posix"] expected_out = "INFO (TEST): Welcome to posix!" expected_err = "WARNING (TEST): Monkey-patched version of posix - module getattr" class CustomGetattr: def __getattr__(self, name: str) -> Any: print(f"{expected_out}") print(expected_err, file=sys.stderr) return getattr(original_module, name) def mocked_sys_modules_getitem(name: str) -> types.ModuleType | CustomGetattr: if name != "posix": return original_sys[name] return CustomGetattr() with mock.patch("astroid.raw_building.sys.modules") as sys_mock: sys_mock.__getitem__.side_effect = mocked_sys_modules_getitem builder = AstroidBuilder() builder.inspect_build(os) out, err = capsys.readouterr() assert expected_out in caplog.text assert expected_err in caplog.text assert not out assert not err