blob: 301564bfc062666d5c8805306cf583df13c9e4e6 [file] [log] [blame]
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00001"""Unit tests for contextlib.py, and other context managers."""
2
R. David Murrayf28fd242010-02-23 00:24:49 +00003import sys
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00004import tempfile
5import unittest
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00006from contextlib import * # Tests __all__
Collin Winterc2898c52007-04-25 17:29:52 +00007from test import test_support
Victor Stinner6a102812010-04-27 23:55:59 +00008try:
9 import threading
10except ImportError:
11 threading = None
Florent Xicluna6257a7b2010-03-31 22:01:03 +000012
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000013
14class ContextManagerTestCase(unittest.TestCase):
15
Nick Coghlanafd5e632006-05-03 13:02:47 +000016 def test_contextmanager_plain(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000017 state = []
Nick Coghlanafd5e632006-05-03 13:02:47 +000018 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000019 def woohoo():
20 state.append(1)
21 yield 42
22 state.append(999)
23 with woohoo() as x:
24 self.assertEqual(state, [1])
25 self.assertEqual(x, 42)
26 state.append(x)
27 self.assertEqual(state, [1, 42, 999])
28
Nick Coghlanafd5e632006-05-03 13:02:47 +000029 def test_contextmanager_finally(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000030 state = []
Nick Coghlanafd5e632006-05-03 13:02:47 +000031 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000032 def woohoo():
33 state.append(1)
34 try:
35 yield 42
36 finally:
37 state.append(999)
Florent Xicluna6257a7b2010-03-31 22:01:03 +000038 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000039 with woohoo() as x:
40 self.assertEqual(state, [1])
41 self.assertEqual(x, 42)
42 state.append(x)
43 raise ZeroDivisionError()
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000044 self.assertEqual(state, [1, 42, 999])
45
Nick Coghlanafd5e632006-05-03 13:02:47 +000046 def test_contextmanager_no_reraise(self):
47 @contextmanager
Phillip J. Eby6edd2582006-03-25 00:28:24 +000048 def whee():
49 yield
Guido van Rossumda5b7012006-05-02 19:47:52 +000050 ctx = whee()
Phillip J. Eby6edd2582006-03-25 00:28:24 +000051 ctx.__enter__()
52 # Calling __exit__ should not result in an exception
Benjamin Peterson5c8da862009-06-30 22:57:08 +000053 self.assertFalse(ctx.__exit__(TypeError, TypeError("foo"), None))
Phillip J. Eby6edd2582006-03-25 00:28:24 +000054
Nick Coghlanafd5e632006-05-03 13:02:47 +000055 def test_contextmanager_trap_yield_after_throw(self):
56 @contextmanager
Phillip J. Eby6edd2582006-03-25 00:28:24 +000057 def whoo():
58 try:
59 yield
60 except:
61 yield
Guido van Rossumda5b7012006-05-02 19:47:52 +000062 ctx = whoo()
Phillip J. Eby6edd2582006-03-25 00:28:24 +000063 ctx.__enter__()
64 self.assertRaises(
65 RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
66 )
67
Nick Coghlanafd5e632006-05-03 13:02:47 +000068 def test_contextmanager_except(self):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000069 state = []
Nick Coghlanafd5e632006-05-03 13:02:47 +000070 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000071 def woohoo():
72 state.append(1)
73 try:
74 yield 42
75 except ZeroDivisionError, e:
76 state.append(e.args[0])
77 self.assertEqual(state, [1, 42, 999])
78 with woohoo() as x:
79 self.assertEqual(state, [1])
80 self.assertEqual(x, 42)
81 state.append(x)
82 raise ZeroDivisionError(999)
83 self.assertEqual(state, [1, 42, 999])
84
R. David Murrayf28fd242010-02-23 00:24:49 +000085 def _create_contextmanager_attribs(self):
Phillip J. Eby35fd1422006-03-28 00:07:24 +000086 def attribs(**kw):
87 def decorate(func):
88 for k,v in kw.items():
89 setattr(func,k,v)
90 return func
91 return decorate
Nick Coghlanafd5e632006-05-03 13:02:47 +000092 @contextmanager
Phillip J. Eby35fd1422006-03-28 00:07:24 +000093 @attribs(foo='bar')
94 def baz(spam):
95 """Whee!"""
R. David Murrayf28fd242010-02-23 00:24:49 +000096 return baz
97
98 def test_contextmanager_attribs(self):
99 baz = self._create_contextmanager_attribs()
Phillip J. Eby35fd1422006-03-28 00:07:24 +0000100 self.assertEqual(baz.__name__,'baz')
101 self.assertEqual(baz.foo, 'bar')
R. David Murrayf28fd242010-02-23 00:24:49 +0000102
103 @unittest.skipIf(sys.flags.optimize >= 2,
104 "Docstrings are omitted with -O2 and above")
105 def test_contextmanager_doc_attrib(self):
106 baz = self._create_contextmanager_attribs()
Phillip J. Eby35fd1422006-03-28 00:07:24 +0000107 self.assertEqual(baz.__doc__, "Whee!")
108
Serhiy Storchakad1d4d8a2015-06-28 17:11:51 +0300109 def test_keywords(self):
110 # Ensure no keyword arguments are inhibited
111 @contextmanager
112 def woohoo(self, func, args, kwds):
113 yield (self, func, args, kwds)
114 with woohoo(self=11, func=22, args=33, kwds=44) as target:
115 self.assertEqual(target, (11, 22, 33, 44))
116
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000117class NestedTestCase(unittest.TestCase):
118
119 # XXX This needs more work
120
121 def test_nested(self):
Nick Coghlanafd5e632006-05-03 13:02:47 +0000122 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000123 def a():
124 yield 1
Nick Coghlanafd5e632006-05-03 13:02:47 +0000125 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000126 def b():
127 yield 2
Nick Coghlanafd5e632006-05-03 13:02:47 +0000128 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000129 def c():
130 yield 3
131 with nested(a(), b(), c()) as (x, y, z):
132 self.assertEqual(x, 1)
133 self.assertEqual(y, 2)
134 self.assertEqual(z, 3)
135
136 def test_nested_cleanup(self):
137 state = []
Nick Coghlanafd5e632006-05-03 13:02:47 +0000138 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000139 def a():
140 state.append(1)
141 try:
142 yield 2
143 finally:
144 state.append(3)
Nick Coghlanafd5e632006-05-03 13:02:47 +0000145 @contextmanager
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000146 def b():
147 state.append(4)
148 try:
149 yield 5
150 finally:
151 state.append(6)
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000152 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000153 with nested(a(), b()) as (x, y):
154 state.append(x)
155 state.append(y)
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000156 1 // 0
157 self.assertEqual(state, [1, 4, 2, 5, 6, 3])
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000158
Nick Coghlanda2268f2006-04-24 04:37:15 +0000159 def test_nested_right_exception(self):
Nick Coghlanafd5e632006-05-03 13:02:47 +0000160 @contextmanager
Nick Coghlanda2268f2006-04-24 04:37:15 +0000161 def a():
162 yield 1
163 class b(object):
164 def __enter__(self):
165 return 2
166 def __exit__(self, *exc_info):
167 try:
168 raise Exception()
169 except:
170 pass
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000171 with self.assertRaises(ZeroDivisionError):
Nick Coghlanda2268f2006-04-24 04:37:15 +0000172 with nested(a(), b()) as (x, y):
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000173 1 // 0
174 self.assertEqual((x, y), (1, 2))
Nick Coghlanda2268f2006-04-24 04:37:15 +0000175
Guido van Rossuma9f06872006-03-01 17:10:01 +0000176 def test_nested_b_swallows(self):
Nick Coghlanafd5e632006-05-03 13:02:47 +0000177 @contextmanager
Guido van Rossuma9f06872006-03-01 17:10:01 +0000178 def a():
179 yield
Nick Coghlanafd5e632006-05-03 13:02:47 +0000180 @contextmanager
Guido van Rossuma9f06872006-03-01 17:10:01 +0000181 def b():
182 try:
183 yield
184 except:
185 # Swallow the exception
186 pass
187 try:
188 with nested(a(), b()):
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000189 1 // 0
Guido van Rossuma9f06872006-03-01 17:10:01 +0000190 except ZeroDivisionError:
191 self.fail("Didn't swallow ZeroDivisionError")
192
193 def test_nested_break(self):
Nick Coghlanafd5e632006-05-03 13:02:47 +0000194 @contextmanager
Guido van Rossuma9f06872006-03-01 17:10:01 +0000195 def a():
196 yield
197 state = 0
198 while True:
199 state += 1
200 with nested(a(), a()):
201 break
202 state += 10
203 self.assertEqual(state, 1)
204
205 def test_nested_continue(self):
Nick Coghlanafd5e632006-05-03 13:02:47 +0000206 @contextmanager
Guido van Rossuma9f06872006-03-01 17:10:01 +0000207 def a():
208 yield
209 state = 0
210 while state < 3:
211 state += 1
212 with nested(a(), a()):
213 continue
214 state += 10
215 self.assertEqual(state, 3)
216
217 def test_nested_return(self):
Nick Coghlanafd5e632006-05-03 13:02:47 +0000218 @contextmanager
Guido van Rossuma9f06872006-03-01 17:10:01 +0000219 def a():
220 try:
221 yield
222 except:
223 pass
224 def foo():
225 with nested(a(), a()):
226 return 1
227 return 10
228 self.assertEqual(foo(), 1)
229
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000230class ClosingTestCase(unittest.TestCase):
231
232 # XXX This needs more work
233
234 def test_closing(self):
235 state = []
236 class C:
237 def close(self):
238 state.append(1)
239 x = C()
240 self.assertEqual(state, [])
241 with closing(x) as y:
242 self.assertEqual(x, y)
243 self.assertEqual(state, [1])
244
245 def test_closing_error(self):
246 state = []
247 class C:
248 def close(self):
249 state.append(1)
250 x = C()
251 self.assertEqual(state, [])
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000252 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000253 with closing(x) as y:
254 self.assertEqual(x, y)
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000255 1 // 0
256 self.assertEqual(state, [1])
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000257
258class FileContextTestCase(unittest.TestCase):
259
260 def testWithOpen(self):
261 tfn = tempfile.mktemp()
262 try:
263 f = None
264 with open(tfn, "w") as f:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000265 self.assertFalse(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000266 f.write("Booh\n")
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000267 self.assertTrue(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000268 f = None
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000269 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000270 with open(tfn, "r") as f:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000271 self.assertFalse(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000272 self.assertEqual(f.read(), "Booh\n")
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000273 1 // 0
274 self.assertTrue(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000275 finally:
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000276 test_support.unlink(tfn)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000277
Victor Stinner6a102812010-04-27 23:55:59 +0000278@unittest.skipUnless(threading, 'Threading required for this test.')
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000279class LockContextTestCase(unittest.TestCase):
280
281 def boilerPlate(self, lock, locked):
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000282 self.assertFalse(locked())
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000283 with lock:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000284 self.assertTrue(locked())
285 self.assertFalse(locked())
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000286 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000287 with lock:
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000288 self.assertTrue(locked())
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000289 1 // 0
290 self.assertFalse(locked())
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000291
292 def testWithLock(self):
293 lock = threading.Lock()
294 self.boilerPlate(lock, lock.locked)
295
296 def testWithRLock(self):
297 lock = threading.RLock()
298 self.boilerPlate(lock, lock._is_owned)
299
300 def testWithCondition(self):
301 lock = threading.Condition()
302 def locked():
303 return lock._is_owned()
304 self.boilerPlate(lock, locked)
305
306 def testWithSemaphore(self):
307 lock = threading.Semaphore()
308 def locked():
309 if lock.acquire(False):
310 lock.release()
311 return False
312 else:
313 return True
314 self.boilerPlate(lock, locked)
315
316 def testWithBoundedSemaphore(self):
317 lock = threading.BoundedSemaphore()
318 def locked():
319 if lock.acquire(False):
320 lock.release()
321 return False
322 else:
323 return True
324 self.boilerPlate(lock, locked)
325
Phillip J. Ebybd0c10f2006-04-10 18:33:17 +0000326# This is needed to make the test actually run under regrtest.py!
327def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +0000328 with test_support.check_warnings(("With-statements now directly support "
329 "multiple context managers",
330 DeprecationWarning)):
Raymond Hettinger822b87f2009-05-29 01:46:48 +0000331 test_support.run_unittest(__name__)
Phillip J. Ebybd0c10f2006-04-10 18:33:17 +0000332
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000333if __name__ == "__main__":
Phillip J. Ebybd0c10f2006-04-10 18:33:17 +0000334 test_main()