summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorNick Coghlan <ncoghlan@gmail.com>2006-04-25 10:56:51 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2006-04-25 10:56:51 (GMT)
commita7e820a408fa3df02f8d42a183e06774e05cd871 (patch)
treee6b219df2083f695df8917045c785dc6acac6584 /Lib
parent327ea38cc4dc4b7dde621f78e57401fd97ef48cc (diff)
downloadcpython-a7e820a408fa3df02f8d42a183e06774e05cd871.zip
cpython-a7e820a408fa3df02f8d42a183e06774e05cd871.tar.gz
cpython-a7e820a408fa3df02f8d42a183e06774e05cd871.tar.bz2
Move the PEP 343 documentation and implementation closer to the
terminology in the alpha 1 documentation. - "context manager" reverts to its alpha 1 definition - the term "context specifier" goes away entirely - contextlib.GeneratorContextManager is renamed GeneratorContext There are still a number of changes relative to alpha 1: - the expression in the with statement is explicitly called the "context expression" in the language reference - the terms 'with statement context', 'context object' or 'with statement context' are used in several places instead of a bare 'context'. The aim of this is to avoid ambiguity in relation to the runtime context set up when the block is executed, and the context objects that already exist in various application domains (such as decimal.Context) - contextlib.contextmanager is renamed to contextfactory This best reflects the nature of the function resulting from the use of that decorator - decimal.ContextManager is renamed to WithStatementContext Simple dropping the 'Manager' part wasn't possible due to the fact that decimal.Context already exists and means something different. WithStatementContext is ugly but workable. A technically unrelated change snuck into this commit: contextlib.closing now avoids the overhead of creating a generator, since it's trivial to implement that particular context manager directly.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/contextlib.py31
-rw-r--r--Lib/decimal.py4
-rw-r--r--Lib/test/test_contextlib.py46
3 files changed, 42 insertions, 39 deletions
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 157b4cc..b2902a4 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -2,10 +2,10 @@
import sys
-__all__ = ["contextmanager", "nested", "closing"]
+__all__ = ["contextfactory", "nested", "closing"]
-class GeneratorContextManager(object):
- """Helper for @contextmanager decorator."""
+class GeneratorContext(object):
+ """Helper for @contextfactory decorator."""
def __init__(self, gen):
self.gen = gen
@@ -48,8 +48,8 @@ class GeneratorContextManager(object):
raise
-def contextmanager(func):
- """@contextmanager decorator.
+def contextfactory(func):
+ """@contextfactory decorator.
Typical usage:
@@ -77,7 +77,7 @@ def contextmanager(func):
"""
def helper(*args, **kwds):
- return GeneratorContextManager(func(*args, **kwds))
+ return GeneratorContext(func(*args, **kwds))
try:
helper.__name__ = func.__name__
helper.__doc__ = func.__doc__
@@ -87,7 +87,7 @@ def contextmanager(func):
return helper
-@contextmanager
+@contextfactory
def nested(*contexts):
"""Support multiple context managers in a single with-statement.
@@ -133,9 +133,8 @@ def nested(*contexts):
raise exc[0], exc[1], exc[2]
-@contextmanager
-def closing(thing):
- """Context manager to automatically close something at the end of a block.
+class closing(object):
+ """Context to automatically close something at the end of a block.
Code like this:
@@ -151,7 +150,11 @@ def closing(thing):
f.close()
"""
- try:
- yield thing
- finally:
- thing.close()
+ def __init__(self, thing):
+ self.thing = thing
+ def __context__(self):
+ return self
+ def __enter__(self):
+ return self.thing
+ def __exit__(self, *exc_info):
+ self.thing.close()
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 967f101..875e38a 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -2173,7 +2173,7 @@ for name in rounding_functions:
del name, val, globalname, rounding_functions
-class ContextManager(object):
+class WithStatementContext(object):
"""Helper class to simplify Context management.
Sample usage:
@@ -2249,7 +2249,7 @@ class Context(object):
return ', '.join(s) + ')'
def __context__(self):
- return ContextManager(self.copy())
+ return WithStatementContext(self.copy())
def clear_flags(self):
"""Reset all flags to zero"""
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index 1a70997..53f23b2 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -13,9 +13,9 @@ from test.test_support import run_suite
class ContextManagerTestCase(unittest.TestCase):
- def test_contextmanager_plain(self):
+ def test_contextfactory_plain(self):
state = []
- @contextmanager
+ @contextfactory
def woohoo():
state.append(1)
yield 42
@@ -26,9 +26,9 @@ class ContextManagerTestCase(unittest.TestCase):
state.append(x)
self.assertEqual(state, [1, 42, 999])
- def test_contextmanager_finally(self):
+ def test_contextfactory_finally(self):
state = []
- @contextmanager
+ @contextfactory
def woohoo():
state.append(1)
try:
@@ -47,8 +47,8 @@ class ContextManagerTestCase(unittest.TestCase):
self.fail("Expected ZeroDivisionError")
self.assertEqual(state, [1, 42, 999])
- def test_contextmanager_no_reraise(self):
- @contextmanager
+ def test_contextfactory_no_reraise(self):
+ @contextfactory
def whee():
yield
ctx = whee().__context__()
@@ -56,8 +56,8 @@ class ContextManagerTestCase(unittest.TestCase):
# Calling __exit__ should not result in an exception
self.failIf(ctx.__exit__(TypeError, TypeError("foo"), None))
- def test_contextmanager_trap_yield_after_throw(self):
- @contextmanager
+ def test_contextfactory_trap_yield_after_throw(self):
+ @contextfactory
def whoo():
try:
yield
@@ -69,9 +69,9 @@ class ContextManagerTestCase(unittest.TestCase):
RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
)
- def test_contextmanager_except(self):
+ def test_contextfactory_except(self):
state = []
- @contextmanager
+ @contextfactory
def woohoo():
state.append(1)
try:
@@ -86,14 +86,14 @@ class ContextManagerTestCase(unittest.TestCase):
raise ZeroDivisionError(999)
self.assertEqual(state, [1, 42, 999])
- def test_contextmanager_attribs(self):
+ def test_contextfactory_attribs(self):
def attribs(**kw):
def decorate(func):
for k,v in kw.items():
setattr(func,k,v)
return func
return decorate
- @contextmanager
+ @contextfactory
@attribs(foo='bar')
def baz(spam):
"""Whee!"""
@@ -106,13 +106,13 @@ class NestedTestCase(unittest.TestCase):
# XXX This needs more work
def test_nested(self):
- @contextmanager
+ @contextfactory
def a():
yield 1
- @contextmanager
+ @contextfactory
def b():
yield 2
- @contextmanager
+ @contextfactory
def c():
yield 3
with nested(a(), b(), c()) as (x, y, z):
@@ -122,14 +122,14 @@ class NestedTestCase(unittest.TestCase):
def test_nested_cleanup(self):
state = []
- @contextmanager
+ @contextfactory
def a():
state.append(1)
try:
yield 2
finally:
state.append(3)
- @contextmanager
+ @contextfactory
def b():
state.append(4)
try:
@@ -148,7 +148,7 @@ class NestedTestCase(unittest.TestCase):
def test_nested_right_exception(self):
state = []
- @contextmanager
+ @contextfactory
def a():
yield 1
class b(object):
@@ -172,10 +172,10 @@ class NestedTestCase(unittest.TestCase):
self.fail("Didn't raise ZeroDivisionError")
def test_nested_b_swallows(self):
- @contextmanager
+ @contextfactory
def a():
yield
- @contextmanager
+ @contextfactory
def b():
try:
yield
@@ -189,7 +189,7 @@ class NestedTestCase(unittest.TestCase):
self.fail("Didn't swallow ZeroDivisionError")
def test_nested_break(self):
- @contextmanager
+ @contextfactory
def a():
yield
state = 0
@@ -201,7 +201,7 @@ class NestedTestCase(unittest.TestCase):
self.assertEqual(state, 1)
def test_nested_continue(self):
- @contextmanager
+ @contextfactory
def a():
yield
state = 0
@@ -213,7 +213,7 @@ class NestedTestCase(unittest.TestCase):
self.assertEqual(state, 3)
def test_nested_return(self):
- @contextmanager
+ @contextfactory
def a():
try:
yield