1
0
forked from VimPlug/jedi

Fix os.path.join static value gathering

This commit is contained in:
Dave Halter
2019-08-06 22:48:28 +02:00
parent 81488bcd20
commit 7c1c4981fb
3 changed files with 40 additions and 10 deletions

View File

@@ -36,7 +36,7 @@ class ParamIssue(Exception):
pass
def repack_with_argument_clinic(string, keep_arguments_param=False):
def repack_with_argument_clinic(string, keep_arguments_param=False, keep_callback_param=False):
"""
Transforms a function or method with arguments to the signature that is
given as an argument clinic notation.
@@ -55,6 +55,8 @@ def repack_with_argument_clinic(string, keep_arguments_param=False):
arguments = kwargs['arguments']
else:
arguments = kwargs.pop('arguments')
if not keep_arguments_param:
kwargs.pop('callback', None)
try:
args += tuple(_iterate_argument_clinic(
context.evaluator,

View File

@@ -106,6 +106,9 @@ _NAMEDTUPLE_FIELD_TEMPLATE = '''\
def execute(callback):
def wrapper(context, arguments):
def call():
return callback(context, arguments=arguments)
try:
obj_name = context.name.string_name
except AttributeError:
@@ -116,7 +119,7 @@ def execute(callback):
elif context.parent_context is not None and context.parent_context.is_module():
module_name = context.parent_context.py__name__()
else:
return callback(context, arguments=arguments)
return call()
if isinstance(context, BoundMethod):
if module_name == 'builtins':
@@ -130,7 +133,7 @@ def execute(callback):
if context.class_context.py__name__() == 'property':
return ContextSet([context.instance])
return callback(context, arguments=arguments)
return call()
# for now we just support builtin functions.
try:
@@ -138,8 +141,8 @@ def execute(callback):
except KeyError:
pass
else:
return func(context, arguments=arguments)
return callback(context, arguments=arguments)
return func(context, arguments=arguments, callback=call)
return call()
return wrapper
@@ -154,15 +157,18 @@ def _follow_param(evaluator, arguments, index):
def argument_clinic(string, want_obj=False, want_context=False,
want_arguments=False, want_evaluator=False):
want_arguments=False, want_evaluator=False,
want_callback=False):
"""
Works like Argument Clinic (PEP 436), to validate function params.
"""
def f(func):
@repack_with_argument_clinic(string, keep_arguments_param=True)
@repack_with_argument_clinic(string, keep_arguments_param=True,
keep_callback_param=True)
def wrapper(obj, *args, **kwargs):
arguments = kwargs.pop('arguments')
callback = kwargs.pop('callback')
assert not kwargs # Python 2...
debug.dbg('builtin start %s' % obj, color='MAGENTA')
result = NO_CONTEXTS
@@ -174,6 +180,8 @@ def argument_clinic(string, want_obj=False, want_context=False,
kwargs['evaluator'] = obj.evaluator
if want_arguments:
kwargs['arguments'] = arguments
if want_callback:
kwargs['callback'] = callback
result = func(*args, **kwargs)
debug.dbg('builtin end: %s', result, color='MAGENTA')
return result
@@ -413,7 +421,7 @@ def builtins_classmethod(functions, obj, arguments):
)
def collections_namedtuple(obj, arguments):
def collections_namedtuple(obj, arguments, callback):
"""
Implementation of the namedtuple function.
@@ -538,7 +546,7 @@ class MergedPartialArguments(AbstractArguments):
yield key_lazy_context
def functools_partial(obj, arguments):
def functools_partial(obj, arguments, callback):
return ContextSet(
PartialObject(instance, arguments)
for instance in obj.py__call__(arguments)
@@ -559,7 +567,7 @@ def _random_choice(sequences):
)
def _dataclass(obj, arguments):
def _dataclass(obj, arguments, callback):
for c in _follow_param(obj.evaluator, arguments, 0):
if c.is_class():
return ContextSet([DataclassWrapper(c)])
@@ -695,6 +703,24 @@ def _create_string_input_function(func):
return wrapper
@argument_clinic('*args, /', want_callback=True)
def _os_path_join(args_set, callback):
if len(args_set) == 1:
string = u''
sequence, = args_set
for lazy_context in sequence.py__iter__():
string_contexts = lazy_context.infer()
if len(string_contexts) != 1:
break
s = get_str_or_none(next(iter(string_contexts)))
if string is None:
break
string += os.path.sep + force_unicode(s)
else:
return ContextSet([compiled.create_simple_object(sequence.evaluator, string)])
return callback()
_implemented = {
'builtins': {
'getattr': builtins_getattr,
@@ -750,6 +776,7 @@ _implemented = {
'dirname': _create_string_input_function(os.path.dirname),
'abspath': _create_string_input_function(os.path.abspath),
'relpath': _create_string_input_function(os.path.relpath),
'join': _os_path_join,
}
}

View File

@@ -209,6 +209,7 @@ os_path = 'from os.path import *\n'
(f1, os_path + 'dirname(__file__) + "%stest' % s, None, [s]),
(f2, os_path + 'dirname(__file__) + "%stest_ca' % s, None, ['che.py']),
(f2, os_path + 'dirname(abspath(__file__)) + sep + "test_ca', None, ['che.py']),
(f2, os_path + 'join(dirname(__file__), "completion") + sep + "basi', None, ['c.py']),
]
)
def test_file_path_completions(Script, file, code, column, expected):