@@ -1982,9 +1982,7 @@ def parse(cls, text):
1982
1982
return self
1983
1983
1984
1984
1985
- @requires_singlephase_init
1986
- class SinglephaseInitTests (unittest .TestCase ):
1987
-
1985
+ class SinglephaseInitTestMixin :
1988
1986
NAME = '_testsinglephase'
1989
1987
1990
1988
@classmethod
@@ -2236,6 +2234,8 @@ def check_copied(self, loaded, base):
2236
2234
self .assertEqual (snap .state_initialized ,
2237
2235
base .snapshot .state_initialized )
2238
2236
2237
+ @requires_singlephase_init
2238
+ class SinglephaseInitTests (SinglephaseInitTestMixin , unittest .TestCase ):
2239
2239
#########################
2240
2240
# the tests
2241
2241
@@ -2499,8 +2499,8 @@ def test_basic_multiple_interpreters_main_no_reset(self):
2499
2499
# * module's global state was updated, not reset
2500
2500
2501
2501
@requires_subinterpreters
2502
- def test_basic_multiple_interpreters_deleted_no_reset_skip_ref_leak_test (self ):
2503
- # without resetting; already loaded in a deleted interpreter
2502
+ def test_basic_multiple_interpreters_reset_each (self ):
2503
+ # resetting between each interpreter
2504
2504
2505
2505
# At this point:
2506
2506
# * alive in 0 interpreters
@@ -2514,61 +2514,65 @@ def test_basic_multiple_interpreters_deleted_no_reset_skip_ref_leak_test(self):
2514
2514
interpid1 = self .add_subinterpreter ()
2515
2515
interpid2 = self .add_subinterpreter ()
2516
2516
2517
- # First, load in the main interpreter but then completely clear it.
2518
- loaded_main = self .load (self .NAME )
2519
- loaded_main .module ._clear_globals ()
2520
- _testinternalcapi .clear_extension (self .NAME , self .FILE )
2521
-
2522
- # At this point:
2523
- # * alive in 0 interpreters
2524
- # * module def loaded already
2525
- # * module def was in _PyRuntime.imports.extensions, but cleared
2526
- # * mod init func ran for the first time (since reset, at least)
2527
- # * m_copy was set, but cleared (was NULL)
2528
- # * module's global state was initialized but cleared
2529
-
2530
- # Start with an interpreter that gets destroyed right away.
2531
- base = self .import_in_subinterp (postscript = '''
2517
+ # Use an interpreter that gets destroyed right away.
2518
+ loaded = self .import_in_subinterp (
2519
+ postscript = '''
2532
2520
# Attrs set after loading are not in m_copy.
2533
2521
mod.spam = 'spam, spam, mash, spam, eggs, and spam'
2534
- ''' )
2535
- self .check_common (base )
2536
- self .check_fresh (base )
2522
+ ''' ,
2523
+ postcleanup = True ,
2524
+ )
2525
+ self .check_common (loaded )
2526
+ self .check_fresh (loaded )
2537
2527
2538
2528
# At this point:
2539
2529
# * alive in 0 interpreters
2540
2530
# * module def in _PyRuntime.imports.extensions
2541
- # * mod init func ran again
2531
+ # * mod init func ran for the first time (since reset, at least)
2542
2532
# * m_copy is NULL (claered when the interpreter was destroyed)
2543
2533
# * module's global state was initialized, not reset
2544
2534
2545
2535
# Use a subinterpreter that sticks around.
2546
- loaded_interp1 = self .import_in_subinterp (interpid1 )
2547
- self .check_common (loaded_interp1 )
2548
- self .check_semi_fresh ( loaded_interp1 , loaded_main , base )
2536
+ loaded = self .import_in_subinterp (interpid1 , postcleanup = True )
2537
+ self .check_common (loaded )
2538
+ self .check_fresh ( loaded )
2549
2539
2550
2540
# At this point:
2551
2541
# * alive in 1 interpreter (interp1)
2552
2542
# * module def still in _PyRuntime.imports.extensions
2553
2543
# * mod init func ran again
2554
2544
# * m_copy was copied from interp1 (was NULL)
2555
- # * module's global state was updated , not reset
2545
+ # * module's global state was initialized , not reset
2556
2546
2557
2547
# Use a subinterpreter while the previous one is still alive.
2558
- loaded_interp2 = self .import_in_subinterp (interpid2 )
2559
- self .check_common (loaded_interp2 )
2560
- self .check_copied ( loaded_interp2 , loaded_interp1 )
2548
+ loaded = self .import_in_subinterp (interpid2 , postcleanup = True )
2549
+ self .check_common (loaded )
2550
+ self .check_fresh ( loaded )
2561
2551
2562
2552
# At this point:
2563
- # * alive in 2 interpreters (interp1 , interp2)
2553
+ # * alive in 2 interpreters (interp2 , interp2)
2564
2554
# * module def still in _PyRuntime.imports.extensions
2565
2555
# * mod init func ran again
2566
2556
# * m_copy was copied from interp2 (was from interp1)
2567
- # * module's global state was updated, not reset
2557
+ # * module's global state was initialized, not reset
2558
+
2559
+
2560
+ @requires_singlephase_init
2561
+ class SinglephaseInitTestsNoRerun (SinglephaseInitTestMixin , unittest .TestCase ):
2562
+ # Tests does not support rerunning are collected in this class
2563
+ _has_run = False
2564
+
2565
+ @classmethod
2566
+ def setUpClass (cls ):
2567
+ super ().setUpClass ()
2568
+ if cls ._has_run :
2569
+ raise unittest .SkipTest ("requires single-phase init" )
2570
+ cls ._has_run = True
2568
2571
2569
2572
@requires_subinterpreters
2570
- def test_basic_multiple_interpreters_reset_each (self ):
2571
- # resetting between each interpreter
2573
+ def test_basic_multiple_interpreters_deleted_no_reset (self ):
2574
+ # without resetting; already loaded in a deleted interpreter
2575
+ # This test intentionally leaks references
2572
2576
2573
2577
# At this point:
2574
2578
# * alive in 0 interpreters
@@ -2582,47 +2586,57 @@ def test_basic_multiple_interpreters_reset_each(self):
2582
2586
interpid1 = self .add_subinterpreter ()
2583
2587
interpid2 = self .add_subinterpreter ()
2584
2588
2585
- # Use an interpreter that gets destroyed right away.
2586
- loaded = self .import_in_subinterp (
2587
- postscript = '''
2589
+ # First, load in the main interpreter but then completely clear it.
2590
+ loaded_main = self .load (self .NAME )
2591
+ loaded_main .module ._clear_globals ()
2592
+ _testinternalcapi .clear_extension (self .NAME , self .FILE )
2593
+
2594
+ # At this point:
2595
+ # * alive in 0 interpreters
2596
+ # * module def loaded already
2597
+ # * module def was in _PyRuntime.imports.extensions, but cleared
2598
+ # * mod init func ran for the first time (since reset, at least)
2599
+ # * m_copy was set, but cleared (was NULL)
2600
+ # * module's global state was initialized but cleared
2601
+
2602
+ # Start with an interpreter that gets destroyed right away.
2603
+ base = self .import_in_subinterp (postscript = '''
2588
2604
# Attrs set after loading are not in m_copy.
2589
2605
mod.spam = 'spam, spam, mash, spam, eggs, and spam'
2590
- ''' ,
2591
- postcleanup = True ,
2592
- )
2593
- self .check_common (loaded )
2594
- self .check_fresh (loaded )
2606
+ ''' )
2607
+ self .check_common (base )
2608
+ self .check_fresh (base )
2595
2609
2596
2610
# At this point:
2597
2611
# * alive in 0 interpreters
2598
2612
# * module def in _PyRuntime.imports.extensions
2599
- # * mod init func ran for the first time (since reset, at least)
2613
+ # * mod init func ran again
2600
2614
# * m_copy is NULL (claered when the interpreter was destroyed)
2601
2615
# * module's global state was initialized, not reset
2602
2616
2603
2617
# Use a subinterpreter that sticks around.
2604
- loaded = self .import_in_subinterp (interpid1 , postcleanup = True )
2605
- self .check_common (loaded )
2606
- self .check_fresh ( loaded )
2618
+ loaded_interp1 = self .import_in_subinterp (interpid1 )
2619
+ self .check_common (loaded_interp1 )
2620
+ self .check_semi_fresh ( loaded_interp1 , loaded_main , base )
2607
2621
2608
2622
# At this point:
2609
2623
# * alive in 1 interpreter (interp1)
2610
2624
# * module def still in _PyRuntime.imports.extensions
2611
2625
# * mod init func ran again
2612
2626
# * m_copy was copied from interp1 (was NULL)
2613
- # * module's global state was initialized , not reset
2627
+ # * module's global state was updated , not reset
2614
2628
2615
2629
# Use a subinterpreter while the previous one is still alive.
2616
- loaded = self .import_in_subinterp (interpid2 , postcleanup = True )
2617
- self .check_common (loaded )
2618
- self .check_fresh ( loaded )
2630
+ loaded_interp2 = self .import_in_subinterp (interpid2 )
2631
+ self .check_common (loaded_interp2 )
2632
+ self .check_copied ( loaded_interp2 , loaded_interp1 )
2619
2633
2620
2634
# At this point:
2621
- # * alive in 2 interpreters (interp2 , interp2)
2635
+ # * alive in 2 interpreters (interp1 , interp2)
2622
2636
# * module def still in _PyRuntime.imports.extensions
2623
2637
# * mod init func ran again
2624
2638
# * m_copy was copied from interp2 (was from interp1)
2625
- # * module's global state was initialized , not reset
2639
+ # * module's global state was updated , not reset
2626
2640
2627
2641
2628
2642
@cpython_only
0 commit comments