@@ -83,6 +83,11 @@ def __init__(self, prog: str) -> None:
83
83
p .add_argument ("--junit-xml" , help = "Write junit.xml to the given file" )
84
84
p .add_argument ("--perf-stats-file" , help = "write performance information to the given file" )
85
85
p .add_argument ("files" , metavar = "FILE" , nargs = "+" , help = "File (or directory) to check" )
86
+ p .add_argument (
87
+ "--export-types" ,
88
+ action = "store_true" ,
89
+ help = "Store types of all expressions in a shared location (useful for inspections)" ,
90
+ )
86
91
87
92
run_parser = p = subparsers .add_parser (
88
93
"run" ,
@@ -96,6 +101,11 @@ def __init__(self, prog: str) -> None:
96
101
"--timeout" , metavar = "TIMEOUT" , type = int , help = "Server shutdown timeout (in seconds)"
97
102
)
98
103
p .add_argument ("--log-file" , metavar = "FILE" , type = str , help = "Direct daemon stdout/stderr to FILE" )
104
+ p .add_argument (
105
+ "--export-types" ,
106
+ action = "store_true" ,
107
+ help = "Store types of all expressions in a shared location (useful for inspections)" ,
108
+ )
99
109
p .add_argument (
100
110
"flags" ,
101
111
metavar = "ARG" ,
@@ -113,6 +123,11 @@ def __init__(self, prog: str) -> None:
113
123
p .add_argument ("-q" , "--quiet" , action = "store_true" , help = argparse .SUPPRESS ) # Deprecated
114
124
p .add_argument ("--junit-xml" , help = "Write junit.xml to the given file" )
115
125
p .add_argument ("--perf-stats-file" , help = "write performance information to the given file" )
126
+ p .add_argument (
127
+ "--export-types" ,
128
+ action = "store_true" ,
129
+ help = "Store types of all expressions in a shared location (useful for inspections)" ,
130
+ )
116
131
p .add_argument (
117
132
"--update" ,
118
133
metavar = "FILE" ,
@@ -164,6 +179,68 @@ def __init__(self, prog: str) -> None:
164
179
help = "Set the maximum number of types to try for a function (default 64)" ,
165
180
)
166
181
182
+ inspect_parser = p = subparsers .add_parser (
183
+ "inspect" , help = "Locate and statically inspect expression(s)"
184
+ )
185
+ p .add_argument (
186
+ "location" ,
187
+ metavar = "LOCATION" ,
188
+ type = str ,
189
+ help = "Location specified as path/to/file.py:line:column[:end_line:end_column]."
190
+ " If position is given (i.e. only line and column), this will return all"
191
+ " enclosing expressions" ,
192
+ )
193
+ p .add_argument (
194
+ "--show" ,
195
+ metavar = "INSPECTION" ,
196
+ type = str ,
197
+ default = "type" ,
198
+ choices = ["type" , "attrs" , "definition" ],
199
+ help = "What kind of inspection to run" ,
200
+ )
201
+ p .add_argument (
202
+ "--verbose" ,
203
+ "-v" ,
204
+ action = "count" ,
205
+ default = 0 ,
206
+ help = "Increase verbosity of the type string representation (can be repeated)" ,
207
+ )
208
+ p .add_argument (
209
+ "--limit" ,
210
+ metavar = "NUM" ,
211
+ type = int ,
212
+ default = 0 ,
213
+ help = "Return at most NUM innermost expressions (if position is given); 0 means no limit" ,
214
+ )
215
+ p .add_argument (
216
+ "--include-span" ,
217
+ action = "store_true" ,
218
+ help = "Prepend each inspection result with the span of corresponding expression"
219
+ ' (e.g. 1:2:3:4:"int")' ,
220
+ )
221
+ p .add_argument (
222
+ "--include-kind" ,
223
+ action = "store_true" ,
224
+ help = "Prepend each inspection result with the kind of corresponding expression"
225
+ ' (e.g. NameExpr:"int")' ,
226
+ )
227
+ p .add_argument (
228
+ "--include-object-attrs" ,
229
+ action = "store_true" ,
230
+ help = 'Include attributes of "object" in "attrs" inspection' ,
231
+ )
232
+ p .add_argument (
233
+ "--union-attrs" ,
234
+ action = "store_true" ,
235
+ help = "Include attributes valid for some of possible expression types"
236
+ " (by default an intersection is returned)" ,
237
+ )
238
+ p .add_argument (
239
+ "--force-reload" ,
240
+ action = "store_true" ,
241
+ help = "Re-parse and re-type-check file before inspection (may be slow)" ,
242
+ )
243
+
167
244
hang_parser = p = subparsers .add_parser ("hang" , help = "Hang for 100 seconds" )
168
245
169
246
daemon_parser = p = subparsers .add_parser ("daemon" , help = "Run daemon in foreground" )
@@ -321,12 +398,24 @@ def do_run(args: argparse.Namespace) -> None:
321
398
# Bad or missing status file or dead process; good to start.
322
399
start_server (args , allow_sources = True )
323
400
t0 = time .time ()
324
- response = request (args .status_file , "run" , version = __version__ , args = args .flags )
401
+ response = request (
402
+ args .status_file ,
403
+ "run" ,
404
+ version = __version__ ,
405
+ args = args .flags ,
406
+ export_types = args .export_types ,
407
+ )
325
408
# If the daemon signals that a restart is necessary, do it
326
409
if "restart" in response :
327
410
print (f"Restarting: { response ['restart' ]} " )
328
411
restart_server (args , allow_sources = True )
329
- response = request (args .status_file , "run" , version = __version__ , args = args .flags )
412
+ response = request (
413
+ args .status_file ,
414
+ "run" ,
415
+ version = __version__ ,
416
+ args = args .flags ,
417
+ export_types = args .export_types ,
418
+ )
330
419
331
420
t1 = time .time ()
332
421
response ["roundtrip_time" ] = t1 - t0
@@ -383,7 +472,7 @@ def do_kill(args: argparse.Namespace) -> None:
383
472
def do_check (args : argparse .Namespace ) -> None :
384
473
"""Ask the daemon to check a list of files."""
385
474
t0 = time .time ()
386
- response = request (args .status_file , "check" , files = args .files )
475
+ response = request (args .status_file , "check" , files = args .files , export_types = args . export_types )
387
476
t1 = time .time ()
388
477
response ["roundtrip_time" ] = t1 - t0
389
478
check_output (response , args .verbose , args .junit_xml , args .perf_stats_file )
@@ -406,9 +495,15 @@ def do_recheck(args: argparse.Namespace) -> None:
406
495
"""
407
496
t0 = time .time ()
408
497
if args .remove is not None or args .update is not None :
409
- response = request (args .status_file , "recheck" , remove = args .remove , update = args .update )
498
+ response = request (
499
+ args .status_file ,
500
+ "recheck" ,
501
+ export_types = args .export_types ,
502
+ remove = args .remove ,
503
+ update = args .update ,
504
+ )
410
505
else :
411
- response = request (args .status_file , "recheck" )
506
+ response = request (args .status_file , "recheck" , export_types = args . export_types )
412
507
t1 = time .time ()
413
508
response ["roundtrip_time" ] = t1 - t0
414
509
check_output (response , args .verbose , args .junit_xml , args .perf_stats_file )
@@ -437,6 +532,25 @@ def do_suggest(args: argparse.Namespace) -> None:
437
532
check_output (response , verbose = False , junit_xml = None , perf_stats_file = None )
438
533
439
534
535
+ @action (inspect_parser )
536
+ def do_inspect (args : argparse .Namespace ) -> None :
537
+ """Ask daemon to print the type of an expression."""
538
+ response = request (
539
+ args .status_file ,
540
+ "inspect" ,
541
+ show = args .show ,
542
+ location = args .location ,
543
+ verbosity = args .verbose ,
544
+ limit = args .limit ,
545
+ include_span = args .include_span ,
546
+ include_kind = args .include_kind ,
547
+ include_object_attrs = args .include_object_attrs ,
548
+ union_attrs = args .union_attrs ,
549
+ force_reload = args .force_reload ,
550
+ )
551
+ check_output (response , verbose = False , junit_xml = None , perf_stats_file = None )
552
+
553
+
440
554
def check_output (
441
555
response : Dict [str , Any ],
442
556
verbose : bool ,
0 commit comments