forked from VimPlug/jedi
Merge branch 'linter' of https://github.com/reinhrst/jedi into pep484
Conflicts: AUTHORS.txt
This commit is contained in:
@@ -23,6 +23,7 @@ from jedi.evaluate import representation as er
|
||||
from jedi.evaluate import dynamic
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate import docstrings
|
||||
from jedi.evaluate import pep0484
|
||||
from jedi.evaluate import iterable
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate import analysis
|
||||
@@ -386,10 +387,11 @@ def _eval_param(evaluator, param, scope):
|
||||
and func.instance.is_generated and str(func.name) == '__init__':
|
||||
param = func.var.params[param.position_nr]
|
||||
|
||||
# Add docstring knowledge.
|
||||
# Add pep0484 and docstring knowledge.
|
||||
pep0484_hints = pep0484.follow_param(evaluator, param)
|
||||
doc_params = docstrings.follow_param(evaluator, param)
|
||||
if doc_params:
|
||||
return doc_params
|
||||
if pep0484_hints or doc_params:
|
||||
return list(set(pep0484_hints) | set(doc_params))
|
||||
|
||||
if isinstance(param, ExecutedParam):
|
||||
return res_new | param.eval(evaluator)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
PEP 0484 ( https://www.python.org/dev/peps/pep-0484/ ) describes type hints
|
||||
through function annotations. There is a strong suggestion in this document
|
||||
that only the type of type hinting defined in PEP0484 should be allowed
|
||||
as annotations in future python versions.
|
||||
|
||||
The (initial / probably incomplete) implementation todo list for pep-0484:
|
||||
v Function parameter annotations with builtin/custom type classes
|
||||
v Function returntype annotations with builtin/custom type classes
|
||||
v Function parameter annotations with strings (forward reference)
|
||||
v Function return type annotations with strings (forward reference)
|
||||
x Local variable type hints
|
||||
v Assigned types: `Url = str\ndef get(url:Url) -> str:`
|
||||
x Type hints in `with` statements
|
||||
x Stub files support
|
||||
x support `@no_type_check` and `@no_type_check_decorator`
|
||||
"""
|
||||
|
||||
from itertools import chain
|
||||
from jedi.parser import Parser, load_grammar
|
||||
from jedi.evaluate.cache import memoize_default
|
||||
from jedi.evaluate.compiled import CompiledObject
|
||||
|
||||
|
||||
def _evaluate_for_annotation(evaluator, annotation):
|
||||
if annotation is not None:
|
||||
definitions = set()
|
||||
for definition in evaluator.eval_element(annotation):
|
||||
if (isinstance(definition, CompiledObject) and
|
||||
isinstance(definition.obj, str)):
|
||||
p = Parser(load_grammar(), definition.obj)
|
||||
try:
|
||||
element = p.module.children[0].children[0]
|
||||
except (AttributeError, IndexError):
|
||||
continue
|
||||
element.parent = annotation.parent
|
||||
definitions |= evaluator.eval_element(element)
|
||||
else:
|
||||
definitions.add(definition)
|
||||
return list(chain.from_iterable(
|
||||
evaluator.execute(d) for d in definitions))
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
@memoize_default(None, evaluator_is_first_arg=True)
|
||||
def follow_param(evaluator, param):
|
||||
annotation = param.annotation()
|
||||
return _evaluate_for_annotation(evaluator, annotation)
|
||||
|
||||
|
||||
@memoize_default(None, evaluator_is_first_arg=True)
|
||||
def find_return_types(evaluator, func):
|
||||
annotation = func.py__annotations__().get("return", None)
|
||||
return _evaluate_for_annotation(evaluator, annotation)
|
||||
@@ -49,6 +49,7 @@ from jedi.evaluate import compiled
|
||||
from jedi.evaluate import recursion
|
||||
from jedi.evaluate import iterable
|
||||
from jedi.evaluate import docstrings
|
||||
from jedi.evaluate import pep0484
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.evaluate import param
|
||||
from jedi.evaluate import flow_analysis
|
||||
@@ -583,6 +584,20 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
|
||||
else:
|
||||
return FunctionExecution(self._evaluator, self, params).get_return_types()
|
||||
|
||||
@memoize_default()
|
||||
def py__annotations__(self):
|
||||
parser_func = self.base
|
||||
return_annotation = parser_func.annotation()
|
||||
if return_annotation:
|
||||
dct = {'return': return_annotation}
|
||||
else:
|
||||
dct = {}
|
||||
for function_param in parser_func.params:
|
||||
param_annotation = function_param.annotation()
|
||||
if param_annotation is not None:
|
||||
dct[function_param.name.value] = param_annotation
|
||||
return dct
|
||||
|
||||
def py__class__(self):
|
||||
return compiled.get_special_object(self._evaluator, 'FUNCTION_CLASS')
|
||||
|
||||
@@ -642,6 +657,7 @@ class FunctionExecution(Executed):
|
||||
else:
|
||||
returns = self.returns
|
||||
types = set(docstrings.find_return_types(self._evaluator, func))
|
||||
types |= set(pep0484.find_return_types(self._evaluator, func))
|
||||
|
||||
for r in returns:
|
||||
check = flow_analysis.break_check(self._evaluator, self, r)
|
||||
|
||||
+16
-3
@@ -873,7 +873,10 @@ class Function(ClassOrFunc):
|
||||
|
||||
def annotation(self):
|
||||
try:
|
||||
return self.children[6] # 6th element: def foo(...) -> bar
|
||||
if self.children[3] == "->":
|
||||
return self.children[4]
|
||||
assert self.children[3] == ":"
|
||||
return None
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
@@ -952,6 +955,10 @@ class Lambda(Function):
|
||||
def is_generator(self):
|
||||
return False
|
||||
|
||||
def annotation(self):
|
||||
# lambda functions do not support annotations
|
||||
return None
|
||||
|
||||
@property
|
||||
def yields(self):
|
||||
return []
|
||||
@@ -1404,8 +1411,14 @@ class Param(BaseNode):
|
||||
return None
|
||||
|
||||
def annotation(self):
|
||||
# Generate from tfpdef.
|
||||
raise NotImplementedError
|
||||
tfpdef = self._tfpdef()
|
||||
if is_node(tfpdef, 'tfpdef'):
|
||||
assert tfpdef.children[1] == ":"
|
||||
assert len(tfpdef.children) == 3
|
||||
annotation = tfpdef.children[2]
|
||||
return annotation
|
||||
else:
|
||||
return None
|
||||
|
||||
def _tfpdef(self):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user