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:
Guido van Rossum 2006-05-02 19:47:52 +00:00
parent 8f6cbe1502
commit da5b701aee
15 changed files with 27 additions and 202 deletions

View File

@ -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}

View File

@ -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)

View File

@ -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.

View File

@ -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]

View File

@ -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)

View File

@ -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):

View File

@ -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):

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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):

View File

@ -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,

View File

@ -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

View File

@ -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);