forked from VimPlug/jedi
WIP of namedtuple/itemgetter/property
This commit is contained in:
@@ -4,12 +4,12 @@ from parso.python import tree
|
|||||||
|
|
||||||
from jedi._compatibility import zip_longest
|
from jedi._compatibility import zip_longest
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.evaluate.utils import to_list
|
from jedi.evaluate.utils import to_list, PushBackIterator
|
||||||
from jedi.evaluate import analysis
|
from jedi.evaluate import analysis
|
||||||
from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts, \
|
from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts, \
|
||||||
LazyTreeContext, get_merged_lazy_context
|
LazyTreeContext, get_merged_lazy_context
|
||||||
from jedi.evaluate.filters import ParamName
|
from jedi.evaluate.filters import ParamName
|
||||||
from jedi.evaluate.base_context import NO_CONTEXTS
|
from jedi.evaluate.base_context import NO_CONTEXTS, ContextSet
|
||||||
from jedi.evaluate.context import iterable
|
from jedi.evaluate.context import iterable
|
||||||
from jedi.evaluate.param import get_executed_params, ExecutedParam
|
from jedi.evaluate.param import get_executed_params, ExecutedParam
|
||||||
|
|
||||||
@@ -63,9 +63,23 @@ def repack_with_argument_clinic(string, keep_arguments_param=False):
|
|||||||
|
|
||||||
def _iterate_argument_clinic(arguments, parameters):
|
def _iterate_argument_clinic(arguments, parameters):
|
||||||
"""Uses a list with argument clinic information (see PEP 436)."""
|
"""Uses a list with argument clinic information (see PEP 436)."""
|
||||||
iterator = arguments.unpack()
|
iterator = PushBackIterator(arguments.unpack())
|
||||||
for i, (name, optional, allow_kwargs) in enumerate(parameters):
|
for i, (name, optional, allow_kwargs, stars) in enumerate(parameters):
|
||||||
|
if stars == 1:
|
||||||
|
lazy_contexts = []
|
||||||
|
for key, argument in iterator:
|
||||||
|
if key is not None:
|
||||||
|
iterator.push_back((key, argument))
|
||||||
|
break
|
||||||
|
|
||||||
|
lazy_contexts.append(argument)
|
||||||
|
yield ContextSet(iterable.FakeSequence(evaluator, u'tuple', lazy_contexts))
|
||||||
|
lazy_contexts
|
||||||
|
continue
|
||||||
|
elif stars == 2:
|
||||||
|
raise NotImplementedError()
|
||||||
key, argument = next(iterator, (None, None))
|
key, argument = next(iterator, (None, None))
|
||||||
|
print(stars)
|
||||||
if key is not None:
|
if key is not None:
|
||||||
debug.warning('Keyword arguments in argument clinic are currently not supported.')
|
debug.warning('Keyword arguments in argument clinic are currently not supported.')
|
||||||
raise ValueError
|
raise ValueError
|
||||||
@@ -93,14 +107,18 @@ def _parse_argument_clinic(string):
|
|||||||
# at the end of the arguments. This is therefore not a proper argument
|
# at the end of the arguments. This is therefore not a proper argument
|
||||||
# clinic implementation. `range()` for exmple allows an optional start
|
# clinic implementation. `range()` for exmple allows an optional start
|
||||||
# value at the beginning.
|
# value at the beginning.
|
||||||
match = re.match('(?:(?:(\[),? ?|, ?|)(\w+)|, ?/)\]*', string)
|
match = re.match('(?:(?:(\[),? ?|, ?|)(\**\w+)|, ?/)\]*', string)
|
||||||
string = string[len(match.group(0)):]
|
string = string[len(match.group(0)):]
|
||||||
if not match.group(2): # A slash -> allow named arguments
|
if not match.group(2): # A slash -> allow named arguments
|
||||||
allow_kwargs = True
|
allow_kwargs = True
|
||||||
continue
|
continue
|
||||||
optional = optional or bool(match.group(1))
|
optional = optional or bool(match.group(1))
|
||||||
word = match.group(2)
|
word = match.group(2)
|
||||||
yield (word, optional, allow_kwargs)
|
stars = word.count('*')
|
||||||
|
word = word[stars:]
|
||||||
|
yield (word, optional, allow_kwargs, stars)
|
||||||
|
if stars:
|
||||||
|
allow_kwargs = True
|
||||||
|
|
||||||
|
|
||||||
class AbstractArguments(object):
|
class AbstractArguments(object):
|
||||||
|
|||||||
@@ -122,6 +122,17 @@ def iterate_contexts(contexts, contextualized_node=None, is_async=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ContextWrapper(object):
|
||||||
|
def __init__(self, wrapped_context):
|
||||||
|
self._wrapped_context = wrapped_context
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._wrapped_context, name)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%s)' % (self.__class__.__name__, self._wrapped_context)
|
||||||
|
|
||||||
|
|
||||||
class TreeContext(Context):
|
class TreeContext(Context):
|
||||||
def __init__(self, evaluator, parent_context, tree_node):
|
def __init__(self, evaluator, parent_context, tree_node):
|
||||||
super(TreeContext, self).__init__(evaluator, parent_context)
|
super(TreeContext, self).__init__(evaluator, parent_context)
|
||||||
|
|||||||
@@ -318,8 +318,8 @@ class BoundMethod(AbstractFunction):
|
|||||||
function.parent_context,
|
function.parent_context,
|
||||||
function.tree_node,
|
function.tree_node,
|
||||||
)
|
)
|
||||||
self._instance = instance
|
self.instance = instance
|
||||||
self._class = klass
|
self.class_context = klass
|
||||||
self._function = function
|
self._function = function
|
||||||
|
|
||||||
def py__class__(self):
|
def py__class__(self):
|
||||||
@@ -327,9 +327,9 @@ class BoundMethod(AbstractFunction):
|
|||||||
|
|
||||||
def _get_arguments(self, arguments):
|
def _get_arguments(self, arguments):
|
||||||
if arguments is None:
|
if arguments is None:
|
||||||
arguments = AnonymousInstanceArguments(self._instance)
|
arguments = AnonymousInstanceArguments(self.instance)
|
||||||
|
|
||||||
return InstanceArguments(self._instance, arguments)
|
return InstanceArguments(self.instance, arguments)
|
||||||
|
|
||||||
def get_function_execution(self, arguments=None):
|
def get_function_execution(self, arguments=None):
|
||||||
arguments = self._get_arguments(arguments)
|
arguments = self._get_arguments(arguments)
|
||||||
@@ -344,7 +344,7 @@ class BoundMethod(AbstractFunction):
|
|||||||
return self._function.get_function_execution(arguments)
|
return self._function.get_function_execution(arguments)
|
||||||
|
|
||||||
def get_default_param_context(self):
|
def get_default_param_context(self):
|
||||||
return self._class
|
return self.class_context
|
||||||
|
|
||||||
def py__call__(self, arguments):
|
def py__call__(self, arguments):
|
||||||
if isinstance(self._function, OverloadedFunctionContext):
|
if isinstance(self._function, OverloadedFunctionContext):
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ from jedi._compatibility import force_unicode
|
|||||||
from jedi.plugins.base import BasePlugin
|
from jedi.plugins.base import BasePlugin
|
||||||
from jedi import debug
|
from jedi import debug
|
||||||
from jedi.evaluate.arguments import ValuesArguments, \
|
from jedi.evaluate.arguments import ValuesArguments, \
|
||||||
repack_with_argument_clinic, AbstractArguments
|
repack_with_argument_clinic, AbstractArguments, TreeArguments
|
||||||
from jedi.evaluate import analysis
|
from jedi.evaluate import analysis
|
||||||
from jedi.evaluate import compiled
|
from jedi.evaluate import compiled
|
||||||
from jedi.evaluate.context.instance import \
|
from jedi.evaluate.context.instance import \
|
||||||
AbstractInstanceContext, CompiledInstance, BoundMethod, InstanceArguments
|
AbstractInstanceContext, CompiledInstance, BoundMethod, InstanceArguments
|
||||||
from jedi.evaluate.base_context import ContextualizedNode, \
|
from jedi.evaluate.base_context import ContextualizedNode, \
|
||||||
NO_CONTEXTS, ContextSet
|
NO_CONTEXTS, ContextSet, ContextWrapper
|
||||||
from jedi.evaluate.context import ClassContext, ModuleContext, \
|
from jedi.evaluate.context import ClassContext, ModuleContext, \
|
||||||
FunctionExecutionContext
|
FunctionExecutionContext
|
||||||
from jedi.evaluate.context import iterable
|
from jedi.evaluate.context import iterable
|
||||||
@@ -49,9 +49,6 @@ _NAMEDTUPLE_INIT = """
|
|||||||
class StdlibPlugin(BasePlugin):
|
class StdlibPlugin(BasePlugin):
|
||||||
def execute(self, callback):
|
def execute(self, callback):
|
||||||
def wrapper(context, arguments):
|
def wrapper(context, arguments):
|
||||||
if isinstance(context, BoundMethod):
|
|
||||||
return callback(context, arguments=arguments)
|
|
||||||
|
|
||||||
debug.dbg('execute: %s %s', context, arguments)
|
debug.dbg('execute: %s %s', context, arguments)
|
||||||
try:
|
try:
|
||||||
obj_name = context.name.string_name
|
obj_name = context.name.string_name
|
||||||
@@ -65,6 +62,16 @@ class StdlibPlugin(BasePlugin):
|
|||||||
else:
|
else:
|
||||||
module_name = ''
|
module_name = ''
|
||||||
|
|
||||||
|
if isinstance(context, BoundMethod):
|
||||||
|
if module_name == 'builtins' and context.py__name__() == '__get__':
|
||||||
|
if context.class_context.py__name__() == 'property':
|
||||||
|
return builtins_property(
|
||||||
|
self._evaluator,
|
||||||
|
context,
|
||||||
|
arguments=arguments
|
||||||
|
)
|
||||||
|
return callback(context, arguments=arguments)
|
||||||
|
|
||||||
# for now we just support builtin functions.
|
# for now we just support builtin functions.
|
||||||
try:
|
try:
|
||||||
func = _implemented[module_name][obj_name]
|
func = _implemented[module_name][obj_name]
|
||||||
@@ -112,6 +119,21 @@ def argument_clinic(string, want_obj=False, want_context=False, want_arguments=F
|
|||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
@argument_clinic('obj, type, /', want_obj=True, want_arguments=True)
|
||||||
|
def builtins_property(evaluator, objects, types, obj, arguments):
|
||||||
|
print(obj)
|
||||||
|
print(obj.instance.var_args)
|
||||||
|
property_args = obj.instance.var_args.unpack()
|
||||||
|
key, lazy_context = next(property_args, (None, None))
|
||||||
|
if key is not None or lazy_context is None:
|
||||||
|
debug.warning('property expected a first param, not %s', arguments)
|
||||||
|
return NO_CONTEXTS
|
||||||
|
print('lazy_context', lazy_context, lazy_context.infer())
|
||||||
|
print()
|
||||||
|
print(objects, type)
|
||||||
|
return NO_CONTEXTS
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('iterator[, default], /')
|
@argument_clinic('iterator[, default], /')
|
||||||
def builtins_next(evaluator, iterators, defaults):
|
def builtins_next(evaluator, iterators, defaults):
|
||||||
"""
|
"""
|
||||||
@@ -291,8 +313,12 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
# Parse source code
|
# Parse source code
|
||||||
module = evaluator.grammar.parse(code)
|
module = evaluator.grammar.parse(code)
|
||||||
generated_class = next(module.iter_classdefs())
|
generated_class = next(module.iter_classdefs())
|
||||||
parent_context = None
|
parent_context = ModuleContext(
|
||||||
raise NotImplementedError('TODO implement parent_context')
|
evaluator, module,
|
||||||
|
path=None,
|
||||||
|
string_names=None,
|
||||||
|
code_lines=parso.split_lines(code, keepends=True),
|
||||||
|
)
|
||||||
|
|
||||||
return ContextSet(ClassContext(evaluator, parent_context, generated_class))
|
return ContextSet(ClassContext(evaluator, parent_context, generated_class))
|
||||||
|
|
||||||
@@ -353,6 +379,24 @@ def _random_choice(evaluator, sequences):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemGetterCallable(object):
|
||||||
|
def __init__(self, args_context_set):
|
||||||
|
# TODO this context is totally incomplete and will raise exceptions.
|
||||||
|
self._args_context_set = args_context_set
|
||||||
|
|
||||||
|
@repack_with_argument_clinic('item, /')
|
||||||
|
def py__call__(self, item):
|
||||||
|
return self._args_context_set.py__getitem__(item)
|
||||||
|
|
||||||
|
|
||||||
|
@argument_clinic('*args, /', want_obj=True, want_arguments=True)
|
||||||
|
def _operator_itemgetter(evaluator, args_context_set, obj, arguments):
|
||||||
|
final = obj.py__call__(arguments)
|
||||||
|
print(final)
|
||||||
|
return final
|
||||||
|
return ItemGetterCallable(args_context_set)
|
||||||
|
|
||||||
|
|
||||||
_implemented = {
|
_implemented = {
|
||||||
'builtins': {
|
'builtins': {
|
||||||
'getattr': builtins_getattr,
|
'getattr': builtins_getattr,
|
||||||
@@ -382,6 +426,9 @@ _implemented = {
|
|||||||
'random': {
|
'random': {
|
||||||
'choice': _random_choice,
|
'choice': _random_choice,
|
||||||
},
|
},
|
||||||
|
'operator': {
|
||||||
|
'itemgetter': _operator_itemgetter,
|
||||||
|
},
|
||||||
'abc': {
|
'abc': {
|
||||||
# Not sure if this is necessary, but it's used a lot in typeshed and
|
# Not sure if this is necessary, but it's used a lot in typeshed and
|
||||||
# it's for now easier to just pass the function.
|
# it's for now easier to just pass the function.
|
||||||
|
|||||||
@@ -241,6 +241,18 @@ with contextlib.closing('asd') as string:
|
|||||||
#? str()
|
#? str()
|
||||||
string
|
string
|
||||||
|
|
||||||
|
# -----------------
|
||||||
|
# operator
|
||||||
|
# -----------------
|
||||||
|
|
||||||
|
import operator
|
||||||
|
|
||||||
|
f = operator.itemgetter([1])
|
||||||
|
#? float()
|
||||||
|
f([1.0])
|
||||||
|
#? str()
|
||||||
|
f([1, ''])
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
# shlex
|
# shlex
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|||||||
Reference in New Issue
Block a user