Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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)
Exemplo n.º 3
0
 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
Exemplo n.º 4
0
 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
Exemplo n.º 5
0
 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)
Exemplo n.º 6
0
 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)
Exemplo n.º 7
0
 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)
Exemplo n.º 8
0
 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))
Exemplo n.º 9
0
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
Exemplo n.º 10
0
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