pylint-dev / pylint

It's not just a linter that annoys you!
https://pylint.readthedocs.io/en/latest/
GNU General Public License v2.0
5.27k stars 1.13k forks source link

Crash pylint - astroid.exceptions.AstroidError #10003

Open gothicVI opened 1 day ago

gothicVI commented 1 day ago

Bug description

The file is saved as tests/test__auth where the module is located in src/package/

When parsing the following a.py:

"""Test the ``_auth`` module."""
import base64
from unittest.mock import (
    mock_open,
    patch,
)

from package._auth import generate_user_auth

def test_generate_user_auth_with_patches() -> None:
    """Test ``generate_user_auth``."""
    # Mock input, getpass, open, and Path.exists
    with (
        patch("package._auth.input", return_value="testuser") as mock_input,
        patch("package._auth.getpass", return_value="testpassword") as mock_getpass,
        patch("package._auth.Path.exists", return_value=False) as mock_exists,
        patch("package._auth.open", new_callable=mock_open, create=True) as mock_open_func,
    ):
        # Call the function to be tested
        generate_user_auth()

        # Assert that input() was called correctly for the username
        mock_input.assert_called_once_with("Enter username: ")

        # Assert that getpass.getpass() was called correctly for the password prompt
        mock_getpass.assert_called_once_with("Enter the password for user testuser: ")

        # Assert that Path.exists() was called to check if the file exists
        mock_exists.assert_called_once_with()

        # Assert that open() was called to create "user_auth.py"
        mock_open_func.assert_called_once_with("user_auth.py", "w", encoding="utf-8")

        # Verify the correct content was written to the file
        inputstring = "testuser:testpassword"
        expected_base64_string = base64.encodebytes(inputstring.encode()).decode().replace("\n", "")
        outputstring = f"BASE_64_STRING = {expected_base64_string!r}\n"

        file_handle = mock_open_func()
        file_handle.write.assert_called_once_with(outputstring)

        mock_open_func.return_value.write.assert_called_once_with(outputstring)

Command used

pylint a.py

Pylint output

pylint crashed with a ``AstroidError`` and with the following stacktrace: ```python Traceback (most recent call last): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 90, in inner yield next(generator) ^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 44, in wrapped if context.push(node): ^^^^^^^^^^^^^^^^^^ RecursionError: maximum recursion depth exceeded During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/lint/pylinter.py", line 788, in _lint_file check_astroid_module(module) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/lint/pylinter.py", line 1017, in check_astroid_module retval = self._check_astroid_module( ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/lint/pylinter.py", line 1069, in _check_astroid_module walker.walk(node) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/utils/ast_walker.py", line 94, in walk self.walk(child) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/utils/ast_walker.py", line 94, in walk self.walk(child) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/utils/ast_walker.py", line 94, in walk self.walk(child) [Previous line repeated 1 more time] File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/utils/ast_walker.py", line 91, in walk callback(astroid) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/checkers/base/basic_checker.py", line 713, in visit_call if utils.is_terminating_func(node): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/checkers/utils.py", line 2160, in is_terminating_func for inferred in node.func.infer(): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_ng.py", line 169, in infer for i, result in enumerate(self._infer(context=context, **kwargs)): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 103, in inner yield from generator File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 49, in wrapped for res in _func(node, context, **kwargs): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_classes.py", line 1090, in _infer_attribute for owner in node.expr.infer(context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_ng.py", line 169, in infer for i, result in enumerate(self._infer(context=context, **kwargs)): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 103, in inner yield from generator File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 49, in wrapped for res in _func(node, context, **kwargs): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_classes.py", line 1090, in _infer_attribute for owner in node.expr.infer(context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_ng.py", line 169, in infer for i, result in enumerate(self._infer(context=context, **kwargs)): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 103, in inner yield from generator File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 49, in wrapped for res in _func(node, context, **kwargs): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/bases.py", line 179, in _infer_stmts for inf in stmt.infer(context=context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_ng.py", line 169, in infer for i, result in enumerate(self._infer(context=context, **kwargs)): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 103, in inner yield from generator File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 49, in wrapped for res in _func(node, context, **kwargs): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/bases.py", line 179, in _infer_stmts for inf in stmt.infer(context=context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_ng.py", line 169, in infer for i, result in enumerate(self._infer(context=context, **kwargs)): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 103, in inner yield from generator File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 49, in wrapped for res in _func(node, context, **kwargs): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_classes.py", line 1765, in _infer yield from callee.infer_call_result( File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/bases.py", line 331, in infer_call_result for res in node.infer_call_result(caller, context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/bases.py", line 331, in infer_call_result for res in node.infer_call_result(caller, context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/bases.py", line 331, in infer_call_result for res in node.infer_call_result(caller, context): [Previous line repeated 922 more times] File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/bases.py", line 328, in infer_call_result for node in self._proxied.igetattr("__call__", context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2511, in igetattr inferred._proxied.getattr("__get__", context) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2415, in getattr values += self._metaclass_lookup_attribute(name, context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2439, in _metaclass_lookup_attribute attrs.update(set(cls_attributes)) ^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2446, in _get_attribute_from_metaclass attrs = cls.getattr(name, context=context, class_context=True) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2415, in getattr values += self._metaclass_lookup_attribute(name, context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2435, in _metaclass_lookup_attribute metaclass = self.metaclass(context=context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2727, in metaclass return self._find_metaclass(context=context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2707, in _find_metaclass klass = self.declared_metaclass(context=context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/scoped_nodes/scoped_nodes.py", line 2679, in declared_metaclass for baseobj in base.infer(context=context): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/nodes/node_ng.py", line 169, in infer for i, result in enumerate(self._infer(context=context, **kwargs)): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/astroid/decorators.py", line 99, in inner raise InferenceError( ^^^^^^^^^^^^^^^ RecursionError: maximum recursion depth exceeded The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/lint/pylinter.py", line 752, in _lint_files self._lint_file(fileitem, module, check_astroid_module) File "/home/user/.vscodium-server/extensions/ms-python.pylint-2023.10.1/bundled/libs/pylint/lint/pylinter.py", line 790, in _lint_file raise astroid.AstroidError from e astroid.exceptions.AstroidError ```

Expected behavior

No crash.

Pylint version

pylint 3.0.2
astroid 3.0.1
Python 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0]

OS / Environment

linux (Linux) VSCodium 1.93.1 Pylint plugin v2023.10.1

Additional dependencies

The module to be testes reads src/package/_auth.py

import base64
from getpass import getpass
from pathlib import Path

def generate_user_auth() -> None:
    """Generate the ``user_auth`` file."""
    user: str = input("Enter username: ")
    pwd: str = getpass(f"Enter the password for user {user}: ")
    new_base_64_string: str = (  # pylint: disable=C0103
        base64.encodebytes((f"{user}:{pwd}").encode()).decode().replace("\n", "")
    )
    print(f"The BASE_64_STRING for the user {user} is {new_base_64_string}")  # noqa: T201
    user_auth_path: Path = Path("./user_auth.py")
    if not user_auth_path.exists():
        with open(user_auth_path.as_posix(), "w", encoding="utf-8") as out_file:
            out_file.write(f"BASE_64_STRING = {new_base_64_string!r}\n")
gothicVI commented 1 day ago

Removing the redundant assertions

        file_handle = mock_open_func()
        file_handle.write.assert_called_once_with(outputstring)

makes the error go away.

jacobtylerwalls commented 1 day ago

Have you tried on the latest versions of pylint and astroid?