9
9
import os
10
10
import sys
11
11
from pathlib import Path
12
- from typing import Dict
13
- from typing import List
14
- from typing import Optional
12
+ from types import ModuleType
13
+ from typing import Any , Dict , List , Optional , Type , cast
15
14
16
15
import pkg_resources
17
16
18
17
from .interestingness .utils import rel_or_abs_import
19
18
from .strategies import DEFAULT as DEFAULT_STRATEGY
19
+ from .strategies import Strategy
20
20
from .testcases import DEFAULT as DEFAULT_TESTCASE
21
+ from .testcases import Testcase
21
22
from .util import LithiumError , quantity , summary_header
22
23
23
24
LOG = logging .getLogger (__name__ )
@@ -28,22 +29,22 @@ class Lithium:
28
29
29
30
def __init__ (self ) -> None :
30
31
31
- self .strategy = None
32
+ self .strategy : Optional [ Strategy ] = None
32
33
33
- self .condition_script = None
34
- self .condition_args = None
34
+ self .condition_script : Optional [ ModuleType ] = None
35
+ self .condition_args : Optional [ List [ str ]] = None
35
36
36
37
self .test_count = 0
37
38
self .test_total = 0
38
39
39
- self .temp_dir : Path = Path ()
40
+ self .temp_dir : Optional [ Path ] = None
40
41
41
- self .testcase = None
42
- self .last_interesting = None
42
+ self .testcase : Optional [ Testcase ] = None
43
+ self .last_interesting : Optional [ Testcase ] = None
43
44
44
45
self .temp_file_count = 1
45
46
46
- def main (self , argv : Optional [List [str ]]) -> int :
47
+ def main (self , argv : Optional [List [str ]] = None ) -> int :
47
48
"""Main entrypoint (parse args and call `run()`)
48
49
49
50
Args:
@@ -69,7 +70,7 @@ def run(self) -> int:
69
70
0 for successful reduction
70
71
"""
71
72
if hasattr (self .condition_script , "init" ):
72
- self .condition_script .init (self .condition_args )
73
+ cast ( Any , self .condition_script ) .init (self .condition_args )
73
74
74
75
try :
75
76
if self .temp_dir is None :
@@ -78,6 +79,8 @@ def run(self) -> int:
78
79
"Intermediate files will be stored in %s%s." , self .temp_dir , os .sep
79
80
)
80
81
82
+ assert self .strategy is not None
83
+ assert self .testcase is not None
81
84
result = self .strategy .main (
82
85
self .testcase , self .interesting , self .testcase_temp_filename
83
86
)
@@ -89,13 +92,13 @@ def run(self) -> int:
89
92
90
93
finally :
91
94
if hasattr (self .condition_script , "cleanup" ):
92
- self .condition_script .cleanup (self .condition_args )
95
+ cast ( Any , self .condition_script ) .cleanup (self .condition_args )
93
96
94
97
# Make sure we exit with an interesting testcase
95
98
if self .last_interesting is not None :
96
99
self .last_interesting .dump ()
97
100
98
- def process_args (self , argv : Optional [List [str ]]) -> None :
101
+ def process_args (self , argv : Optional [List [str ]] = None ) -> None :
99
102
"""Parse command-line args and initialize self.
100
103
101
104
Args:
@@ -106,10 +109,12 @@ def process_args(self, argv: Optional[List[str]]) -> None:
106
109
class _ArgParseTry (argparse .ArgumentParser ):
107
110
# pylint: disable=arguments-differ,no-self-argument
108
111
109
- def exit (_ , ** kwds ) -> None :
112
+ def exit ( # type: ignore[override]
113
+ self , status : int = 0 , message : Optional [str ] = None
114
+ ) -> None :
110
115
pass
111
116
112
- def error (_ , message ) -> None :
117
+ def error (self , message : str ) -> None : # type: ignore[override]
113
118
pass
114
119
115
120
early_parser = _ArgParseTry (add_help = False )
@@ -122,8 +127,8 @@ def error(_, message) -> None:
122
127
grp_opt = parser .add_argument_group (description = "Lithium options" )
123
128
grp_atoms = grp_opt .add_mutually_exclusive_group ()
124
129
125
- strategies : Dict [str , str ] = {}
126
- testcase_types : Dict [str , str ] = {}
130
+ strategies : Dict [str , Type [ Strategy ] ] = {}
131
+ testcase_types : Dict [str , Type [ Testcase ] ] = {}
127
132
for entry_point in pkg_resources .iter_entry_points ("lithium_strategies" ):
128
133
try :
129
134
strategy_cls = entry_point .load ()
@@ -174,10 +179,10 @@ def error(_, message) -> None:
174
179
early_parser .add_argument (
175
180
"--strategy" , default = DEFAULT_STRATEGY , choices = strategies .keys ()
176
181
)
177
- args = early_parser .parse_known_args (argv )
178
- atom = args [0 ].atom if args else DEFAULT_TESTCASE
182
+ early_args = early_parser .parse_known_args (argv )
183
+ atom = early_args [0 ].atom if early_args else DEFAULT_TESTCASE
179
184
self .strategy = strategies .get (
180
- args [0 ].strategy if args else None , strategies [DEFAULT_STRATEGY ]
185
+ early_args [0 ].strategy if early_args else None , strategies [DEFAULT_STRATEGY ]
181
186
)()
182
187
183
188
grp_opt .add_argument (
@@ -192,6 +197,7 @@ def error(_, message) -> None:
192
197
"-v" , "--verbose" , action = "store_true" , help = "enable verbose debug logging"
193
198
)
194
199
# this has already been parsed above, it's only here for the help message
200
+ assert self .strategy is not None
195
201
grp_opt .add_argument (
196
202
"--strategy" ,
197
203
default = self .strategy .name ,
@@ -250,6 +256,9 @@ def testcase_temp_filename(
250
256
if use_number :
251
257
filename_stem = "%d-%s" % (self .temp_file_count , filename_stem )
252
258
self .temp_file_count += 1
259
+ assert self .testcase is not None
260
+ assert self .testcase .extension is not None
261
+ assert self .temp_dir is not None
253
262
return self .temp_dir / (filename_stem + self .testcase .extension )
254
263
255
264
def create_temp_dir (self ) -> None :
@@ -269,7 +278,7 @@ def create_temp_dir(self) -> None:
269
278
270
279
# If the file is still interesting after the change, changes "parts" and returns
271
280
# True.
272
- def interesting (self , testcase_suggestion , write_it : bool = True ) -> bool :
281
+ def interesting (self , testcase_suggestion : Testcase , write_it : bool = True ) -> bool :
273
282
"""Test whether a testcase suggestion is interesting.
274
283
275
284
Args:
@@ -286,9 +295,15 @@ def interesting(self, testcase_suggestion, write_it: bool = True) -> bool:
286
295
self .test_count += 1
287
296
self .test_total += len (testcase_suggestion )
288
297
298
+ assert self .temp_dir is not None
289
299
temp_prefix = str (self .temp_dir / str (self .temp_file_count ))
290
300
291
- inter = self .condition_script .interesting (self .condition_args , temp_prefix )
301
+ assert self .condition_script is not None
302
+ inter = bool (
303
+ cast (Any , self .condition_script ).interesting (
304
+ self .condition_args , temp_prefix
305
+ )
306
+ )
292
307
293
308
# Save an extra copy of the file inside the temp directory.
294
309
# This is useful if you're reducing an assertion and encounter a crash:
0 commit comments