29
29
# Usage: python deccheck.py [--short|--medium|--long|--all]
30
30
#
31
31
32
- import sys , random
32
+
33
+ import sys
34
+ import os
35
+ import time
36
+ import random
33
37
from copy import copy
34
38
from collections import defaultdict
39
+
40
+ import argparse
41
+ import subprocess
42
+ from subprocess import PIPE , STDOUT
43
+ from queue import Queue , Empty
44
+ from threading import Thread , Event , Lock
45
+
35
46
from test .support import import_fresh_module
36
47
from randdec import randfloat , all_unary , all_binary , all_ternary
37
48
from randdec import unary_optarg , binary_optarg , ternary_optarg
@@ -1124,18 +1135,35 @@ def check_untested(funcdict, c_cls, p_cls):
1124
1135
1125
1136
funcdict ['untested' ] = tuple (sorted (intersect - tested ))
1126
1137
1127
- #for key in ('untested', 'c_only', 'p_only'):
1128
- # s = 'Context' if c_cls == C.Context else 'Decimal'
1129
- # print("\n%s %s:\n%s" % (s, key, funcdict[key]))
1138
+ # for key in ('untested', 'c_only', 'p_only'):
1139
+ # s = 'Context' if c_cls == C.Context else 'Decimal'
1140
+ # print("\n%s %s:\n%s" % (s, key, funcdict[key]))
1130
1141
1131
1142
1132
1143
if __name__ == '__main__' :
1133
1144
1134
- import time
1145
+ parser = argparse .ArgumentParser (prog = "deccheck.py" )
1146
+
1147
+ group = parser .add_mutually_exclusive_group ()
1148
+ group .add_argument ('--short' , dest = 'time' , action = "store_const" , const = 'short' , default = 'short' , help = "short test (default)" )
1149
+ group .add_argument ('--medium' , dest = 'time' , action = "store_const" , const = 'medium' , default = 'short' , help = "medium test (reasonable run time)" )
1150
+ group .add_argument ('--long' , dest = 'time' , action = "store_const" , const = 'long' , default = 'short' , help = "long test (long run time)" )
1151
+ group .add_argument ('--all' , dest = 'time' , action = "store_const" , const = 'all' , default = 'short' , help = "all tests (excessive run time)" )
1152
+
1153
+ group = parser .add_mutually_exclusive_group ()
1154
+ group .add_argument ('--single' , dest = 'single' , nargs = 1 , default = False , metavar = "TEST" , help = "run a single test" )
1155
+ group .add_argument ('--multicore' , dest = 'multicore' , action = "store_true" , default = False , help = "use all available cores" )
1156
+
1157
+ args = parser .parse_args ()
1158
+ assert args .single is False or args .multicore is False
1159
+ if args .single :
1160
+ args .single = args .single [0 ]
1161
+
1135
1162
1136
1163
randseed = int (time .time ())
1137
1164
random .seed (randseed )
1138
1165
1166
+
1139
1167
# Set up the testspecs list. A testspec is simply a dictionary
1140
1168
# that determines the amount of different contexts that 'test_method'
1141
1169
# will generate.
@@ -1168,17 +1196,17 @@ def check_untested(funcdict, c_cls, p_cls):
1168
1196
{'prec' : [34 ], 'expts' : [(- 6143 , 6144 )], 'clamp' : 1 , 'iter' : None }
1169
1197
]
1170
1198
1171
- if '-- medium' in sys . argv :
1199
+ if args . time == ' medium' :
1172
1200
base ['expts' ].append (('rand' , 'rand' ))
1173
1201
# 5 random precisions
1174
1202
base ['samples' ] = 5
1175
1203
testspecs = [small ] + ieee + [base ]
1176
- if '-- long' in sys . argv :
1204
+ elif args . time == ' long' :
1177
1205
base ['expts' ].append (('rand' , 'rand' ))
1178
1206
# 10 random precisions
1179
1207
base ['samples' ] = 10
1180
1208
testspecs = [small ] + ieee + [base ]
1181
- elif '-- all' in sys . argv :
1209
+ elif args . time == ' all' :
1182
1210
base ['expts' ].append (('rand' , 'rand' ))
1183
1211
# All precisions in [1, 100]
1184
1212
base ['samples' ] = 100
@@ -1195,39 +1223,100 @@ def check_untested(funcdict, c_cls, p_cls):
1195
1223
small ['expts' ] = [(- prec , prec )]
1196
1224
testspecs = [small , rand_ieee , base ]
1197
1225
1226
+
1198
1227
check_untested (Functions , C .Decimal , P .Decimal )
1199
1228
check_untested (ContextFunctions , C .Context , P .Context )
1200
1229
1201
1230
1202
- log ("\n \n Random seed: %d\n \n " , randseed )
1231
+ if args .multicore :
1232
+ q = Queue ()
1233
+ elif args .single :
1234
+ log ("Random seed: %d" , randseed )
1235
+ else :
1236
+ log ("\n \n Random seed: %d\n \n " , randseed )
1237
+
1238
+
1239
+ FOUND_METHOD = False
1240
+ def do_single (method , f ):
1241
+ global FOUND_METHOD
1242
+ if args .multicore :
1243
+ q .put (method )
1244
+ elif not args .single or args .single == method :
1245
+ FOUND_METHOD = True
1246
+ f ()
1203
1247
1204
1248
# Decimal methods:
1205
1249
for method in Functions ['unary' ] + Functions ['unary_ctx' ] + \
1206
1250
Functions ['unary_rnd_ctx' ]:
1207
- test_method (method , testspecs , test_unary )
1251
+ do_single ( method , lambda : test_method (method , testspecs , test_unary ) )
1208
1252
1209
1253
for method in Functions ['binary' ] + Functions ['binary_ctx' ]:
1210
- test_method (method , testspecs , test_binary )
1254
+ do_single ( method , lambda : test_method (method , testspecs , test_binary ) )
1211
1255
1212
1256
for method in Functions ['ternary' ] + Functions ['ternary_ctx' ]:
1213
- test_method (method , testspecs , test_ternary )
1257
+ name = '__powmod__' if method == '__pow__' else method
1258
+ do_single (name , lambda : test_method (method , testspecs , test_ternary ))
1214
1259
1215
- test_method ('__format__' , testspecs , test_format )
1216
- test_method ('__round__' , testspecs , test_round )
1217
- test_method ('from_float' , testspecs , test_from_float )
1218
- test_method ('quantize' , testspecs , test_quantize_api )
1260
+ do_single ( '__format__' , lambda : test_method ('__format__' , testspecs , test_format ) )
1261
+ do_single ( '__round__' , lambda : test_method ('__round__' , testspecs , test_round ) )
1262
+ do_single ( 'from_float' , lambda : test_method ('from_float' , testspecs , test_from_float ) )
1263
+ do_single ( 'quantize_api' , lambda : test_method ('quantize' , testspecs , test_quantize_api ) )
1219
1264
1220
1265
# Context methods:
1221
1266
for method in ContextFunctions ['unary' ]:
1222
- test_method (method , testspecs , test_unary )
1267
+ do_single ( method , lambda : test_method (method , testspecs , test_unary ) )
1223
1268
1224
1269
for method in ContextFunctions ['binary' ]:
1225
- test_method (method , testspecs , test_binary )
1270
+ do_single ( method , lambda : test_method (method , testspecs , test_binary ) )
1226
1271
1227
1272
for method in ContextFunctions ['ternary' ]:
1228
- test_method (method , testspecs , test_ternary )
1273
+ name = 'context.powmod' if method == 'context.power' else method
1274
+ do_single (name , lambda : test_method (method , testspecs , test_ternary ))
1275
+
1276
+ do_single ('context.create_decimal_from_float' ,
1277
+ lambda : test_method ('context.create_decimal_from_float' ,
1278
+ testspecs , test_from_float ))
1279
+
1280
+ if args .multicore :
1281
+ error = Event ()
1282
+ write_lock = Lock ()
1229
1283
1230
- test_method ('context.create_decimal_from_float' , testspecs , test_from_float )
1284
+ def write_output (out , returncode ):
1285
+ if returncode != 0 :
1286
+ error .set ()
1287
+
1288
+ with write_lock :
1289
+ sys .stdout .buffer .write (out + b"\n " )
1290
+ sys .stdout .buffer .flush ()
1291
+
1292
+ def tfunc ():
1293
+ while not error .is_set ():
1294
+ try :
1295
+ test = q .get (block = False , timeout = - 1 )
1296
+ except Empty :
1297
+ return
1231
1298
1299
+ cmd = [sys .executable , "deccheck.py" , "--%s" % args .time , "--single" , test ]
1300
+ p = subprocess .Popen (cmd , stdout = PIPE , stderr = STDOUT )
1301
+ out , _ = p .communicate ()
1302
+ write_output (out , p .returncode )
1232
1303
1233
- sys .exit (EXIT_STATUS )
1304
+ N = os .cpu_count ()
1305
+ t = N * [None ]
1306
+
1307
+ for i in range (N ):
1308
+ t [i ] = Thread (target = tfunc )
1309
+ t [i ].start ()
1310
+
1311
+ for i in range (N ):
1312
+ t [i ].join ()
1313
+
1314
+ sys .exit (1 if error .is_set () else 0 )
1315
+
1316
+ elif args .single :
1317
+ if not FOUND_METHOD :
1318
+ log ("\n error: cannot find method \" %s\" " % args .single )
1319
+ EXIT_STATUS = 1
1320
+ sys .exit (EXIT_STATUS )
1321
+ else :
1322
+ sys .exit (EXIT_STATUS )
0 commit comments