-
-
Notifications
You must be signed in to change notification settings - Fork 525
Description
Summary
The jedi.Script.goto() function occasionally fails with an AttributeError: 'NoneType' object has no attribute 'type' when analyzing a method decorated by a dynamically chosen decorator.
This exception is inconsistent and unstable; it occurs intermittently, even with identical code and environment configurations.
Expected Behavior
In our case, script.goto() should consistently succeed and return the correct definition for the symbol at the target position.
Even in the case of failure, script.goto() should return an empty list ([]) instead of raising an unhandled exception.
Observed Behavior
- Intermittent Crash: Calling
script.goto(line, column, follow_imports=True)repeatedly on a target symbol within a decorated method results in an intermittentAttributeError: 'NoneType' object has no attribute 'type'.
Environment
Linux. Clean conda environment just with the latest (master) jedi.
Reproduction
Just run the below code in a clean directory.
import jedi
import os
import sys
##############################################################################
# data
PREFIX = "testwork"
CACHE_FILE_PATH = PREFIX + "/" + "cache.py"
MAIN_FILE_PATH = PREFIX + "/" + "main.py"
CACHE_PY_CONTENT = """\
import os
def deco1(maxsize):
def func_wrapper(func):
def wrapper(*args, **kwargs):
print('deco1')
retval = func(*args, **kwargs)
return retval
return wrapper
return func_wrapper
def deco2(func):
print('deco2')
return func
if os.getenv('CHOICE') == "deco1":
deco = deco1(1000)
else:
deco = deco2
"""
MAIN_PY_CONTENT = """\
from cache import deco
class Expr:
flag = True
__slots__ = []
def __new__(cls, expr, *args, **kwargs):
obj = object.__new__(cls)
obj.args = args
return obj
@property
def func(self):
return self.__class__
@deco
def contains(self, expr):
if expr.flag:
pass
obj = self.func(expr, *self.args[1:])
return self.contains(obj)
def __contains__(self, other):
result = self.contains(other)
return result
"""
TARGET_POS = (19, 17) # points to the get_data in process()
##############################################################################
# init
print(f"Creating files: {CACHE_FILE_PATH} and {MAIN_FILE_PATH}...")
project = jedi.Project(path=PREFIX, environment_path=None)
os.makedirs(PREFIX, exist_ok=True)
with open(CACHE_FILE_PATH, "w") as f:
f.write(CACHE_PY_CONTENT.strip())
with open(MAIN_FILE_PATH, "w") as f:
f.write(MAIN_PY_CONTENT.strip())
print("Files created successfully.")
##############################################################################
# run
script = jedi.Script(code=MAIN_PY_CONTENT, path=MAIN_FILE_PATH, project=project)
while True:
try:
definitions = script.goto(*TARGET_POS, follow_imports=True)
definition = definitions[0]
except AttributeError as e:
raise e
except Exception as e:
continue
print(definition)
print(definition.full_name, definition.module_path, definition.line, definition.column)It should fail like
(if the script runs fine, just try a couple more rounds and it'll fail. It's unstable.)
$ python main.py
Creating files: testwork/cache.py and testwork/main.py...
Files created successfully.
Traceback (most recent call last):
File "/home/den/Programs/test/testjedi2/main.py", line 81, in <module>
raise e
File "/home/den/Programs/test/testjedi2/main.py", line 78, in <module>
definitions = script.goto(*TARGET_POS, follow_imports=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/api/helpers.py", line 487, in wrapper
return func(self, line, column, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/api/__init__.py", line 300, in goto
names = list(name.goto())
^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/names.py", line 205, in goto
values = infer_call_of_leaf(context, name, cut_own_trailer=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/helpers.py", line 104, in infer_call_of_leaf
values = context.infer_node(base)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 224, in infer_node
return infer_node(self, node)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 157, in infer_node
return _infer_node_if_inferred(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 170, in _infer_node_if_inferred
return _infer_node_cached(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/cache.py", line 44, in wrapper
rv = function(obj, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 175, in _infer_node_cached
return _infer_node(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/debug.py", line 81, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 83, in wrapper
return func(context, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 185, in _infer_node
return infer_atom(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 305, in infer_atom
return context.py__getattribute__(atom, position=position)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 77, in py__getattribute__
values = ValueSet.from_sets(name.infer() for name in names)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/base_value.py", line 430, in from_sets
for set_ in sets:
^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 77, in <genexpr>
values = ValueSet.from_sets(name.infer() for name in names)
^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/plugins/__init__.py", line 21, in wrapper
return built_functions[public_name](*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/plugins/pytest.py", line 76, in wrapper
return func(param_name)
^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/names.py", line 528, in infer
values = dynamic_param_lookup(self.function_value, param.position_index)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/debug.py", line 81, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/dynamic_params.py", line 47, in wrapper
return func(function_value, param_index)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/dynamic_params.py", line 92, in dynamic_param_lookup
values = ValueSet.from_sets(
^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/base_value.py", line 430, in from_sets
for set_ in sets:
^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/dynamic_params.py", line 93, in <genexpr>
get_executed_param_names(
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/param.py", line 245, in get_executed_param_names
return get_executed_param_names_and_issues(function_value, arguments)[0]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/param.py", line 100, in get_executed_param_names_and_issues
unpacked_va = list(arguments.unpack(funcdef))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/value/instance.py", line 610, in unpack
yield from self._wrapped_arguments.unpack(func)
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/arguments.py", line 185, in unpack
arrays = self.context.infer_node(el)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 224, in infer_node
return infer_node(self, node)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 157, in infer_node
return _infer_node_if_inferred(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 170, in _infer_node_if_inferred
return _infer_node_cached(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/cache.py", line 44, in wrapper
rv = function(obj, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 175, in _infer_node_cached
return _infer_node(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/debug.py", line 81, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 83, in wrapper
return func(context, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 198, in _infer_node
value_set = context.infer_node(first_child)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 224, in infer_node
return infer_node(self, node)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 157, in infer_node
return _infer_node_if_inferred(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 170, in _infer_node_if_inferred
return _infer_node_cached(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/cache.py", line 44, in wrapper
rv = function(obj, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 175, in _infer_node_cached
return _infer_node(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/debug.py", line 81, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 83, in wrapper
return func(context, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 185, in _infer_node
return infer_atom(context, element)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/syntax_tree.py", line 305, in infer_atom
return context.py__getattribute__(atom, position=position)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 88, in py__getattribute__
return self._check_for_additional_knowledge(name_or_str, name_context, position)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/context.py", line 102, in _check_for_additional_knowledge
n = check_flow_information(name_context, flow_scope,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/inference/finder.py", line 66, in check_flow_information
if is_scope(flow):
^^^^^^^^^^^^^^
File "/home/den/anaconda3/lib/python3.12/site-packages/jedi/parser_utils.py", line 208, in is_scope
t = node.type
^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'type'
(jedi_bug_tset)
[~/Programs/test/testjedi2] [ ] [08:12:40 PM] den exited 1
$ pip list | grep jedi
jedi 0.19.2