コード例 #1
0
ファイル: infer.py プロジェクト: shigon/pytype
def infer_types(src,
                errorlog, options,
                filename=None, run_builtins=True,
                deep=True, solve_unknowns=True,
                reverse_operators=True, cache_unknowns=False,
                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
    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.
    solve_unknowns: If yes, try to replace structural types ("~unknowns") with
      nominal types.
    reverse_operators: If True, emulate operations like __radd__.
    cache_unknowns: If True, do a faster approximation of unknown types.
    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.pythonpath),
                      reverse_operators=reverse_operators,
                      cache_unknowns=cache_unknowns,
                      maximum_depth=maximum_depth)
  loc, defs, builtin_names = tracer.run_program(src, filename, run_builtins)
  log.info("===Done run_program===")
  # TODO(pludemann): make test_inference.InferDedent and this code the same:
  if deep:
    tracer.exitpoint = tracer.analyze(loc, defs, builtin_names)
  else:
    tracer.exitpoint = loc
  ast = tracer.compute_types(defs, builtin_names)
  ast = tracer.loader.resolve_ast(ast)
  if solve_unknowns:
    log.info("=========== PyTD to solve =============\n%s", pytd.Print(ast))
    ast = convert_structural.convert_pytd(ast, tracer.loader.concat_all())
  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 = 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()
  if options.output_pseudocode:
    src = program_to_pseudocode(tracer.program)
    with open(options.output_pseudocode, "w") as fi:
      fi.write(src)

  return ast
コード例 #2
0
 def test_isinstance(self):
   sourcecode = textwrap.dedent("""
     x = ...  # type: `~unknown1`
     def `~isinstance`(object: int, class_or_type_or_tuple: tuple[nothing]) -> `~unknown1`
     class `~unknown1`(object):
       pass
   """)
   expected = textwrap.dedent("""
     x = ...  # type: bool
   """).strip()
   ast = parser.parse_string(sourcecode)
   ast = convert_structural.convert_pytd(ast, self.builtins_pytd)
   self.assertMultiLineEqual(pytd.Print(ast), expected)
コード例 #3
0
 def test_convert(self):
   sourcecode = textwrap.dedent("""
     class A(object):
         def foo(self, x: `~unknown1`) -> ?
         def foobaz(self, x: int) -> int
     class `~unknown1`(object):
         def foobaz(self, x: int) -> int
   """)
   expected = textwrap.dedent("""
     class A(object):
         def foo(self, x: A) -> Any: ...
         def foobaz(self, x: int) -> int: ...
   """).lstrip()
   ast = parser.parse_string(sourcecode)
   ast = convert_structural.convert_pytd(ast, self.builtins_pytd)
   self.assertMultiLineEqual(pytd.Print(ast), expected)
コード例 #4
0
  def test_convert_with_type_params(self):
    sourcecode = textwrap.dedent("""
      class A(object):
          def foo(self, x: `~unknown1`) -> bool

      class `~unknown1`():
          def __setitem__(self, _1: str, _2: `~unknown2`) -> ?
          def update(self, _1: NoneType or Dict[nothing, nothing]) -> ?

      class `~unknown2`():
          def append(self, v:NoneType) -> NoneType
    """)
    expected = textwrap.dedent("""
      class A(object):
          def foo(self, x: Dict[str, List[Any]]) -> bool: ...
    """).lstrip()
    ast = parser.parse_string(sourcecode)
    ast = convert_structural.convert_pytd(ast, self.builtins_pytd)
    self.assertMultiLineEqual(pytd.Print(ast), expected)
コード例 #5
0
ファイル: infer.py プロジェクト: pombredanne/pytype
def infer_types(
    src,
    python_version,
    filename=None,
    run_builtins=True,
    pybuiltins_filename=None,
    pythonpath=(),
    find_pytd_import_ext=".pytd",
    import_drop_prefixes=(),
    output_cfg=None,
    output_typegraph=None,
    output_pseudocode=None,
    deep=True,
    solve_unknowns=True,
    reverse_operators=False,
    cache_unknowns=False,
    skip_repeat_calls=True,
):
    """Given Python source return its types.

  Args:
    src: A string containing Python source code.
    python_version: The python version to emulate (major, minor).
    filename: Filename of the program we're parsing.
    run_builtins: Whether to preload the native Python builtins when running
      the program.
    pybuiltins_filename: Path to Python builtins, or None for default.
    pythonpath: List of directories to search for .pytd-gen files.
    find_pytd_import_ext: Extension pattern to use when looking up import PyTD
                          in pythonpath.
    import_drop_prefixes: List of prefixes to drop when resolving module names.
    output_cfg: A filename into which to save an SVG of the control flow graph.
    output_typegraph: A filename into which to save an SVG of the typegraph.
    output_pseudocode: A filename to write pseudo code to.
    deep: If True, analyze all functions, even the ones not called by the main
      execution flow.
    solve_unknowns: If yes, try to replace structural types ("~unknowns") with
      nominal types.
    reverse_operators: If True, emulate operations like __radd__.
    cache_unknowns: If True, do a faster approximation of unknown types.
    skip_repeat_calls: If True, don't rerun functions that have been called
      before with the same arguments and environment.
  Returns:
    A TypeDeclUnit
  Raises:
    AssertionError: In case of a bad parameter combination.
  """
    tracer = CallTracer(
        python_version=python_version,
        module_name=_get_module_name(filename, pythonpath),
        reverse_operators=reverse_operators,
        cache_unknowns=cache_unknowns,
        pythonpath=pythonpath,
        find_pytd_import_ext=find_pytd_import_ext,
        import_drop_prefixes=import_drop_prefixes,
        pybuiltins_filename=pybuiltins_filename,
        skip_repeat_calls=skip_repeat_calls,
    )
    loc, defs, builtin_names = tracer.run_program(src, filename, run_builtins)
    log.info("===Done run_program===")
    # TODO(pludemann): make test_inference.InferDedent and this code the same:
    if deep:
        tracer.exitpoint = tracer.analyze(loc, defs, builtin_names)
    else:
        tracer.exitpoint = loc
    ast = tracer.compute_types(defs, builtin_names)
    if solve_unknowns:
        log.info("=========== PyTD to solve =============\n%s", pytd.Print(ast))
        ast = convert_structural.convert_pytd(ast, tracer.loader.concat_all())
    if output_cfg or output_typegraph:
        if output_cfg and output_typegraph:
            raise AssertionError("Can output CFG or typegraph, but not both")
        dot = program_to_dot(tracer.program, set([]), bool(output_cfg))
        proc = subprocess.Popen(
            ["/usr/bin/dot", "-T", "svg", "-o", output_cfg or output_typegraph], stdin=subprocess.PIPE
        )
        proc.stdin.write(dot)
        proc.stdin.close()
    if output_pseudocode:
        src = program_to_pseudocode(tracer.program)
        with open(output_pseudocode, "w") as fi:
            fi.write(src)

    return ast