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.
diff --git a/Doc/lib/libcontextlib.tex b/Doc/lib/libcontextlib.tex
index 9ff8524..6c80a71 100644
--- a/Doc/lib/libcontextlib.tex
+++ b/Doc/lib/libcontextlib.tex
@@ -54,34 +54,6 @@
reraise that exception. Otherwise the \keyword{with} statement will
treat the exception as having been handled, and resume execution with
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}
\begin{funcdesc}{nested}{ctx1\optional{, ctx2\optional{, ...}}}
@@ -147,25 +119,6 @@
without needing to explicitly close \code{page}. Even if an error
occurs, \code{page.close()} will be called when the \keyword{with}
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}
\begin{seealso}
diff --git a/Doc/ref/ref3.tex b/Doc/ref/ref3.tex
index d22448c..ba0594f 100644
--- a/Doc/ref/ref3.tex
+++ b/Doc/ref/ref3.tex
@@ -2138,22 +2138,6 @@
see ``\ulink{Context Types}{../lib/typecontext.html}'' in the
\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}
Enter the runtime context related to this object. The \keyword{with}
statement will bind this method's return value to the target(s)
diff --git a/Doc/ref/ref7.tex b/Doc/ref/ref7.tex
index 4453e87..4a23133 100644
--- a/Doc/ref/ref7.tex
+++ b/Doc/ref/ref7.tex
@@ -322,21 +322,18 @@
\begin{productionlist}
\production{with_stmt}
- {"with" \token{expression} ["as" target_list] ":" \token{suite}}
+ {"with" \token{expression} ["as" target] ":" \token{suite}}
\end{productionlist}
The execution of the \keyword{with} statement proceeds as follows:
\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
-invoked to obtain a \keyword{with} statement context object.
+\item The context manager's \method{__enter__()} method is invoked.
-\item The context object's \method{__enter__()} method is invoked.
-
-\item If a target list was included in the \keyword{with}
+\item If a target was included in the \keyword{with}
statement, the return value from \method{__enter__()} is assigned to it.
\note{The \keyword{with} statement guarantees that if the
@@ -347,7 +344,7 @@
\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
traceback are passed as arguments to \method{__exit__()}. Otherwise,
three \constant{None} arguments are supplied.
diff --git a/Lib/calendar.py b/Lib/calendar.py
index 7800aae..00948ef 100644
--- a/Lib/calendar.py
+++ b/Lib/calendar.py
@@ -484,9 +484,6 @@
def __init__(self, locale):
self.locale = locale
- def __context__(self):
- return self
-
def __enter__(self):
self.oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
return locale.getlocale(locale.LC_TIME)[1]
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py
index f25b3fb..d5d68aa 100644
--- a/Lib/compiler/pycodegen.py
+++ b/Lib/compiler/pycodegen.py
@@ -833,8 +833,6 @@
self.__with_count += 1
self.set_lineno(node)
self.visit(node.expr)
- self.emit('LOAD_ATTR', '__context__')
- self.emit('CALL_FUNCTION', 0)
self.emit('DUP_TOP')
self.emit('LOAD_ATTR', '__exit__')
self._implicitNameOp('STORE', exitvar)
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 4e3b9c2..9d2c6a3 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -10,9 +10,6 @@
def __init__(self, gen):
self.gen = gen
- def __context__(self):
- return self
-
def __enter__(self):
try:
return self.gen.next()
@@ -88,7 +85,7 @@
@contextfactory
-def nested(*contexts):
+def nested(*managers):
"""Support multiple context managers in a single with-statement.
Code like this:
@@ -109,8 +106,7 @@
exc = (None, None, None)
try:
try:
- for context in contexts:
- mgr = context.__context__()
+ for mgr in managers:
exit = mgr.__exit__
enter = mgr.__enter__
vars.append(enter())
@@ -152,8 +148,6 @@
"""
def __init__(self, thing):
self.thing = thing
- def __context__(self):
- return self
def __enter__(self):
return self.thing
def __exit__(self, *exc_info):
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 875e38a..2f989a8 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -2248,7 +2248,7 @@
s.append('traps=[' + ', '.join([t.__name__ for t, v in self.traps.items() if v]) + ']')
return ', '.join(s) + ')'
- def __context__(self):
+ def context_manager(self):
return WithStatementContext(self.copy())
def clear_flags(self):
diff --git a/Lib/dummy_thread.py b/Lib/dummy_thread.py
index d69d840..21fd03f 100644
--- a/Lib/dummy_thread.py
+++ b/Lib/dummy_thread.py
@@ -118,9 +118,6 @@
def __exit__(self, typ, val, tb):
self.release()
- def __context__(self):
- return self
-
def release(self):
"""Release the dummy lock."""
# XXX Perhaps shouldn't actually bother to test? Could lead
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index 53f23b2..8d3dd1a 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -51,7 +51,7 @@
@contextfactory
def whee():
yield
- ctx = whee().__context__()
+ ctx = whee()
ctx.__enter__()
# Calling __exit__ should not result in an exception
self.failIf(ctx.__exit__(TypeError, TypeError("foo"), None))
@@ -63,7 +63,7 @@
yield
except:
yield
- ctx = whoo().__context__()
+ ctx = whoo()
ctx.__enter__()
self.assertRaises(
RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
@@ -152,8 +152,6 @@
def a():
yield 1
class b(object):
- def __context__(self):
- return self
def __enter__(self):
return 2
def __exit__(self, *exc_info):
@@ -341,12 +339,12 @@
orig_context = ctx.copy()
try:
ctx.prec = save_prec = decimal.ExtendedContext.prec + 5
- with decimal.ExtendedContext:
+ with decimal.ExtendedContext.context_manager():
self.assertEqual(decimal.getcontext().prec,
decimal.ExtendedContext.prec)
self.assertEqual(decimal.getcontext().prec, save_prec)
try:
- with decimal.ExtendedContext:
+ with decimal.ExtendedContext.context_manager():
self.assertEqual(decimal.getcontext().prec,
decimal.ExtendedContext.prec)
1/0
diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py
index 7adb05e..765bfec 100644
--- a/Lib/test/test_with.py
+++ b/Lib/test/test_with.py
@@ -17,15 +17,10 @@
class MockContextManager(GeneratorContext):
def __init__(self, gen):
GeneratorContext.__init__(self, gen)
- self.context_called = False
self.enter_called = False
self.exit_called = False
self.exit_args = None
- def __context__(self):
- self.context_called = True
- return GeneratorContext.__context__(self)
-
def __enter__(self):
self.enter_called = True
return GeneratorContext.__enter__(self)
@@ -60,21 +55,17 @@
class Nested(object):
- def __init__(self, *contexts):
- self.contexts = contexts
+ def __init__(self, *managers):
+ self.managers = managers
self.entered = None
- def __context__(self):
- return self
-
def __enter__(self):
if self.entered is not None:
raise RuntimeError("Context is not reentrant")
self.entered = deque()
vars = []
try:
- for context in self.contexts:
- mgr = context.__context__()
+ for mgr in self.managers:
vars.append(mgr.__enter__())
self.entered.appendleft(mgr)
except:
@@ -99,17 +90,12 @@
class MockNested(Nested):
- def __init__(self, *contexts):
- Nested.__init__(self, *contexts)
- self.context_called = False
+ def __init__(self, *managers):
+ Nested.__init__(self, *managers)
self.enter_called = False
self.exit_called = False
self.exit_args = None
- def __context__(self):
- self.context_called = True
- return Nested.__context__(self)
-
def __enter__(self):
self.enter_called = True
return Nested.__enter__(self)
@@ -126,24 +112,8 @@
with foo: pass
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):
class LacksEnter(object):
- def __context__(self):
- pass
-
def __exit__(self, type, value, traceback):
pass
@@ -154,9 +124,6 @@
def testExitAttributeError(self):
class LacksExit(object):
- def __context__(self):
- pass
-
def __enter__(self):
pass
@@ -192,27 +159,10 @@
'with mock as (foo, None, bar):\n'
' 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):
class EnterThrows(object):
- def __context__(self):
- return self
-
def __enter__(self):
- raise RuntimeError("Context threw")
-
+ raise RuntimeError("Enter threw")
def __exit__(self, *args):
pass
@@ -226,8 +176,6 @@
def testExitThrows(self):
class ExitThrows(object):
- def __context__(self):
- return self
def __enter__(self):
return
def __exit__(self, *args):
@@ -241,13 +189,11 @@
TEST_EXCEPTION = RuntimeError("test exception")
def assertInWithManagerInvariants(self, mock_manager):
- self.assertTrue(mock_manager.context_called)
self.assertTrue(mock_manager.enter_called)
self.assertFalse(mock_manager.exit_called)
self.assertEqual(mock_manager.exit_args, None)
def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
- self.assertTrue(mock_manager.context_called)
self.assertTrue(mock_manager.enter_called)
self.assertTrue(mock_manager.exit_called)
self.assertEqual(mock_manager.exit_args, exit_args)
@@ -268,7 +214,6 @@
raise self.TEST_EXCEPTION
def assertAfterWithManagerInvariantsWithError(self, mock_manager):
- self.assertTrue(mock_manager.context_called)
self.assertTrue(mock_manager.enter_called)
self.assertTrue(mock_manager.exit_called)
self.assertEqual(mock_manager.exit_args[0], RuntimeError)
@@ -472,7 +417,6 @@
# The inner statement stuff should never have been touched
self.assertEqual(self.bar, None)
- self.assertFalse(mock_b.context_called)
self.assertFalse(mock_b.enter_called)
self.assertFalse(mock_b.exit_called)
self.assertEqual(mock_b.exit_args, None)
@@ -506,13 +450,9 @@
self.assertRaises(StopIteration, shouldThrow)
def testRaisedStopIteration2(self):
- class cm (object):
- def __context__(self):
- return self
-
+ class cm(object):
def __enter__(self):
pass
-
def __exit__(self, type, value, traceback):
pass
@@ -535,12 +475,8 @@
def testRaisedGeneratorExit2(self):
class cm (object):
- def __context__(self):
- return self
-
def __enter__(self):
pass
-
def __exit__(self, type, value, traceback):
pass
@@ -629,7 +565,6 @@
def testMultipleComplexTargets(self):
class C:
- def __context__(self): return self
def __enter__(self): return 1, 2, 3
def __exit__(self, t, v, tb): pass
targets = {1: [0, 1, 2]}
@@ -651,7 +586,6 @@
def testExitTrueSwallowsException(self):
class AfricanSwallow:
- def __context__(self): return self
def __enter__(self): pass
def __exit__(self, t, v, tb): return True
try:
@@ -662,7 +596,6 @@
def testExitFalseDoesntSwallowException(self):
class EuropeanSwallow:
- def __context__(self): return self
def __enter__(self): pass
def __exit__(self, t, v, tb): return False
try:
diff --git a/Lib/threading.py b/Lib/threading.py
index 27ec6b4..c27140d 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -90,9 +90,6 @@
self.__owner and self.__owner.getName(),
self.__count)
- def __context__(self):
- return self
-
def acquire(self, blocking=1):
me = currentThread()
if self.__owner is me:
@@ -182,8 +179,11 @@
pass
self.__waiters = []
- def __context__(self):
- return self.__lock.__context__()
+ def __enter__(self):
+ return self.__lock.__enter__()
+
+ def __exit__(self, *args):
+ return self.__lock.__exit__(*args)
def __repr__(self):
return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
@@ -278,9 +278,6 @@
self.__cond = Condition(Lock())
self.__value = value
- def __context__(self):
- return self
-
def acquire(self, blocking=1):
rc = False
self.__cond.acquire()
diff --git a/Misc/Vim/syntax_test.py b/Misc/Vim/syntax_test.py
index a530a25..ccc7f30 100644
--- a/Misc/Vim/syntax_test.py
+++ b/Misc/Vim/syntax_test.py
@@ -19,8 +19,6 @@
def foo(): # function definition
return []
class Bar(object): # Class definition
- def __context__(self):
- return self
def __enter__(self):
pass
def __exit__(self, *args):
diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c
index 83313df..9ac9881 100644
--- a/Modules/threadmodule.c
+++ b/Modules/threadmodule.c
@@ -98,13 +98,6 @@
\n\
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[] = {
{"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
METH_VARARGS, acquire_doc},
@@ -118,8 +111,6 @@
METH_NOARGS, locked_doc},
{"locked", (PyCFunction)lock_locked_lock,
METH_NOARGS, locked_doc},
- {"__context__", (PyCFunction)lock_context,
- METH_NOARGS, PyDoc_STR("__context__() -> self.")},
{"__enter__", (PyCFunction)lock_PyThread_acquire_lock,
METH_VARARGS, acquire_doc},
{"__exit__", (PyCFunction)lock_PyThread_release_lock,
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 25b3361..0f166cd 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -1706,9 +1706,6 @@
PyDoc_STRVAR(isatty_doc,
"isatty() -> true or false. True if the file is connected to a tty device.");
-PyDoc_STRVAR(context_doc,
- "__context__() -> self.");
-
PyDoc_STRVAR(enter_doc,
"__enter__() -> self.");
@@ -1729,7 +1726,6 @@
{"flush", (PyCFunction)file_flush, METH_NOARGS, flush_doc},
{"close", (PyCFunction)file_close, METH_NOARGS, close_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},
{"__exit__", (PyCFunction)file_close, METH_VARARGS, close_doc},
{NULL, NULL} /* sentinel */
@@ -2445,4 +2441,3 @@
#ifdef __cplusplus
}
#endif
-
diff --git a/Python/compile.c b/Python/compile.c
index 8b6f2f1..15e7e15 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -3371,7 +3371,7 @@
It is implemented roughly as:
- context = (EXPR).__context__()
+ context = EXPR
exit = context.__exit__ # not calling it
value = context.__enter__()
try:
@@ -3387,17 +3387,12 @@
static int
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;
identifier tmpexit, tmpvalue = NULL;
assert(s->kind == With_kind);
- if (!context_attr) {
- context_attr = PyString_InternFromString("__context__");
- if (!context_attr)
- return 0;
- }
if (!enter_attr) {
enter_attr = PyString_InternFromString("__enter__");
if (!enter_attr)
@@ -3436,10 +3431,8 @@
PyArena_AddPyObject(c->c_arena, tmpvalue);
}
- /* Evaluate (EXPR).__context__() */
+ /* Evaluate 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__ */
ADDOP(c, DUP_TOP);