def check_types(src, filename, errorlog, options, loader, deep=True, init_maximum_depth=INIT_MAXIMUM_DEPTH, maximum_depth=None, **kwargs): """Verify the Python code.""" ctx = context.Context(errorlog=errorlog, options=options, generate_unknowns=False, loader=loader, **kwargs) loc, defs = ctx.vm.run_program(src, filename, init_maximum_depth) snapshotter = metrics.get_metric("memory", metrics.Snapshot) snapshotter.take_snapshot("analyze:check_types:tracer") if deep: if maximum_depth is None: maximum_depth = (QUICK_CHECK_MAXIMUM_DEPTH if options.quick else MAXIMUM_DEPTH) ctx.vm.analyze(loc, defs, maximum_depth=maximum_depth) snapshotter.take_snapshot("analyze:check_types:post") _maybe_output_debug(options, ctx.program)
def trace(src, options=None): """Generates type traces for the given source code. Args: src: The source text. options: A pytype.config.Options object that can be used to specify options such as the target Python version. Returns: A source.Code object. """ errorlog = errors.ErrorLog() options = options or config.Options.create() with config.verbosity_from(options): loader = load_pytd.create_loader(options) ctx = context.Context(errorlog=errorlog, options=options, generate_unknowns=options.protocols, loader=loader) pytd_module, _ = analyze.infer_types(src=src, filename=options.input, errorlog=errorlog, options=options, loader=loader, ctx=ctx) raw_traces = [] for op, symbol, data in ctx.vm.opcode_traces: raw_traces.append( (op, symbol, tuple(_to_pytd(d, loader, pytd_module) for d in data))) return source.Code(src, raw_traces, TypeTrace, options.input)
def setUp(self): super().setUp() options = config.Options.create(python_version=self.python_version, color="never") self.ctx = context.Context(errors.ErrorLog(), options, load_pytd.Loader(options)) self.node = self.ctx.root_node self.attribute_handler = self.ctx.attribute_handler
def setUp(self): super().setUp() options = config.Options.create(python_version=self.python_version) self._ctx = context.Context(errors.ErrorLog(), options, load_pytd.Loader(options)) self._program = self._ctx.program self._node = self._ctx.root_node.ConnectNew("test_node") self._convert = self._ctx.convert
def test_simple(self): # Disassembled from: # | return None code = self.make_code( [ 0x64, 1, # 0 LOAD_CONST, arg=1 (1) 0x53, 0, # 3 RETURN_VALUE (0) ], name="simple") code = blocks.process_code(code, self.python_version) ctx = context.Context(self.errorlog, self.options, loader=self.loader) ctx.vm = vm.VirtualMachine(ctx) ctx.vm.run_bytecode(ctx.program.NewCFGNode(), code)
def test_diamond(self): # Disassembled from: # | if []: # | y = 1 # | elif []: # | y = 2 # | elif []: # | y = None # | return y o = test_utils.Py37Opcodes code = self.make_code([ o.BUILD_LIST, 0, o.POP_JUMP_IF_FALSE, 10, o.LOAD_CONST, 1, o.STORE_FAST, 0, o.JUMP_FORWARD, 18, o.BUILD_LIST, 0, o.POP_JUMP_IF_FALSE, 20, o.LOAD_CONST, 2, o.STORE_FAST, 0, o.JUMP_FORWARD, 8, o.BUILD_LIST, 0, o.POP_JUMP_IF_FALSE, 28, o.LOAD_CONST, 0, o.STORE_FAST, 0, o.LOAD_FAST, 0, o.RETURN_VALUE, 0, ]) code = blocks.process_code(code, self.python_version) ctx = context.Context(self.errorlog, self.options, loader=self.loader) ctx.vm = vm.VirtualMachine(ctx) ctx.vm.run_bytecode(ctx.program.NewCFGNode(), code)
def setUp(self): super().setUp() self.errorlog = errors.ErrorLog() self.ctx = context.Context(self.errorlog, self.options, self.loader) self.ctx.vm = TraceVM(self.ctx)
def setUp(self): super().setUp() options = config.Options.create(python_version=self.python_version) self._ctx = context.Context(errors.ErrorLog(), options, load_pytd.Loader(options))
def infer_types(src, errorlog, options, loader, filename=None, deep=True, init_maximum_depth=INIT_MAXIMUM_DEPTH, show_library_calls=False, maximum_depth=None, ctx=None, **kwargs): """Given Python source return its types. Args: src: A string containing Python source code. errorlog: Where error messages go. Instance of errors.ErrorLog. options: config.Options object loader: A load_pytd.Loader instance to load PYI information. filename: Filename of the program we're parsing. deep: If True, analyze all functions, even the ones not called by the main execution flow. init_maximum_depth: Depth of analysis during module loading. show_library_calls: If True, call traces are kept in the output. maximum_depth: Depth of the analysis. Default: unlimited. ctx: An instance of context.Context, in case the caller wants to instantiate and retain the abstract context used for type inference. **kwargs: Additional parameters to pass to context.Context Returns: A tuple of (ast: TypeDeclUnit, builtins: TypeDeclUnit) Raises: AssertionError: In case of a bad parameter combination. """ if not ctx: ctx = context.Context(errorlog=errorlog, options=options, generate_unknowns=options.protocols, store_all_calls=not deep, loader=loader, **kwargs) loc, defs = ctx.vm.run_program(src, filename, init_maximum_depth) log.info("===Done running definitions and module-level code===") snapshotter = metrics.get_metric("memory", metrics.Snapshot) snapshotter.take_snapshot("analyze:infer_types:tracer") if deep: if maximum_depth is None: if not options.quick: maximum_depth = MAXIMUM_DEPTH elif options.analyze_annotated: # Since there's no point in analyzing annotated functions for inference, # the presence of this option means that the user wants checking, too. maximum_depth = QUICK_CHECK_MAXIMUM_DEPTH else: maximum_depth = QUICK_INFER_MAXIMUM_DEPTH ctx.exitpoint = ctx.vm.analyze(loc, defs, maximum_depth) else: ctx.exitpoint = loc snapshotter.take_snapshot("analyze:infer_types:post") ast = ctx.vm.compute_types(defs) ast = ctx.loader.resolve_ast(ast) if ctx.vm.has_unknown_wildcard_imports or any( a in defs for a in abstract_utils.DYNAMIC_ATTRIBUTE_MARKERS): if "__getattr__" not in ast: ast = pytd_utils.Concat(ast, ctx.loader.get_default_ast()) # If merged with other if statement, triggers a ValueError: Unresolved class # when attempts to load from the protocols file if options.protocols: protocols_pytd = ctx.loader.import_name("protocols") else: protocols_pytd = None builtins_pytd = ctx.loader.concat_all() # Insert type parameters, where appropriate ast = ast.Visit(visitors.CreateTypeParametersForSignatures()) if options.protocols: log.info("=========== PyTD to solve =============\n%s", pytd_utils.Print(ast)) ast = convert_structural.convert_pytd(ast, builtins_pytd, protocols_pytd) elif not show_library_calls: log.info("Solving is turned off. Discarding call traces.") # Rename remaining "~unknown" to "?" ast = ast.Visit(visitors.RemoveUnknownClasses()) # Remove "~list" etc.: ast = convert_structural.extract_local(ast) _maybe_output_debug(options, ctx.program) return ast, builtins_pytd
def process_file(options, source_text=None, generate_callgraphs=False, preserve_pytype_vm=False): """Process a single file and return cross references. Args: options: A dictionary of pytype options. source_text: Optional text of the file; will be read from the file pointed to by options.input if not supplied. generate_callgraphs: Collect call graph information preserve_pytype_vm: Preserve the pytype vm in the indexer Returns: The Indexer object used for indexing. Raises: PytypeError if pytype fails. """ with config.verbosity_from(options): errorlog = errors.ErrorLog() loader = load_pytd.create_loader(options) src = source_text or io.read_source_file(options.input) ctx = context.Context(errorlog=errorlog, options=options, generate_unknowns=options.protocols, store_all_calls=True, loader=loader) with io.wrap_pytype_exceptions(PytypeError, filename=options.input): pytd_module, _ = analyze.infer_types(src=src, filename=options.input, errorlog=errorlog, options=options, loader=loader, ctx=ctx) # pylint: disable=unexpected-keyword-arg ast_root_node = ast3.parse(src, options.input, feature_version=options.python_version[1]) # pylint: enable=unexpected-keyword-arg # TODO(mdemello): Get from args module_name = "module" src_code = source.Code(src, ctx.vm.opcode_traces, VmTrace, filename=options.input) ix = Indexer(ast=ast3, src=src_code, loader=ctx.loader, module_name=module_name, pytd_module=pytd_module) ix.index(ast_root_node) ix.finalize() # Make the vm available via indexer.vm for post-finalize() functions. ix.vm = ctx.vm # Use the indexer as a single object to hold data for calling processes. if generate_callgraphs: ix.function_map = callgraph.collect_function_map(ix) # Release the vm before returning if not preserve_pytype_vm: ix.vm = None return ix