Skip to content

Commit

Permalink
Merge pull request #11 from ncoghlan/issue7-infinite-loop-on-py35
Browse files Browse the repository at this point in the history
Issue7 infinite loop on py35
  • Loading branch information
ncoghlan committed Jul 31, 2016
2 parents e4fbea4 + 31aa120 commit d533028
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 12 deletions.
36 changes: 25 additions & 11 deletions NEWS.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
Release History
---------------

0.5.4 (2016-07-31)
^^^^^^^^^^^^^^^^^^

* Thanks to the welcome efforts of Jannis Leidel, contextlib2 is now a
[Jazzband](https://jazzband.co/) project! This means that I (Nick Coghlan)
am no longer a single point of failure for backports of future contextlib
updates to earlier Python versions.

* Issue `#7 <https://github.com/jazzband/contextlib2/issues/7>`__: Backported
fix for CPython issue `#27122 <http://bugs.python.org/issue27122>`__,
preventing a potential infinite loop on Python 3.5 when handling
``RuntimeError`` (CPython updates by Gregory P. Smith & Serhiy Storchaka)


0.5.3 (2016-05-02)
^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -53,29 +67,29 @@ Release History
0.4.0 (2012-05-05)
^^^^^^^^^^^^^^^^^^

* Issue #8: Replace ContextStack with ExitStack (old ContextStack API
retained for backwards compatibility)
* (BitBucket) Issue #8: Replace ContextStack with ExitStack (old ContextStack
API retained for backwards compatibility)

* Fall back to unittest2 if unittest is missing required functionality


0.3.1 (2012-01-17)
^^^^^^^^^^^^^^^^^^

* Issue #7: Add MANIFEST.in so PyPI package contains all relevant files
(patch contributed by Doug Latornell)
* (BitBucket) Issue #7: Add MANIFEST.in so PyPI package contains all relevant
files (patch contributed by Doug Latornell)


0.3 (2012-01-04)
^^^^^^^^^^^^^^^^

* Issue #5: ContextStack.register no longer pointlessly returns the wrapped
function
* Issue #2: Add examples and recipes section to docs
* Issue #3: ContextStack.register_exit() now accepts objects with __exit__
attributes in addition to accepting exit callbacks directly
* Issue #1: Add ContextStack.preserve() to move all registered callbacks to
a new ContextStack object
* (BitBucket) Issue #5: ContextStack.register no longer pointlessly returns the
wrapped function
* (BitBucket) Issue #2: Add examples and recipes section to docs
* (BitBucket) Issue #3: ContextStack.register_exit() now accepts objects with
__exit__ attributes in addition to accepting exit callbacks directly
* (BitBucket) Issue #1: Add ContextStack.preserve() to move all registered
callbacks to a new ContextStack object
* Wrapped callbacks now expose __wrapped__ (for direct callbacks) or __self__
(for context manager methods) attributes to aid in introspection
* Moved version number to a VERSION.txt file (read by both docs and setup.py)
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.3
0.5.4
3 changes: 3 additions & 0 deletions contextlib2.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ def __exit__(self, type, value, traceback):
# raised inside the "with" statement from being suppressed.
return exc is not value
except RuntimeError as exc:
# Don't re-raise the passed in exception
if exc is value:
return False
# Likewise, avoid suppressing if a StopIteration exception
# was passed to throw() and later wrapped into a RuntimeError
# (see PEP 479).
Expand Down
38 changes: 38 additions & 0 deletions test_contextlib2.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,44 @@ def __call__(self, *exc_details):
pass


def test_dont_reraise_RuntimeError(self):
# https://bugs.python.org/issue27122
class UniqueException(Exception): pass
class UniqueRuntimeError(RuntimeError): pass

@contextmanager
def second():
try:
yield 1
except Exception as exc:
# Py2 compatible explicit exception chaining
new_exc = UniqueException("new exception")
new_exc.__cause__ = exc
raise new_exc

@contextmanager
def first():
try:
yield 1
except Exception as exc:
raise exc

# The UniqueRuntimeError should be caught by second()'s exception
# handler which chain raised a new UniqueException.
with self.assertRaises(UniqueException) as err_ctx:
with ExitStack() as es_ctx:
es_ctx.enter_context(second())
es_ctx.enter_context(first())
raise UniqueRuntimeError("please no infinite loop.")

exc = err_ctx.exception
self.assertIsInstance(exc, UniqueException)
self.assertIsInstance(exc.__cause__, UniqueRuntimeError)
if check_exception_chaining:
self.assertIs(exc.__context__, exc.__cause__)
self.assertIsNone(exc.__cause__.__context__)
self.assertIsNone(exc.__cause__.__cause__)


class TestRedirectStream:

Expand Down

0 comments on commit d533028

Please sign in to comment.