def builtins_isinstance(evaluator, objects, types, arguments): bool_results = set([]) for o in objects: try: mro_func = o.py__class__().py__mro__ except AttributeError: # This is temporary. Everything should have a class attribute in # Python?! Maybe we'll leave it here, because some numpy objects or # whatever might not. return set([compiled.create(True), compiled.create(False)]) mro = mro_func() for cls_or_tup in types: if cls_or_tup.is_class(): bool_results.add(cls_or_tup in mro) elif cls_or_tup.name.string_name == 'tuple' \ and cls_or_tup.get_root_context() == evaluator.BUILTINS: # Check for tuples. classes = unite( lazy_context.infer() for lazy_context in cls_or_tup.py__iter__() ) bool_results.add(any(cls in mro for cls in classes)) else: _, lazy_context = list(arguments.unpack())[1] if isinstance(lazy_context, LazyTreeContext): node = lazy_context.data message = 'TypeError: isinstance() arg 2 must be a ' \ 'class, type, or tuple of classes and types, ' \ 'not %s.' % cls_or_tup analysis.add(lazy_context._context, 'type-error-isinstance', node, message) return set(compiled.create(evaluator, x) for x in bool_results)
def _element_calculate(evaluator, left, operator, right): from jedi.evaluate import iterable, representation as er l_is_num = _is_number(left) r_is_num = _is_number(right) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.Array) or _is_string(left): return [left] elif isinstance(right, iterable.Array) or _is_string(right): return [right] elif operator == '+': if l_is_num and r_is_num or _is_string(left) and _is_string(right): return [create(evaluator, left.obj + right.obj)] elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): return [iterable.MergedArray(evaluator, (left, right))] elif operator == '-': if l_is_num and r_is_num: return [create(evaluator, left.obj - right.obj)] elif operator == '%': # With strings and numbers the left type typically remains. Except for # `int() % float()`. return [left] def check(obj): """Checks if a Jedi object is either a float or an int.""" return isinstance(obj, er.Instance) and obj.name in ('int', 'float') # Static analysis, one is a number, the other one is not. if operator in ('+', '-') and l_is_num != r_is_num \ and not (check(left) or check(right)): message = "TypeError: unsupported operand type(s) for +: %s and %s" analysis.add(evaluator, 'type-error-operation', operator, message % (left, right)) return [left, right]
def _element_calculate(evaluator, context, left, operator, right): from jedi.evaluate import iterable, instance l_is_num = _is_number(left) r_is_num = _is_number(right) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.AbstractSequence) or is_string(left): return set([left]) elif isinstance(right, iterable.AbstractSequence) or is_string(right): return set([right]) elif operator == '+': if l_is_num and r_is_num or is_string(left) and is_string(right): return set([create(evaluator, left.obj + right.obj)]) elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): return set([iterable.MergedArray(evaluator, (left, right))]) elif operator == '-': if l_is_num and r_is_num: return set([create(evaluator, left.obj - right.obj)]) elif operator == '%': # With strings and numbers the left type typically remains. Except for # `int() % float()`. return set([left]) elif operator in COMPARISON_OPERATORS: operation = COMPARISON_OPERATORS[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 try: result = operation(left, right) except TypeError: # Could be True or False. return set([create(evaluator, True), create(evaluator, False)]) else: return set([create(evaluator, result)]) elif operator == 'in': return set() def check(obj): """Checks if a Jedi object is either a float or an int.""" return isinstance(obj, instance.CompiledInstance) and \ obj.name.string_name in ('int', 'float') # Static analysis, one is a number, the other one is not. if operator in ('+', '-') and l_is_num != r_is_num \ and not (check(left) or check(right)): message = "TypeError: unsupported operand type(s) for +: %s and %s" analysis.add(context, 'type-error-operation', operator, message % (left, right)) return set([left, right])
def _element_calculate(evaluator, context, left, operator, right): from jedi.evaluate import iterable, instance l_is_num = _is_number(left) r_is_num = _is_number(right) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.AbstractSequence) or is_string(left): return set([left]) elif isinstance(right, iterable.AbstractSequence) or is_string(right): return set([right]) elif operator == '+': if l_is_num and r_is_num or is_string(left) and is_string(right): return set([create(evaluator, left.obj + right.obj)]) elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): return set([iterable.MergedArray(evaluator, (left, right))]) elif operator == '-': if l_is_num and r_is_num: return set([create(evaluator, left.obj - right.obj)]) elif operator == '%': # With strings and numbers the left type typically remains. Except for # `int() % float()`. return set([left]) elif operator in COMPARISON_OPERATORS: operation = COMPARISON_OPERATORS[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 try: result = operation(left, right) except TypeError: # Could be True or False. return set([create(evaluator, True), create(evaluator, False)]) else: return set([create(evaluator, result)]) elif operator == 'in': return set() def check(obj): """Checks if a Jedi object is either a float or an int.""" return isinstance(obj, instance.CompiledInstance) and \ obj.name.string_name in ('int', 'float') # Static analysis, one is a number, the other one is not. if operator in ('+', '-') and l_is_num != r_is_num \ and not (check(left) or check(right)): message = "TypeError: unsupported operand type(s) for +: %s and %s" analysis.add(context, 'type-error-operation', operator, message % (left, right)) return set([left, right])
def _element_calculate(evaluator, left, operator, right): from jedi.evaluate import iterable, representation as er l_is_num = _is_number(left) r_is_num = _is_number(right) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.Array) or is_string(left): return [left] elif isinstance(right, iterable.Array) or is_string(right): return [right] elif operator == '+': if l_is_num and r_is_num or is_string(left) and is_string(right): return [create(evaluator, left.obj + right.obj)] elif _is_tuple(left) and _is_tuple(right) or _is_list( left) and _is_list(right): return [iterable.MergedArray(evaluator, (left, right))] elif operator == '-': if l_is_num and r_is_num: return [create(evaluator, left.obj - right.obj)] elif operator == '%': # With strings and numbers the left type typically remains. Except for # `int() % float()`. return [left] elif operator in COMPARISON_OPERATORS: operation = COMPARISON_OPERATORS[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 try: return [keyword_from_value(operation(left, right))] except TypeError: # Could be True or False. return [true_obj, false_obj] elif operator == 'in': return [] def check(obj): """Checks if a Jedi object is either a float or an int.""" return isinstance( obj, er.Instance) and obj.name.get_code() in ('int', 'float') # Static analysis, one is a number, the other one is not. if operator in ('+', '-') and l_is_num != r_is_num \ and not (check(left) or check(right)): message = "TypeError: unsupported operand type(s) for +: %s and %s" analysis.add(evaluator, 'type-error-operation', operator, message % (left, right)) return [left, right]
def _element_calculate(evaluator, left, operator, right): if operator == '*': # for iterables, ignore * operations from jedi.evaluate import iterable if isinstance(left, iterable.Array) or _is_string(left): return [left] elif operator == '+': if _is_number(left) and _is_number(right) or _is_string(left) and _is_string(right): return [create(evaluator, left.obj + right.obj)] elif operator == '-': if _is_number(left) and _is_number(right): return [create(evaluator, left.obj - right.obj)] return [left, right]
def _element_calculate(evaluator, left, operator, right): if operator == '*': # for iterables, ignore * operations from jedi.evaluate import iterable if isinstance(left, iterable.Array) or _is_string(left): return [left] elif operator == '+': if _is_number(left) and _is_number(right) or _is_string( left) and _is_string(right): return [create(evaluator, left.obj + right.obj)] elif operator == '-': if _is_number(left) and _is_number(right): return [create(evaluator, left.obj - right.obj)] return [left, right]
def _element_calculate(evaluator, left, operator, right): from jedi.evaluate import iterable, representation as er l_is_num = _is_number(left) r_is_num = _is_number(right) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.Array) or is_string(left): return [left] elif isinstance(right, iterable.Array) or is_string(right): return [right] elif operator == '+': if l_is_num and r_is_num or is_string(left) and is_string(right): return [create(evaluator, left.obj + right.obj)] elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right): return [iterable.MergedArray(evaluator, (left, right))] elif operator == '-': if l_is_num and r_is_num: return [create(evaluator, left.obj - right.obj)] elif operator == '%': # With strings and numbers the left type typically remains. Except for # `int() % float()`. return [left] elif operator in COMPARISON_OPERATORS: operation = COMPARISON_OPERATORS[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 try: return [keyword_from_value(operation(left, right))] except TypeError: # Could be True or False. return [true_obj, false_obj] elif operator == 'in': return [] def check(obj): """Checks if a Jedi object is either a float or an int.""" return isinstance(obj, er.Instance) and obj.name.get_code() in ('int', 'float') # Static analysis, one is a number, the other one is not. if operator in ('+', '-') and l_is_num != r_is_num \ and not (check(left) or check(right)): message = "TypeError: unsupported operand type(s) for +: %s and %s" analysis.add(evaluator, 'type-error-operation', operator, message % (left, right)) return [left, right]
def eval_factor(context_set, operator): """ Calculates `+`, `-`, `~` and `not` prefixes. """ for context in context_set: if operator == '-': if is_number(context): yield compiled.create(context.evaluator, -context.obj) elif operator == 'not': value = context.py__bool__() if value is None: # Uncertainty. return yield compiled.create(context.evaluator, not value) else: yield context
def factor_calculate(evaluator, types, operator): """ Calculates `+`, `-`, `~` and `not` prefixes. """ for typ in types: if operator == '-': if _is_number(typ): yield create(evaluator, -typ.obj) elif operator == 'not': value = typ.py__bool__() if value is None: # Uncertainty. return yield create(evaluator, not value) else: yield typ
def eval_factor(context_set, operator): """ Calculates `+`, `-`, `~` and `not` prefixes. """ for context in context_set: if operator == '-': if is_number(context): yield compiled.create(context.evaluator, -context.obj) elif operator == 'not': value = context.py__bool__() if value is None: # Uncertainty. return yield compiled.create(context.evaluator, not value) else: yield context
def factor_calculate(evaluator, types, operator): """ Calculates `+`, `-`, `~` and `not` prefixes. """ for typ in types: if operator == '-': if _is_number(typ): yield create(evaluator, -typ.obj) elif operator == 'not': value = typ.py__bool__() if value is None: # Uncertainty. return yield create(evaluator, not value) else: yield typ
def get_return_values(self, check_yields=False): funcdef = self.tree_node if funcdef.type == 'lambdef': return self.evaluator.eval_element(self, funcdef.children[-1]) if check_yields: types = set() returns = get_yield_exprs(self.evaluator, funcdef) else: returns = funcdef.iter_return_stmts() types = set(docstrings.infer_return_types(self.function_context)) types |= set(pep0484.infer_return_types(self.function_context)) for r in returns: check = flow_analysis.reachability_check(self, funcdef, r) if check is flow_analysis.UNREACHABLE: debug.dbg('Return unreachable: %s', r) else: if check_yields: types |= set(self._eval_yield(r)) else: try: children = r.children except AttributeError: types.add(compiled.create(self.evaluator, None)) else: types |= self.eval_node(children[1]) if check is flow_analysis.REACHABLE: debug.dbg('Return reachable: %s', r) break return types
def py__bases__(self): arglist = self.base.get_super_arglist() if arglist: args = param.Arguments(self._evaluator, arglist) return list(chain.from_iterable(args.eval_args())) else: return [compiled.create(self._evaluator, object)]
def _eval_element_not_cached(self, element): debug.dbg('eval_element %s@%s', element, element.start_pos) types = set() if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node( element, 'atom'): types = self._eval_atom(element) elif isinstance(element, tree.Keyword): # For False/True/None if element.value in ('False', 'True', 'None'): types.add(compiled.builtin_from_name(self, element.value)) # else: print e.g. could be evaluated like this in Python 2.7 elif element.isinstance(tree.Lambda): types = set([er.LambdaWrapper(self, element)]) elif element.isinstance(er.LambdaWrapper): types = set([element ]) # TODO this is no real evaluation. id:121 gh:122 elif element.type == 'expr_stmt': types = self.eval_statement(element) elif element.type in ('power', 'atom_expr'): types = self._eval_atom(element.children[0]) for trailer in element.children[1:]: if trailer == '**': # has a power operation. right = self.eval_element(element.children[2]) types = set( precedence.calculate(self, types, trailer, right)) break types = self.eval_trailer(types, trailer) elif element.type in ( 'testlist_star_expr', 'testlist', ): # The implicit tuple in statements. types = set([iterable.ImplicitTuple(self, element)]) elif element.type in ('not_test', 'factor'): types = self.eval_element(element.children[-1]) for operator in element.children[:-1]: types = set(precedence.factor_calculate(self, types, operator)) elif element.type == 'test': # `x if foo else y` case. types = (self.eval_element(element.children[0]) | self.eval_element(element.children[-1])) elif element.type == 'operator': # Must be an ellipsis, other operators are not evaluated. assert element.value == '...' types = set([compiled.create(self, Ellipsis)]) elif element.type == 'dotted_name': types = self._eval_atom(element.children[0]) for next_name in element.children[2::2]: 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]) elif element.type == 'annassign': types = self.eval_element(element.children[1]) else: types = precedence.calculate_children(self, element.children) debug.dbg('eval_element result %s', types) return types
def _create(evaluator, obj, parent_context=None, *args): tree_node, path = find_syntax_node_name(evaluator, obj) compiled_object = compiled.create( evaluator, obj, parent_context=parent_context.compiled_object) if tree_node is None: return compiled_object module_node = tree_node.get_root_node() if parent_context.tree_node.get_root_node() == module_node: module_context = parent_context.get_root_context() else: module_context = ModuleContext(evaluator, module_node, path=path) # TODO this __name__ is probably wrong. name = compiled_object.get_root_context().py__name__() imports.add_module(evaluator, name, module_context) tree_context = module_context.create_context( tree_node, node_is_context=True, node_is_object=True ) if tree_node.type == 'classdef': if not inspect.isclass(obj): # Is an instance, not a class. tree_context, = tree_context.execute_evaluated() return MixedObject( evaluator, parent_context, compiled_object, tree_context=tree_context )
def py__bases__(self): arglist = self.tree_node.get_super_arglist() if arglist: args = param.TreeArguments(self.evaluator, self, arglist) return [value for key, value in args.unpack() if key is None] else: return [context.LazyKnownContext(compiled.create(self.evaluator, object))]
def py__bases__(self): arglist = self.tree_node.get_super_arglist() if arglist: args = param.TreeArguments(self.evaluator, self, arglist) return [value for key, value in args.unpack() if key is None] else: return [context.LazyKnownContext(compiled.create(self.evaluator, object))]
def create(evaluator, obj, parent_context=None, *args): tree_node, path = find_syntax_node_name(evaluator, obj) compiled_object = compiled.create( evaluator, obj, parent_context=parent_context.compiled_object) if tree_node is None: return compiled_object module_node = tree_node.get_root_node() if parent_context.tree_node.get_root_node() == module_node: module_context = parent_context.get_root_context() else: from jedi.evaluate.representation import ModuleContext module_context = ModuleContext(evaluator, module_node, path=path) name = compiled_object.get_root_context().py__name__() imports.add_module(evaluator, name, module_context) tree_context = module_context.create_context( tree_node, node_is_context=True, node_is_object=True ) return MixedObject( evaluator, parent_context, compiled_object, tree_context=tree_context )
def py__bases__(self): arglist = self.base.get_super_arglist() if arglist: args = param.Arguments(self._evaluator, arglist) return list(chain.from_iterable(args.eval_args())) else: return [compiled.create(self._evaluator, object)]
def eval_call_path(self, path, scope, position): """ Follows a path generated by `pr.StatementElement.generate_call_path()`. """ current = next(path) if isinstance(current, pr.Array): if current.type == pr.Array.NOARRAY: try: lst_cmp = current[0].expression_list()[0] if not isinstance(lst_cmp, pr.ListComprehension): raise IndexError except IndexError: types = list(chain.from_iterable(self.eval_statement(s) for s in current)) else: types = [iterable.GeneratorComprehension(self, lst_cmp)] else: types = [iterable.Array(self, current)] else: if isinstance(current, pr.Name): # This is the first global lookup. types = self.find_types(scope, current, position=position, search_global=True) else: # for pr.Literal types = [compiled.create(self, current.value)] types = imports.follow_imports(self, types) return self.follow_path(path, types, scope)
def _eval_atom(self, atom): """ Basically to process ``atom`` nodes. The parser sometimes doesn't generate the node (because it has just one child). In that case an atom might be a name or a literal as well. """ if isinstance(atom, pr.Name): # This is the first global lookup. stmt = atom.get_definition() scope = stmt.get_parent_until(pr.IsScope, include_current=True) if isinstance(stmt, pr.CompFor): stmt = stmt.get_parent_until((pr.ClassOrFunc, pr.ExprStmt)) if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = atom return self.find_types(scope, atom, stmt.start_pos, search_global=True) elif isinstance(atom, pr.Literal): return [compiled.create(self, atom.eval())] else: c = atom.children # Parentheses without commas are not tuples. if c[0] == '(' and not len(c) == 2 \ and not(pr.is_node(c[1], 'testlist_comp') and len(c[1].children) > 1): return self.eval_element(c[1]) try: comp_for = c[1].children[1] except (IndexError, AttributeError): pass else: if isinstance(comp_for, pr.CompFor): return [iterable.Comprehension.from_atom(self, atom)] return [iterable.Array(self, atom)]
def get_return_values(self, check_yields=False): funcdef = self.tree_node if funcdef.type == 'lambdef': return self.evaluator.eval_element(self, funcdef.children[-1]) if check_yields: types = set() returns = get_yield_exprs(self.evaluator, funcdef) else: returns = funcdef.iter_return_stmts() types = set(docstrings.infer_return_types(self.function_context)) types |= set(pep0484.infer_return_types(self.function_context)) for r in returns: check = flow_analysis.reachability_check(self, funcdef, r) if check is flow_analysis.UNREACHABLE: debug.dbg('Return unreachable: %s', r) else: if check_yields: types |= set(self._eval_yield(r)) else: try: children = r.children except AttributeError: types.add(compiled.create(self.evaluator, None)) else: types |= self.eval_node(children[1]) if check is flow_analysis.REACHABLE: debug.dbg('Return reachable: %s', r) break return types
def _eval_atom(self, atom): """ Basically to process ``atom`` nodes. The parser sometimes doesn't generate the node (because it has just one child). In that case an atom might be a name or a literal as well. """ if isinstance(atom, pr.Name): # This is the first global lookup. stmt = atom.get_definition() scope = stmt.get_parent_until(pr.IsScope, include_current=True) if isinstance(stmt, pr.CompFor): stmt = stmt.get_parent_until((pr.ClassOrFunc, pr.ExprStmt)) if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = atom return self.find_types(scope, atom, stmt.start_pos, search_global=True) elif isinstance(atom, pr.Literal): return [compiled.create(self, atom.eval())] else: c = atom.children # Parentheses without commas are not tuples. if c[0] == '(' and not len(c) == 2 \ and not(pr.is_node(c[1], 'testlist_comp') and len(c[1].children) > 1): return self.eval_element(c[1]) try: comp_for = c[1].children[1] except (IndexError, AttributeError): pass else: if isinstance(comp_for, pr.CompFor): return [iterable.Comprehension.from_atom(self, atom)] return [iterable.Array(self, atom)]
def create(evaluator, obj, parent_context=None, *args): tree_node, path = find_syntax_node_name(evaluator, obj) compiled_object = compiled.create( evaluator, obj, parent_context=parent_context.compiled_object) if tree_node is None: return compiled_object module_node = tree_node.get_root_node() if parent_context.tree_node.get_root_node() == module_node: module_context = parent_context.get_root_context() else: from jedi.evaluate.representation import ModuleContext module_context = ModuleContext(evaluator, module_node, path=path) name = compiled_object.get_root_context().py__name__() imports.add_module(evaluator, name, module_context) tree_context = module_context.create_context(tree_node, node_is_context=True, node_is_object=True) return MixedObject(evaluator, parent_context, compiled_object, tree_context=tree_context)
def test_fake_loading(): assert isinstance(compiled.create(Evaluator(), next), Function) string = compiled.builtin.get_subscope_by_name('str') from_name = compiled._create_from_name(compiled.builtin, string, '__init__') assert isinstance(from_name, Function)
def _eval_atom(self, atom): """ Basically to process ``atom`` nodes. The parser sometimes doesn't generate the node (because it has just one child). In that case an atom might be a name or a literal as well. """ if isinstance(atom, tree.Name): # This is the first global lookup. stmt = atom.get_definition() scope = stmt.get_parent_until(tree.IsScope, include_current=True) if isinstance(scope, (tree.Function, er.FunctionExecution)): # Adjust scope: If the name is not in the suite, it's a param # default or annotation and will be resolved as part of the # parent scope. colon = scope.children.index(':') if atom.start_pos < scope.children[colon + 1].start_pos: scope = scope.get_parent_scope() if isinstance(stmt, tree.CompFor): stmt = stmt.get_parent_until((tree.ClassOrFunc, tree.ExprStmt)) if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = atom return self.find_types(scope, atom, stmt.start_pos, search_global=True) elif isinstance(atom, tree.Literal): return set([compiled.create(self, atom.eval())]) else: c = atom.children if c[0].type == 'string': # Will be one string. types = self._eval_atom(c[0]) for string in c[1:]: right = self._eval_atom(string) types = precedence.calculate(self, types, '+', right) return types # Parentheses without commas are not tuples. elif c[0] == '(' and not len(c) == 2 \ and not(tree.is_node(c[1], 'testlist_comp') and len(c[1].children) > 1): return self.eval_element(c[1]) try: comp_for = c[1].children[1] except (IndexError, AttributeError): pass else: if comp_for == ':': # Dict comprehensions have a colon at the 3rd index. try: comp_for = c[1].children[3] except IndexError: pass if comp_for.type == 'comp_for': return set([iterable.Comprehension.from_atom(self, atom)]) return set([iterable.Array(self, atom)])
def _eval_element_not_cached(self, context, element): debug.dbg('eval_element %s@%s', element, element.start_pos) types = set() typ = element.type if typ in ('name', 'number', 'string', 'atom'): types = self.eval_atom(context, element) elif typ == 'keyword': # For False/True/None if element.value in ('False', 'True', 'None'): types.add(compiled.builtin_from_name(self, element.value)) # else: print e.g. could be evaluated like this in Python 2.7 elif typ == 'lambdef': types = set([er.FunctionContext(self, context, element)]) elif typ == 'expr_stmt': types = self.eval_statement(context, element) elif typ in ('power', 'atom_expr'): first_child = element.children[0] if not (first_child.type == 'keyword' and first_child.value == 'await'): types = self.eval_atom(context, first_child) for trailer in element.children[1:]: if trailer == '**': # has a power operation. right = self.eval_element(context, element.children[2]) types = set(precedence.calculate(self, context, types, trailer, right)) break types = self.eval_trailer(context, types, trailer) elif typ in ('testlist_star_expr', 'testlist',): # The implicit tuple in statements. types = set([iterable.SequenceLiteralContext(self, context, element)]) elif typ in ('not_test', 'factor'): types = self.eval_element(context, element.children[-1]) for operator in element.children[:-1]: types = set(precedence.factor_calculate(self, types, operator)) elif typ == 'test': # `x if foo else y` case. types = (self.eval_element(context, element.children[0]) | self.eval_element(context, element.children[-1])) elif typ == 'operator': # Must be an ellipsis, other operators are not evaluated. # In Python 2 ellipsis is coded as three single dot tokens, not # as one token 3 dot token. assert element.value in ('.', '...') types = set([compiled.create(self, Ellipsis)]) elif typ == 'dotted_name': types = self.eval_atom(context, element.children[0]) for next_name in element.children[2::2]: # TODO add search_global=True? types = unite( typ.py__getattribute__(next_name, name_context=context) for typ in types ) types = types elif typ == 'eval_input': types = self._eval_element_not_cached(context, element.children[0]) elif typ == 'annassign': types = pep0484._evaluate_for_annotation(context, element.children[1]) else: types = precedence.calculate_children(self, context, element.children) debug.dbg('eval_element result %s', types) return types
def _module_attributes(self): names = [ '__file__', '__package__', '__doc__', '__name__', '__version__' ] # All the additional module attributes are strings. parent = Instance(self._evaluator, compiled.create(self._evaluator, str)) return [helpers.FakeName(n, parent) for n in names]
def create(evaluator, obj, parent_context=None, *args): tree_name = find_syntax_node_name(evaluator, obj) compiled_object = compiled.create( evaluator, obj, parent_context=parent_context.compiled_object) if tree_name is None: return compiled_object return MixedObject(evaluator, parent_context, compiled_object, tree_name)
def create(evaluator, obj, parent_context=None, *args): tree_name = find_syntax_node_name(evaluator, obj) compiled_object = compiled.create( evaluator, obj, parent_context=parent_context.compiled_object) if tree_name is None: return compiled_object return MixedObject(evaluator, parent_context, compiled_object, tree_name)
def test_fake_loading(): e = _evaluator() assert isinstance(compiled.create(e, next), Function) builtin = compiled.get_special_object(e, 'BUILTINS') string = builtin.get_subscope_by_name('str') from_name = compiled._create_from_name(e, builtin, string, '__init__') assert isinstance(from_name, Function)
def test_fake_loading(): e = _evaluator() assert isinstance(compiled.create(e, next), FunctionContext) builtin = compiled.get_special_object(e, 'BUILTINS') string, = builtin.py__getattribute__('str') from_name = compiled._create_from_name(e, builtin, string, '__init__') assert isinstance(from_name, FunctionContext)
def py__getitem__(self, index): try: method = self.get_subscope_by_name('__getitem__') except KeyError: debug.warning('No __getitem__, cannot access the array.') return set() else: index_obj = compiled.create(self._evaluator, index) return self._evaluator.execute_evaluated(method, index_obj)
def py__getitem__(self, index): try: names = self.get_function_slot_names('__getitem__') except KeyError: debug.warning('No __getitem__, cannot access the array.') return NO_CONTEXTS else: index_obj = compiled.create(self.evaluator, index) return self.execute_function_slots(names, index_obj)
def py__getitem__(self, index): try: method = self.get_subscope_by_name('__getitem__') except KeyError: debug.warning('No __getitem__, cannot access the array.') return set() else: index_obj = compiled.create(self._evaluator, index) return self._evaluator.execute_evaluated(method, index_obj)
def py__getitem__(self, index): try: names = self.get_function_slot_names('__getitem__') except KeyError: debug.warning('No __getitem__, cannot access the array.') return set() else: index_obj = compiled.create(self.evaluator, index) return self.execute_function_slots(names, index_obj)
def _eval_atom(self, atom): """ Basically to process ``atom`` nodes. The parser sometimes doesn't generate the node (because it has just one child). In that case an atom might be a name or a literal as well. """ if isinstance(atom, tree.Name): # This is the first global lookup. stmt = atom.get_definition() scope = stmt.get_parent_until(tree.IsScope, include_current=True) if isinstance(scope, (tree.Function, er.FunctionExecution)): # Adjust scope: If the name is not in the suite, it's a param # default or annotation and will be resolved as part of the # parent scope. colon = scope.children.index(':') if atom.start_pos < scope.children[colon + 1].start_pos: scope = scope.get_parent_scope() if isinstance(stmt, tree.CompFor): stmt = stmt.get_parent_until((tree.ClassOrFunc, tree.ExprStmt)) if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because # there the name cannot be used. stmt = atom return self.find_types(scope, atom, stmt.start_pos, search_global=True) elif isinstance(atom, tree.Literal): return set([compiled.create(self, atom.eval())]) else: c = atom.children if c[0].type == 'string': # Will be one string. types = self._eval_atom(c[0]) for string in c[1:]: right = self._eval_atom(string) types = precedence.calculate(self, types, '+', right) return types # Parentheses without commas are not tuples. elif c[0] == '(' and not len(c) == 2 \ and not(tree.is_node(c[1], 'testlist_comp') and len(c[1].children) > 1): return self.eval_element(c[1]) try: comp_for = c[1].children[1] except (IndexError, AttributeError): pass else: if comp_for == ':': # Dict comprehensions have a colon at the 3rd index. try: comp_for = c[1].children[3] except IndexError: pass if comp_for.type == 'comp_for': return set([iterable.Comprehension.from_atom(self, atom)]) return set([iterable.Array(self, atom)])
def get_descriptor_returns(self, obj): """ Throws a KeyError if there's no method. """ # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. none_obj = compiled.create(self._evaluator, None) args = [obj, obj.base] if isinstance(obj, Instance) else [none_obj, obj] try: return self.execute_subscope_by_name('__get__', *args) except KeyError: return set([self])
def test_fake_loading(): assert isinstance(compiled.create(Evaluator(load_grammar()), next), Function) string = compiled.builtin.get_subscope_by_name('str') from_name = compiled._create_from_name( compiled.builtin, string, '__init__' ) assert isinstance(from_name, Function)
def _factor_calculate(evaluator, operator, right): if _is_number(right): if operator == '-': return create(evaluator, -right.obj) if operator == 'not': value = right.py__bool__() if value is None: # Uncertainty. return None return keyword_from_value(not value) return right
def get_descriptor_returns(self, obj): """ Throws a KeyError if there's no method. """ # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. none_obj = compiled.create(self._evaluator, None) args = [obj, obj.base] if isinstance(obj, Instance) else [none_obj, obj] try: return self.execute_subscope_by_name('__get__', *args) except KeyError: return set([self])
def py__getitem__(context, typ, node): if not typ.get_root_context().name.string_name == "typing": return None # we assume that any class using [] in a module called # "typing" with a name for which we have a replacement # should be replaced by that class. This is not 100% # airtight but I don't have a better idea to check that it's # actually the PEP-0484 typing module and not some other if node.type == "subscriptlist": nodes = node.children[::2] # skip the commas else: nodes = [node] del node nodes = [_fix_forward_reference(context, node) for node in nodes] type_name = typ.name.string_name # hacked in Union and Optional, since it's hard to do nicely in parsed code if type_name in ("Union", '_Union'): # In Python 3.6 it's still called typing.Union but it's an instance # called _Union. return unite(context.eval_node(node) for node in nodes) if type_name in ("Optional", '_Optional'): # Here we have the same issue like in Union. Therefore we also need to # check for the instance typing._Optional (Python 3.6). return context.eval_node(nodes[0]) from jedi.evaluate.representation import ModuleContext typing = ModuleContext( context.evaluator, module_node=_get_typing_replacement_module(), path=None ) factories = typing.py__getattribute__("factory") assert len(factories) == 1 factory = list(factories)[0] assert factory function_body_nodes = factory.tree_node.children[4].children valid_classnames = set(child.name.value for child in function_body_nodes if isinstance(child, tree.Class)) if type_name not in valid_classnames: return None compiled_classname = compiled.create(context.evaluator, type_name) from jedi.evaluate.iterable import FakeSequence args = FakeSequence( context.evaluator, "tuple", [LazyTreeContext(context, n) for n in nodes] ) result = factory.execute_evaluated(compiled_classname, args) return result
def py__getitem__(context, typ, node): if not typ.get_root_context().name.string_name == "typing": return None # we assume that any class using [] in a module called # "typing" with a name for which we have a replacement # should be replaced by that class. This is not 100% # airtight but I don't have a better idea to check that it's # actually the PEP-0484 typing module and not some other if node.type == "subscriptlist": nodes = node.children[::2] # skip the commas else: nodes = [node] del node nodes = [_fix_forward_reference(context, node) for node in nodes] type_name = typ.name.string_name # hacked in Union and Optional, since it's hard to do nicely in parsed code if type_name in ("Union", '_Union'): # In Python 3.6 it's still called typing.Union but it's an instance # called _Union. return unite(context.eval_node(node) for node in nodes) if type_name in ("Optional", '_Optional'): # Here we have the same issue like in Union. Therefore we also need to # check for the instance typing._Optional (Python 3.6). return context.eval_node(nodes[0]) from jedi.evaluate.representation import ModuleContext typing = ModuleContext( context.evaluator, module_node=_get_typing_replacement_module(context.evaluator.latest_grammar), path=None ) factories = typing.py__getattribute__("factory") assert len(factories) == 1 factory = list(factories)[0] assert factory function_body_nodes = factory.tree_node.children[4].children valid_classnames = set(child.name.value for child in function_body_nodes if isinstance(child, tree.Class)) if type_name not in valid_classnames: return None compiled_classname = compiled.create(context.evaluator, type_name) from jedi.evaluate.iterable import FakeSequence args = FakeSequence( context.evaluator, "tuple", [LazyTreeContext(context, n) for n in nodes] ) result = factory.execute_evaluated(compiled_classname, args) return result
def _element_calculate(left, operator, right): def is_string(obj): return isinstance(obj, CompiledObject) \ and isinstance(obj.obj, (str, unicode)) def is_number(obj): return isinstance(obj, CompiledObject) \ and isinstance(obj.obj, (int, float)) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.Array) or is_string(left): return [left] elif operator == '+': if is_number(left) and is_number(right) or is_string(left) and is_string(right): return [create(left.obj + right.obj)] elif operator == '-': if is_number(left) and is_number(right): return [create(left.obj - right.obj)] return [left, right]
def parent(self): obj = self._value parser_path = [] if inspect.ismodule(obj): module = obj else: class FakeParent(pr.Base): parent = None # To avoid having no parent for NamePart. path = None names = [] try: o = obj.__objclass__ names.append(obj.__name__) obj = o except AttributeError: pass try: module_name = obj.__module__ names.insert(0, obj.__name__) except AttributeError: # Unfortunately in some cases like `int` there's no __module__ module = builtins else: module = __import__(module_name) fake_name = helpers.FakeName(names, FakeParent()) parser_path = fake_name.names raw_module = get_module(self._value) try: path = module.__file__ except AttributeError: pass else: path = re.sub('c$', '', path) if path.endswith('.py'): # cut the `c` from `.pyc` with open(path) as f: source = source_to_unicode(f.read()) mod = FastParser(source, path[:-1]).module if not parser_path: return mod found = self._evaluator.eval_call_path(iter(parser_path), mod, None) if found: return found[0] debug.warning('Interpreter lookup for Python code failed %s', mod) module = compiled.CompiledObject(raw_module) if raw_module == builtins: # The builtins module is special and always cached. module = compiled.builtin return compiled.create(self._evaluator, self._value, module, module)
def _element_calculate(left, operator, right): def is_string(obj): return isinstance(obj, CompiledObject) \ and isinstance(obj.obj, (str, unicode)) def is_number(obj): return isinstance(obj, CompiledObject) \ and isinstance(obj.obj, (int, float)) if operator == '*': # for iterables, ignore * operations if isinstance(left, iterable.Array) or is_string(left): return [left] elif operator == '+': if is_number(left) and is_number(right) or is_string( left) and is_string(right): return [create(left.obj + right.obj)] elif operator == '-': if is_number(left) and is_number(right): return [create(left.obj - right.obj)] return [left, right]
def get_filters(self, *args, **kwargs): for filter in self._module_context.get_filters(*args, **kwargs): yield filter for namespace_obj in self._namespace_objects: compiled_object = compiled.create(self.evaluator, namespace_obj) mixed_object = mixed.MixedObject(self.evaluator, parent_context=self, compiled_object=compiled_object, tree_context=self._module_context) for filter in mixed_object.get_filters(*args, **kwargs): yield filter
def py__get__(self, obj): # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. names = self.get_function_slot_names('__get__') if names: if isinstance(obj, AbstractInstanceContext): return self.execute_function_slots(names, obj, obj.class_context) else: none_obj = compiled.create(self.evaluator, None) return self.execute_function_slots(names, none_obj, obj) else: return set([self])
def py__get__(self, obj): # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. names = self.get_function_slot_names('__get__') if names: if isinstance(obj, AbstractInstanceContext): return self.execute_function_slots(names, obj, obj.class_context) else: none_obj = compiled.create(self.evaluator, None) return self.execute_function_slots(names, none_obj, obj) else: return ContextSet(self)
def _eval_element_not_cached(self, element): debug.dbg('eval_element %s@%s', element, element.start_pos) types = set() if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node(element, 'atom'): types = self._eval_atom(element) elif isinstance(element, tree.Keyword): # For False/True/None if element.value in ('False', 'True', 'None'): types.add(compiled.builtin_from_name(self, element.value)) # else: print e.g. could be evaluated like this in Python 2.7 elif element.isinstance(tree.Lambda): types = set([er.LambdaWrapper(self, element)]) elif element.isinstance(er.LambdaWrapper): types = set([element]) # TODO this is no real evaluation. elif element.type == 'expr_stmt': types = self.eval_statement(element) elif element.type in ('power', 'atom_expr'): types = self._eval_atom(element.children[0]) for trailer in element.children[1:]: if trailer == '**': # has a power operation. right = self.eval_element(element.children[2]) types = set(precedence.calculate(self, types, trailer, right)) break types = self.eval_trailer(types, trailer) elif element.type in ('testlist_star_expr', 'testlist',): # The implicit tuple in statements. types = set([iterable.ImplicitTuple(self, element)]) elif element.type in ('not_test', 'factor'): types = self.eval_element(element.children[-1]) for operator in element.children[:-1]: types = set(precedence.factor_calculate(self, types, operator)) elif element.type == 'test': # `x if foo else y` case. types = (self.eval_element(element.children[0]) | self.eval_element(element.children[-1])) elif element.type == 'operator': # Must be an ellipsis, other operators are not evaluated. assert element.value == '...' types = set([compiled.create(self, Ellipsis)]) elif element.type == 'dotted_name': types = self._eval_atom(element.children[0]) for next_name in element.children[2::2]: 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]) elif element.type == 'annassign': types = self.eval_element(element.children[1]) else: types = precedence.calculate_children(self, element.children) debug.dbg('eval_element result %s', types) return types
def _eval_yield(self, yield_expr): if yield_expr.type == 'keyword': # `yield` just yields None. yield context.LazyKnownContext(compiled.create(self.evaluator, None)) return node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. cn = ContextualizedNode(self, node.children[1]) for lazy_context in iterable.py__iter__(self.evaluator, cn.infer(), cn): yield lazy_context else: yield context.LazyTreeContext(self, node)
def _eval_yield(self, yield_expr): if yield_expr.type == 'keyword': # `yield` just yields None. yield LazyKnownContext(compiled.create(self.evaluator, None)) return node = yield_expr.children[1] if node.type == 'yield_arg': # It must be a yield from. cn = ContextualizedNode(self, node.children[1]) for lazy_context in cn.infer().iterate(cn): yield lazy_context else: yield LazyTreeContext(self, node)
def _check_getattr(self, inst): """Checks for both __getattr__ and __getattribute__ methods""" # str is important, because it shouldn't be `Name`! name = compiled.create(self._evaluator, self._string_name) # This is a little bit special. `__getattribute__` is in Python # executed before `__getattr__`. But: I know no use case, where # this could be practical and where Jedi would return wrong types. # If you ever find something, let me know! # We are inversing this, because a hand-crafted `__getattribute__` # could still call another hand-crafted `__getattr__`, but not the # other way around. names = (inst.get_function_slot_names('__getattr__') or inst.get_function_slot_names('__getattribute__')) return inst.execute_function_slots(names, name)
def _check_getattr(self, inst): """Checks for both __getattr__ and __getattribute__ methods""" result = [] # str is important, because it shouldn't be `Name`! name = compiled.create(self._evaluator, str(self.name_str)) with common.ignored(KeyError): result = inst.execute_subscope_by_name('__getattr__', name) if not result: # this is a little bit special. `__getattribute__` is executed # before anything else. But: I know no use case, where this # could be practical and the jedi would return wrong types. If # you ever have something, let me know! with common.ignored(KeyError): result = inst.execute_subscope_by_name('__getattribute__', name) return result