Skip to content

Commit 0545192

Browse files
bje-Pierre-Sassoulascdce8p
authored
Capture unwanted output signaled in #1904. (#1978)
Co-authored-by: Pierre Sassoulas <[email protected]> Co-authored-by: Marc Mueller <[email protected]>
1 parent e31c9c4 commit 0545192

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

astroid/raw_building.py

+26-1
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,24 @@
1010

1111
import builtins
1212
import inspect
13+
import io
14+
import logging
1315
import os
1416
import sys
1517
import types
1618
import warnings
1719
from collections.abc import Iterable
20+
from contextlib import redirect_stderr, redirect_stdout
1821
from typing import Any, Union
1922

2023
from astroid import bases, nodes
2124
from astroid.const import _EMPTY_OBJECT_MARKER, IS_PYPY
2225
from astroid.manager import AstroidManager
2326
from astroid.nodes import node_classes
2427

28+
logger = logging.getLogger(__name__)
29+
30+
2531
_FunctionTypes = Union[
2632
types.FunctionType,
2733
types.MethodType,
@@ -471,7 +477,26 @@ def imported_member(self, node, member, name: str) -> bool:
471477
# check if it sounds valid and then add an import node, else use a
472478
# dummy node
473479
try:
474-
getattr(sys.modules[modname], name)
480+
with redirect_stderr(io.StringIO()) as stderr, redirect_stdout(
481+
io.StringIO()
482+
) as stdout:
483+
getattr(sys.modules[modname], name)
484+
stderr_value = stderr.getvalue()
485+
if stderr_value:
486+
logger.error(
487+
"Captured stderr while getting %s from %s:\n%s",
488+
name,
489+
sys.modules[modname],
490+
stderr_value,
491+
)
492+
stdout_value = stdout.getvalue()
493+
if stdout_value:
494+
logger.info(
495+
"Captured stdout while getting %s from %s:\n%s",
496+
name,
497+
sys.modules[modname],
498+
stdout_value,
499+
)
475500
except (KeyError, AttributeError):
476501
attach_dummy_node(node, name, member)
477502
else:

tests/unittest_raw_building.py

+47
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,15 @@
88
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
99
# Copyright (c) https://github.com/PyCQA/astroid/blob/main/CONTRIBUTORS.txt
1010

11+
from __future__ import annotations
12+
13+
import logging
14+
import os
15+
import sys
1116
import types
1217
import unittest
18+
from typing import Any
19+
from unittest import mock
1320

1421
import _io
1522
import pytest
@@ -117,5 +124,45 @@ def test_module_object_with_broken_getattr(self) -> None:
117124
AstroidBuilder().inspect_build(fm_getattr, "test")
118125

119126

127+
@pytest.mark.skipif(
128+
"posix" not in sys.builtin_module_names, reason="Platform doesn't support posix"
129+
)
130+
def test_build_module_getattr_catch_output(
131+
capsys: pytest.CaptureFixture[str],
132+
caplog: pytest.LogCaptureFixture,
133+
) -> None:
134+
"""Catch stdout and stderr in module __getattr__ calls when building a module.
135+
136+
Usually raised by DeprecationWarning or FutureWarning.
137+
"""
138+
caplog.set_level(logging.INFO)
139+
original_sys = sys.modules
140+
original_module = sys.modules["posix"]
141+
expected_out = "INFO (TEST): Welcome to posix!"
142+
expected_err = "WARNING (TEST): Monkey-patched version of posix - module getattr"
143+
144+
class CustomGetattr:
145+
def __getattr__(self, name: str) -> Any:
146+
print(f"{expected_out}")
147+
print(expected_err, file=sys.stderr)
148+
return getattr(original_module, name)
149+
150+
def mocked_sys_modules_getitem(name: str) -> types.ModuleType | CustomGetattr:
151+
if name != "posix":
152+
return original_sys[name]
153+
return CustomGetattr()
154+
155+
with mock.patch("astroid.raw_building.sys.modules") as sys_mock:
156+
sys_mock.__getitem__.side_effect = mocked_sys_modules_getitem
157+
builder = AstroidBuilder()
158+
builder.inspect_build(os)
159+
160+
out, err = capsys.readouterr()
161+
assert expected_out in caplog.text
162+
assert expected_err in caplog.text
163+
assert not out
164+
assert not err
165+
166+
120167
if __name__ == "__main__":
121168
unittest.main()

0 commit comments

Comments
 (0)