def eval_node(context, element): debug.dbg('eval_node %s@%s in %s', element, element.start_pos, context) evaluator = context.evaluator typ = element.type if typ in ('name', 'number', 'string', 'atom', 'strings', 'keyword', 'fstring'): return eval_atom(context, element) elif typ == 'lambdef': return ContextSet([FunctionContext.from_context(context, element)]) elif typ == 'expr_stmt': return eval_expr_stmt(context, element) elif typ in ('power', 'atom_expr'): first_child = element.children[0] children = element.children[1:] had_await = False if first_child.type == 'keyword' and first_child.value == 'await': had_await = True first_child = children.pop(0) context_set = context.eval_node(first_child) for (i, trailer) in enumerate(children): if trailer == '**': # has a power operation. right = context.eval_node(children[i + 1]) context_set = _eval_comparison(evaluator, context, context_set, trailer, right) break context_set = eval_trailer(context, context_set, trailer) if had_await: return context_set.py__await__().py__stop_iteration_returns() return context_set elif typ in ( 'testlist_star_expr', 'testlist', ): # The implicit tuple in statements. return ContextSet( [iterable.SequenceLiteralContext(evaluator, context, element)]) elif typ in ('not_test', 'factor'): context_set = context.eval_node(element.children[-1]) for operator in element.children[:-1]: context_set = eval_factor(context_set, operator) return context_set elif typ == 'test': # `x if foo else y` case. return (context.eval_node(element.children[0]) | context.eval_node(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. if element.value not in ('.', '...'): origin = element.parent raise AssertionError("unhandled operator %s in %s " % (repr(element.value), origin)) return ContextSet([compiled.builtin_from_name(evaluator, u'Ellipsis')]) elif typ == 'dotted_name': context_set = eval_atom(context, element.children[0]) for next_name in element.children[2::2]: # TODO add search_global=True? context_set = context_set.py__getattribute__(next_name, name_context=context) return context_set elif typ == 'eval_input': return eval_node(context, element.children[0]) elif typ == 'annassign': return annotation.eval_annotation(context, element.children[1]) \ .execute_annotation() elif typ == 'yield_expr': if len(element.children) and element.children[1].type == 'yield_arg': # Implies that it's a yield from. element = element.children[1].children[1] generators = context.eval_node(element) \ .py__getattribute__('__iter__').execute_evaluated() return generators.py__stop_iteration_returns() # Generator.send() is not implemented. return NO_CONTEXTS elif typ == 'namedexpr_test': return eval_node(context, element.children[2]) else: return eval_or_test(context, element)
def tree_name_to_contexts(evaluator, context, tree_name): context_set = NO_CONTEXTS module_node = context.get_root_context().tree_node # First check for annotations, like: `foo: int = 3` if module_node is not None: names = module_node.get_used_names().get(tree_name.value, []) for name in names: expr_stmt = name.parent if expr_stmt.type == "expr_stmt" and expr_stmt.children[ 1].type == "annassign": correct_scope = parser_utils.get_parent_scope( name) == context.tree_node if correct_scope: context_set |= annotation.eval_annotation( context, expr_stmt.children[1].children[1]).execute_annotation( ) if context_set: return context_set types = [] node = tree_name.get_definition(import_name_always=True) if node is None: node = tree_name.parent if node.type == 'global_stmt': context = evaluator.create_context(context, tree_name) finder = NameFinder(evaluator, context, context, tree_name.value) filters = finder.get_filters(search_global=True) # For global_stmt lookups, we only need the first possible scope, # which means the function itself. filters = [next(filters)] return finder.find(filters, attribute_lookup=False) elif node.type not in ('import_from', 'import_name'): context = evaluator.create_context(context, tree_name) return eval_atom(context, tree_name) typ = node.type if typ == 'for_stmt': types = annotation.find_type_from_comment_hint_for( context, node, tree_name) if types: return types if typ == 'with_stmt': types = annotation.find_type_from_comment_hint_with( context, node, tree_name) if types: return types if typ in ('for_stmt', 'comp_for', 'sync_comp_for'): try: types = context.predefined_names[node][tree_name.value] except KeyError: cn = ContextualizedNode(context, node.children[3]) for_types = iterate_contexts( cn.infer(), contextualized_node=cn, is_async=node.parent.type == 'async_stmt', ) c_node = ContextualizedName(context, tree_name) types = check_tuple_assignments(evaluator, c_node, for_types) elif typ == 'expr_stmt': types = _remove_statements(evaluator, context, node, tree_name) elif typ == 'with_stmt': context_managers = context.eval_node( node.get_test_node_from_name(tree_name)) enter_methods = context_managers.py__getattribute__(u'__enter__') return enter_methods.execute_evaluated() elif typ in ('import_from', 'import_name'): types = imports.infer_import(context, tree_name) elif typ in ('funcdef', 'classdef'): types = _apply_decorators(context, node) elif typ == 'try_stmt': # TODO an exception can also be a tuple. Check for those. # TODO check for types that are not classes and add it to # the static analysis report. exceptions = context.eval_node( tree_name.get_previous_sibling().get_previous_sibling()) types = exceptions.execute_evaluated() elif node.type == 'param': types = NO_CONTEXTS else: raise ValueError("Should not happen. type: %s" % typ) return types