Refactor some call details

This commit is contained in:
Dave Halter
2019-07-05 14:30:59 -07:00
parent a26cb42d07
commit ef9d803ce3
4 changed files with 92 additions and 13 deletions

View File

@@ -127,3 +127,11 @@ def skip_python2(environment):
# This if is just needed to avoid that tests ever skip way more than # This if is just needed to avoid that tests ever skip way more than
# they should for all Python versions. # they should for all Python versions.
pytest.skip() pytest.skip()
@pytest.fixture()
def skip_pre_python38(environment):
if environment.version_info < (3, 8):
# This if is just needed to avoid that tests ever skip way more than
# they should for all Python versions.
pytest.skip()

View File

@@ -385,10 +385,7 @@ class Script(object):
# TODO here we use stubs instead of the actual contexts. We should use # TODO here we use stubs instead of the actual contexts. We should use
# the signatures from stubs, but the actual contexts, probably?! # the signatures from stubs, but the actual contexts, probably?!
return [classes.CallSignature(self._evaluator, signature, return [classes.CallSignature(self._evaluator, signature, call_signature_details)
call_signature_details.bracket_leaf.start_pos,
call_signature_details.call_index,
call_signature_details.keyword_name_str)
for signature in definitions.get_signatures()] for signature in definitions.get_signatures()]
def _analysis(self): def _analysis(self):

View File

@@ -604,11 +604,9 @@ class CallSignature(Definition):
It knows what functions you are currently in. e.g. `isinstance(` would It knows what functions you are currently in. e.g. `isinstance(` would
return the `isinstance` function. without `(` it would return nothing. return the `isinstance` function. without `(` it would return nothing.
""" """
def __init__(self, evaluator, signature, bracket_start_pos, index, key_name_str): def __init__(self, evaluator, signature, call_details):
super(CallSignature, self).__init__(evaluator, signature.name) super(CallSignature, self).__init__(evaluator, signature.name)
self._index = index self._call_details = call_details
self._key_name_str = key_name_str
self._bracket_start_pos = bracket_start_pos
self._signature = signature self._signature = signature
@property @property
@@ -617,9 +615,9 @@ class CallSignature(Definition):
The Param index of the current call. The Param index of the current call.
Returns None if the index cannot be found in the curent call. Returns None if the index cannot be found in the curent call.
""" """
if self._key_name_str is not None: if self._call_details.keyword_name_str is not None:
for i, param in enumerate(self.params): for i, param in enumerate(self.params):
if self._key_name_str == param.name: if self._call_details.keyword_name_str == param.name:
return i return i
if self.params: if self.params:
param_name = self.params[-1]._name param_name = self.params[-1]._name
@@ -628,7 +626,7 @@ class CallSignature(Definition):
return i return i
return None return None
if self._index >= len(self.params): if self._call_details.call_index >= len(self.params):
for i, param in enumerate(self.params): for i, param in enumerate(self.params):
tree_name = param._name.tree_name tree_name = param._name.tree_name
if tree_name is not None: if tree_name is not None:
@@ -636,7 +634,7 @@ class CallSignature(Definition):
if tree_name.get_definition().star_count == 1: if tree_name.get_definition().star_count == 1:
return i return i
return None return None
return self._index return self._call_details.call_index
@property @property
def params(self): def params(self):
@@ -648,7 +646,7 @@ class CallSignature(Definition):
The indent of the bracket that is responsible for the last function The indent of the bracket that is responsible for the last function
call. call.
""" """
return self._bracket_start_pos return self._call_details.bracket_leaf.start_pos
@property @property
def _params_str(self): def _params_str(self):

View File

@@ -395,6 +395,82 @@ def test_keyword_argument_index(Script, environment):
assert get(both + 'foo(a, b, c').index == 0 assert get(both + 'foo(a, b, c').index == 0
code1 = 'def f(u, /, v=3, *, abc, abd, xyz): pass'
code2 = 'def f(u, /, v=3, *, abc, abd, xyz, **kwargs): pass'
code3 = 'def f(u, /, v, *args, x=1, y): pass'
code4 = 'def f(u, /, v, *args, x=1, y, **kwargs): pass'
@pytest.mark.parametrize(
'code, call, index', [
# No *args, **kwargs
(code1, 'f(', 0),
(code1, 'f(a', 0),
(code1, 'f(a,', 1),
(code1, 'f(a,b', 1),
(code1, 'f(a,b,', 2),
(code1, 'f(a,b,c', None),
(code1, 'f(a,b,a', 2),
(code1, 'f(a,b,a=', None),
(code1, 'f(a,b,abc', 2),
(code1, 'f(a,b,abc=(', 2),
(code1, 'f(a,b,abc=(f,1,2,3', 2),
(code1, 'f(a,b,abd', 3),
(code1, 'f(a,b,x', 4),
(code1, 'f(a,b,xy', 4),
(code1, 'f(a,b,xyz=', 4),
(code1, 'f(a,b,xy=', None),
(code1, 'f(u=', None),
(code1, 'f(v=', 1),
# **kwargs
(code2, 'f(a,b,a', 2),
(code2, 'f(a,b,abd', 2),
(code2, 'f(a,b,arr', 5),
(code2, 'f(a,b,xy', 4),
(code2, 'f(a,b,xy=', 4),
(code2, 'f(a,b,abc=1,abd=4,', 5),
(code2, 'f(a,b,abc=1,abd=4,lala', 5),
(code2, 'f(a,b,abc=1,abd=4,lala=', 5),
(code2, 'f(a,b,kw', 5),
(code2, 'f(a,b,kwargs=', 5),
(code2, 'f(u=', 5),
(code2, 'f(v=', 1),
# *args
(code3, 'f(a,b,c', 2),
(code3, 'f(a,b,c,', 2),
(code3, 'f(a,b,c,d', 2),
(code3, 'f(a,b,c,d[', 2),
(code3, 'f(a,b,c,d(3,', 2),
(code3, 'f(a,b,c,(3,)', 2),
(code3, 'f(a,b,args=', None),
(code3, 'f(a,b=', 1),
(code3, 'f(a=', None),
# *args, **kwargs
(code4, 'f(a,b,c,d', 2),
(code4, 'f(a,b,c,d,e', 2),
(code4, 'f(a,b,c,d,e=', 5),
(code4, 'f(a,b,c,d,e=3', 5),
(code4, 'f(a,b,c,d=,', 3),
(code4, 'f(a,b,c,d=,x=', 3),
(code4, 'f(a,b,c,d=5,x=4', 3),
(code4, 'f(a,b,c,d=5,x=4,y', 4),
(code4, 'f(a,b,c,d=5,x=4,y=3,', 5),
(code4, 'f(a,b,c,d=5,y=4,x=3', 4),
(code4, 'f(a,b,c,d=5,y=4,x=3,', 5),
(code4, 'f(a,b,c,d=4,', 5),
(code4, 'f(a,b,c,d=,', 5),
]
)
def test_signature_index(skip_pre_python38, Script, code, call, index):
sig, = Script(code + '\n' + call).call_signatures()
print(call)
print('index', index)
assert index == sig.index
@pytest.mark.skipif(sys.version_info[0] == 2, reason="Python 2 doesn't support __signature__") @pytest.mark.skipif(sys.version_info[0] == 2, reason="Python 2 doesn't support __signature__")
@pytest.mark.parametrize('code', ['foo', 'instance.foo']) @pytest.mark.parametrize('code', ['foo', 'instance.foo'])
def test_arg_defaults(Script, environment, code): def test_arg_defaults(Script, environment, code):