@@ -1241,11 +1241,6 @@ def _importer(target):
1241
1241
return thing
1242
1242
1243
1243
1244
- def _is_started (patcher ):
1245
- # XXXX horrible
1246
- return hasattr (patcher , 'is_local' )
1247
-
1248
-
1249
1244
class _patch (object ):
1250
1245
1251
1246
attribute_name = None
@@ -1316,34 +1311,16 @@ def decorate_class(self, klass):
1316
1311
@contextlib .contextmanager
1317
1312
def decoration_helper (self , patched , args , keywargs ):
1318
1313
extra_args = []
1319
- entered_patchers = []
1320
- patching = None
1321
-
1322
- exc_info = tuple ()
1323
- try :
1314
+ with contextlib .ExitStack () as exit_stack :
1324
1315
for patching in patched .patchings :
1325
- arg = patching .__enter__ ()
1326
- entered_patchers .append (patching )
1316
+ arg = exit_stack .enter_context (patching )
1327
1317
if patching .attribute_name is not None :
1328
1318
keywargs .update (arg )
1329
1319
elif patching .new is DEFAULT :
1330
1320
extra_args .append (arg )
1331
1321
1332
1322
args += tuple (extra_args )
1333
1323
yield (args , keywargs )
1334
- except :
1335
- if (patching not in entered_patchers and
1336
- _is_started (patching )):
1337
- # the patcher may have been started, but an exception
1338
- # raised whilst entering one of its additional_patchers
1339
- entered_patchers .append (patching )
1340
- # Pass the exception to __exit__
1341
- exc_info = sys .exc_info ()
1342
- # re-raise the exception
1343
- raise
1344
- finally :
1345
- for patching in reversed (entered_patchers ):
1346
- patching .__exit__ (* exc_info )
1347
1324
1348
1325
1349
1326
def decorate_callable (self , func ):
@@ -1520,25 +1497,26 @@ def __enter__(self):
1520
1497
1521
1498
self .temp_original = original
1522
1499
self .is_local = local
1523
- setattr (self .target , self .attribute , new_attr )
1524
- if self .attribute_name is not None :
1525
- extra_args = {}
1526
- if self .new is DEFAULT :
1527
- extra_args [self .attribute_name ] = new
1528
- for patching in self .additional_patchers :
1529
- arg = patching .__enter__ ()
1530
- if patching .new is DEFAULT :
1531
- extra_args .update (arg )
1532
- return extra_args
1533
-
1534
- return new
1535
-
1500
+ self ._exit_stack = contextlib .ExitStack ()
1501
+ try :
1502
+ setattr (self .target , self .attribute , new_attr )
1503
+ if self .attribute_name is not None :
1504
+ extra_args = {}
1505
+ if self .new is DEFAULT :
1506
+ extra_args [self .attribute_name ] = new
1507
+ for patching in self .additional_patchers :
1508
+ arg = self ._exit_stack .enter_context (patching )
1509
+ if patching .new is DEFAULT :
1510
+ extra_args .update (arg )
1511
+ return extra_args
1512
+
1513
+ return new
1514
+ except :
1515
+ if not self .__exit__ (* sys .exc_info ()):
1516
+ raise
1536
1517
1537
1518
def __exit__ (self , * exc_info ):
1538
1519
"""Undo the patch."""
1539
- if not _is_started (self ):
1540
- return
1541
-
1542
1520
if self .is_local and self .temp_original is not DEFAULT :
1543
1521
setattr (self .target , self .attribute , self .temp_original )
1544
1522
else :
@@ -1553,9 +1531,9 @@ def __exit__(self, *exc_info):
1553
1531
del self .temp_original
1554
1532
del self .is_local
1555
1533
del self .target
1556
- for patcher in reversed ( self .additional_patchers ):
1557
- if _is_started ( patcher ):
1558
- patcher .__exit__ (* exc_info )
1534
+ exit_stack = self ._exit_stack
1535
+ del self . _exit_stack
1536
+ return exit_stack .__exit__ (* exc_info )
1559
1537
1560
1538
1561
1539
def start (self ):
@@ -1571,9 +1549,9 @@ def stop(self):
1571
1549
self ._active_patches .remove (self )
1572
1550
except ValueError :
1573
1551
# If the patch hasn't been started this will fail
1574
- pass
1552
+ return None
1575
1553
1576
- return self .__exit__ ()
1554
+ return self .__exit__ (None , None , None )
1577
1555
1578
1556
1579
1557
@@ -1873,9 +1851,9 @@ def stop(self):
1873
1851
_patch ._active_patches .remove (self )
1874
1852
except ValueError :
1875
1853
# If the patch hasn't been started this will fail
1876
- pass
1854
+ return None
1877
1855
1878
- return self .__exit__ ()
1856
+ return self .__exit__ (None , None , None )
1879
1857
1880
1858
1881
1859
def _clear_dict (in_dict ):
0 commit comments