Get rid of __context__, per the latest changes to PEP 343 and python-dev
discussion. There are two places of documentation that still mention __context__: Doc/lib/libstdtypes.tex -- I wasn't quite sure how to rewrite that without spending a whole lot of time thinking about it; and whatsnew, which Andrew usually likes to change himself.
This commit is contained in:
parent
8f6cbe1502
commit
da5b701aee
|
@ -54,34 +54,6 @@ action (rather than to suppress it entirely), the generator must
|
||||||
reraise that exception. Otherwise the \keyword{with} statement will
|
reraise that exception. Otherwise the \keyword{with} statement will
|
||||||
treat the exception as having been handled, and resume execution with
|
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.
|
||||||
|
|
||||||
Note that you can use \code{@contextfactory} to define a context
|
|
||||||
manager's \method{__context__} method. This is usually more
|
|
||||||
convenient than creating another class just to serve as a context
|
|
||||||
object. For example:
|
|
||||||
|
|
||||||
\begin{verbatim}
|
|
||||||
from __future__ import with_statement
|
|
||||||
from contextlib import contextfactory
|
|
||||||
|
|
||||||
class Tag:
|
|
||||||
def __init__(self, name):
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
@contextfactory
|
|
||||||
def __context__(self):
|
|
||||||
print "<%s>" % self.name
|
|
||||||
yield self
|
|
||||||
print "</%s>" % self.name
|
|
||||||
|
|
||||||
h1 = Tag("h1")
|
|
||||||
|
|
||||||
>>> with h1 as me:
|
|
||||||
... print "hello from", me
|
|
||||||
<h1>
|
|
||||||
hello from <__main__.Tag instance at 0x402ce8ec>
|
|
||||||
</h1>
|
|
||||||
\end{verbatim}
|
|
||||||
\end{funcdesc}
|
\end{funcdesc}
|
||||||
|
|
||||||
\begin{funcdesc}{nested}{ctx1\optional{, ctx2\optional{, ...}}}
|
\begin{funcdesc}{nested}{ctx1\optional{, ctx2\optional{, ...}}}
|
||||||
|
@ -147,25 +119,6 @@ with closing(urllib.urlopen('http://www.python.org')) as page:
|
||||||
without needing to explicitly close \code{page}. Even if an error
|
without needing to explicitly close \code{page}. Even if an error
|
||||||
occurs, \code{page.close()} will be called when the \keyword{with}
|
occurs, \code{page.close()} will be called when the \keyword{with}
|
||||||
block is exited.
|
block is exited.
|
||||||
|
|
||||||
Context managers with a close method can use this context factory
|
|
||||||
to easily implement their own \method{__context__()} method.
|
|
||||||
\begin{verbatim}
|
|
||||||
from __future__ import with_statement
|
|
||||||
from contextlib import closing
|
|
||||||
|
|
||||||
class MyClass:
|
|
||||||
def close(self):
|
|
||||||
print "Closing", self
|
|
||||||
def __context__(self):
|
|
||||||
return closing(self)
|
|
||||||
|
|
||||||
>>> with MyClass() as x:
|
|
||||||
... print "Hello from", x
|
|
||||||
...
|
|
||||||
Hello from <__main__.MyClass instance at 0xb7df02ec>
|
|
||||||
Closing <__main__.MyClass instance at 0xb7df02ec>
|
|
||||||
\end{verbatim}
|
|
||||||
\end{funcdesc}
|
\end{funcdesc}
|
||||||
|
|
||||||
\begin{seealso}
|
\begin{seealso}
|
||||||
|
|
|
@ -2138,22 +2138,6 @@ For more information on context managers and context objects,
|
||||||
see ``\ulink{Context Types}{../lib/typecontext.html}'' in the
|
see ``\ulink{Context Types}{../lib/typecontext.html}'' in the
|
||||||
\citetitle[../lib/lib.html]{Python Library Reference}.
|
\citetitle[../lib/lib.html]{Python Library Reference}.
|
||||||
|
|
||||||
\begin{methoddesc}[context manager]{__context__}{self}
|
|
||||||
Invoked when the object is used as the context expression of a
|
|
||||||
\keyword{with} statement. The returned object must implement
|
|
||||||
\method{__enter__()} and \method{__exit__()} methods.
|
|
||||||
|
|
||||||
Context managers written in Python can also implement this method
|
|
||||||
using a generator function decorated with the
|
|
||||||
\function{contextlib.contextfactory} decorator, as this can be simpler
|
|
||||||
than writing individual \method{__enter__()} and \method{__exit__()}
|
|
||||||
methods on a separate object when the state to be managed is complex.
|
|
||||||
|
|
||||||
\keyword{with} statement context objects also need to implement this
|
|
||||||
method; they are required to return themselves (that is, this method
|
|
||||||
will simply return \var{self}).
|
|
||||||
\end{methoddesc}
|
|
||||||
|
|
||||||
\begin{methoddesc}[with statement context]{__enter__}{self}
|
\begin{methoddesc}[with statement context]{__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)
|
||||||
|
|
|
@ -322,21 +322,18 @@ be encapsulated for convenient reuse.
|
||||||
|
|
||||||
\begin{productionlist}
|
\begin{productionlist}
|
||||||
\production{with_stmt}
|
\production{with_stmt}
|
||||||
{"with" \token{expression} ["as" target_list] ":" \token{suite}}
|
{"with" \token{expression} ["as" target] ":" \token{suite}}
|
||||||
\end{productionlist}
|
\end{productionlist}
|
||||||
|
|
||||||
The execution of the \keyword{with} statement proceeds as follows:
|
The execution of the \keyword{with} statement proceeds as follows:
|
||||||
|
|
||||||
\begin{enumerate}
|
\begin{enumerate}
|
||||||
|
|
||||||
\item The context expression is evaluated, to obtain a context manager.
|
\item The context expression is evaluated to obtain a context manager.
|
||||||
|
|
||||||
\item The context manger's \method{__context__()} method is
|
\item The context manager's \method{__enter__()} method is invoked.
|
||||||
invoked to obtain a \keyword{with} statement context object.
|
|
||||||
|
|
||||||
\item The context object's \method{__enter__()} method is invoked.
|
\item If a target was included in the \keyword{with}
|
||||||
|
|
||||||
\item If a target list was included in the \keyword{with}
|
|
||||||
statement, the return value from \method{__enter__()} is assigned to it.
|
statement, the return value from \method{__enter__()} is assigned to it.
|
||||||
|
|
||||||
\note{The \keyword{with} statement guarantees that if the
|
\note{The \keyword{with} statement guarantees that if the
|
||||||
|
@ -347,7 +344,7 @@ an error occurring within the suite would be. See step 6 below.}
|
||||||
|
|
||||||
\item The suite is executed.
|
\item The suite is executed.
|
||||||
|
|
||||||
\item The context object's \method{__exit__()} method is invoked. If
|
\item The context manager's \method{__exit__()} method is invoked. If
|
||||||
an exception caused the suite to be exited, its type, value, and
|
an exception caused the suite to be exited, its type, value, and
|
||||||
traceback are passed as arguments to \method{__exit__()}. Otherwise,
|
traceback are passed as arguments to \method{__exit__()}. Otherwise,
|
||||||
three \constant{None} arguments are supplied.
|
three \constant{None} arguments are supplied.
|
||||||
|
|
|
@ -484,9 +484,6 @@ class TimeEncoding:
|
||||||
def __init__(self, locale):
|
def __init__(self, locale):
|
||||||
self.locale = locale
|
self.locale = locale
|
||||||
|
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
|
self.oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
|
||||||
return locale.getlocale(locale.LC_TIME)[1]
|
return locale.getlocale(locale.LC_TIME)[1]
|
||||||
|
|
|
@ -833,8 +833,6 @@ class CodeGenerator:
|
||||||
self.__with_count += 1
|
self.__with_count += 1
|
||||||
self.set_lineno(node)
|
self.set_lineno(node)
|
||||||
self.visit(node.expr)
|
self.visit(node.expr)
|
||||||
self.emit('LOAD_ATTR', '__context__')
|
|
||||||
self.emit('CALL_FUNCTION', 0)
|
|
||||||
self.emit('DUP_TOP')
|
self.emit('DUP_TOP')
|
||||||
self.emit('LOAD_ATTR', '__exit__')
|
self.emit('LOAD_ATTR', '__exit__')
|
||||||
self._implicitNameOp('STORE', exitvar)
|
self._implicitNameOp('STORE', exitvar)
|
||||||
|
|
|
@ -10,9 +10,6 @@ class GeneratorContext(object):
|
||||||
def __init__(self, gen):
|
def __init__(self, gen):
|
||||||
self.gen = gen
|
self.gen = gen
|
||||||
|
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
try:
|
try:
|
||||||
return self.gen.next()
|
return self.gen.next()
|
||||||
|
@ -88,7 +85,7 @@ def contextfactory(func):
|
||||||
|
|
||||||
|
|
||||||
@contextfactory
|
@contextfactory
|
||||||
def nested(*contexts):
|
def nested(*managers):
|
||||||
"""Support multiple context managers in a single with-statement.
|
"""Support multiple context managers in a single with-statement.
|
||||||
|
|
||||||
Code like this:
|
Code like this:
|
||||||
|
@ -109,8 +106,7 @@ def nested(*contexts):
|
||||||
exc = (None, None, None)
|
exc = (None, None, None)
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
for context in contexts:
|
for mgr in managers:
|
||||||
mgr = context.__context__()
|
|
||||||
exit = mgr.__exit__
|
exit = mgr.__exit__
|
||||||
enter = mgr.__enter__
|
enter = mgr.__enter__
|
||||||
vars.append(enter())
|
vars.append(enter())
|
||||||
|
@ -152,8 +148,6 @@ class closing(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self, thing):
|
def __init__(self, thing):
|
||||||
self.thing = thing
|
self.thing = thing
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self.thing
|
return self.thing
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
|
|
|
@ -2248,7 +2248,7 @@ 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__(self):
|
def context_manager(self):
|
||||||
return WithStatementContext(self.copy())
|
return WithStatementContext(self.copy())
|
||||||
|
|
||||||
def clear_flags(self):
|
def clear_flags(self):
|
||||||
|
|
|
@ -118,9 +118,6 @@ class LockType(object):
|
||||||
def __exit__(self, typ, val, tb):
|
def __exit__(self, typ, val, tb):
|
||||||
self.release()
|
self.release()
|
||||||
|
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
"""Release the dummy lock."""
|
"""Release the dummy lock."""
|
||||||
# XXX Perhaps shouldn't actually bother to test? Could lead
|
# XXX Perhaps shouldn't actually bother to test? Could lead
|
||||||
|
|
|
@ -51,7 +51,7 @@ class ContextManagerTestCase(unittest.TestCase):
|
||||||
@contextfactory
|
@contextfactory
|
||||||
def whee():
|
def whee():
|
||||||
yield
|
yield
|
||||||
ctx = whee().__context__()
|
ctx = whee()
|
||||||
ctx.__enter__()
|
ctx.__enter__()
|
||||||
# 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))
|
||||||
|
@ -63,7 +63,7 @@ class ContextManagerTestCase(unittest.TestCase):
|
||||||
yield
|
yield
|
||||||
except:
|
except:
|
||||||
yield
|
yield
|
||||||
ctx = whoo().__context__()
|
ctx = whoo()
|
||||||
ctx.__enter__()
|
ctx.__enter__()
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
|
RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
|
||||||
|
@ -152,8 +152,6 @@ class NestedTestCase(unittest.TestCase):
|
||||||
def a():
|
def a():
|
||||||
yield 1
|
yield 1
|
||||||
class b(object):
|
class b(object):
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return 2
|
return 2
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
|
@ -341,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:
|
with decimal.ExtendedContext.context_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:
|
with decimal.ExtendedContext.context_manager():
|
||||||
self.assertEqual(decimal.getcontext().prec,
|
self.assertEqual(decimal.getcontext().prec,
|
||||||
decimal.ExtendedContext.prec)
|
decimal.ExtendedContext.prec)
|
||||||
1/0
|
1/0
|
||||||
|
|
|
@ -17,15 +17,10 @@ from test.test_support import run_unittest
|
||||||
class MockContextManager(GeneratorContext):
|
class MockContextManager(GeneratorContext):
|
||||||
def __init__(self, gen):
|
def __init__(self, gen):
|
||||||
GeneratorContext.__init__(self, gen)
|
GeneratorContext.__init__(self, gen)
|
||||||
self.context_called = False
|
|
||||||
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 __context__(self):
|
|
||||||
self.context_called = True
|
|
||||||
return GeneratorContext.__context__(self)
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.enter_called = True
|
self.enter_called = True
|
||||||
return GeneratorContext.__enter__(self)
|
return GeneratorContext.__enter__(self)
|
||||||
|
@ -60,21 +55,17 @@ def mock_contextmanager_generator():
|
||||||
|
|
||||||
class Nested(object):
|
class Nested(object):
|
||||||
|
|
||||||
def __init__(self, *contexts):
|
def __init__(self, *managers):
|
||||||
self.contexts = contexts
|
self.managers = managers
|
||||||
self.entered = None
|
self.entered = None
|
||||||
|
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
if self.entered is not None:
|
if self.entered is not None:
|
||||||
raise RuntimeError("Context is not reentrant")
|
raise RuntimeError("Context is not reentrant")
|
||||||
self.entered = deque()
|
self.entered = deque()
|
||||||
vars = []
|
vars = []
|
||||||
try:
|
try:
|
||||||
for context in self.contexts:
|
for mgr in self.managers:
|
||||||
mgr = context.__context__()
|
|
||||||
vars.append(mgr.__enter__())
|
vars.append(mgr.__enter__())
|
||||||
self.entered.appendleft(mgr)
|
self.entered.appendleft(mgr)
|
||||||
except:
|
except:
|
||||||
|
@ -99,17 +90,12 @@ class Nested(object):
|
||||||
|
|
||||||
|
|
||||||
class MockNested(Nested):
|
class MockNested(Nested):
|
||||||
def __init__(self, *contexts):
|
def __init__(self, *managers):
|
||||||
Nested.__init__(self, *contexts)
|
Nested.__init__(self, *managers)
|
||||||
self.context_called = False
|
|
||||||
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 __context__(self):
|
|
||||||
self.context_called = True
|
|
||||||
return Nested.__context__(self)
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.enter_called = True
|
self.enter_called = True
|
||||||
return Nested.__enter__(self)
|
return Nested.__enter__(self)
|
||||||
|
@ -126,24 +112,8 @@ class FailureTestCase(unittest.TestCase):
|
||||||
with foo: pass
|
with foo: pass
|
||||||
self.assertRaises(NameError, fooNotDeclared)
|
self.assertRaises(NameError, fooNotDeclared)
|
||||||
|
|
||||||
def testContextAttributeError(self):
|
|
||||||
class LacksContext(object):
|
|
||||||
def __enter__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def fooLacksContext():
|
|
||||||
foo = LacksContext()
|
|
||||||
with foo: pass
|
|
||||||
self.assertRaises(AttributeError, fooLacksContext)
|
|
||||||
|
|
||||||
def testEnterAttributeError(self):
|
def testEnterAttributeError(self):
|
||||||
class LacksEnter(object):
|
class LacksEnter(object):
|
||||||
def __context__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -154,9 +124,6 @@ class FailureTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def testExitAttributeError(self):
|
def testExitAttributeError(self):
|
||||||
class LacksExit(object):
|
class LacksExit(object):
|
||||||
def __context__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -192,27 +159,10 @@ class FailureTestCase(unittest.TestCase):
|
||||||
'with mock as (foo, None, bar):\n'
|
'with mock as (foo, None, bar):\n'
|
||||||
' pass')
|
' pass')
|
||||||
|
|
||||||
def testContextThrows(self):
|
|
||||||
class ContextThrows(object):
|
|
||||||
def __context__(self):
|
|
||||||
raise RuntimeError("Context threw")
|
|
||||||
|
|
||||||
def shouldThrow():
|
|
||||||
ct = ContextThrows()
|
|
||||||
self.foo = None
|
|
||||||
with ct as self.foo:
|
|
||||||
pass
|
|
||||||
self.assertRaises(RuntimeError, shouldThrow)
|
|
||||||
self.assertEqual(self.foo, None)
|
|
||||||
|
|
||||||
def testEnterThrows(self):
|
def testEnterThrows(self):
|
||||||
class EnterThrows(object):
|
class EnterThrows(object):
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
raise RuntimeError("Context threw")
|
raise RuntimeError("Enter threw")
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -226,8 +176,6 @@ class FailureTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def testExitThrows(self):
|
def testExitThrows(self):
|
||||||
class ExitThrows(object):
|
class ExitThrows(object):
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return
|
return
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
@ -241,13 +189,11 @@ class ContextmanagerAssertionMixin(object):
|
||||||
TEST_EXCEPTION = RuntimeError("test exception")
|
TEST_EXCEPTION = RuntimeError("test exception")
|
||||||
|
|
||||||
def assertInWithManagerInvariants(self, mock_manager):
|
def assertInWithManagerInvariants(self, mock_manager):
|
||||||
self.assertTrue(mock_manager.context_called)
|
|
||||||
self.assertTrue(mock_manager.enter_called)
|
self.assertTrue(mock_manager.enter_called)
|
||||||
self.assertFalse(mock_manager.exit_called)
|
self.assertFalse(mock_manager.exit_called)
|
||||||
self.assertEqual(mock_manager.exit_args, None)
|
self.assertEqual(mock_manager.exit_args, None)
|
||||||
|
|
||||||
def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
|
def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
|
||||||
self.assertTrue(mock_manager.context_called)
|
|
||||||
self.assertTrue(mock_manager.enter_called)
|
self.assertTrue(mock_manager.enter_called)
|
||||||
self.assertTrue(mock_manager.exit_called)
|
self.assertTrue(mock_manager.exit_called)
|
||||||
self.assertEqual(mock_manager.exit_args, exit_args)
|
self.assertEqual(mock_manager.exit_args, exit_args)
|
||||||
|
@ -268,7 +214,6 @@ class ContextmanagerAssertionMixin(object):
|
||||||
raise self.TEST_EXCEPTION
|
raise self.TEST_EXCEPTION
|
||||||
|
|
||||||
def assertAfterWithManagerInvariantsWithError(self, mock_manager):
|
def assertAfterWithManagerInvariantsWithError(self, mock_manager):
|
||||||
self.assertTrue(mock_manager.context_called)
|
|
||||||
self.assertTrue(mock_manager.enter_called)
|
self.assertTrue(mock_manager.enter_called)
|
||||||
self.assertTrue(mock_manager.exit_called)
|
self.assertTrue(mock_manager.exit_called)
|
||||||
self.assertEqual(mock_manager.exit_args[0], RuntimeError)
|
self.assertEqual(mock_manager.exit_args[0], RuntimeError)
|
||||||
|
@ -472,7 +417,6 @@ class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
|
||||||
|
|
||||||
# The inner statement stuff should never have been touched
|
# The inner statement stuff should never have been touched
|
||||||
self.assertEqual(self.bar, None)
|
self.assertEqual(self.bar, None)
|
||||||
self.assertFalse(mock_b.context_called)
|
|
||||||
self.assertFalse(mock_b.enter_called)
|
self.assertFalse(mock_b.enter_called)
|
||||||
self.assertFalse(mock_b.exit_called)
|
self.assertFalse(mock_b.exit_called)
|
||||||
self.assertEqual(mock_b.exit_args, None)
|
self.assertEqual(mock_b.exit_args, None)
|
||||||
|
@ -506,13 +450,9 @@ class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
|
||||||
self.assertRaises(StopIteration, shouldThrow)
|
self.assertRaises(StopIteration, shouldThrow)
|
||||||
|
|
||||||
def testRaisedStopIteration2(self):
|
def testRaisedStopIteration2(self):
|
||||||
class cm (object):
|
class cm(object):
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -535,12 +475,8 @@ class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
|
||||||
|
|
||||||
def testRaisedGeneratorExit2(self):
|
def testRaisedGeneratorExit2(self):
|
||||||
class cm (object):
|
class cm (object):
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -629,7 +565,6 @@ class AssignmentTargetTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def testMultipleComplexTargets(self):
|
def testMultipleComplexTargets(self):
|
||||||
class C:
|
class C:
|
||||||
def __context__(self): return self
|
|
||||||
def __enter__(self): return 1, 2, 3
|
def __enter__(self): return 1, 2, 3
|
||||||
def __exit__(self, t, v, tb): pass
|
def __exit__(self, t, v, tb): pass
|
||||||
targets = {1: [0, 1, 2]}
|
targets = {1: [0, 1, 2]}
|
||||||
|
@ -651,7 +586,6 @@ class ExitSwallowsExceptionTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def testExitTrueSwallowsException(self):
|
def testExitTrueSwallowsException(self):
|
||||||
class AfricanSwallow:
|
class AfricanSwallow:
|
||||||
def __context__(self): return self
|
|
||||||
def __enter__(self): pass
|
def __enter__(self): pass
|
||||||
def __exit__(self, t, v, tb): return True
|
def __exit__(self, t, v, tb): return True
|
||||||
try:
|
try:
|
||||||
|
@ -662,7 +596,6 @@ class ExitSwallowsExceptionTestCase(unittest.TestCase):
|
||||||
|
|
||||||
def testExitFalseDoesntSwallowException(self):
|
def testExitFalseDoesntSwallowException(self):
|
||||||
class EuropeanSwallow:
|
class EuropeanSwallow:
|
||||||
def __context__(self): return self
|
|
||||||
def __enter__(self): pass
|
def __enter__(self): pass
|
||||||
def __exit__(self, t, v, tb): return False
|
def __exit__(self, t, v, tb): return False
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -90,9 +90,6 @@ class _RLock(_Verbose):
|
||||||
self.__owner and self.__owner.getName(),
|
self.__owner and self.__owner.getName(),
|
||||||
self.__count)
|
self.__count)
|
||||||
|
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def acquire(self, blocking=1):
|
def acquire(self, blocking=1):
|
||||||
me = currentThread()
|
me = currentThread()
|
||||||
if self.__owner is me:
|
if self.__owner is me:
|
||||||
|
@ -182,8 +179,11 @@ class _Condition(_Verbose):
|
||||||
pass
|
pass
|
||||||
self.__waiters = []
|
self.__waiters = []
|
||||||
|
|
||||||
def __context__(self):
|
def __enter__(self):
|
||||||
return self.__lock.__context__()
|
return self.__lock.__enter__()
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
return self.__lock.__exit__(*args)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
|
return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
|
||||||
|
@ -278,9 +278,6 @@ class _Semaphore(_Verbose):
|
||||||
self.__cond = Condition(Lock())
|
self.__cond = Condition(Lock())
|
||||||
self.__value = value
|
self.__value = value
|
||||||
|
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def acquire(self, blocking=1):
|
def acquire(self, blocking=1):
|
||||||
rc = False
|
rc = False
|
||||||
self.__cond.acquire()
|
self.__cond.acquire()
|
||||||
|
|
|
@ -19,8 +19,6 @@ assert True # keyword
|
||||||
def foo(): # function definition
|
def foo(): # function definition
|
||||||
return []
|
return []
|
||||||
class Bar(object): # Class definition
|
class Bar(object): # Class definition
|
||||||
def __context__(self):
|
|
||||||
return self
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
pass
|
pass
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
|
|
|
@ -98,13 +98,6 @@ PyDoc_STRVAR(locked_doc,
|
||||||
\n\
|
\n\
|
||||||
Return whether the lock is in the locked state.");
|
Return whether the lock is in the locked state.");
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
lock_context(lockobject *self)
|
|
||||||
{
|
|
||||||
Py_INCREF(self);
|
|
||||||
return (PyObject *)self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef lock_methods[] = {
|
static PyMethodDef lock_methods[] = {
|
||||||
{"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
|
{"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
|
||||||
METH_VARARGS, acquire_doc},
|
METH_VARARGS, acquire_doc},
|
||||||
|
@ -118,8 +111,6 @@ static PyMethodDef lock_methods[] = {
|
||||||
METH_NOARGS, locked_doc},
|
METH_NOARGS, locked_doc},
|
||||||
{"locked", (PyCFunction)lock_locked_lock,
|
{"locked", (PyCFunction)lock_locked_lock,
|
||||||
METH_NOARGS, locked_doc},
|
METH_NOARGS, locked_doc},
|
||||||
{"__context__", (PyCFunction)lock_context,
|
|
||||||
METH_NOARGS, PyDoc_STR("__context__() -> self.")},
|
|
||||||
{"__enter__", (PyCFunction)lock_PyThread_acquire_lock,
|
{"__enter__", (PyCFunction)lock_PyThread_acquire_lock,
|
||||||
METH_VARARGS, acquire_doc},
|
METH_VARARGS, acquire_doc},
|
||||||
{"__exit__", (PyCFunction)lock_PyThread_release_lock,
|
{"__exit__", (PyCFunction)lock_PyThread_release_lock,
|
||||||
|
|
|
@ -1706,9 +1706,6 @@ PyDoc_STRVAR(close_doc,
|
||||||
PyDoc_STRVAR(isatty_doc,
|
PyDoc_STRVAR(isatty_doc,
|
||||||
"isatty() -> true or false. True if the file is connected to a tty device.");
|
"isatty() -> true or false. True if the file is connected to a tty device.");
|
||||||
|
|
||||||
PyDoc_STRVAR(context_doc,
|
|
||||||
"__context__() -> self.");
|
|
||||||
|
|
||||||
PyDoc_STRVAR(enter_doc,
|
PyDoc_STRVAR(enter_doc,
|
||||||
"__enter__() -> self.");
|
"__enter__() -> self.");
|
||||||
|
|
||||||
|
@ -1729,7 +1726,6 @@ static PyMethodDef file_methods[] = {
|
||||||
{"flush", (PyCFunction)file_flush, METH_NOARGS, flush_doc},
|
{"flush", (PyCFunction)file_flush, METH_NOARGS, flush_doc},
|
||||||
{"close", (PyCFunction)file_close, METH_NOARGS, close_doc},
|
{"close", (PyCFunction)file_close, METH_NOARGS, close_doc},
|
||||||
{"isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc},
|
{"isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc},
|
||||||
{"__context__", (PyCFunction)file_self, METH_NOARGS, context_doc},
|
|
||||||
{"__enter__", (PyCFunction)file_self, METH_NOARGS, enter_doc},
|
{"__enter__", (PyCFunction)file_self, METH_NOARGS, enter_doc},
|
||||||
{"__exit__", (PyCFunction)file_close, METH_VARARGS, close_doc},
|
{"__exit__", (PyCFunction)file_close, METH_VARARGS, close_doc},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
|
@ -2445,4 +2441,3 @@ Py_UniversalNewlineFread(char *buf, size_t n,
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -3371,7 +3371,7 @@ expr_constant(expr_ty e)
|
||||||
|
|
||||||
It is implemented roughly as:
|
It is implemented roughly as:
|
||||||
|
|
||||||
context = (EXPR).__context__()
|
context = EXPR
|
||||||
exit = context.__exit__ # not calling it
|
exit = context.__exit__ # not calling it
|
||||||
value = context.__enter__()
|
value = context.__enter__()
|
||||||
try:
|
try:
|
||||||
|
@ -3387,17 +3387,12 @@ expr_constant(expr_ty e)
|
||||||
static int
|
static int
|
||||||
compiler_with(struct compiler *c, stmt_ty s)
|
compiler_with(struct compiler *c, stmt_ty s)
|
||||||
{
|
{
|
||||||
static identifier context_attr, enter_attr, exit_attr;
|
static identifier enter_attr, exit_attr;
|
||||||
basicblock *block, *finally;
|
basicblock *block, *finally;
|
||||||
identifier tmpexit, tmpvalue = NULL;
|
identifier tmpexit, tmpvalue = NULL;
|
||||||
|
|
||||||
assert(s->kind == With_kind);
|
assert(s->kind == With_kind);
|
||||||
|
|
||||||
if (!context_attr) {
|
|
||||||
context_attr = PyString_InternFromString("__context__");
|
|
||||||
if (!context_attr)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!enter_attr) {
|
if (!enter_attr) {
|
||||||
enter_attr = PyString_InternFromString("__enter__");
|
enter_attr = PyString_InternFromString("__enter__");
|
||||||
if (!enter_attr)
|
if (!enter_attr)
|
||||||
|
@ -3436,10 +3431,8 @@ compiler_with(struct compiler *c, stmt_ty s)
|
||||||
PyArena_AddPyObject(c->c_arena, tmpvalue);
|
PyArena_AddPyObject(c->c_arena, tmpvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Evaluate (EXPR).__context__() */
|
/* Evaluate EXPR */
|
||||||
VISIT(c, expr, s->v.With.context_expr);
|
VISIT(c, expr, s->v.With.context_expr);
|
||||||
ADDOP_O(c, LOAD_ATTR, context_attr, names);
|
|
||||||
ADDOP_I(c, CALL_FUNCTION, 0);
|
|
||||||
|
|
||||||
/* Squirrel away context.__exit__ */
|
/* Squirrel away context.__exit__ */
|
||||||
ADDOP(c, DUP_TOP);
|
ADDOP(c, DUP_TOP);
|
||||||
|
|
Loading…
Reference in New Issue