@@ -1414,6 +1414,113 @@ def test_call_invalid(self):
1414
1414
with self .assertRaises (interpreters .NotShareableError ):
1415
1415
interp .call (func , op , 'eggs!' )
1416
1416
1417
+ def test_callable_requires_frame (self ):
1418
+ # There are various functions that require a current frame.
1419
+ interp = interpreters .create ()
1420
+ for call , expected in [
1421
+ ((eval , '[1, 2, 3]' ),
1422
+ [1 , 2 , 3 ]),
1423
+ ((eval , 'sum([1, 2, 3])' ),
1424
+ 6 ),
1425
+ ((exec , '...' ),
1426
+ None ),
1427
+ ]:
1428
+ with self .subTest (str (call )):
1429
+ res = interp .call (* call )
1430
+ self .assertEqual (res , expected )
1431
+
1432
+ result_not_pickleable = [
1433
+ globals ,
1434
+ locals ,
1435
+ vars ,
1436
+ ]
1437
+ for func , expectedtype in {
1438
+ globals : dict ,
1439
+ locals : dict ,
1440
+ vars : dict ,
1441
+ dir : list ,
1442
+ }.items ():
1443
+ with self .subTest (str (func )):
1444
+ if func in result_not_pickleable :
1445
+ with self .assertRaises (interpreters .NotShareableError ):
1446
+ interp .call (func )
1447
+ else :
1448
+ res = interp .call (func )
1449
+ self .assertIsInstance (res , expectedtype )
1450
+ self .assertIn ('__builtins__' , res )
1451
+
1452
+ def test_globals_from_builtins (self ):
1453
+ # The builtins exec(), eval(), globals(), locals(), vars(),
1454
+ # and dir() each runs relative to the target interpreter's
1455
+ # __main__ module, when called directly. However,
1456
+ # globals(), locals(), and vars() don't work when called
1457
+ # directly so we don't check them.
1458
+ from _frozen_importlib import BuiltinImporter
1459
+ interp = interpreters .create ()
1460
+
1461
+ names = interp .call (dir )
1462
+ self .assertEqual (names , [
1463
+ '__builtins__' ,
1464
+ '__doc__' ,
1465
+ '__loader__' ,
1466
+ '__name__' ,
1467
+ '__package__' ,
1468
+ '__spec__' ,
1469
+ ])
1470
+
1471
+ values = {name : interp .call (eval , name )
1472
+ for name in names if name != '__builtins__' }
1473
+ self .assertEqual (values , {
1474
+ '__name__' : '__main__' ,
1475
+ '__doc__' : None ,
1476
+ '__spec__' : None , # It wasn't imported, so no module spec?
1477
+ '__package__' : None ,
1478
+ '__loader__' : BuiltinImporter ,
1479
+ })
1480
+ with self .assertRaises (ExecutionFailed ):
1481
+ interp .call (eval , 'spam' ),
1482
+
1483
+ interp .call (exec , f'assert dir() == { names } ' )
1484
+
1485
+ # Update the interpreter's __main__.
1486
+ interp .prepare_main (spam = 42 )
1487
+ expected = names + ['spam' ]
1488
+
1489
+ names = interp .call (dir )
1490
+ self .assertEqual (names , expected )
1491
+
1492
+ value = interp .call (eval , 'spam' )
1493
+ self .assertEqual (value , 42 )
1494
+
1495
+ interp .call (exec , f'assert dir() == { expected } , dir()' )
1496
+
1497
+ def test_globals_from_stateless_func (self ):
1498
+ # A stateless func, which doesn't depend on any globals,
1499
+ # doesn't go through pickle, so it runs in __main__.
1500
+ def set_global (name , value ):
1501
+ globals ()[name ] = value
1502
+
1503
+ def get_global (name ):
1504
+ return globals ().get (name )
1505
+
1506
+ interp = interpreters .create ()
1507
+
1508
+ modname = interp .call (get_global , '__name__' )
1509
+ self .assertEqual (modname , '__main__' )
1510
+
1511
+ res = interp .call (get_global , 'spam' )
1512
+ self .assertIsNone (res )
1513
+
1514
+ interp .exec ('spam = True' )
1515
+ res = interp .call (get_global , 'spam' )
1516
+ self .assertTrue (res )
1517
+
1518
+ interp .call (set_global , 'spam' , 42 )
1519
+ res = interp .call (get_global , 'spam' )
1520
+ self .assertEqual (res , 42 )
1521
+
1522
+ interp .exec ('assert spam == 42, repr(spam)' )
1523
+
1417
1524
def test_call_in_thread (self ):
1418
1525
interp = interpreters .create ()
1419
1526
0 commit comments