28
28
from mypy import cgen
29
29
from mypy import icode
30
30
from mypy import parse
31
+ from mypy import stats
31
32
from mypy import transform
32
33
33
34
@@ -103,6 +104,7 @@ def build(program_path: str,
103
104
output_dir : str = None ,
104
105
pyversion : int = 3 ,
105
106
custom_typing_module : str = None ,
107
+ html_report_dir : str = None ,
106
108
flags : List [str ] = None ) -> BuildResult :
107
109
"""Build a mypy program.
108
110
@@ -160,7 +162,8 @@ def build(program_path: str,
160
162
manager = BuildManager (data_dir , lib_path , target , output_dir ,
161
163
pyversion = pyversion , flags = flags ,
162
164
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 )
164
167
165
168
program_path = program_path or lookup_program (module , lib_path )
166
169
if program_text is None :
@@ -172,7 +175,10 @@ def build(program_path: str,
172
175
# Perform the build by sending the file as new file (UnprocessedFile is the
173
176
# initial state of all files) to the manager. The manager will process the
174
177
# 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
176
182
177
183
178
184
def default_data_dir (bin_dir : str ) -> str :
@@ -293,7 +299,8 @@ def __init__(self, data_dir: str,
293
299
pyversion : int ,
294
300
flags : List [str ],
295
301
ignore_prefix : str ,
296
- custom_typing_module : str ) -> None :
302
+ custom_typing_module : str ,
303
+ html_report_dir : str ) -> None :
297
304
self .data_dir = data_dir
298
305
self .errors = Errors ()
299
306
self .errors .set_ignore_prefix (ignore_prefix )
@@ -303,6 +310,7 @@ def __init__(self, data_dir: str,
303
310
self .pyversion = pyversion
304
311
self .flags = flags
305
312
self .custom_typing_module = custom_typing_module
313
+ self .html_report_dir = html_report_dir
306
314
self .semantic_analyzer = SemanticAnalyzer (lib_path , self .errors ,
307
315
pyversion = pyversion )
308
316
self .semantic_analyzer_pass3 = ThirdPass (self .errors )
@@ -850,7 +858,7 @@ def process(self) -> None:
850
858
"""Perform final pass of semantic analysis and advance state."""
851
859
self .semantic_analyzer_pass3 ().visit_file (self .tree , self .tree .path )
852
860
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 )
854
862
self .switch_state (SemanticallyAnalyzedFile (self .info (), self .tree ))
855
863
856
864
def state (self ) -> int :
@@ -863,8 +871,13 @@ def process(self) -> None:
863
871
if self .manager .target >= TYPE_CHECK :
864
872
self .type_checker ().visit_file (self .tree , self .tree .path )
865
873
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 )
868
881
869
882
# FIX remove from active state list to speed up processing
870
883
@@ -958,158 +971,3 @@ def make_parent_dirs(path: str) -> None:
958
971
os .makedirs (parent )
959
972
except OSError :
960
973
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