mirror of
				https://github.com/python/cpython.git
				synced 2025-11-01 06:01:29 +00:00 
			
		
		
		
	Finish bringing SVN into line with latest version of PEP 343 by getting rid of all remaining references to context objects that I could find. Without a __context__() method context objects no longer exist. Also get test_with working again, and adopt a suggestion from Neal for decimal.Context.get_manager()
This commit is contained in:
		
							parent
							
								
									1b06a1d4e3
								
							
						
					
					
						commit
						afd5e63e24
					
				
					 8 changed files with 101 additions and 120 deletions
				
			
		|  | @ -11,19 +11,20 @@ This module provides utilities for common tasks involving the | |||
| 
 | ||||
| Functions provided: | ||||
| 
 | ||||
| \begin{funcdesc}{context}{func} | ||||
| \begin{funcdesc}{contextmanager}{func} | ||||
| This function is a decorator that can be used to define a factory | ||||
| function for \keyword{with} statement context objects, without | ||||
| needing to create a class or separate \method{__enter__()} and | ||||
| \method{__exit__()} methods. | ||||
| 
 | ||||
| A simple example: | ||||
| A simple example (this is not recommended as a real way of | ||||
| generating HTML!): | ||||
| 
 | ||||
| \begin{verbatim} | ||||
| from __future__ import with_statement | ||||
| from contextlib import contextfactory | ||||
| from contextlib import contextmanager | ||||
| 
 | ||||
| @contextfactory | ||||
| @contextmanager | ||||
| def tag(name): | ||||
|     print "<%s>" % name | ||||
|     yield | ||||
|  | @ -56,7 +57,7 @@ treat the exception as having been handled, and resume execution with | |||
| the statement immediately following the \keyword{with} statement. | ||||
| \end{funcdesc} | ||||
| 
 | ||||
| \begin{funcdesc}{nested}{ctx1\optional{, ctx2\optional{, ...}}} | ||||
| \begin{funcdesc}{nested}{mgr1\optional{, mgr2\optional{, ...}}} | ||||
| Combine multiple context managers into a single nested context manager. | ||||
| 
 | ||||
| Code like this: | ||||
|  | @ -78,12 +79,12 @@ with A as X: | |||
| \end{verbatim} | ||||
| 
 | ||||
| Note that if the \method{__exit__()} method of one of the nested | ||||
| context objects indicates an exception should be suppressed, no | ||||
| context managers indicates an exception should be suppressed, no | ||||
| exception information will be passed to any remaining outer context | ||||
| objects. Similarly, if the \method{__exit__()} method of one of the | ||||
| nested context objects raises an exception, any previous exception | ||||
| nested context managers raises an exception, any previous exception | ||||
| state will be lost; the new exception will be passed to the | ||||
| \method{__exit__()} methods of any remaining outer context objects. | ||||
| \method{__exit__()} methods of any remaining outer context managers. | ||||
| In general, \method{__exit__()} methods should avoid raising | ||||
| exceptions, and in particular they should not re-raise a | ||||
| passed-in exception. | ||||
|  | @ -91,13 +92,13 @@ passed-in exception. | |||
| 
 | ||||
| \label{context-closing} | ||||
| \begin{funcdesc}{closing}{thing} | ||||
| Return a context that closes \var{thing} upon completion of the | ||||
| block.  This is basically equivalent to: | ||||
| Return a context manager that closes \var{thing} upon completion of | ||||
| the block.  This is basically equivalent to: | ||||
| 
 | ||||
| \begin{verbatim} | ||||
| from contextlib import contextfactory | ||||
| from contextlib import contextmanager | ||||
| 
 | ||||
| @contextfactory | ||||
| @contextmanager | ||||
| def closing(thing): | ||||
|     try: | ||||
|         yield thing | ||||
|  |  | |||
|  | @ -1753,67 +1753,50 @@ implemented in C will have to provide a writable | |||
| \end{memberdesc} | ||||
| 
 | ||||
| 
 | ||||
| \subsection{Context Types \label{typecontext}} | ||||
| \subsection{Context Manager Types \label{typecontextmanager}} | ||||
| 
 | ||||
| \versionadded{2.5} | ||||
| \index{with statement context protocol} | ||||
| \index{context manager} | ||||
| \index{context management protocol} | ||||
| \index{protocol!with statement context} | ||||
| \index{protocol!context management} | ||||
| 
 | ||||
| Python's \keyword{with} statement supports the concept of a runtime | ||||
| context defined by a context manager.  This is implemented using | ||||
| three distinct methods; these are used to allow user-defined | ||||
| classes to define a runtime context. | ||||
| two separate methods that allow user-defined classes to define | ||||
| a runtime context that is entered before the statement body is | ||||
| executed and exited when the statement ends. | ||||
| 
 | ||||
| The \dfn{context management protocol} consists of a single | ||||
| method that needs to be provided for a context manager object to | ||||
| The \dfn{context management protocol} consists of a pair of | ||||
| methods that need to be provided for a context manager object to | ||||
| define a runtime context: | ||||
| 
 | ||||
| \begin{methoddesc}[context manager]{__context__}{} | ||||
|   Return a with statement context object.  The object is required to | ||||
|   support the with statement context protocol described below.  If an | ||||
|   object supports different kinds of runtime context, additional | ||||
|   methods can be provided to specifically request context objects for | ||||
|   those kinds of runtime context.  (An example of an object supporting | ||||
|   multiple kinds of context would be a synchronisation object which | ||||
|   supported both a locked context for normal thread synchronisation | ||||
|   and an unlocked context to temporarily release a held lock while | ||||
|   performing a potentially long running operation) | ||||
| \end{methoddesc} | ||||
| \begin{methoddesc}[context manager]{__enter__}{} | ||||
|   Enter the runtime context and return either this object or another | ||||
|   object related to the runtime context. The value returned by this | ||||
|   method is bound to the identifier in the \keyword{as} clause of | ||||
|   \keyword{with} statements using this context manager. | ||||
| 
 | ||||
| The with statement context objects themselves are required to support the | ||||
| following three methods, which together form the | ||||
| \dfn{with statement context protocol}: | ||||
| 
 | ||||
| \begin{methoddesc}[with statement context]{__context__}{} | ||||
|   Return the context object itself.  This is required to allow both | ||||
|   context objects and context managers to be used in a \keyword{with} | ||||
|   An example of a context manager that returns itself is a file object. | ||||
|   File objects return themselves from __enter__() to allow | ||||
|   \function{open()} to be used as the context expression in a with | ||||
|   statement. | ||||
| 
 | ||||
|   An example of a context manager that returns a related | ||||
|   object is the one returned by \code{decimal.Context.get_manager()}. | ||||
|   These managers set the active decimal context to a copy of the | ||||
|   original decimal context and then return the copy. This allows | ||||
|   changes to be made to the current decimal context in the body of | ||||
|   the \keyword{with} statement without affecting code outside | ||||
|   the \keyword{with} statement. | ||||
| \end{methoddesc} | ||||
| 
 | ||||
| \begin{methoddesc}[with statement context]{__enter__}{} | ||||
|   Enter the runtime context and return either the defining context | ||||
|   manager or another object related to the runtime context. The value | ||||
|   returned by this method is bound to the identifier in the | ||||
|   \keyword{as} clause of \keyword{with} statements using this context. | ||||
|   (An example of a context object that returns the original context | ||||
|   manager is file objects, which are returned from __enter__() to | ||||
|   allow \function{open()} to be used directly in a with | ||||
|   statement. An example of a context object that returns a related | ||||
|   object is \code{decimal.Context} which sets the active decimal | ||||
|   context to a copy of the context manager and then returns the copy. | ||||
|   This allows changes to be made to the current decimal context in the | ||||
|   body of the \keyword{with} statement without affecting code outside | ||||
|   the \keyword{with} statement). | ||||
| \end{methoddesc} | ||||
| 
 | ||||
| \begin{methoddesc}[with statement context]{__exit__}{exc_type, exc_val, exc_tb} | ||||
| \begin{methoddesc}[context manager]{__exit__}{exc_type, exc_val, exc_tb} | ||||
|   Exit the runtime context and return a Boolean flag indicating if any | ||||
|   expection that occurred should be suppressed. If an exception | ||||
|   occurred while executing the body of the \keyword{with} statement, the | ||||
|   arguments contain the exception type, value and traceback information. | ||||
|   Otherwise, all three arguments are \var{None}. | ||||
| 
 | ||||
|   Returning a true value from this method will cause the \keyword{with} | ||||
|   statement to suppress the exception and continue execution with the | ||||
|   statement immediately following the \keyword{with} statement. Otherwise | ||||
|  | @ -1821,6 +1804,7 @@ following three methods, which together form the | |||
|   executing. Exceptions that occur during execution of this method will | ||||
|   replace any exception that occurred in the body of the \keyword{with} | ||||
|   statement. | ||||
| 
 | ||||
|   The exception passed in should never be reraised explicitly - instead, | ||||
|   this method should return a false value to indicate that the method | ||||
|   completed successfully and does not want to suppress the raised | ||||
|  | @ -1829,20 +1813,18 @@ following three methods, which together form the | |||
|   \method{__exit__()} method has actually failed. | ||||
| \end{methoddesc} | ||||
| 
 | ||||
| Python defines several context objects and managers to support | ||||
| easy thread synchronisation, prompt closure of files or other | ||||
| objects, and thread-safe manipulation of the decimal arithmetic | ||||
| context. The specific types are not important beyond their | ||||
| implementation of the context management and with statement context | ||||
| protocols. | ||||
| Python defines several context managers to support easy thread | ||||
| synchronisation, prompt closure of files or other objects, and | ||||
| simpler manipulation of the active decimal arithmetic | ||||
| context. The specific types are not treated specially beyond | ||||
| their implementation of the context management protocol. | ||||
| 
 | ||||
| Python's generators and the \code{contextlib.contextfactory} decorator | ||||
| provide a convenient way to implement these protocols.  If a context | ||||
| manager's \method{__context__()} method is implemented as a | ||||
| generator decorated with the \code{contextlib.contextfactory} | ||||
| decorator, it will automatically return a with statement context | ||||
| object supplying the necessary \method{__context__()}, | ||||
| \method{__enter__()} and \method{__exit__()} methods. | ||||
| provide a convenient way to implement these protocols.  If a generator | ||||
| function is decorated with the \code{contextlib.contextfactory} | ||||
| decorator, it will return a context manager implementing the necessary | ||||
| \method{__enter__()} and \method{__exit__()} methods, rather than the | ||||
| iterator produced by an undecorated generator function. | ||||
| 
 | ||||
| Note that there is no specific slot for any of these methods in the | ||||
| type structure for Python objects in the Python/C API. Extension | ||||
|  |  | |||
|  | @ -2112,14 +2112,13 @@ implement a \method{__coerce__()} method, for use by the built-in | |||
| 
 | ||||
| \end{itemize} | ||||
| 
 | ||||
| \subsection{With Statement Contexts and Context Managers\label{context-managers}} | ||||
| \subsection{With Statement Context Managers\label{context-managers}} | ||||
| 
 | ||||
| \versionadded{2.5} | ||||
| 
 | ||||
| A \dfn{context manager} is an object that defines the runtime | ||||
| context to be established when executing a \keyword{with} | ||||
| statement. The context manager provides a | ||||
| \dfn{with statement context object} which manages the entry into, | ||||
| statement. The context manager handles the entry into, | ||||
| and the exit from, the desired runtime context for the execution | ||||
| of the block of code.  Context managers are normally invoked using | ||||
| the \keyword{with} statement (described in section~\ref{with}), but | ||||
|  | @ -2127,18 +2126,16 @@ can also be used by directly invoking their methods. | |||
| 
 | ||||
| \stindex{with} | ||||
| \index{context manager} | ||||
| \index{context (with statement)} | ||||
| \index{with statement context} | ||||
| 
 | ||||
| Typical uses of context managers and contexts include saving and | ||||
| Typical uses of context managers include saving and | ||||
| restoring various kinds of global state, locking and unlocking | ||||
| resources, closing opened files, etc. | ||||
| 
 | ||||
| For more information on context managers and context objects, | ||||
| see ``\ulink{Context Types}{../lib/typecontext.html}'' in the | ||||
| For more information on context managers, see | ||||
| ``\ulink{Context Types}{../lib/typecontextmanager.html}'' in the | ||||
| \citetitle[../lib/lib.html]{Python Library Reference}. | ||||
| 
 | ||||
| \begin{methoddesc}[with statement context]{__enter__}{self} | ||||
| \begin{methoddesc}[context manager]{__enter__}{self} | ||||
| Enter the runtime context related to this object. The \keyword{with} | ||||
| statement will bind this method's return value to the target(s) | ||||
| specified in the \keyword{as} clause of the statement, if any. | ||||
|  |  | |||
|  | @ -315,8 +315,8 @@ statement to generate exceptions may be found in section~\ref{raise}. | |||
| \versionadded{2.5} | ||||
| 
 | ||||
| The \keyword{with} statement is used to wrap the execution of a block | ||||
| with methods defined by a context manager or \keyword{with} statement context | ||||
| object (see section~\ref{context-managers}). This allows common | ||||
| with methods defined by a context manager (see | ||||
| section~\ref{context-managers}). This allows common | ||||
| \keyword{try}...\keyword{except}...\keyword{finally} usage patterns to | ||||
| be encapsulated for convenient reuse. | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,10 +2,10 @@ | |||
| 
 | ||||
| import sys | ||||
| 
 | ||||
| __all__ = ["contextfactory", "nested", "closing"] | ||||
| __all__ = ["contextmanager", "nested", "closing"] | ||||
| 
 | ||||
| class GeneratorContext(object): | ||||
|     """Helper for @contextfactory decorator.""" | ||||
| class GeneratorContextManager(object): | ||||
|     """Helper for @contextmanager decorator.""" | ||||
| 
 | ||||
|     def __init__(self, gen): | ||||
|         self.gen = gen | ||||
|  | @ -45,12 +45,12 @@ def __exit__(self, type, value, traceback): | |||
|                     raise | ||||
| 
 | ||||
| 
 | ||||
| def contextfactory(func): | ||||
|     """@contextfactory decorator. | ||||
| def contextmanager(func): | ||||
|     """@contextmanager decorator. | ||||
| 
 | ||||
|     Typical usage: | ||||
| 
 | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def some_generator(<arguments>): | ||||
|             <setup> | ||||
|             try: | ||||
|  | @ -74,7 +74,7 @@ def some_generator(<arguments>): | |||
| 
 | ||||
|     """ | ||||
|     def helper(*args, **kwds): | ||||
|         return GeneratorContext(func(*args, **kwds)) | ||||
|         return GeneratorContextManager(func(*args, **kwds)) | ||||
|     try: | ||||
|         helper.__name__ = func.__name__ | ||||
|         helper.__doc__ = func.__doc__ | ||||
|  | @ -84,7 +84,7 @@ def helper(*args, **kwds): | |||
|     return helper | ||||
| 
 | ||||
| 
 | ||||
| @contextfactory | ||||
| @contextmanager | ||||
| def nested(*managers): | ||||
|     """Support multiple context managers in a single with-statement. | ||||
| 
 | ||||
|  |  | |||
|  | @ -2173,7 +2173,7 @@ def __deepcopy__(self, memo): | |||
| 
 | ||||
| del name, val, globalname, rounding_functions | ||||
| 
 | ||||
| class WithStatementContext(object): | ||||
| class ContextManager(object): | ||||
|     """Helper class to simplify Context management. | ||||
| 
 | ||||
|     Sample usage: | ||||
|  | @ -2248,8 +2248,8 @@ def __repr__(self): | |||
|         s.append('traps=[' + ', '.join([t.__name__ for t, v in self.traps.items() if v]) + ']') | ||||
|         return ', '.join(s) + ')' | ||||
| 
 | ||||
|     def context_manager(self): | ||||
|         return WithStatementContext(self.copy()) | ||||
|     def get_manager(self): | ||||
|         return ContextManager(self.copy()) | ||||
| 
 | ||||
|     def clear_flags(self): | ||||
|         """Reset all flags to zero""" | ||||
|  |  | |||
|  | @ -13,9 +13,9 @@ | |||
| 
 | ||||
| class ContextManagerTestCase(unittest.TestCase): | ||||
| 
 | ||||
|     def test_contextfactory_plain(self): | ||||
|     def test_contextmanager_plain(self): | ||||
|         state = [] | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def woohoo(): | ||||
|             state.append(1) | ||||
|             yield 42 | ||||
|  | @ -26,9 +26,9 @@ def woohoo(): | |||
|             state.append(x) | ||||
|         self.assertEqual(state, [1, 42, 999]) | ||||
| 
 | ||||
|     def test_contextfactory_finally(self): | ||||
|     def test_contextmanager_finally(self): | ||||
|         state = [] | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def woohoo(): | ||||
|             state.append(1) | ||||
|             try: | ||||
|  | @ -47,8 +47,8 @@ def woohoo(): | |||
|             self.fail("Expected ZeroDivisionError") | ||||
|         self.assertEqual(state, [1, 42, 999]) | ||||
| 
 | ||||
|     def test_contextfactory_no_reraise(self): | ||||
|         @contextfactory | ||||
|     def test_contextmanager_no_reraise(self): | ||||
|         @contextmanager | ||||
|         def whee(): | ||||
|             yield | ||||
|         ctx = whee() | ||||
|  | @ -56,8 +56,8 @@ def whee(): | |||
|         # Calling __exit__ should not result in an exception | ||||
|         self.failIf(ctx.__exit__(TypeError, TypeError("foo"), None)) | ||||
| 
 | ||||
|     def test_contextfactory_trap_yield_after_throw(self): | ||||
|         @contextfactory | ||||
|     def test_contextmanager_trap_yield_after_throw(self): | ||||
|         @contextmanager | ||||
|         def whoo(): | ||||
|             try: | ||||
|                 yield | ||||
|  | @ -69,9 +69,9 @@ def whoo(): | |||
|             RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None | ||||
|         ) | ||||
| 
 | ||||
|     def test_contextfactory_except(self): | ||||
|     def test_contextmanager_except(self): | ||||
|         state = [] | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def woohoo(): | ||||
|             state.append(1) | ||||
|             try: | ||||
|  | @ -86,14 +86,14 @@ def woohoo(): | |||
|             raise ZeroDivisionError(999) | ||||
|         self.assertEqual(state, [1, 42, 999]) | ||||
| 
 | ||||
|     def test_contextfactory_attribs(self): | ||||
|     def test_contextmanager_attribs(self): | ||||
|         def attribs(**kw): | ||||
|             def decorate(func): | ||||
|                 for k,v in kw.items(): | ||||
|                     setattr(func,k,v) | ||||
|                 return func | ||||
|             return decorate | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         @attribs(foo='bar') | ||||
|         def baz(spam): | ||||
|             """Whee!""" | ||||
|  | @ -106,13 +106,13 @@ class NestedTestCase(unittest.TestCase): | |||
|     # XXX This needs more work | ||||
| 
 | ||||
|     def test_nested(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             yield 1 | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def b(): | ||||
|             yield 2 | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def c(): | ||||
|             yield 3 | ||||
|         with nested(a(), b(), c()) as (x, y, z): | ||||
|  | @ -122,14 +122,14 @@ def c(): | |||
| 
 | ||||
|     def test_nested_cleanup(self): | ||||
|         state = [] | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             state.append(1) | ||||
|             try: | ||||
|                 yield 2 | ||||
|             finally: | ||||
|                 state.append(3) | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def b(): | ||||
|             state.append(4) | ||||
|             try: | ||||
|  | @ -148,7 +148,7 @@ def b(): | |||
| 
 | ||||
|     def test_nested_right_exception(self): | ||||
|         state = [] | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             yield 1 | ||||
|         class b(object): | ||||
|  | @ -170,10 +170,10 @@ def __exit__(self, *exc_info): | |||
|             self.fail("Didn't raise ZeroDivisionError") | ||||
| 
 | ||||
|     def test_nested_b_swallows(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             yield | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def b(): | ||||
|             try: | ||||
|                 yield | ||||
|  | @ -187,7 +187,7 @@ def b(): | |||
|             self.fail("Didn't swallow ZeroDivisionError") | ||||
| 
 | ||||
|     def test_nested_break(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             yield | ||||
|         state = 0 | ||||
|  | @ -199,7 +199,7 @@ def a(): | |||
|         self.assertEqual(state, 1) | ||||
| 
 | ||||
|     def test_nested_continue(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             yield | ||||
|         state = 0 | ||||
|  | @ -211,7 +211,7 @@ def a(): | |||
|         self.assertEqual(state, 3) | ||||
| 
 | ||||
|     def test_nested_return(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def a(): | ||||
|             try: | ||||
|                 yield | ||||
|  | @ -339,12 +339,12 @@ def testBasic(self): | |||
|         orig_context = ctx.copy() | ||||
|         try: | ||||
|             ctx.prec = save_prec = decimal.ExtendedContext.prec + 5 | ||||
|             with decimal.ExtendedContext.context_manager(): | ||||
|             with decimal.ExtendedContext.get_manager(): | ||||
|                 self.assertEqual(decimal.getcontext().prec, | ||||
|                                  decimal.ExtendedContext.prec) | ||||
|             self.assertEqual(decimal.getcontext().prec, save_prec) | ||||
|             try: | ||||
|                 with decimal.ExtendedContext.context_manager(): | ||||
|                 with decimal.ExtendedContext.get_manager(): | ||||
|                     self.assertEqual(decimal.getcontext().prec, | ||||
|                                      decimal.ExtendedContext.prec) | ||||
|                     1/0 | ||||
|  |  | |||
|  | @ -10,25 +10,26 @@ | |||
| import sys | ||||
| import unittest | ||||
| from collections import deque | ||||
| from contextlib import GeneratorContext, contextfactory | ||||
| from contextlib import GeneratorContextManager, contextmanager | ||||
| from test.test_support import run_unittest | ||||
| 
 | ||||
| 
 | ||||
| class MockContextManager(GeneratorContext): | ||||
| class MockContextManager(GeneratorContextManager): | ||||
|     def __init__(self, gen): | ||||
|         GeneratorContext.__init__(self, gen) | ||||
|         GeneratorContextManager.__init__(self, gen) | ||||
|         self.enter_called = False | ||||
|         self.exit_called = False | ||||
|         self.exit_args = None | ||||
| 
 | ||||
|     def __enter__(self): | ||||
|         self.enter_called = True | ||||
|         return GeneratorContext.__enter__(self) | ||||
|         return GeneratorContextManager.__enter__(self) | ||||
| 
 | ||||
|     def __exit__(self, type, value, traceback): | ||||
|         self.exit_called = True | ||||
|         self.exit_args = (type, value, traceback) | ||||
|         return GeneratorContext.__exit__(self, type, value, traceback) | ||||
|         return GeneratorContextManager.__exit__(self, type, | ||||
|                                                 value, traceback) | ||||
| 
 | ||||
| 
 | ||||
| def mock_contextmanager(func): | ||||
|  | @ -439,7 +440,7 @@ def shouldThrow(): | |||
|         self.assertAfterWithGeneratorInvariantsNoError(self.bar) | ||||
| 
 | ||||
|     def testRaisedStopIteration1(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def cm(): | ||||
|             yield | ||||
| 
 | ||||
|  | @ -463,7 +464,7 @@ def shouldThrow(): | |||
|         self.assertRaises(StopIteration, shouldThrow) | ||||
| 
 | ||||
|     def testRaisedGeneratorExit1(self): | ||||
|         @contextfactory | ||||
|         @contextmanager | ||||
|         def cm(): | ||||
|             yield | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Nick Coghlan
						Nick Coghlan