Commit da5b701a authored by Guido van Rossum's avatar Guido van Rossum

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.
parent 8f6cbe15
...@@ -54,34 +54,6 @@ action (rather than to suppress it entirely), the generator must ...@@ -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: ...@@ -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, ...@@ -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. ...@@ -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.} ...@@ -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: ...@@ -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: ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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(): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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 ...@@ -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, ...@@ -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[] = { ...@@ -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, ...@@ -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[] = { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
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