Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
204
venv/Lib/site-packages/jedi/inference/value/dynamic_arrays.py
Normal file
204
venv/Lib/site-packages/jedi/inference/value/dynamic_arrays.py
Normal file
|
@ -0,0 +1,204 @@
|
|||
"""
|
||||
A module to deal with stuff like `list.append` and `set.add`.
|
||||
|
||||
Array modifications
|
||||
*******************
|
||||
|
||||
If the content of an array (``set``/``list``) is requested somewhere, the
|
||||
current module will be checked for appearances of ``arr.append``,
|
||||
``arr.insert``, etc. If the ``arr`` name points to an actual array, the
|
||||
content will be added
|
||||
|
||||
This can be really cpu intensive, as you can imagine. Because |jedi| has to
|
||||
follow **every** ``append`` and check whether it's the right array. However this
|
||||
works pretty good, because in *slow* cases, the recursion detector and other
|
||||
settings will stop this process.
|
||||
|
||||
It is important to note that:
|
||||
|
||||
1. Array modfications work only in the current module.
|
||||
2. Jedi only checks Array additions; ``list.pop``, etc are ignored.
|
||||
"""
|
||||
from jedi import debug
|
||||
from jedi import settings
|
||||
from jedi.inference import recursion
|
||||
from jedi.inference.base_value import ValueSet, NO_VALUES, HelperValueMixin, \
|
||||
ValueWrapper
|
||||
from jedi.inference.lazy_value import LazyKnownValues
|
||||
from jedi.inference.helpers import infer_call_of_leaf
|
||||
from jedi.inference.cache import inference_state_method_cache
|
||||
|
||||
_sentinel = object()
|
||||
|
||||
|
||||
def check_array_additions(context, sequence):
|
||||
""" Just a mapper function for the internal _internal_check_array_additions """
|
||||
if sequence.array_type not in ('list', 'set'):
|
||||
# TODO also check for dict updates
|
||||
return NO_VALUES
|
||||
|
||||
return _internal_check_array_additions(context, sequence)
|
||||
|
||||
|
||||
@inference_state_method_cache(default=NO_VALUES)
|
||||
@debug.increase_indent
|
||||
def _internal_check_array_additions(context, sequence):
|
||||
"""
|
||||
Checks if a `Array` has "add" (append, insert, extend) statements:
|
||||
|
||||
>>> a = [""]
|
||||
>>> a.append(1)
|
||||
"""
|
||||
from jedi.inference import arguments
|
||||
|
||||
debug.dbg('Dynamic array search for %s' % sequence, color='MAGENTA')
|
||||
module_context = context.get_root_context()
|
||||
if not settings.dynamic_array_additions or module_context.is_compiled():
|
||||
debug.dbg('Dynamic array search aborted.', color='MAGENTA')
|
||||
return NO_VALUES
|
||||
|
||||
def find_additions(context, arglist, add_name):
|
||||
params = list(arguments.TreeArguments(context.inference_state, context, arglist).unpack())
|
||||
result = set()
|
||||
if add_name in ['insert']:
|
||||
params = params[1:]
|
||||
if add_name in ['append', 'add', 'insert']:
|
||||
for key, lazy_value in params:
|
||||
result.add(lazy_value)
|
||||
elif add_name in ['extend', 'update']:
|
||||
for key, lazy_value in params:
|
||||
result |= set(lazy_value.infer().iterate())
|
||||
return result
|
||||
|
||||
temp_param_add, settings.dynamic_params_for_other_modules = \
|
||||
settings.dynamic_params_for_other_modules, False
|
||||
|
||||
is_list = sequence.name.string_name == 'list'
|
||||
search_names = (['append', 'extend', 'insert'] if is_list else ['add', 'update'])
|
||||
|
||||
added_types = set()
|
||||
for add_name in search_names:
|
||||
try:
|
||||
possible_names = module_context.tree_node.get_used_names()[add_name]
|
||||
except KeyError:
|
||||
continue
|
||||
else:
|
||||
for name in possible_names:
|
||||
value_node = context.tree_node
|
||||
if not (value_node.start_pos < name.start_pos < value_node.end_pos):
|
||||
continue
|
||||
trailer = name.parent
|
||||
power = trailer.parent
|
||||
trailer_pos = power.children.index(trailer)
|
||||
try:
|
||||
execution_trailer = power.children[trailer_pos + 1]
|
||||
except IndexError:
|
||||
continue
|
||||
else:
|
||||
if execution_trailer.type != 'trailer' \
|
||||
or execution_trailer.children[0] != '(' \
|
||||
or execution_trailer.children[1] == ')':
|
||||
continue
|
||||
|
||||
random_context = context.create_context(name)
|
||||
|
||||
with recursion.execution_allowed(context.inference_state, power) as allowed:
|
||||
if allowed:
|
||||
found = infer_call_of_leaf(
|
||||
random_context,
|
||||
name,
|
||||
cut_own_trailer=True
|
||||
)
|
||||
if sequence in found:
|
||||
# The arrays match. Now add the results
|
||||
added_types |= find_additions(
|
||||
random_context,
|
||||
execution_trailer.children[1],
|
||||
add_name
|
||||
)
|
||||
|
||||
# reset settings
|
||||
settings.dynamic_params_for_other_modules = temp_param_add
|
||||
debug.dbg('Dynamic array result %s', added_types, color='MAGENTA')
|
||||
return added_types
|
||||
|
||||
|
||||
def get_dynamic_array_instance(instance, arguments):
|
||||
"""Used for set() and list() instances."""
|
||||
ai = _DynamicArrayAdditions(instance, arguments)
|
||||
from jedi.inference import arguments
|
||||
return arguments.ValuesArguments([ValueSet([ai])])
|
||||
|
||||
|
||||
class _DynamicArrayAdditions(HelperValueMixin):
|
||||
"""
|
||||
Used for the usage of set() and list().
|
||||
This is definitely a hack, but a good one :-)
|
||||
It makes it possible to use set/list conversions.
|
||||
|
||||
This is not a proper context, because it doesn't have to be. It's not used
|
||||
in the wild, it's just used within typeshed as an argument to `__init__`
|
||||
for set/list and never used in any other place.
|
||||
"""
|
||||
def __init__(self, instance, arguments):
|
||||
self._instance = instance
|
||||
self._arguments = arguments
|
||||
|
||||
def py__class__(self):
|
||||
tuple_, = self._instance.inference_state.builtins_module.py__getattribute__('tuple')
|
||||
return tuple_
|
||||
|
||||
def py__iter__(self, contextualized_node=None):
|
||||
arguments = self._arguments
|
||||
try:
|
||||
_, lazy_value = next(arguments.unpack())
|
||||
except StopIteration:
|
||||
pass
|
||||
else:
|
||||
for lazy in lazy_value.infer().iterate():
|
||||
yield lazy
|
||||
|
||||
from jedi.inference.arguments import TreeArguments
|
||||
if isinstance(arguments, TreeArguments):
|
||||
additions = _internal_check_array_additions(arguments.context, self._instance)
|
||||
for addition in additions:
|
||||
yield addition
|
||||
|
||||
def iterate(self, contextualized_node=None, is_async=False):
|
||||
return self.py__iter__(contextualized_node)
|
||||
|
||||
|
||||
class _Modification(ValueWrapper):
|
||||
def __init__(self, wrapped_value, assigned_values, contextualized_key):
|
||||
super(_Modification, self).__init__(wrapped_value)
|
||||
self._assigned_values = assigned_values
|
||||
self._contextualized_key = contextualized_key
|
||||
|
||||
def py__getitem__(self, *args, **kwargs):
|
||||
return self._wrapped_value.py__getitem__(*args, **kwargs) | self._assigned_values
|
||||
|
||||
def py__simple_getitem__(self, index):
|
||||
actual = [
|
||||
v.get_safe_value(_sentinel)
|
||||
for v in self._contextualized_key.infer()
|
||||
]
|
||||
if index in actual:
|
||||
return self._assigned_values
|
||||
return self._wrapped_value.py__simple_getitem__(index)
|
||||
|
||||
|
||||
class DictModification(_Modification):
|
||||
def py__iter__(self, contextualized_node=None):
|
||||
for lazy_context in self._wrapped_value.py__iter__(contextualized_node):
|
||||
yield lazy_context
|
||||
yield self._contextualized_key
|
||||
|
||||
def get_key_values(self):
|
||||
return self._wrapped_value.get_key_values() | self._contextualized_key.infer()
|
||||
|
||||
|
||||
class ListModification(_Modification):
|
||||
def py__iter__(self, contextualized_node=None):
|
||||
for lazy_context in self._wrapped_value.py__iter__(contextualized_node):
|
||||
yield lazy_context
|
||||
yield LazyKnownValues(self._assigned_values)
|
Loading…
Add table
Add a link
Reference in a new issue