assert isinstance checks

This commit is contained in:
David Halter
2012-10-07 15:13:40 +02:00
parent 8795b4fbac
commit 39f89462b4
6 changed files with 50 additions and 13 deletions

View File

@@ -60,14 +60,13 @@ Jedi supports many of the widely used Python features:
- class decorators (py3k feature, are being ignored too, until I find a use
case, that doesn't work with Jedi)
- simple/usual ``sys.path`` modifications
- ``isinstance`` checks for if/while
- ``isinstance`` checks for if/while/assert
However, it does not yet support (and probably will in future versions, because
they are on my todo list):
- manipulations of instances outside the instance variables, without using
functions
- assert
It does not support (and most probably will not in future versions):

View File

@@ -494,18 +494,32 @@ class RelatedName(BaseOutput):
return hash((self.start_pos, self.module_path))
def check_flow_information(flow, search_name):
def check_flow_information(flow, search_name, pos):
""" Try to find out the type of a variable just with the information that
is given by the flows: e.g.
is given by the flows: e.g. It is also responsible for assert checks.
>>> if isinstance(k, str):
>>> k. # <- completion here
ensures that `k` is a string.
"""
result = []
if isinstance(flow, parsing.Scope) and not result:
for ass in reversed(flow.asserts):
if ass.start_pos > pos:
continue
result = check_statement_information(ass, search_name)
if result:
break
if isinstance(flow, parsing.Flow) and not result:
if flow.command in ['if', 'while'] and len(flow.inits) == 1:
result = check_statement_information(flow.inits[0], search_name)
return result
def check_statement_information(stmt, search_name):
try:
assert flow.command in ['if', 'while']
assert len(flow.inits) == 1
ass = flow.inits[0].get_assignment_calls()
ass = stmt.get_assignment_calls()
assert len(ass.values) == 1 and len(ass.values[0]) == 1
call = ass.values[0][0]
assert type(call) == parsing.Call and str(call.name) == 'isinstance'

View File

@@ -264,7 +264,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)):
def __getattr__(self, name):
if name not in ['start_pos', 'end_pos', 'name', 'get_imports',
'docstr']:
'docstr', 'asserts']:
raise AttributeError("Instance %s: Don't touch this (%s)!"
% (self, name))
return getattr(self.base, name)
@@ -386,7 +386,7 @@ class Class(use_metaclass(CachedMetaClass, parsing.Base)):
def __getattr__(self, name):
if name not in ['start_pos', 'end_pos', 'parent', 'subscopes',
'get_imports', 'get_parent_until', 'docstr']:
'get_imports', 'get_parent_until', 'docstr', 'asserts']:
raise AttributeError("Don't touch this (%s)!" % name)
return getattr(self.base, name)
@@ -726,6 +726,11 @@ class Execution(Executable):
def returns(self):
return self.copy_properties('returns')
@property
@memoize_default()
def asserts(self):
return self.copy_properties('asserts')
@property
@memoize_default()
def statements(self):
@@ -1148,10 +1153,13 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
if result:
break
while flow_scope and flow_scope.isinstance(parsing.Flow):
result = dynamic.check_flow_information(flow_scope, name_str)
while flow_scope:
result = dynamic.check_flow_information(flow_scope, name_str,
position)
if result:
break
if flow_scope == nscope:
break
flow_scope = flow_scope.parent()
flow_scope = nscope
if result:

View File

@@ -92,7 +92,7 @@ class ExecutionRecursionDecorator(object):
self.reset()
def __call__(self, execution, evaluate_generator=False):
debug.dbg('Execution recursions: ', execution, self.recursion_level,
debug.dbg('Execution recursions: %s' % execution, self.recursion_level,
self.execution_count, len(self.execution_funcs))
if self.check_recursion(execution, evaluate_generator):
result = []

View File

@@ -139,6 +139,7 @@ class Scope(Simple):
self.imports = []
self.statements = []
self.docstr = docstr
self.asserts = []
def add_scope(self, sub, decorators):
sub.parent = weakref.ref(self)
@@ -1416,7 +1417,7 @@ class PyFuzzyParser(object):
string += ".".join(n.names)
continue
elif token_type == tokenize.NAME:
if tok in ['return', 'yield', 'del', 'raise', 'assert']:
if tok in ['return', 'yield', 'del', 'raise']:
if len(tok_list) > 1:
# this happens, when a statement has opening
# brackets, which are not closed again, here I just
@@ -1751,6 +1752,10 @@ class PyFuzzyParser(object):
decorators.append(stmt)
elif tok == 'pass':
continue
elif tok == 'assert':
stmt, tok = self._parse_statement()
stmt.parent = weakref.ref(self.scope)
self.scope.asserts.append(stmt)
# default
elif token_type in [tokenize.NAME, tokenize.STRING,
tokenize.NUMBER] \

View File

@@ -17,3 +17,14 @@ if not isinstance(k, (str, int)):
while not isinstance(k, (str, int)):
#?
k
assert isinstance(ass, int):
#? int()
ass
assert isinstance(ass, str):
assert not isinstance(ass, int):
if 2:
#? str()
ass