@@ -1170,7 +1170,6 @@ class MyType:
1170
1170
self .assertEqual (get_type_fullyqualname (MyType ), 'my_qualname' )
1171
1171
1172
1172
1173
-
1174
1173
@requires_limited_api
1175
1174
class TestHeapTypeRelative (unittest .TestCase ):
1176
1175
"""Test API for extending opaque types (PEP 697)"""
@@ -1326,6 +1325,125 @@ def test_pyobject_getitemdata_error(self):
1326
1325
_testcapi .pyobject_getitemdata (0 )
1327
1326
1328
1327
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
+
1329
1447
class TestPendingCalls (unittest .TestCase ):
1330
1448
1331
1449
# See the comment in ceval.c (at the "handle_eval_breaker" label)
0 commit comments