31
31
import _testmultiphase
32
32
except ImportError :
33
33
_testmultiphase = None
34
+ try :
35
+ import _testsinglephase
36
+ except ImportError :
37
+ _testsinglephase = None
34
38
35
39
# Skip this test if the _testcapi module isn't available.
36
40
_testcapi = import_helper .import_module ('_testcapi' )
@@ -1297,17 +1301,20 @@ def test_configured_settings(self):
1297
1301
"""
1298
1302
import json
1299
1303
1304
+ EXTENSIONS = 1 << 8
1300
1305
THREADS = 1 << 10
1301
1306
DAEMON_THREADS = 1 << 11
1302
1307
FORK = 1 << 15
1303
1308
EXEC = 1 << 16
1304
1309
1305
- features = ['fork' , 'exec' , 'threads' , 'daemon_threads' ]
1310
+ features = ['fork' , 'exec' , 'threads' , 'daemon_threads' , 'extensions' ]
1306
1311
kwlist = [f'allow_{ n } ' for n in features ]
1312
+ kwlist [- 1 ] = 'check_multi_interp_extensions'
1307
1313
for config , expected in {
1308
- (True , True , True , True ): FORK | EXEC | THREADS | DAEMON_THREADS ,
1309
- (False , False , False , False ): 0 ,
1310
- (False , False , True , False ): THREADS ,
1314
+ (True , True , True , True , True ):
1315
+ FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS ,
1316
+ (False , False , False , False , False ): 0 ,
1317
+ (False , False , True , False , True ): THREADS | EXTENSIONS ,
1311
1318
}.items ():
1312
1319
kwargs = dict (zip (kwlist , config ))
1313
1320
expected = {
@@ -1322,12 +1329,93 @@ def test_configured_settings(self):
1322
1329
json.dump(settings, stdin)
1323
1330
''' )
1324
1331
with os .fdopen (r ) as stdout :
1325
- support .run_in_subinterp_with_config (script , ** kwargs )
1332
+ ret = support .run_in_subinterp_with_config (script , ** kwargs )
1333
+ self .assertEqual (ret , 0 )
1326
1334
out = stdout .read ()
1327
1335
settings = json .loads (out )
1328
1336
1329
1337
self .assertEqual (settings , expected )
1330
1338
1339
+ @unittest .skipIf (_testsinglephase is None , "test requires _testsinglephase module" )
1340
+ @unittest .skipUnless (hasattr (os , "pipe" ), "requires os.pipe()" )
1341
+ def test_overridden_setting_extensions_subinterp_check (self ):
1342
+ """
1343
+ PyInterpreterConfig.check_multi_interp_extensions can be overridden
1344
+ with PyInterpreterState.override_multi_interp_extensions_check.
1345
+ This verifies that the override works but does not modify
1346
+ the underlying setting.
1347
+ """
1348
+ import json
1349
+
1350
+ EXTENSIONS = 1 << 8
1351
+ THREADS = 1 << 10
1352
+ DAEMON_THREADS = 1 << 11
1353
+ FORK = 1 << 15
1354
+ EXEC = 1 << 16
1355
+ BASE_FLAGS = FORK | EXEC | THREADS | DAEMON_THREADS
1356
+ base_kwargs = {
1357
+ 'allow_fork' : True ,
1358
+ 'allow_exec' : True ,
1359
+ 'allow_threads' : True ,
1360
+ 'allow_daemon_threads' : True ,
1361
+ }
1362
+
1363
+ def check (enabled , override ):
1364
+ kwargs = dict (
1365
+ base_kwargs ,
1366
+ check_multi_interp_extensions = enabled ,
1367
+ )
1368
+ flags = BASE_FLAGS | EXTENSIONS if enabled else BASE_FLAGS
1369
+ settings = {
1370
+ 'feature_flags' : flags ,
1371
+ }
1372
+
1373
+ expected = {
1374
+ 'requested' : override ,
1375
+ 'override__initial' : 0 ,
1376
+ 'override_after' : override ,
1377
+ 'override_restored' : 0 ,
1378
+ # The override should not affect the config or settings.
1379
+ 'settings__initial' : settings ,
1380
+ 'settings_after' : settings ,
1381
+ 'settings_restored' : settings ,
1382
+ # These are the most likely values to be wrong.
1383
+ 'allowed__initial' : not enabled ,
1384
+ 'allowed_after' : not ((override > 0 ) if override else enabled ),
1385
+ 'allowed_restored' : not enabled ,
1386
+ }
1387
+
1388
+ r , w = os .pipe ()
1389
+ script = textwrap .dedent (f'''
1390
+ from test.test_capi.check_config import run_singlephase_check
1391
+ run_singlephase_check({ override } , { w } )
1392
+ ''' )
1393
+ with os .fdopen (r ) as stdout :
1394
+ ret = support .run_in_subinterp_with_config (script , ** kwargs )
1395
+ self .assertEqual (ret , 0 )
1396
+ out = stdout .read ()
1397
+ results = json .loads (out )
1398
+
1399
+ self .assertEqual (results , expected )
1400
+
1401
+ self .maxDiff = None
1402
+
1403
+ # setting: check disabled
1404
+ with self .subTest ('config: check disabled; override: disabled' ):
1405
+ check (False , - 1 )
1406
+ with self .subTest ('config: check disabled; override: use config' ):
1407
+ check (False , 0 )
1408
+ with self .subTest ('config: check disabled; override: enabled' ):
1409
+ check (False , 1 )
1410
+
1411
+ # setting: check enabled
1412
+ with self .subTest ('config: check enabled; override: disabled' ):
1413
+ check (True , - 1 )
1414
+ with self .subTest ('config: check enabled; override: use config' ):
1415
+ check (True , 0 )
1416
+ with self .subTest ('config: check enabled; override: enabled' ):
1417
+ check (True , 1 )
1418
+
1331
1419
def test_mutate_exception (self ):
1332
1420
"""
1333
1421
Exceptions saved in global module state get shared between
0 commit comments