1
0
forked from VimPlug/jedi

Merge branch 'pep484' into linter

This commit is contained in:
Dave Halter
2015-12-20 23:19:10 +01:00
28 changed files with 541 additions and 207 deletions

View File

@@ -305,6 +305,8 @@ class Evaluator(object):
types = set(chain.from_iterable(self.find_types(typ, next_name)
for typ in types))
types = types
elif element.type == 'eval_input':
types = self._eval_element_not_cached(element.children[0])
else:
types = precedence.calculate_children(self, element.children)
debug.dbg('eval_element result %s', types)

View File

@@ -8,7 +8,7 @@ import os
import inspect
from jedi._compatibility import is_py3, builtins, unicode
from jedi.parser import Parser, load_grammar
from jedi.parser import ParserWithRecovery, load_grammar
from jedi.parser import tree as pt
from jedi.evaluate.helpers import FakeName
@@ -31,7 +31,7 @@ def _load_faked_module(module):
modules[module_name] = None
return
grammar = load_grammar('grammar3.4')
module = Parser(grammar, unicode(source), module_name).module
module = ParserWithRecovery(grammar, unicode(source), module_name).module
modules[module_name] = module
if module_name == 'builtins' and not is_py3:
@@ -68,7 +68,11 @@ def get_module(obj):
# Happens for example in `(_ for _ in []).send.__module__`.
return builtins
else:
return __import__(imp_plz)
try:
return __import__(imp_plz)
except ImportError:
# __module__ can be something arbitrary that doesn't exist.
return builtins
def _faked(module, obj, name):

View File

@@ -20,7 +20,7 @@ from itertools import chain
from textwrap import dedent
from jedi.evaluate.cache import memoize_default
from jedi.parser import Parser, load_grammar
from jedi.parser import ParserWithRecovery, load_grammar
from jedi.common import indent_block
from jedi.evaluate.iterable import Array, FakeSequence, AlreadyEvaluated
@@ -130,7 +130,7 @@ 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 = Parser(load_grammar(), code % indent_block(string))
p = ParserWithRecovery(load_grammar(), code % indent_block(string))
try:
pseudo_cls = p.module.subscopes[0]
# First pick suite, then simple_stmt (-2 for DEDENT) and then the node,

View File

@@ -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)
@@ -485,8 +487,8 @@ def global_names_dict_generator(evaluator, scope, position):
the current scope is function:
>>> from jedi._compatibility import u, no_unicode_pprint
>>> from jedi.parser import Parser, load_grammar
>>> parser = Parser(load_grammar(), u('''
>>> from jedi.parser import ParserWithRecovery, load_grammar
>>> parser = ParserWithRecovery(load_grammar(), u('''
... x = ['a', 'b', 'c']
... def func():
... y = None

59
jedi/evaluate/pep0484.py Normal file
View File

@@ -0,0 +1,59 @@
"""
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`
x support for type hint comments `# type: (int, str) -> int`. See comment from
Guido https://github.com/davidhalter/jedi/issues/662
"""
from itertools import chain
from jedi.parser import Parser, load_grammar
from jedi.evaluate.cache import memoize_default
from jedi.evaluate.compiled import CompiledObject
from jedi import debug
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, start='eval_input')
element = p.get_parsed_node()
if element is None:
debug.warning('Annotation not parsed: %s' % definition.obj)
else:
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)

View File

@@ -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)

View File

@@ -14,7 +14,7 @@ from jedi.common import unite
from jedi.evaluate import compiled
from jedi.evaluate import representation as er
from jedi.evaluate import iterable
from jedi.parser import Parser
from jedi.parser import ParserWithRecovery
from jedi.parser import tree
from jedi import debug
from jedi.evaluate import precedence
@@ -243,7 +243,7 @@ def collections_namedtuple(evaluator, obj, arguments):
)
# Parse source
generated_class = Parser(evaluator.grammar, unicode(source)).module.subscopes[0]
generated_class = ParserWithRecovery(evaluator.grammar, unicode(source)).module.subscopes[0]
return set([er.Class(evaluator, generated_class)])

View File

@@ -5,7 +5,7 @@ from jedi.evaluate.site import addsitedir
from jedi._compatibility import exec_function, unicode
from jedi.parser import tree
from jedi.parser import Parser
from jedi.parser import ParserWithRecovery
from jedi.evaluate.cache import memoize_default
from jedi import debug
from jedi import common
@@ -209,7 +209,7 @@ def _get_paths_from_buildout_script(evaluator, buildout_script):
debug.dbg('Error trying to read buildout_script: %s', buildout_script)
return
p = Parser(evaluator.grammar, source, buildout_script)
p = ParserWithRecovery(evaluator.grammar, source, buildout_script)
cache.save_parser(buildout_script, p)
return p.module