Пример #1
0
def get_dependencies_of_target(
        module_id: str, module_tree: MypyFile, target: Node,
        type_map: Dict[Expression, Type],
        python_version: Tuple[int, int]) -> Dict[str, Set[str]]:
    """Get dependencies of a target -- don't recursive into nested targets."""
    # TODO: Add tests for this function.
    visitor = DependencyVisitor(type_map, python_version,
                                module_tree.alias_deps)
    visitor.scope.enter_file(module_id)
    if isinstance(target, MypyFile):
        # Only get dependencies of the top-level of the module. Don't recurse into
        # functions.
        for defn in target.defs:
            # TODO: Recurse into top-level statements and class bodies but skip functions.
            if not isinstance(
                    defn, (ClassDef, Decorator, FuncDef, OverloadedFuncDef)):
                defn.accept(visitor)
    elif isinstance(target, FuncBase) and target.info:
        # It's a method.
        # TODO: Methods in nested classes.
        visitor.scope.enter_class(target.info)
        target.accept(visitor)
        visitor.scope.leave()
    else:
        target.accept(visitor)
    visitor.scope.leave()
    return visitor.map
Пример #2
0
def get_dependencies_of_target(module_id: str,
                               module_tree: MypyFile,
                               target: Node,
                               type_map: Dict[Expression, Type],
                               python_version: Tuple[int, int]) -> Dict[str, Set[str]]:
    """Get dependencies of a target -- don't recursive into nested targets."""
    # TODO: Add tests for this function.
    visitor = DependencyVisitor(type_map, python_version, module_tree.alias_deps)
    visitor.scope.enter_file(module_id)
    if isinstance(target, MypyFile):
        # Only get dependencies of the top-level of the module. Don't recurse into
        # functions.
        for defn in target.defs:
            # TODO: Recurse into top-level statements and class bodies but skip functions.
            if not isinstance(defn, (ClassDef, Decorator, FuncDef, OverloadedFuncDef)):
                defn.accept(visitor)
    elif isinstance(target, FuncBase) and target.info:
        # It's a method.
        # TODO: Methods in nested classes.
        visitor.scope.enter_class(target.info)
        target.accept(visitor)
        visitor.scope.leave()
    else:
        target.accept(visitor)
    visitor.scope.leave()
    return visitor.map
Пример #3
0
def generate_html_report(tree: Node, path: str, type_map: Dict[Node, Type],
                         output_dir: str) -> None:
    if is_special_module(path):
        return
    # There may be more than one right answer for "what should we do here?"
    # but this is a reasonable one.
    path = os.path.relpath(path)
    if path.startswith('..'):
        return
    visitor = StatisticsVisitor(inferred=True,
                                typemap=type_map,
                                all_nodes=True)
    tree.accept(visitor)
    assert not os.path.isabs(path) and not path.startswith('..')
    # This line is *wrong* if the preceding assert fails.
    target_path = os.path.join(output_dir, 'html', path)
    # replace .py or .pyi with .html
    target_path = os.path.splitext(target_path)[0] + '.html'
    assert target_path.endswith('.html')
    ensure_dir_exists(os.path.dirname(target_path))
    output = []  # type: List[str]
    append = output.append
    append('''\
<html>
<head>
  <style>
    .red { background-color: #faa; }
    .yellow { background-color: #ffa; }
    .white { }
    .lineno { color: #999; }
  </style>
</head>
<body>
<pre>''')
    num_imprecise_lines = 0
    num_lines = 0
    with open(path) as input_file:
        for i, line in enumerate(input_file):
            lineno = i + 1
            status = visitor.line_map.get(lineno, TYPE_PRECISE)
            style_map = {
                TYPE_PRECISE: 'white',
                TYPE_IMPRECISE: 'yellow',
                TYPE_ANY: 'red'
            }
            style = style_map[status]
            append('<span class="lineno">%4d</span>   ' % lineno +
                   '<span class="%s">%s</span>' % (style, cgi.escape(line)))
            if status != TYPE_PRECISE:
                num_imprecise_lines += 1
            if line.strip():
                num_lines += 1
    append('</pre>')
    append('</body></html>')
    with open(target_path, 'w') as output_file:
        output_file.writelines(output)
    target_path = target_path[len(output_dir) + 1:]
    html_files.append((path, target_path, num_lines, num_imprecise_lines))
Пример #4
0
def find_classes(node: Node) -> Set[str]:
    results = set()  # type: Set[str]

    class ClassTraverser(mypy.traverser.TraverserVisitor):
        def visit_class_def(self, o: ClassDef) -> None:
            results.add(o.name)

    node.accept(ClassTraverser())
    return results
Пример #5
0
def generate_html_report(tree: Node, path: str, type_map: Dict[Node, Type],
                         output_dir: str) -> None:
    if is_special_module(path):
        return
    # There may be more than one right answer for "what should we do here?"
    # but this is a reasonable one.
    path = os.path.relpath(path)
    if path.startswith('..'):
        return
    visitor = StatisticsVisitor(inferred=True, typemap=type_map, all_nodes=True)
    tree.accept(visitor)
    assert not os.path.isabs(path) and not path.startswith('..')
    # This line is *wrong* if the preceding assert fails.
    target_path = os.path.join(output_dir, 'html', path)
    # replace .py or .pyi with .html
    target_path = os.path.splitext(target_path)[0] + '.html'
    assert target_path.endswith('.html')
    ensure_dir_exists(os.path.dirname(target_path))
    output = []  # type: List[str]
    append = output.append
    append('''\
<html>
<head>
  <style>
    .red { background-color: #faa; }
    .yellow { background-color: #ffa; }
    .white { }
    .lineno { color: #999; }
  </style>
</head>
<body>
<pre>''')
    num_imprecise_lines = 0
    num_lines = 0
    with open(path) as input_file:
        for i, line in enumerate(input_file):
            lineno = i + 1
            status = visitor.line_map.get(lineno, TYPE_PRECISE)
            style_map = {TYPE_PRECISE: 'white',
                         TYPE_IMPRECISE: 'yellow',
                         TYPE_ANY: 'red'}
            style = style_map[status]
            append('<span class="lineno">%4d</span>   ' % lineno +
                   '<span class="%s">%s</span>' % (style,
                                                   cgi.escape(line)))
            if status != TYPE_PRECISE:
                num_imprecise_lines += 1
            if line.strip():
                num_lines += 1
    append('</pre>')
    append('</body></html>')
    with open(target_path, 'w') as output_file:
        output_file.writelines(output)
    target_path = target_path[len(output_dir) + 1:]
    html_files.append((path, target_path, num_lines, num_imprecise_lines))
Пример #6
0
def get_dependencies_of_target(prefix: str, node: Node,
                               type_map: Dict[Expression, Type]) -> Dict[str, Set[str]]:
    """Get dependencies of a target -- don't recursive into nested targets."""
    visitor = DependencyVisitor(prefix, type_map)
    if isinstance(node, MypyFile):
        for defn in node.defs:
            if not isinstance(defn, (ClassDef, FuncDef)):
                defn.accept(visitor)
    else:
        node.accept(visitor)
    return visitor.map
Пример #7
0
def generate_html_report(tree: Node, path: str, type_map: Dict[Node, Type],
                         output_dir: str) -> None:
    if is_special_module(path):
        return
    visitor = StatisticsVisitor(inferred=True,
                                typemap=type_map,
                                all_nodes=True)
    tree.accept(visitor)
    target_path = os.path.join(output_dir, 'html', path)
    target_path = re.sub(r'\.py$', '.html', target_path)
    ensure_dir_exists(os.path.dirname(target_path))
    output = []  # type: List[str]
    append = output.append
    append('''\
<html>
<head>
  <style>
    .red { background-color: #faa; }
    .yellow { background-color: #ffa; }
    .white { }
    .lineno { color: #999; }
  </style>
</head>
<body>
<pre>''')
    num_imprecise_lines = 0
    num_lines = 0
    with open(path) as input_file:
        for i, line in enumerate(input_file):
            lineno = i + 1
            status = visitor.line_map.get(lineno, TYPE_PRECISE)
            style_map = {
                TYPE_PRECISE: 'white',
                TYPE_IMPRECISE: 'yellow',
                TYPE_ANY: 'red'
            }
            style = style_map[status]
            append('<span class="lineno">%4d</span>   ' % lineno +
                   '<span class="%s">%s</span>' % (style, cgi.escape(line)))
            if status != TYPE_PRECISE:
                num_imprecise_lines += 1
            if line.strip():
                num_lines += 1
    append('</pre>')
    append('</body></html>')
    with open(target_path, 'w') as output_file:
        output_file.writelines(output)
    target_path = target_path[len(output_dir) + 1:]
    html_files.append((path, target_path, num_lines, num_imprecise_lines))
Пример #8
0
def get_file(manager, node: Node, mypy_file: MypyFile) -> Optional[str]:
    # print(f'looking for {type(node)}')
    if isinstance(node, MypyFile):
        return node.path

    mypy_files = [mypy_file]

    if isinstance(node, Var):
        tup = lookup_fully_qualified(node.fullname(), manager.modules)
        if tup is None:
            # print('Var not found in modules')
            return None
        else:
            var, mod = tup
            if var.node == node:
                return mod.path
            else:
                # print(f'Found var but not identical. Found type is {short_type(var.node)}')
                if mod != mypy_file:
                    mypy_files.append(mod)

    # Search in current file first because the definition is usually in the same file.
    mypy_files.extend(
        [f for f in manager.modules.values() if f not in mypy_files])

    if isinstance(node, TypeInfo):
        node = node.defn
    finder = NodeFinder(node)
    for file in mypy_files:
        # print('looking in %s' % file.path)
        file.accept(finder)
        if finder.found:
            return file.path

    return None
Пример #9
0
 def accept(self,
            node: Node,
            target: Register = INVALID_REGISTER) -> Register:
     self.targets.append(target)
     actual = node.accept(self)
     self.targets.pop()
     return actual
Пример #10
0
def generate_html_report(tree: Node, path: str, type_map: Dict[Node, Type],
                         output_dir: str) -> None:
    if is_special_module(path):
        return
    visitor = StatisticsVisitor(inferred=True, typemap=type_map, all_nodes=True)
    tree.accept(visitor)
    target_path = os.path.join(output_dir, 'html', path)
    target_path = re.sub(r'\.py$', '.html', target_path)
    ensure_dir_exists(os.path.dirname(target_path))
    output = []  # type: List[str]
    append = output.append
    append('''\
<html>
<head>
  <style>
    .red { background-color: #faa; }
    .yellow { background-color: #ffa; }
    .white { }
    .lineno { color: #999; }
  </style>
</head>
<body>
<pre>''')
    num_imprecise_lines = 0
    num_lines = 0
    with open(path) as input_file:
        for i, line in enumerate(input_file):
            lineno = i + 1
            status = visitor.line_map.get(lineno, TYPE_PRECISE)
            style_map = { TYPE_PRECISE: 'white',
                          TYPE_IMPRECISE: 'yellow',
                          TYPE_ANY: 'red' }
            style = style_map[status]
            append('<span class="lineno">%4d</span>   ' % lineno +
                   '<span class="%s">%s</span>' % (style,
                                                   cgi.escape(line)))
            if status != TYPE_PRECISE:
                num_imprecise_lines += 1
            if line.strip():
                num_lines += 1
    append('</pre>')
    append('</body></html>')
    with open(target_path, 'w') as output_file:
        output_file.writelines(output)
    target_path = target_path[len(output_dir) + 1:]
    html_files.append((path, target_path, num_lines, num_imprecise_lines))
Пример #11
0
def dump_type_stats(tree: Node, path: str, inferred: bool = False, typemap: Dict[Node, Type] = None) -> None:
    if is_special_module(path):
        return
    print(path)
    visitor = StatisticsVisitor(inferred, typemap)
    tree.accept(visitor)
    for line in visitor.output:
        print(line)
    print("  ** precision **")
    print("  precise  ", visitor.num_precise)
    print("  imprecise", visitor.num_imprecise)
    print("  any      ", visitor.num_any)
    print("  ** kinds **")
    print("  simple   ", visitor.num_simple)
    print("  generic  ", visitor.num_generic)
    print("  function ", visitor.num_function)
    print("  tuple    ", visitor.num_tuple)
    print("  typevar  ", visitor.num_typevar)
    print("  complex  ", visitor.num_complex)
    print("  any      ", visitor.num_any)
Пример #12
0
def dump_type_stats(tree: Node, path: str, inferred: bool = False,
                    typemap: Dict[Node, Type] = None) -> None:
    if is_special_module(path):
        return
    print(path)
    visitor = StatisticsVisitor(inferred, typemap)
    tree.accept(visitor)
    for line in visitor.output:
        print(line)
    print('  ** precision **')
    print('  precise  ', visitor.num_precise)
    print('  imprecise', visitor.num_imprecise)
    print('  any      ', visitor.num_any)
    print('  ** kinds **')
    print('  simple   ', visitor.num_simple)
    print('  generic  ', visitor.num_generic)
    print('  function ', visitor.num_function)
    print('  tuple    ', visitor.num_tuple)
    print('  TypeVar  ', visitor.num_typevar)
    print('  complex  ', visitor.num_complex)
    print('  any      ', visitor.num_any)
Пример #13
0
def all_yield_expressions(node: Node) -> List[Tuple[YieldExpr, bool]]:
    v = YieldCollector()
    node.accept(v)
    return v.yield_expressions
Пример #14
0
 def accept(self, node: Node) -> None:
     try:
         node.accept(self)
     except Exception as err:
         report_internal_error(err, self.errors.file, node.line,
                               self.errors, self.options)
Пример #15
0
def get_dependencies(prefix: str, node: Node,
                     type_map: Dict[Expression, Type]) -> Dict[str, Set[str]]:
    """Get all dependencies of a node, recursively."""
    visitor = DependencyVisitor(prefix, type_map)
    node.accept(visitor)
    return visitor.map
Пример #16
0
def all_return_statements(node: Node) -> List[ReturnStmt]:
    v = ReturnCollector()
    node.accept(v)
    return v.return_statements
Пример #17
0
def get_subexpressions(node: Node) -> List[Expression]:
    visitor = SubexpressionFinder()
    node.accept(visitor)
    return visitor.expressions
Пример #18
0
 def node(self, n: Node) -> None:
     n.accept(self)
Пример #19
0
 def node(self, node: Node) -> Node:
     new = node.accept(self)
     new.set_line(node.line)
     return new
Пример #20
0
 def accept(self, n: Node, target: int = -1) -> int:
     self.targets.append(target)
     actual = n.accept(self)
     self.targets.pop()
     return actual
Пример #21
0
 def perform_transform(self, node: Node, transform: Callable[[Type], Type]) -> None:
     """Apply transform to all types associated with node."""
     if isinstance(node, ForStmt):
         if node.index_type:
             node.index_type = transform(node.index_type)
         self.transform_types_in_lvalue(node.index, transform)
     if isinstance(node, WithStmt):
         node.analyzed_types = [transform(typ) for typ in node.analyzed_types]
         for n in node.target:
             if isinstance(n, NameExpr) and isinstance(n.node, Var) and n.node.type:
                 n.node.type = transform(n.node.type)
     if isinstance(node, (FuncDef, OverloadedFuncDef, CastExpr, AssignmentStmt,
                          TypeAliasExpr, Var)):
         assert node.type, "Scheduled patch for non-existent type"
         node.type = transform(node.type)
     if isinstance(node, TypeAlias):
         node.target = transform(node.target)
     if isinstance(node, NewTypeExpr):
         assert node.old_type, "Scheduled patch for non-existent type"
         node.old_type = transform(node.old_type)
         if node.info:
             new_bases = []  # type: List[Instance]
             for b in node.info.bases:
                 new_b = transform(b)
                 # TODO: this code can be combined with code in second pass.
                 if isinstance(new_b, Instance):
                     new_bases.append(new_b)
                 elif isinstance(new_b, TupleType):
                     new_bases.append(new_b.partial_fallback)
                 else:
                     self.fail("Argument 2 to NewType(...) must be subclassable"
                               " (got {})".format(new_b), node)
                     new_bases.append(self.builtin_type('object'))
             node.info.bases = new_bases
     if isinstance(node, TypeVarExpr):
         if node.upper_bound:
             node.upper_bound = transform(node.upper_bound)
         if node.values:
             node.values = [transform(v) for v in node.values]
     if isinstance(node, TypedDictExpr):
         assert node.info.typeddict_type, "Scheduled patch for non-existent type"
         node.info.typeddict_type = cast(TypedDictType,
                                         transform(node.info.typeddict_type))
     if isinstance(node, NamedTupleExpr):
         assert node.info.tuple_type, "Scheduled patch for non-existent type"
         node.info.tuple_type = cast(TupleType,
                                     transform(node.info.tuple_type))
     if isinstance(node, TypeApplication):
         node.types = [transform(t) for t in node.types]
     if isinstance(node, TypeInfo):
         for tvar in node.defn.type_vars:
             if tvar.upper_bound:
                 tvar.upper_bound = transform(tvar.upper_bound)
             if tvar.values:
                 tvar.values = [transform(v) for v in tvar.values]
         new_bases = []
         for base in node.bases:
             new_base = transform(base)
             if isinstance(new_base, Instance):
                 new_bases.append(new_base)
             else:
                 # Don't fix the NamedTuple bases, they are Instance's intentionally.
                 # Patch the 'args' just in case, although generic tuple types are
                 # not supported yet.
                 alt_base = Instance(base.type, [transform(a) for a in base.args])
                 new_bases.append(alt_base)
         node.bases = new_bases
         if node.tuple_type:
             new_tuple_type = transform(node.tuple_type)
             assert isinstance(new_tuple_type, TupleType)
             node.tuple_type = new_tuple_type
Пример #22
0
 def perform_transform(self, node: Node, transform: Callable[[Type],
                                                             Type]) -> None:
     """Apply transform to all types associated with node."""
     if isinstance(node, ForStmt):
         if node.index_type:
             node.index_type = transform(node.index_type)
         self.transform_types_in_lvalue(node.index, transform)
     if isinstance(node, WithStmt):
         node.analyzed_types = [
             transform(typ) for typ in node.analyzed_types
         ]
         for n in node.target:
             if isinstance(n, NameExpr) and isinstance(n.node,
                                                       Var) and n.node.type:
                 n.node.type = transform(n.node.type)
     if isinstance(node, (FuncDef, OverloadedFuncDef, CastExpr,
                          AssignmentStmt, TypeAliasExpr, Var)):
         assert node.type, "Scheduled patch for non-existent type"
         node.type = transform(node.type)
     if isinstance(node, TypeAlias):
         node.target = transform(node.target)
     if isinstance(node, NewTypeExpr):
         assert node.old_type, "Scheduled patch for non-existent type"
         node.old_type = transform(node.old_type)
         if node.info:
             new_bases = []  # type: List[Instance]
             for b in node.info.bases:
                 new_b = transform(b)
                 # TODO: this code can be combined with code in second pass.
                 if isinstance(new_b, Instance):
                     new_bases.append(new_b)
                 elif isinstance(new_b, TupleType):
                     new_bases.append(new_b.partial_fallback)
                 else:
                     self.fail(
                         "Argument 2 to NewType(...) must be subclassable"
                         " (got {})".format(new_b), node)
                     new_bases.append(self.builtin_type('object'))
             node.info.bases = new_bases
     if isinstance(node, TypeVarExpr):
         if node.upper_bound:
             node.upper_bound = transform(node.upper_bound)
         if node.values:
             node.values = [transform(v) for v in node.values]
     if isinstance(node, TypedDictExpr):
         assert node.info.typeddict_type, "Scheduled patch for non-existent type"
         node.info.typeddict_type = cast(
             TypedDictType, transform(node.info.typeddict_type))
     if isinstance(node, NamedTupleExpr):
         assert node.info.tuple_type, "Scheduled patch for non-existent type"
         node.info.tuple_type = cast(TupleType,
                                     transform(node.info.tuple_type))
     if isinstance(node, TypeApplication):
         node.types = [transform(t) for t in node.types]
     if isinstance(node, TypeInfo):
         for tvar in node.defn.type_vars:
             if tvar.upper_bound:
                 tvar.upper_bound = transform(tvar.upper_bound)
             if tvar.values:
                 tvar.values = [transform(v) for v in tvar.values]
         new_bases = []
         for base in node.bases:
             new_base = transform(base)
             if isinstance(new_base, Instance):
                 new_bases.append(new_base)
             else:
                 # Don't fix the NamedTuple bases, they are Instance's intentionally.
                 # Patch the 'args' just in case, although generic tuple types are
                 # not supported yet.
                 alt_base = Instance(base.type,
                                     [transform(a) for a in base.args])
                 new_bases.append(alt_base)
         node.bases = new_bases
         if node.tuple_type:
             new_tuple_type = transform(node.tuple_type)
             assert isinstance(new_tuple_type, TupleType)
             node.tuple_type = new_tuple_type
Пример #23
0
 def node(self, n: Node) -> None:
     n.accept(self)
Пример #24
0
 def node(self, node: Node) -> Node:
     new = node.accept(self)
     new.set_line(node.line)
     return new
Пример #25
0
 def accept(self, n: Node, target: int = -1) -> int:
     self.targets.append(target)
     actual = n.accept(self)
     self.targets.pop()
     return actual
Пример #26
0
 def accept(self, node: Node) -> None:
     try:
         node.accept(self)
     except Exception as err:
         report_internal_error(err, self.errors.file, node.line, self.errors, self.options)
Пример #27
0
def get_subexpressions(node: Node) -> List[Expression]:
    visitor = SubexpressionFinder()
    node.accept(visitor)
    return visitor.expressions