mirror of
https://github.com/davidhalter/jedi.git
synced 2026-05-11 09:08:43 +08:00
Merge branch 'add-partialmethod' of https://github.com/ffe4/jedi
This commit is contained in:
+24
-7
@@ -471,13 +471,12 @@ def collections_namedtuple(value, arguments, callback):
|
|||||||
return ValueSet([ClassValue(inference_state, parent_context, generated_class)])
|
return ValueSet([ClassValue(inference_state, parent_context, generated_class)])
|
||||||
|
|
||||||
|
|
||||||
class PartialObject(object):
|
class PartialObject(ValueWrapper):
|
||||||
def __init__(self, actual_value, arguments):
|
def __init__(self, actual_value, arguments, instance=None):
|
||||||
|
super(PartialObject, self).__init__(actual_value)
|
||||||
self._actual_value = actual_value
|
self._actual_value = actual_value
|
||||||
self._arguments = arguments
|
self._arguments = arguments
|
||||||
|
self._instance = instance
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self._actual_value, name)
|
|
||||||
|
|
||||||
def _get_function(self, unpacked_arguments):
|
def _get_function(self, unpacked_arguments):
|
||||||
key, lazy_value = next(unpacked_arguments, (None, None))
|
key, lazy_value = next(unpacked_arguments, (None, None))
|
||||||
@@ -493,6 +492,8 @@ class PartialObject(object):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
arg_count = 0
|
arg_count = 0
|
||||||
|
if self._instance is not None:
|
||||||
|
arg_count = 1
|
||||||
keys = set()
|
keys = set()
|
||||||
for key, _ in unpacked_arguments:
|
for key, _ in unpacked_arguments:
|
||||||
if key is None:
|
if key is None:
|
||||||
@@ -501,13 +502,16 @@ class PartialObject(object):
|
|||||||
keys.add(key)
|
keys.add(key)
|
||||||
return [PartialSignature(s, arg_count, keys) for s in func.get_signatures()]
|
return [PartialSignature(s, arg_count, keys) for s in func.get_signatures()]
|
||||||
|
|
||||||
|
def py__get__(self, instance, class_value):
|
||||||
|
return ValueSet([PartialObject(self._actual_value, self._arguments, self._instance)])
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
func = self._get_function(self._arguments.unpack())
|
func = self._get_function(self._arguments.unpack())
|
||||||
if func is None:
|
if func is None:
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
|
||||||
return func.execute(
|
return func.execute(
|
||||||
MergedPartialArguments(self._arguments, arguments)
|
MergedPartialArguments(self._arguments, arguments, self._instance)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -523,15 +527,18 @@ class PartialSignature(SignatureWrapper):
|
|||||||
|
|
||||||
|
|
||||||
class MergedPartialArguments(AbstractArguments):
|
class MergedPartialArguments(AbstractArguments):
|
||||||
def __init__(self, partial_arguments, call_arguments):
|
def __init__(self, partial_arguments, call_arguments, instance=None):
|
||||||
self._partial_arguments = partial_arguments
|
self._partial_arguments = partial_arguments
|
||||||
self._call_arguments = call_arguments
|
self._call_arguments = call_arguments
|
||||||
|
self._instance = instance
|
||||||
|
|
||||||
def unpack(self, funcdef=None):
|
def unpack(self, funcdef=None):
|
||||||
unpacked = self._partial_arguments.unpack(funcdef)
|
unpacked = self._partial_arguments.unpack(funcdef)
|
||||||
# Ignore this one, it's the function. It was checked before that it's
|
# Ignore this one, it's the function. It was checked before that it's
|
||||||
# there.
|
# there.
|
||||||
next(unpacked)
|
next(unpacked)
|
||||||
|
if self._instance is not None:
|
||||||
|
yield None, LazyKnownValue(self._instance)
|
||||||
for key_lazy_value in unpacked:
|
for key_lazy_value in unpacked:
|
||||||
yield key_lazy_value
|
yield key_lazy_value
|
||||||
for key_lazy_value in self._call_arguments.unpack(funcdef):
|
for key_lazy_value in self._call_arguments.unpack(funcdef):
|
||||||
@@ -545,6 +552,15 @@ def functools_partial(value, arguments, callback):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def functools_partialmethod(value, arguments, callback):
|
||||||
|
return ValueSet(
|
||||||
|
# XXX last argument is a placeholder. See:
|
||||||
|
# https://github.com/davidhalter/jedi/pull/1522#discussion_r392474671
|
||||||
|
PartialObject(instance, arguments, True)
|
||||||
|
for instance in value.py__call__(arguments)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('first, /')
|
@argument_clinic('first, /')
|
||||||
def _return_first_param(firsts):
|
def _return_first_param(firsts):
|
||||||
return firsts
|
return firsts
|
||||||
@@ -742,6 +758,7 @@ _implemented = {
|
|||||||
},
|
},
|
||||||
'functools': {
|
'functools': {
|
||||||
'partial': functools_partial,
|
'partial': functools_partial,
|
||||||
|
'partialmethod': functools_partialmethod,
|
||||||
'wraps': _functools_wraps,
|
'wraps': _functools_wraps,
|
||||||
},
|
},
|
||||||
'_weakref': {
|
'_weakref': {
|
||||||
|
|||||||
@@ -158,6 +158,46 @@ tup[0]
|
|||||||
#? float()
|
#? float()
|
||||||
tup[1]
|
tup[1]
|
||||||
|
|
||||||
|
class X:
|
||||||
|
def function(self, a, b):
|
||||||
|
return a, b
|
||||||
|
a = functools.partialmethod(function, 0)
|
||||||
|
kw = functools.partialmethod(function, b=1.0)
|
||||||
|
|
||||||
|
#? int()
|
||||||
|
X().a('')[0]
|
||||||
|
#? str()
|
||||||
|
X().a('')[1]
|
||||||
|
|
||||||
|
#? int()
|
||||||
|
X.a('')[0]
|
||||||
|
#? str()
|
||||||
|
X.a('')[1]
|
||||||
|
|
||||||
|
#? int()
|
||||||
|
X.a(X(), '')[0]
|
||||||
|
#? str()
|
||||||
|
X.a(X(), '')[1]
|
||||||
|
|
||||||
|
tup = X().kw(1)
|
||||||
|
#? int()
|
||||||
|
tup[0]
|
||||||
|
#? float()
|
||||||
|
tup[1]
|
||||||
|
|
||||||
|
tup = X.kw(1)
|
||||||
|
#? int()
|
||||||
|
tup[0]
|
||||||
|
#? float()
|
||||||
|
tup[1]
|
||||||
|
|
||||||
|
tup = X.kw(X(), 1)
|
||||||
|
#? int()
|
||||||
|
tup[0]
|
||||||
|
#? float()
|
||||||
|
tup[1]
|
||||||
|
|
||||||
|
|
||||||
def my_decorator(f):
|
def my_decorator(f):
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapper(*args, **kwds):
|
def wrapper(*args, **kwds):
|
||||||
|
|||||||
@@ -65,6 +65,19 @@ d = functools.partial()
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
partialmethod_code = '''
|
||||||
|
import functools
|
||||||
|
|
||||||
|
class X:
|
||||||
|
def func(self, a, b, c):
|
||||||
|
pass
|
||||||
|
a = functools.partialmethod(func)
|
||||||
|
b = functools.partialmethod(func, 1)
|
||||||
|
c = functools.partialmethod(func, 1, c=2)
|
||||||
|
d = functools.partialmethod()
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'code, expected', [
|
'code, expected', [
|
||||||
('def f(a, * args, x): pass\n f(', 'f(a, *args, x)'),
|
('def f(a, * args, x): pass\n f(', 'f(a, *args, x)'),
|
||||||
@@ -82,6 +95,13 @@ d = functools.partial()
|
|||||||
(partial_code + 'b(', 'func(b, c)'),
|
(partial_code + 'b(', 'func(b, c)'),
|
||||||
(partial_code + 'c(', 'func(b)'),
|
(partial_code + 'c(', 'func(b)'),
|
||||||
(partial_code + 'd(', None),
|
(partial_code + 'd(', None),
|
||||||
|
|
||||||
|
(partialmethod_code + 'X().a(', 'func(a, b, c)'),
|
||||||
|
(partialmethod_code + 'X().b(', 'func(b, c)'),
|
||||||
|
(partialmethod_code + 'X().c(', 'func(b)'),
|
||||||
|
(partialmethod_code + 'X().d(', None),
|
||||||
|
(partialmethod_code + 'X.c(', 'func(b)'),
|
||||||
|
(partialmethod_code + 'X.d(', None),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_tree_signature(Script, environment, code, expected):
|
def test_tree_signature(Script, environment, code, expected):
|
||||||
|
|||||||
Reference in New Issue
Block a user