dostring fixes.

This commit is contained in:
Dave Halter
2016-11-13 20:23:17 +01:00
parent b2bdfe4a28
commit 65d3e29146
5 changed files with 52 additions and 35 deletions

View File

@@ -26,7 +26,7 @@ class Context(object):
return context
context = context.parent_context
def execute(self, arguments=None):
def execute(self, arguments):
return self.evaluator.execute(self, arguments)
def execute_evaluated(self, *value_list):

View File

@@ -16,12 +16,14 @@ annotations.
from ast import literal_eval
import re
from itertools import chain
from textwrap import dedent
from jedi._compatibility import u
from jedi.common import unite
from jedi.evaluate import context
from jedi.evaluate.cache import memoize_default
from jedi.parser import ParserWithRecovery, load_grammar
from jedi.parser.tree import Class
from jedi.parser.tree import search_ancestor
from jedi.common import indent_block
from jedi.evaluate.iterable import ArrayLiteralContext, FakeSequence, AlreadyEvaluated
@@ -114,12 +116,12 @@ def _strip_rst_role(type_str):
return type_str
def _evaluate_for_statement_string(evaluator, string, module):
code = dedent("""
def _evaluate_for_statement_string(module_context, string):
code = dedent(u("""
def pseudo_docstring_stuff():
# Create a pseudo function for docstring statements.
%s
""")
{0}
"""))
if string is None:
return []
@@ -131,31 +133,39 @@ def _evaluate_for_statement_string(evaluator, string, module):
# Take the default grammar here, if we load the Python 2.7 grammar here, it
# will be impossible to use `...` (Ellipsis) as a token. Docstring types
# don't need to conform with the current grammar.
p = ParserWithRecovery(load_grammar(), code % indent_block(string))
p = ParserWithRecovery(load_grammar(), code.format(indent_block(string)))
try:
pseudo_cls = p.module.subscopes[0]
funcdef = p.module.subscopes[0]
# First pick suite, then simple_stmt and then the node,
# which is also not the last item, because there's a newline.
stmt = pseudo_cls.children[-1].children[-1].children[-2]
stmt = funcdef.children[-1].children[-1].children[-2]
except (AttributeError, IndexError):
return []
from jedi.evaluate.param import ValuesArguments
from jedi.evaluate.representation import FunctionExecutionContext
func_context = FunctionExecutionContext(
module_context.evaluator,
module_context,
funcdef,
ValuesArguments([])
)
# Use the module of the param.
# TODO this module is not the module of the param in case of a function
# call. In that case it's the module of the function call.
# stuffed with content from a function call.
pseudo_cls.parent = module
return list(_execute_types_in_stmt(evaluator, stmt))
return list(_execute_types_in_stmt(func_context, stmt))
def _execute_types_in_stmt(evaluator, stmt):
def _execute_types_in_stmt(module_context, stmt):
"""
Executing all types or general elements that we find in a statement. This
doesn't include tuple, list and dict literals, because the stuff they
contain is executed. (Used as type information).
"""
definitions = evaluator.eval_element(stmt)
return chain.from_iterable(_execute_array_values(evaluator, d) for d in definitions)
definitions = module_context.eval_node(stmt)
return unite(_execute_array_values(module_context.evaluator, d) for d in definitions)
def _execute_array_values(evaluator, array):
@@ -165,35 +175,33 @@ def _execute_array_values(evaluator, array):
"""
if isinstance(array, ArrayLiteralContext):
values = []
for types in array.py__iter__():
objects = set(chain.from_iterable(_execute_array_values(evaluator, typ) for typ in types))
values.append(AlreadyEvaluated(objects))
return [FakeSequence(evaluator, values, array.type)]
for lazy_context in array.py__iter__():
objects = unite(_execute_array_values(evaluator, typ) for typ in lazy_context.infer())
values.append(context.LazyKnownContexts(objects))
return set([FakeSequence(evaluator, array.array_type, values)])
else:
return evaluator.execute(array)
return array.execute_evaluated()
@memoize_default(None, evaluator_is_first_arg=True)
def follow_param(evaluator, param):
@memoize_default()
def follow_param(module_context, param):
def eval_docstring(docstring):
return set(
[p for param_str in _search_param_in_docstr(docstring, str(param.name))
for p in _evaluate_for_statement_string(evaluator, param_str, module)]
for p in _evaluate_for_statement_string(module_context, param_str)]
)
func = param.parent_function
module = param.get_parent_until()
types = eval_docstring(func.raw_doc)
if func.name.value == '__init__':
cls = func.get_parent_until(Class)
cls = search_ancestor(func, 'classdef')
if cls.type == 'classdef':
types |= eval_docstring(cls.raw_doc)
return types
@memoize_default(None, evaluator_is_first_arg=True)
def find_return_types(evaluator, func):
@memoize_default()
def find_return_types(module_context, func):
def search_return_in_docstr(code):
for p in DOCSTRING_RETURN_PATTERNS:
match = p.search(code)
@@ -201,4 +209,4 @@ def find_return_types(evaluator, func):
return _strip_rst_role(match.group(1))
type_str = search_return_in_docstr(func.raw_doc)
return _evaluate_for_statement_string(evaluator, type_str, func.get_parent_until())
return _evaluate_for_statement_string(module_context, type_str)

View File

@@ -7,6 +7,7 @@ from jedi.parser import tree
from jedi.evaluate import iterable
from jedi.evaluate import analysis
from jedi.evaluate import context
from jedi.evaluate import docstrings
def try_iter_content(types, depth=0):
@@ -175,13 +176,19 @@ class ValuesArguments(AbstractArguments):
class ExecutedParam(object):
"""Fake a param and give it values."""
def __init__(self, original_param, var_args, lazy_context):
def __init__(self, var_args_context, original_param, var_args, lazy_context):
self._root_context = var_args_context.get_root_context()
self._original_param = original_param
self.var_args = var_args
self._lazy_context = lazy_context
self.string_name = self._original_param.name.value
def infer(self):
pep0484_hints = set()#pep0484.follow_param(evaluator, param)
doc_params = docstrings.follow_param(self._root_context, self._original_param)
if pep0484_hints or doc_params:
return list(set(pep0484_hints) | set(doc_params))
return self._lazy_context.infer()
@property
@@ -253,7 +260,7 @@ def get_params(evaluator, parent_context, func, var_args):
analysis.add(evaluator, 'type-error-multiple-values',
calling_va, message=m)
else:
keys_used[key] = ExecutedParam(key_param, var_args, argument)
keys_used[key] = ExecutedParam(parent_context, key_param, var_args, argument)
key, argument = next(var_arg_iterator, (None, None))
try:
@@ -297,7 +304,7 @@ def get_params(evaluator, parent_context, func, var_args):
else:
result_arg = argument
result_params.append(ExecutedParam(param, var_args, result_arg))
result_params.append(ExecutedParam(parent_context, param, var_args, result_arg))
keys_used[param.name.value] = result_params[-1]
if keys_only:
@@ -403,4 +410,4 @@ def create_default_param(parent_context, param):
result_arg = context.LazyUnknownContext()
else:
result_arg = context.LazyTreeContext(parent_context, param.default)
return ExecutedParam(param, None, result_arg)
return ExecutedParam(parent_context, param, None, result_arg)

View File

@@ -643,7 +643,7 @@ class FunctionExecutionContext(Executed):
returns = funcdef.yields
else:
returns = funcdef.returns
types = set(docstrings.find_return_types(self.evaluator, funcdef))
types = set(docstrings.find_return_types(self.get_root_context(), funcdef))
types |= set(pep0484.find_return_types(self.evaluator, funcdef))
for r in returns:

View File

@@ -122,6 +122,7 @@ from jedi import debug
from jedi._compatibility import unicode, is_py3
from jedi.parser import Parser, load_grammar
from jedi.api.classes import Definition
from jedi.api.completion import get_user_scope
from jedi.evaluate.representation import ModuleContext
@@ -193,7 +194,8 @@ class IntegrationTestCase(object):
module_context = script._get_module()
# The context shouldn't matter for the test results.
element.parent = module_context.module_node
results = evaluator.eval_element(module_context, element)
user_context = get_user_scope(module_context, (self.line_nr, 0))
results = evaluator.eval_element(user_context, element)
if not results:
raise Exception('Could not resolve %s on line %s'
% (match.string, self.line_nr - 1))