2929# Usage: python deccheck.py [--short|--medium|--long|--all]
3030#
3131
32- import sys , random
32+
33+ import sys
34+ import os
35+ import time
36+ import random
3337from copy import copy
3438from 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+
3546from test .support import import_fresh_module
3647from randdec import randfloat , all_unary , all_binary , all_ternary
3748from randdec import unary_optarg , binary_optarg , ternary_optarg
@@ -1124,18 +1135,35 @@ def check_untested(funcdict, c_cls, p_cls):
11241135
11251136 funcdict ['untested' ] = tuple (sorted (intersect - tested ))
11261137
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]))
11301141
11311142
11321143if __name__ == '__main__' :
11331144
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+
11351162
11361163 randseed = int (time .time ())
11371164 random .seed (randseed )
11381165
1166+
11391167 # Set up the testspecs list. A testspec is simply a dictionary
11401168 # that determines the amount of different contexts that 'test_method'
11411169 # will generate.
@@ -1168,17 +1196,17 @@ def check_untested(funcdict, c_cls, p_cls):
11681196 {'prec' : [34 ], 'expts' : [(- 6143 , 6144 )], 'clamp' : 1 , 'iter' : None }
11691197 ]
11701198
1171- if '-- medium' in sys . argv :
1199+ if args . time == ' medium' :
11721200 base ['expts' ].append (('rand' , 'rand' ))
11731201 # 5 random precisions
11741202 base ['samples' ] = 5
11751203 testspecs = [small ] + ieee + [base ]
1176- if '-- long' in sys . argv :
1204+ elif args . time == ' long' :
11771205 base ['expts' ].append (('rand' , 'rand' ))
11781206 # 10 random precisions
11791207 base ['samples' ] = 10
11801208 testspecs = [small ] + ieee + [base ]
1181- elif '-- all' in sys . argv :
1209+ elif args . time == ' all' :
11821210 base ['expts' ].append (('rand' , 'rand' ))
11831211 # All precisions in [1, 100]
11841212 base ['samples' ] = 100
@@ -1195,39 +1223,100 @@ def check_untested(funcdict, c_cls, p_cls):
11951223 small ['expts' ] = [(- prec , prec )]
11961224 testspecs = [small , rand_ieee , base ]
11971225
1226+
11981227 check_untested (Functions , C .Decimal , P .Decimal )
11991228 check_untested (ContextFunctions , C .Context , P .Context )
12001229
12011230
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 ()
12031247
12041248 # Decimal methods:
12051249 for method in Functions ['unary' ] + Functions ['unary_ctx' ] + \
12061250 Functions ['unary_rnd_ctx' ]:
1207- test_method (method , testspecs , test_unary )
1251+ do_single ( method , lambda : test_method (method , testspecs , test_unary ) )
12081252
12091253 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 ) )
12111255
12121256 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 ))
12141259
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 ) )
12191264
12201265 # Context methods:
12211266 for method in ContextFunctions ['unary' ]:
1222- test_method (method , testspecs , test_unary )
1267+ do_single ( method , lambda : test_method (method , testspecs , test_unary ) )
12231268
12241269 for method in ContextFunctions ['binary' ]:
1225- test_method (method , testspecs , test_binary )
1270+ do_single ( method , lambda : test_method (method , testspecs , test_binary ) )
12261271
12271272 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 ()
12291283
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
12311298
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 )
12321303
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