@@ -1170,7 +1170,6 @@ class MyType:
11701170 self .assertEqual (get_type_fullyqualname (MyType ), 'my_qualname' )
11711171
11721172
1173-
11741173@requires_limited_api
11751174class TestHeapTypeRelative (unittest .TestCase ):
11761175 """Test API for extending opaque types (PEP 697)"""
@@ -1326,6 +1325,125 @@ def test_pyobject_getitemdata_error(self):
13261325 _testcapi .pyobject_getitemdata (0 )
13271326
13281327
1328+ def test_function_get_closure (self ):
1329+ from types import CellType
1330+
1331+ def regular_function (): ...
1332+ def unused_one_level (arg1 ):
1333+ def inner (arg2 , arg3 ): ...
1334+ return inner
1335+ def unused_two_levels (arg1 , arg2 ):
1336+ def decorator (arg3 , arg4 ):
1337+ def inner (arg5 , arg6 ): ...
1338+ return inner
1339+ return decorator
1340+ def with_one_level (arg1 ):
1341+ def inner (arg2 , arg3 ):
1342+ return arg1 + arg2 + arg3
1343+ return inner
1344+ def with_two_levels (arg1 , arg2 ):
1345+ def decorator (arg3 , arg4 ):
1346+ def inner (arg5 , arg6 ):
1347+ return arg1 + arg2 + arg3 + arg4 + arg5 + arg6
1348+ return inner
1349+ return decorator
1350+
1351+ # Functions without closures:
1352+ self .assertIsNone (_testcapi .function_get_closure (regular_function ))
1353+ self .assertIsNone (regular_function .__closure__ )
1354+
1355+ func = unused_one_level (1 )
1356+ closure = _testcapi .function_get_closure (func )
1357+ self .assertIsNone (closure )
1358+ self .assertIsNone (func .__closure__ )
1359+
1360+ func = unused_two_levels (1 , 2 )(3 , 4 )
1361+ closure = _testcapi .function_get_closure (func )
1362+ self .assertIsNone (closure )
1363+ self .assertIsNone (func .__closure__ )
1364+
1365+ # Functions with closures:
1366+ func = with_one_level (5 )
1367+ closure = _testcapi .function_get_closure (func )
1368+ self .assertEqual (closure , func .__closure__ )
1369+ self .assertIsInstance (closure , tuple )
1370+ self .assertEqual (len (closure ), 1 )
1371+ self .assertEqual (len (closure ), len (func .__code__ .co_freevars ))
1372+ self .assertTrue (all (isinstance (cell , CellType ) for cell in closure ))
1373+ self .assertTrue (closure [0 ].cell_contents , 5 )
1374+
1375+ func = with_two_levels (1 , 2 )(3 , 4 )
1376+ closure = _testcapi .function_get_closure (func )
1377+ self .assertEqual (closure , func .__closure__ )
1378+ self .assertIsInstance (closure , tuple )
1379+ self .assertEqual (len (closure ), 4 )
1380+ self .assertEqual (len (closure ), len (func .__code__ .co_freevars ))
1381+ self .assertTrue (all (isinstance (cell , CellType ) for cell in closure ))
1382+ self .assertEqual ([cell .cell_contents for cell in closure ],
1383+ [1 , 2 , 3 , 4 ])
1384+
1385+ def test_function_get_closure_error (self ):
1386+ with self .assertRaises (SystemError ):
1387+ _testcapi .function_get_closure (1 )
1388+ with self .assertRaises (SystemError ):
1389+ _testcapi .function_get_closure (None )
1390+
1391+ def test_function_set_closure (self ):
1392+ from types import CellType
1393+
1394+ def function_without_closure (): ...
1395+ def function_with_closure (arg ):
1396+ def inner ():
1397+ return arg
1398+ return inner
1399+
1400+ func = function_without_closure
1401+ _testcapi .function_set_closure (func , (CellType (1 ), CellType (1 )))
1402+ closure = _testcapi .function_get_closure (func )
1403+ self .assertEqual ([c .cell_contents for c in closure ], [1 , 1 ])
1404+ self .assertEqual ([c .cell_contents for c in func .__closure__ ], [1 , 1 ])
1405+
1406+ func = function_with_closure (1 )
1407+ _testcapi .function_set_closure (func ,
1408+ (CellType (1 ), CellType (2 ), CellType (3 )))
1409+ closure = _testcapi .function_get_closure (func )
1410+ self .assertEqual ([c .cell_contents for c in closure ], [1 , 2 , 3 ])
1411+ self .assertEqual ([c .cell_contents for c in func .__closure__ ], [1 , 2 , 3 ])
1412+
1413+ def test_function_set_closure_none (self ):
1414+ def function_without_closure (): ...
1415+ def function_with_closure (arg ):
1416+ def inner ():
1417+ return arg
1418+ return inner
1419+
1420+ _testcapi .function_set_closure (function_without_closure , None )
1421+ self .assertIsNone (
1422+ _testcapi .function_get_closure (function_without_closure ))
1423+ self .assertIsNone (function_without_closure .__closure__ )
1424+
1425+ _testcapi .function_set_closure (function_with_closure , None )
1426+ self .assertIsNone (
1427+ _testcapi .function_get_closure (function_with_closure ))
1428+ self .assertIsNone (function_with_closure .__closure__ )
1429+
1430+ def test_function_set_closure_errors (self ):
1431+ def function_without_closure (): ...
1432+
1433+ with self .assertRaises (SystemError ):
1434+ _testcapi .function_set_closure (None , ()) # not a function
1435+
1436+ with self .assertRaises (SystemError ):
1437+ _testcapi .function_set_closure (function_without_closure , 1 )
1438+ self .assertIsNone (function_without_closure .__closure__ ) # no change
1439+
1440+ # NOTE: this works, but goes against the docs:
1441+ _testcapi .function_set_closure (function_without_closure , (1 , 2 ))
1442+ self .assertEqual (
1443+ _testcapi .function_get_closure (function_without_closure ), (1 , 2 ))
1444+ self .assertEqual (function_without_closure .__closure__ , (1 , 2 ))
1445+
1446+
13291447class TestPendingCalls (unittest .TestCase ):
13301448
13311449 # See the comment in ceval.c (at the "handle_eval_breaker" label)
0 commit comments