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

View File

@@ -106,6 +106,9 @@ _NAMEDTUPLE_FIELD_TEMPLATE = '''\
def execute(callback): def execute(callback):
def wrapper(context, arguments): def wrapper(context, arguments):
def call():
return callback(context, arguments=arguments)
try: try:
obj_name = context.name.string_name obj_name = context.name.string_name
except AttributeError: except AttributeError:
@@ -116,7 +119,7 @@ def execute(callback):
elif context.parent_context is not None and context.parent_context.is_module(): elif context.parent_context is not None and context.parent_context.is_module():
module_name = context.parent_context.py__name__() module_name = context.parent_context.py__name__()
else: else:
return callback(context, arguments=arguments) return call()
if isinstance(context, BoundMethod): if isinstance(context, BoundMethod):
if module_name == 'builtins': if module_name == 'builtins':
@@ -130,7 +133,7 @@ def execute(callback):
if context.class_context.py__name__() == 'property': if context.class_context.py__name__() == 'property':
return ContextSet([context.instance]) return ContextSet([context.instance])
return callback(context, arguments=arguments) return call()
# for now we just support builtin functions. # for now we just support builtin functions.
try: try:
@@ -138,8 +141,8 @@ def execute(callback):
except KeyError: except KeyError:
pass pass
else: else:
return func(context, arguments=arguments) return func(context, arguments=arguments, callback=call)
return callback(context, arguments=arguments) return call()
return wrapper return wrapper
@@ -154,15 +157,18 @@ def _follow_param(evaluator, arguments, index):
def argument_clinic(string, want_obj=False, want_context=False, 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. Works like Argument Clinic (PEP 436), to validate function params.
""" """
def f(func): 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): def wrapper(obj, *args, **kwargs):
arguments = kwargs.pop('arguments') arguments = kwargs.pop('arguments')
callback = kwargs.pop('callback')
assert not kwargs # Python 2... assert not kwargs # Python 2...
debug.dbg('builtin start %s' % obj, color='MAGENTA') debug.dbg('builtin start %s' % obj, color='MAGENTA')
result = NO_CONTEXTS result = NO_CONTEXTS
@@ -174,6 +180,8 @@ def argument_clinic(string, want_obj=False, want_context=False,
kwargs['evaluator'] = obj.evaluator kwargs['evaluator'] = obj.evaluator
if want_arguments: if want_arguments:
kwargs['arguments'] = arguments kwargs['arguments'] = arguments
if want_callback:
kwargs['callback'] = callback
result = func(*args, **kwargs) result = func(*args, **kwargs)
debug.dbg('builtin end: %s', result, color='MAGENTA') debug.dbg('builtin end: %s', result, color='MAGENTA')
return result 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. Implementation of the namedtuple function.
@@ -538,7 +546,7 @@ class MergedPartialArguments(AbstractArguments):
yield key_lazy_context yield key_lazy_context
def functools_partial(obj, arguments): def functools_partial(obj, arguments, callback):
return ContextSet( return ContextSet(
PartialObject(instance, arguments) PartialObject(instance, arguments)
for instance in obj.py__call__(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): for c in _follow_param(obj.evaluator, arguments, 0):
if c.is_class(): if c.is_class():
return ContextSet([DataclassWrapper(c)]) return ContextSet([DataclassWrapper(c)])
@@ -695,6 +703,24 @@ def _create_string_input_function(func):
return wrapper 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 = { _implemented = {
'builtins': { 'builtins': {
'getattr': builtins_getattr, 'getattr': builtins_getattr,
@@ -750,6 +776,7 @@ _implemented = {
'dirname': _create_string_input_function(os.path.dirname), 'dirname': _create_string_input_function(os.path.dirname),
'abspath': _create_string_input_function(os.path.abspath), 'abspath': _create_string_input_function(os.path.abspath),
'relpath': _create_string_input_function(os.path.relpath), '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]), (f1, os_path + 'dirname(__file__) + "%stest' % s, None, [s]),
(f2, os_path + 'dirname(__file__) + "%stest_ca' % s, None, ['che.py']), (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 + '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): def test_file_path_completions(Script, file, code, column, expected):