@@ -1414,6 +1414,113 @@ def test_call_invalid(self):
14141414 with self .assertRaises (interpreters .NotShareableError ):
14151415 interp .call (func , op , 'eggs!' )
14161416
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+
14171524 def test_call_in_thread (self ):
14181525 interp = interpreters .create ()
14191526
0 commit comments