[BUG] Cannot import Astroid with schemathesis 3.19.6
kain88-de opened this issue · 4 comments
Describe the bug
When I start a pytest session the astroid package enters an infinite loop when it is imported.
To Reproduce
I prepared a pipenv file that creates an environment to reproduce the issues.
Once you downloaded all files run
make .venv
run-pipenv run python -m pytest t.py --pdb
This will drop you in a debugger session at the place where astroid is stuck in a loop. With version 3.19.0 everything still works.
Expected behavior
Adding schemathesis as a dependency has no impact if I can import astroid in a pytest environment or not.
Environment (please complete the following information):
- OS: linux
- Python: 3.11
Additional context
I'm not sure what the root cause is so I will also open tickets for this with pytest and schemathesis
Pure Python reproducer from over at pytest-dev/pytest#11053 (comment):
from dataclasses import dataclass
print(type(__builtins__))
print(hasattr(__builtins__, "__builtins__"))
@dataclass
class Bla(Exception):
__module__ = "builtins"
print(type(__builtins__))
print(hasattr(__builtins__, "__builtins__"))
import astroid.nodes
Apparently, for whatever reason, declaring a dataclass like this causes a __builtins__.__builtins__
to appear (which is __builtins__
again), and that causes astroid to choke with an endless recursion:
Traceback (most recent call last):
File "/home/florian/tmp/blabla/dc.py", line 14, in <module>
import astroid.nodes
File "/usr/lib/python3.11/site-packages/astroid/__init__.py", line 46, in <module>
from astroid import inference, raw_building
File "/usr/lib/python3.11/site-packages/astroid/inference.py", line 17, in <module>
from astroid import bases, constraint, decorators, helpers, nodes, protocols, util
File "/usr/lib/python3.11/site-packages/astroid/helpers.py", line 11, in <module>
from astroid import bases, manager, nodes, objects, raw_building, util
File "/usr/lib/python3.11/site-packages/astroid/raw_building.py", line 643, in <module>
_astroid_bootstrapping()
File "/usr/lib/python3.11/site-packages/astroid/raw_building.py", line 544, in _astroid_bootstrapping
astroid_builtin = builder.inspect_build(builtins)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/astroid/raw_building.py", line 404, in inspect_build
self.object_build(node, module)
File "/usr/lib/python3.11/site-packages/astroid/raw_building.py", line 455, in object_build
attach_const_node(node, name, member)
File "/usr/lib/python3.11/site-packages/astroid/raw_building.py", line 78, in attach_const_node
_attach_local_node(node, nodes.const_factory(value), name)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/astroid/nodes/node_classes.py", line 5641, in const_factory
instance.postinit(_create_dict_items(value, instance))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/astroid/nodes/node_classes.py", line 5615, in _create_dict_items
value_node = const_factory(value)
^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/astroid/nodes/node_classes.py", line 5641, in const_factory
instance.postinit(_create_dict_items(value, instance))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/astroid/nodes/node_classes.py", line 5615, in _create_dict_items
value_node = const_factory(value)
^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/astroid/nodes/node_classes.py", line 5641, in const_factory
instance.postinit(_create_dict_items(value, instance))
[...]
Thank you for the investigation @The-Compiler !
Even smaller reproducer:
python3 -c 'exec("", __builtins__.__dict__, {}); import astroid.nodes'
And this behavior actually seems to be documented:
If the globals dictionary does not contain a value for the key
__builtins__
, a reference to the dictionary of the built-in modulebuiltins
is inserted under that key. That way you can control what builtins are available to the executed code by inserting your own__builtins__
dictionary into globals before passing it toexec()
.
So the solution for astroid would be to handle builtins as a special case and remove the self-reference if it exists.