isinstance checks for if/while

This commit is contained in:
David Halter
2012-10-04 00:34:26 +02:00
parent 8d842dd596
commit 7e39a7d1ba
4 changed files with 77 additions and 7 deletions

View File

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

View File

@@ -492,3 +492,43 @@ class RelatedName(BaseOutput):
def __hash__(self): def __hash__(self):
return hash((self.start_pos, self.module_path)) return hash((self.start_pos, self.module_path))
def check_flow_information(flow, search_name):
""" Try to find out the type of a variable just with the information that
is given by the flows: e.g.
>>> if isinstance(k, str):
>>> k. # <- completion here
ensures that `k` is a string.
"""
try:
assert flow.command in ['if', 'while']
assert len(flow.inits) == 1
ass = flow.inits[0].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'
assert bool(call.execution)
# isinstance check
isinst = call.execution.values
assert len(isinst) == 2
assert len(isinst[0]) == 1
assert len(isinst[1]) == 1
assert isinstance(isinst[0][0], parsing.Call)
# names fit?
assert str(isinst[0][0].name) == search_name
classes_call = isinst[1][0] # class_or_type_or_tuple
assert isinstance(classes_call, parsing.Call)
result = []
for c in evaluate.follow_call(classes_call):
if isinstance(c, evaluate.Array):
result += c.get_index_types()
else:
result.append(c)
for i, c in enumerate(result):
result[i] = evaluate.Instance(c)
return result
except AssertionError:
return []

View File

@@ -1118,10 +1118,11 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
result.append(par) result.append(par)
return result, no_break_scope return result, no_break_scope
flow_scope = scope
result = [] result = []
# compare func uses the tuple of line/indent = line/column # compare func uses the tuple of line/indent = line/column
comparison_func = lambda name: (name.start_pos) comparison_func = lambda name: (name.start_pos)
for scope, name_list in scope_generator: for nscope, name_list in scope_generator:
break_scopes = [] break_scopes = []
# here is the position stuff happening (sorting of variables) # here is the position stuff happening (sorting of variables)
for name in sorted(name_list, key=comparison_func, reverse=True): for name in sorted(name_list, key=comparison_func, reverse=True):
@@ -1136,7 +1137,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
else: else:
result += r result += r
# for comparison we need the raw class # for comparison we need the raw class
s = scope.base if isinstance(scope, Class) else scope s = nscope.base if isinstance(nscope, Class) else nscope
# this means that a definition was found and is not e.g. # this means that a definition was found and is not e.g.
# in if/else. # in if/else.
if result and not no_break_scope: if result and not no_break_scope:
@@ -1147,10 +1148,19 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False,
if result: if result:
break break
if not result and isinstance(scope, Instance): while flow_scope and flow_scope.isinstance(parsing.Flow):
result = dynamic.check_flow_information(flow_scope, name_str)
if result:
break
flow_scope = flow_scope.parent()
flow_scope = nscope
if result:
break
if not result and isinstance(nscope, Instance):
# getattr() / __getattr__ / __getattribute__ # getattr() / __getattr__ / __getattribute__
result += check_getattr(scope, name_str) result += check_getattr(nscope, name_str)
debug.dbg('sfn filter "%s" in %s: %s' % (name_str, scope, result)) debug.dbg('sfn filter "%s" in %s: %s' % (name_str, nscope, result))
return result return result
def descriptor_check(result): def descriptor_check(result):

View File

@@ -0,0 +1,19 @@
if isinstance(i, str):
#? str()
i
if isinstance(j, (str, int)):
#? str() int()
j
while isinstance(k, (str, int)):
#? str() int()
k
if not isinstance(k, (str, int)):
#?
k
while not isinstance(k, (str, int)):
#?
k