Skip to content

Commit afc7025

Browse files
committed
Merged jukkaleh/mypy into master
2 parents a5f7fac + 26adf2b commit afc7025

File tree

3 files changed

+375
-162
lines changed

3 files changed

+375
-162
lines changed

mypy/build.py

Lines changed: 19 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from mypy import cgen
2929
from mypy import icode
3030
from mypy import parse
31+
from mypy import stats
3132
from mypy import transform
3233

3334

@@ -103,6 +104,7 @@ def build(program_path: str,
103104
output_dir: str = None,
104105
pyversion: int = 3,
105106
custom_typing_module: str = None,
107+
html_report_dir: str = None,
106108
flags: List[str] = None) -> BuildResult:
107109
"""Build a mypy program.
108110
@@ -160,7 +162,8 @@ def build(program_path: str,
160162
manager = BuildManager(data_dir, lib_path, target, output_dir,
161163
pyversion=pyversion, flags=flags,
162164
ignore_prefix=os.getcwd(),
163-
custom_typing_module=custom_typing_module)
165+
custom_typing_module=custom_typing_module,
166+
html_report_dir=html_report_dir)
164167

165168
program_path = program_path or lookup_program(module, lib_path)
166169
if program_text is None:
@@ -172,7 +175,10 @@ def build(program_path: str,
172175
# Perform the build by sending the file as new file (UnprocessedFile is the
173176
# initial state of all files) to the manager. The manager will process the
174177
# file and all dependant modules recursively.
175-
return manager.process(UnprocessedFile(info, program_text))
178+
result = manager.process(UnprocessedFile(info, program_text))
179+
if 'html-report' in flags:
180+
stats.generate_html_index(html_report_dir)
181+
return result
176182

177183

178184
def default_data_dir(bin_dir: str) -> str:
@@ -293,7 +299,8 @@ def __init__(self, data_dir: str,
293299
pyversion: int,
294300
flags: List[str],
295301
ignore_prefix: str,
296-
custom_typing_module: str) -> None:
302+
custom_typing_module: str,
303+
html_report_dir: str) -> None:
297304
self.data_dir = data_dir
298305
self.errors = Errors()
299306
self.errors.set_ignore_prefix(ignore_prefix)
@@ -303,6 +310,7 @@ def __init__(self, data_dir: str,
303310
self.pyversion = pyversion
304311
self.flags = flags
305312
self.custom_typing_module = custom_typing_module
313+
self.html_report_dir = html_report_dir
306314
self.semantic_analyzer = SemanticAnalyzer(lib_path, self.errors,
307315
pyversion=pyversion)
308316
self.semantic_analyzer_pass3 = ThirdPass(self.errors)
@@ -850,7 +858,7 @@ def process(self) -> None:
850858
"""Perform final pass of semantic analysis and advance state."""
851859
self.semantic_analyzer_pass3().visit_file(self.tree, self.tree.path)
852860
if 'dump-type-stats' in self.manager.flags:
853-
analyze_types(self.tree, self.tree.path)
861+
stats.dump_type_stats(self.tree, self.tree.path)
854862
self.switch_state(SemanticallyAnalyzedFile(self.info(), self.tree))
855863

856864
def state(self) -> int:
@@ -863,8 +871,13 @@ def process(self) -> None:
863871
if self.manager.target >= TYPE_CHECK:
864872
self.type_checker().visit_file(self.tree, self.tree.path)
865873
if 'dump-infer-stats' in self.manager.flags:
866-
analyze_types(self.tree, self.tree.path, inferred=True,
867-
typemap=self.manager.type_checker.type_map)
874+
stats.dump_type_stats(self.tree, self.tree.path, inferred=True,
875+
typemap=self.manager.type_checker.type_map)
876+
elif 'html-report' in self.manager.flags:
877+
stats.generate_html_report(
878+
self.tree, self.tree.path,
879+
type_map=self.manager.type_checker.type_map,
880+
output_dir=self.manager.html_report_dir)
868881

869882
# FIX remove from active state list to speed up processing
870883

@@ -958,158 +971,3 @@ def make_parent_dirs(path: str) -> None:
958971
os.makedirs(parent)
959972
except OSError:
960973
pass
961-
962-
963-
def analyze_types(tree, path, inferred=False, typemap=None):
964-
from os.path import basename
965-
if basename(path) in ('abc.py', 'typing.py', 'builtins.py'):
966-
return
967-
print(path)
968-
v = MyVisitor(inferred, typemap)
969-
tree.accept(v)
970-
print(' ** precision **')
971-
print(' precise ', v.num_precise)
972-
print(' imprecise', v.num_imprecise)
973-
print(' any ', v.num_any)
974-
print(' ** kinds **')
975-
print(' simple ', v.num_simple)
976-
print(' generic ', v.num_generic)
977-
print(' function ', v.num_function)
978-
print(' tuple ', v.num_tuple)
979-
print(' typevar ', v.num_typevar)
980-
print(' complex ', v.num_complex)
981-
print(' any ', v.num_any)
982-
983-
984-
from mypy.traverser import TraverserVisitor
985-
from mypy.types import (
986-
AnyType, Instance, FunctionLike, TupleType, Void, TypeVar
987-
)
988-
from mypy import nodes
989-
990-
991-
class MyVisitor(TraverserVisitor):
992-
def __init__(self, inferred, typemap=None):
993-
self.inferred = inferred
994-
self.typemap = typemap
995-
996-
self.num_precise = 0
997-
self.num_imprecise = 0
998-
self.num_any = 0
999-
1000-
self.num_simple = 0
1001-
self.num_generic = 0
1002-
self.num_tuple = 0
1003-
self.num_function = 0
1004-
self.num_typevar = 0
1005-
self.num_complex = 0
1006-
1007-
self.line = -1
1008-
1009-
TraverserVisitor.__init__(self)
1010-
1011-
def visit_func_def(self, o):
1012-
self.line = o.line
1013-
if len(o.expanded) > 1:
1014-
for defn in o.expanded:
1015-
self.visit_func_def(defn)
1016-
else:
1017-
if o.type:
1018-
sig = o.type
1019-
arg_types = sig.arg_types
1020-
if (sig.arg_names and sig.arg_names[0] == 'self' and
1021-
not self.inferred):
1022-
arg_types = arg_types[1:]
1023-
for arg in arg_types:
1024-
self.type(arg)
1025-
self.type(sig.ret_type)
1026-
super().visit_func_def(o)
1027-
1028-
def visit_type_application(self, o):
1029-
self.line = o.line
1030-
for t in o.types:
1031-
self.type(t)
1032-
super().visit_type_application(o)
1033-
1034-
def visit_assignment_stmt(self, o):
1035-
self.line = o.line
1036-
if (isinstance(o.rvalue, nodes.CallExpr) and
1037-
isinstance(o.rvalue.analyzed, nodes.TypeVarExpr)):
1038-
# Type variable definition -- not a real assignment.
1039-
return
1040-
if o.type:
1041-
self.type(o.type)
1042-
elif self.inferred:
1043-
for lvalue in o.lvalues:
1044-
if isinstance(lvalue, nodes.ParenExpr):
1045-
lvalue = lvalue.expr
1046-
if isinstance(lvalue, (nodes.TupleExpr, nodes.ListExpr)):
1047-
items = lvalue.items
1048-
else:
1049-
items = [lvalue]
1050-
for item in items:
1051-
if hasattr(item, 'is_def') and item.is_def:
1052-
t = self.typemap.get(item)
1053-
if t:
1054-
self.type(t)
1055-
else:
1056-
print(' !! No inferred type on line', self.line)
1057-
super().visit_assignment_stmt(o)
1058-
1059-
def type(self, t):
1060-
if isinstance(t, AnyType):
1061-
print(' !! Any type around line', self.line)
1062-
self.num_any += 1
1063-
elif is_imprecise(t):
1064-
print(' !! Imprecise type around line', self.line)
1065-
self.num_imprecise += 1
1066-
else:
1067-
self.num_precise += 1
1068-
1069-
if isinstance(t, Instance):
1070-
if t.args:
1071-
if any(is_complex(arg) for arg in t.args):
1072-
self.num_complex += 1
1073-
else:
1074-
self.num_generic += 1
1075-
else:
1076-
self.num_simple += 1
1077-
elif isinstance(t, Void):
1078-
self.num_simple += 1
1079-
elif isinstance(t, FunctionLike):
1080-
self.num_function += 1
1081-
elif isinstance(t, TupleType):
1082-
if any(is_complex(item) for item in t.items):
1083-
self.num_complex += 1
1084-
else:
1085-
self.num_tuple += 1
1086-
elif isinstance(t, TypeVar):
1087-
self.num_typevar += 1
1088-
1089-
1090-
def is_imprecise(t):
1091-
return t.accept(HasAnyQuery())
1092-
1093-
from mypy.types import TypeQuery, ANY_TYPE_STRATEGY
1094-
1095-
class HasAnyQuery(TypeQuery):
1096-
def __init__(self):
1097-
super().__init__(False, ANY_TYPE_STRATEGY)
1098-
1099-
def visit_any(self, t):
1100-
return True
1101-
1102-
def visit_instance(self, t):
1103-
if t.type.fullname() == 'builtins.tuple':
1104-
return True
1105-
else:
1106-
return super().visit_instance(t)
1107-
1108-
1109-
def is_generic(t):
1110-
return isinstance(t, Instance) and t.args
1111-
1112-
1113-
def is_complex(t):
1114-
return is_generic(t) or isinstance(t, (FunctionLike, TupleType,
1115-
TypeVar))

0 commit comments

Comments
 (0)