def testProgramToDot(self): v1 = self.prog.NewVariable() b = v1.AddBinding("x", [], self.current_location) n = self.current_location.ConnectNew() v2 = self.prog.NewVariable() v2.AddBinding("y", {b}, n) # smoke test assert isinstance(debug.program_to_dot(self.prog, ignored=()), str)
def _maybe_output_debug(options, program): """Maybe emit debugging output.""" if options.output_cfg or options.output_typegraph: dot = debug.program_to_dot(program, set([]), bool(options.output_cfg)) proc = subprocess.Popen(["/usr/bin/dot", "-T", "svg", "-o", options.output_cfg or options.output_typegraph], stdin=subprocess.PIPE) proc.stdin.write(dot) proc.stdin.close() if options.output_debug: text = debug.program_to_text(program) if options.output_debug == "-": log.info("=========== Program Dump =============\n%s", text) else: with open(options.output_debug, "w") as fi: fi.write(text)
def _maybe_output_debug(options, program): """Maybe emit debugging output.""" if options.output_cfg or options.output_typegraph: dot = debug.program_to_dot(program, set([]), bool(options.output_cfg)) svg_file = options.output_cfg or options.output_typegraph proc = subprocess.Popen(["/usr/bin/dot", "-T", "svg", "-o", svg_file], stdin=subprocess.PIPE, universal_newlines=True) (_, stderr) = proc.communicate(dot) if stderr: log.info("Failed to create %s: %s", svg_file, stderr) if options.output_debug: text = debug.program_to_text(program) if options.output_debug == "-": log.info("=========== Program Dump =============\n%s", text) else: with options.open_function(options.output_debug, "w") as fi: fi.write(text)
def infer_types(src, errorlog, options, loader, filename=None, run_builtins=True, deep=True, cache_unknowns=False, show_library_calls=False, analyze_annotated=False, init_maximum_depth=INIT_MAXIMUM_DEPTH, maximum_depth=None): """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. run_builtins: Whether to preload the native Python builtins when running the program. deep: If True, analyze all functions, even the ones not called by the main execution flow. cache_unknowns: If True, do a faster approximation of unknown types. show_library_calls: If True, call traces are kept in the output. analyze_annotated: If True, analyze methods with type annotations, too. init_maximum_depth: Depth of analysis during module loading. maximum_depth: Depth of the analysis. Default: unlimited. Returns: A TypeDeclUnit Raises: AssertionError: In case of a bad parameter combination. """ tracer = CallTracer(errorlog=errorlog, options=options, module_name=get_module_name(filename, options), cache_unknowns=cache_unknowns, analyze_annotated=analyze_annotated, generate_unknowns=options.protocols, store_all_calls=not deep, loader=loader) loc, defs = tracer.run_program(src, filename, init_maximum_depth, run_builtins) log.info("===Done running definitions and module-level code===") snapshotter = metrics.get_metric("memory", metrics.Snapshot) snapshotter.take_snapshot("infer:infer_types:tracer") if deep: tracer.exitpoint = tracer.analyze(loc, defs, maximum_depth) else: tracer.exitpoint = loc snapshotter.take_snapshot("infer:infer_types:post") ast = tracer.compute_types(defs) ast = tracer.loader.resolve_ast(ast) if tracer.has_unknown_wildcard_imports or ("HAS_DYNAMIC_ATTRIBUTES" in defs or "has_dynamic_attributes" in defs): try: ast.Lookup("__getattr__") except KeyError: ast = pytd_utils.Concat( ast, builtins.GetDefaultAst(options.python_version)) # If merged with other if statement, triggers a ValueError: Unresolved class # when attempts to load from the protocols file if options.protocols: protocols_pytd = tracer.loader.import_name("protocols") else: protocols_pytd = None builtins_pytd = tracer.loader.concat_all() # Insert type parameters, where appropriate ast = ast.Visit(visitors.CreateTypeParametersForSignatures()) if options.protocols: log.info("=========== PyTD to solve =============\n%s", pytd.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) if options.output_cfg or options.output_typegraph: if options.output_cfg and options.output_typegraph: raise AssertionError("Can output CFG or typegraph, but not both") dot = debug.program_to_dot(tracer.program, set([]), bool(options.output_cfg)) proc = subprocess.Popen([ "/usr/bin/dot", "-T", "svg", "-o", options.output_cfg or options.output_typegraph ], stdin=subprocess.PIPE) proc.stdin.write(dot) proc.stdin.close() _maybe_output_debug(options, tracer.program) return ast, builtins_pytd