10
10
import os
11
11
import os .path
12
12
import shlex
13
+ import signal
13
14
import sys
14
15
import textwrap
15
16
import traceback
17
+ import types
16
18
17
19
from typing import cast , Any , NoReturn
18
20
@@ -227,7 +229,15 @@ class Opts:
227
229
"" , "--version" , action = "store_true" ,
228
230
help = "Display version information and exit." ,
229
231
)
230
-
232
+ dump_signal = optparse .make_option (
233
+ '' , '--dump_signal' , action = 'store' , metavar = 'DUMP_SIGNAL' ,
234
+ choices = ['USR1' , 'USR2' ],
235
+ help = (
236
+ "Define a system signal that will trigger coverage report dump. " +
237
+ "It is important that target script do not intercept this signal. " +
238
+ "Currently supported options are: USR1, USR2."
239
+ ),
240
+ )
231
241
232
242
class CoverageOptionParser (optparse .OptionParser ):
233
243
"""Base OptionParser for coverage.py.
@@ -251,6 +261,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
251
261
data_file = None ,
252
262
debug = None ,
253
263
directory = None ,
264
+ dump_signal = None ,
254
265
fail_under = None ,
255
266
format = None ,
256
267
help = None ,
@@ -525,6 +536,7 @@ def get_prog_name(self) -> str:
525
536
Opts .parallel_mode ,
526
537
Opts .source ,
527
538
Opts .timid ,
539
+ Opts .dump_signal ,
528
540
] + GLOBAL_ARGS ,
529
541
usage = "[options] <pyfile> [program options]" ,
530
542
description = "Run a Python program, measuring code execution." ,
@@ -807,6 +819,11 @@ def do_help(
807
819
808
820
return False
809
821
822
+ def do_dump (self , _signum : int , _frame : types .FrameType | None ) -> None :
823
+ """ Signal handler to dump coverage report """
824
+ print ("Dumping coverage data ..." )
825
+ self .coverage .save ()
826
+
810
827
def do_run (self , options : optparse .Values , args : list [str ]) -> int :
811
828
"""Implementation of 'coverage run'."""
812
829
@@ -851,6 +868,15 @@ def do_run(self, options: optparse.Values, args: list[str]) -> int:
851
868
if options .append :
852
869
self .coverage .load ()
853
870
871
+ if options .dump_signal :
872
+ if options .dump_signal .upper () == 'USR1' :
873
+ signal .signal (signal .SIGUSR1 , self .do_dump )
874
+ elif options .dump_signal .upper () == 'USR2' :
875
+ signal .signal (signal .SIGUSR2 , self .do_dump )
876
+ else :
877
+ show_help (f"Unsupported signal for dump coverage report: { options .dump_signal } " )
878
+ return ERR
879
+
854
880
# Run the script.
855
881
self .coverage .start ()
856
882
code_ran = True
0 commit comments