diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index ee18d5d4..b676406e 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -412,6 +412,9 @@ magic_function_class = CompiledObject(type(load_module), parent=builtin) generator_obj = CompiledObject(_a_generator(1.0)) type_names = [] # Need this, because it's return in get_defined_names. type_names = builtin.get_by_name('type').get_defined_names() +none_obj = builtin.get_by_name('None') +false_obj = builtin.get_by_name('False') +true_obj = builtin.get_by_name('True') def compiled_objects_cache(func): diff --git a/jedi/evaluate/precedence.py b/jedi/evaluate/precedence.py index 39e4afc9..8f453cae 100644 --- a/jedi/evaluate/precedence.py +++ b/jedi/evaluate/precedence.py @@ -1,14 +1,24 @@ """ Handles operator precedence. """ +import operator from jedi._compatibility import unicode from jedi.parser import representation as pr from jedi import debug from jedi.common import PushBackIterator -from jedi.evaluate.compiled import CompiledObject, create, builtin +from jedi.evaluate.compiled import (CompiledObject, create, builtin, false_obj, + true_obj, none_obj) from jedi.evaluate import analysis +# Maps Python syntax to the operator module. +OPERATOR_MAPPING = { + '==': operator.eq, + '!=': operator.ne, + 'is': operator.is_, + 'is not': operator.is_not, +} + class PythonGrammar(object): """ @@ -260,6 +270,15 @@ def _is_list(obj): return isinstance(obj, iterable.Array) and obj.type == pr.Array.LIST +def _keyword_from_value(obj): + if obj is None: + return none_obj + elif obj is False: + return false_obj + elif obj is True: + return true_obj + + def _element_calculate(evaluator, left, operator, right): from jedi.evaluate import iterable, representation as er l_is_num = _is_number(left) @@ -282,6 +301,13 @@ def _element_calculate(evaluator, left, operator, right): # With strings and numbers the left type typically remains. Except for # `int() % float()`. return [left] + elif operator in OPERATOR_MAPPING: + operation = OPERATOR_MAPPING[operator] + if isinstance(left, CompiledObject) and isinstance(right, CompiledObject): + # Possible, because the return is not an option. Just compare. + left = left.obj + right = right.obj + return [_keyword_from_value(operation(left, right))] def check(obj): """Checks if a Jedi object is either a float or an int.""" diff --git a/test/completion/flow_analysis.py b/test/completion/flow_analysis.py index 2b0730fb..3cff6af0 100644 --- a/test/completion/flow_analysis.py +++ b/test/completion/flow_analysis.py @@ -88,12 +88,41 @@ def check(a): if a is None: return 1 return '' + return set #? int() check(None) #? str() check('asb') +a = list +if 2 == True: + a = set +elif 1 == True: + a = 0 + +#? int() +a +if check != 1: + a = '' +#? str() +a +if check == check: + a = list +#? list +a +if check != check: + a = set +else: + a = dict +#? dict +a +if (check is not check): + a = 1 +#? dict +a + + # ----------------- # name resolution # ----------------- @@ -121,5 +150,3 @@ else: #? int a - -