Kaydet (Commit) afd5e63e authored tarafından Nick Coghlan's avatar Nick Coghlan

Finish bringing SVN into line with latest version of PEP 343 by getting rid of…

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