blob: 48f8fa96379c542b07974bcc75af7fc4e72e32f8 [file] [log] [blame]
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00001"""Unit tests for contextlib.py, and other context managers."""
2
Raymond Hettinger088cbf22013-10-10 00:46:57 -07003import io
R. David Murray378c0cf2010-02-24 01:46:21 +00004import sys
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00005import tempfile
6import unittest
Guido van Rossum1a5e21e2006-02-28 21:57:43 +00007from contextlib import * # Tests __all__
Benjamin Petersonee8712c2008-05-20 21:35:26 +00008from test import support
Victor Stinner45df8202010-04-28 22:31:17 +00009try:
10 import threading
11except ImportError:
12 threading = None
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000013
Florent Xicluna41fe6152010-04-02 18:52:12 +000014
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000015class ContextManagerTestCase(unittest.TestCase):
16
17 def test_contextmanager_plain(self):
18 state = []
19 @contextmanager
20 def woohoo():
21 state.append(1)
22 yield 42
23 state.append(999)
24 with woohoo() as x:
25 self.assertEqual(state, [1])
26 self.assertEqual(x, 42)
27 state.append(x)
28 self.assertEqual(state, [1, 42, 999])
29
30 def test_contextmanager_finally(self):
31 state = []
32 @contextmanager
33 def woohoo():
34 state.append(1)
35 try:
36 yield 42
37 finally:
38 state.append(999)
Florent Xicluna41fe6152010-04-02 18:52:12 +000039 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000040 with woohoo() as x:
41 self.assertEqual(state, [1])
42 self.assertEqual(x, 42)
43 state.append(x)
44 raise ZeroDivisionError()
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000045 self.assertEqual(state, [1, 42, 999])
46
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000047 def test_contextmanager_no_reraise(self):
48 @contextmanager
49 def whee():
50 yield
Thomas Wouters477c8d52006-05-27 19:21:47 +000051 ctx = whee()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000052 ctx.__enter__()
53 # Calling __exit__ should not result in an exception
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000054 self.assertFalse(ctx.__exit__(TypeError, TypeError("foo"), None))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000055
56 def test_contextmanager_trap_yield_after_throw(self):
57 @contextmanager
58 def whoo():
59 try:
60 yield
61 except:
62 yield
Thomas Wouters477c8d52006-05-27 19:21:47 +000063 ctx = whoo()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000064 ctx.__enter__()
65 self.assertRaises(
66 RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
67 )
68
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000069 def test_contextmanager_except(self):
70 state = []
71 @contextmanager
72 def woohoo():
73 state.append(1)
74 try:
75 yield 42
Guido van Rossumb940e112007-01-10 16:19:56 +000076 except ZeroDivisionError as e:
Guido van Rossum1a5e21e2006-02-28 21:57:43 +000077 state.append(e.args[0])
78 self.assertEqual(state, [1, 42, 999])
79 with woohoo() as x:
80 self.assertEqual(state, [1])
81 self.assertEqual(x, 42)
82 state.append(x)
83 raise ZeroDivisionError(999)
84 self.assertEqual(state, [1, 42, 999])
85
R. David Murray378c0cf2010-02-24 01:46:21 +000086 def _create_contextmanager_attribs(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000087 def attribs(**kw):
88 def decorate(func):
89 for k,v in kw.items():
90 setattr(func,k,v)
91 return func
92 return decorate
93 @contextmanager
94 @attribs(foo='bar')
95 def baz(spam):
96 """Whee!"""
R. David Murray378c0cf2010-02-24 01:46:21 +000097 return baz
98
99 def test_contextmanager_attribs(self):
100 baz = self._create_contextmanager_attribs()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000101 self.assertEqual(baz.__name__,'baz')
102 self.assertEqual(baz.foo, 'bar')
R. David Murray378c0cf2010-02-24 01:46:21 +0000103
104 @unittest.skipIf(sys.flags.optimize >= 2,
105 "Docstrings are omitted with -O2 and above")
106 def test_contextmanager_doc_attrib(self):
107 baz = self._create_contextmanager_attribs()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000108 self.assertEqual(baz.__doc__, "Whee!")
109
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000110class ClosingTestCase(unittest.TestCase):
111
112 # XXX This needs more work
113
114 def test_closing(self):
115 state = []
116 class C:
117 def close(self):
118 state.append(1)
119 x = C()
120 self.assertEqual(state, [])
121 with closing(x) as y:
122 self.assertEqual(x, y)
123 self.assertEqual(state, [1])
124
125 def test_closing_error(self):
126 state = []
127 class C:
128 def close(self):
129 state.append(1)
130 x = C()
131 self.assertEqual(state, [])
Florent Xicluna41fe6152010-04-02 18:52:12 +0000132 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000133 with closing(x) as y:
134 self.assertEqual(x, y)
Florent Xicluna41fe6152010-04-02 18:52:12 +0000135 1 / 0
136 self.assertEqual(state, [1])
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000137
138class FileContextTestCase(unittest.TestCase):
139
140 def testWithOpen(self):
141 tfn = tempfile.mktemp()
142 try:
143 f = None
144 with open(tfn, "w") as f:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000145 self.assertFalse(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000146 f.write("Booh\n")
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000147 self.assertTrue(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000148 f = None
Florent Xicluna41fe6152010-04-02 18:52:12 +0000149 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000150 with open(tfn, "r") as f:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000151 self.assertFalse(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000152 self.assertEqual(f.read(), "Booh\n")
Florent Xicluna41fe6152010-04-02 18:52:12 +0000153 1 / 0
154 self.assertTrue(f.closed)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000155 finally:
Florent Xicluna41fe6152010-04-02 18:52:12 +0000156 support.unlink(tfn)
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000157
Victor Stinner45df8202010-04-28 22:31:17 +0000158@unittest.skipUnless(threading, 'Threading required for this test.')
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000159class LockContextTestCase(unittest.TestCase):
160
161 def boilerPlate(self, lock, locked):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000162 self.assertFalse(locked())
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000163 with lock:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000164 self.assertTrue(locked())
165 self.assertFalse(locked())
Florent Xicluna41fe6152010-04-02 18:52:12 +0000166 with self.assertRaises(ZeroDivisionError):
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000167 with lock:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000168 self.assertTrue(locked())
Florent Xicluna41fe6152010-04-02 18:52:12 +0000169 1 / 0
170 self.assertFalse(locked())
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000171
172 def testWithLock(self):
173 lock = threading.Lock()
174 self.boilerPlate(lock, lock.locked)
175
176 def testWithRLock(self):
177 lock = threading.RLock()
178 self.boilerPlate(lock, lock._is_owned)
179
180 def testWithCondition(self):
181 lock = threading.Condition()
182 def locked():
183 return lock._is_owned()
184 self.boilerPlate(lock, locked)
185
186 def testWithSemaphore(self):
187 lock = threading.Semaphore()
188 def locked():
189 if lock.acquire(False):
190 lock.release()
191 return False
192 else:
193 return True
194 self.boilerPlate(lock, locked)
195
196 def testWithBoundedSemaphore(self):
197 lock = threading.BoundedSemaphore()
198 def locked():
199 if lock.acquire(False):
200 lock.release()
201 return False
202 else:
203 return True
204 self.boilerPlate(lock, locked)
205
Michael Foordb3a89842010-06-30 12:17:50 +0000206
207class mycontext(ContextDecorator):
208 started = False
209 exc = None
210 catch = False
211
212 def __enter__(self):
213 self.started = True
214 return self
215
216 def __exit__(self, *exc):
217 self.exc = exc
218 return self.catch
219
220
221class TestContextDecorator(unittest.TestCase):
222
223 def test_contextdecorator(self):
224 context = mycontext()
225 with context as result:
226 self.assertIs(result, context)
227 self.assertTrue(context.started)
228
229 self.assertEqual(context.exc, (None, None, None))
230
231
232 def test_contextdecorator_with_exception(self):
233 context = mycontext()
234
Ezio Melottied3a7d22010-12-01 02:32:32 +0000235 with self.assertRaisesRegex(NameError, 'foo'):
Michael Foordb3a89842010-06-30 12:17:50 +0000236 with context:
237 raise NameError('foo')
238 self.assertIsNotNone(context.exc)
239 self.assertIs(context.exc[0], NameError)
240
241 context = mycontext()
242 context.catch = True
243 with context:
244 raise NameError('foo')
245 self.assertIsNotNone(context.exc)
246 self.assertIs(context.exc[0], NameError)
247
248
249 def test_decorator(self):
250 context = mycontext()
251
252 @context
253 def test():
254 self.assertIsNone(context.exc)
255 self.assertTrue(context.started)
256 test()
257 self.assertEqual(context.exc, (None, None, None))
258
259
260 def test_decorator_with_exception(self):
261 context = mycontext()
262
263 @context
264 def test():
265 self.assertIsNone(context.exc)
266 self.assertTrue(context.started)
267 raise NameError('foo')
268
Ezio Melottied3a7d22010-12-01 02:32:32 +0000269 with self.assertRaisesRegex(NameError, 'foo'):
Michael Foordb3a89842010-06-30 12:17:50 +0000270 test()
271 self.assertIsNotNone(context.exc)
272 self.assertIs(context.exc[0], NameError)
273
274
275 def test_decorating_method(self):
276 context = mycontext()
277
278 class Test(object):
279
280 @context
281 def method(self, a, b, c=None):
282 self.a = a
283 self.b = b
284 self.c = c
285
286 # these tests are for argument passing when used as a decorator
287 test = Test()
288 test.method(1, 2)
289 self.assertEqual(test.a, 1)
290 self.assertEqual(test.b, 2)
291 self.assertEqual(test.c, None)
292
293 test = Test()
294 test.method('a', 'b', 'c')
295 self.assertEqual(test.a, 'a')
296 self.assertEqual(test.b, 'b')
297 self.assertEqual(test.c, 'c')
298
299 test = Test()
300 test.method(a=1, b=2)
301 self.assertEqual(test.a, 1)
302 self.assertEqual(test.b, 2)
303
304
305 def test_typo_enter(self):
306 class mycontext(ContextDecorator):
307 def __unter__(self):
308 pass
309 def __exit__(self, *exc):
310 pass
311
312 with self.assertRaises(AttributeError):
313 with mycontext():
314 pass
315
316
317 def test_typo_exit(self):
318 class mycontext(ContextDecorator):
319 def __enter__(self):
320 pass
321 def __uxit__(self, *exc):
322 pass
323
324 with self.assertRaises(AttributeError):
325 with mycontext():
326 pass
327
328
329 def test_contextdecorator_as_mixin(self):
330 class somecontext(object):
331 started = False
332 exc = None
333
334 def __enter__(self):
335 self.started = True
336 return self
337
338 def __exit__(self, *exc):
339 self.exc = exc
340
341 class mycontext(somecontext, ContextDecorator):
342 pass
343
344 context = mycontext()
345 @context
346 def test():
347 self.assertIsNone(context.exc)
348 self.assertTrue(context.started)
349 test()
350 self.assertEqual(context.exc, (None, None, None))
351
352
353 def test_contextmanager_as_decorator(self):
Michael Foordb3a89842010-06-30 12:17:50 +0000354 @contextmanager
355 def woohoo(y):
356 state.append(y)
357 yield
358 state.append(999)
359
Nick Coghlan0ded3e32011-05-05 23:49:25 +1000360 state = []
Michael Foordb3a89842010-06-30 12:17:50 +0000361 @woohoo(1)
362 def test(x):
363 self.assertEqual(state, [1])
364 state.append(x)
365 test('something')
366 self.assertEqual(state, [1, 'something', 999])
367
Nick Coghlan0ded3e32011-05-05 23:49:25 +1000368 # Issue #11647: Ensure the decorated function is 'reusable'
369 state = []
370 test('something else')
371 self.assertEqual(state, [1, 'something else', 999])
372
Michael Foordb3a89842010-06-30 12:17:50 +0000373
Nick Coghlan3267a302012-05-21 22:54:43 +1000374class TestExitStack(unittest.TestCase):
375
376 def test_no_resources(self):
377 with ExitStack():
378 pass
379
380 def test_callback(self):
381 expected = [
382 ((), {}),
383 ((1,), {}),
384 ((1,2), {}),
385 ((), dict(example=1)),
386 ((1,), dict(example=1)),
387 ((1,2), dict(example=1)),
388 ]
389 result = []
390 def _exit(*args, **kwds):
391 """Test metadata propagation"""
392 result.append((args, kwds))
393 with ExitStack() as stack:
394 for args, kwds in reversed(expected):
395 if args and kwds:
396 f = stack.callback(_exit, *args, **kwds)
397 elif args:
398 f = stack.callback(_exit, *args)
399 elif kwds:
400 f = stack.callback(_exit, **kwds)
401 else:
402 f = stack.callback(_exit)
403 self.assertIs(f, _exit)
404 for wrapper in stack._exit_callbacks:
405 self.assertIs(wrapper.__wrapped__, _exit)
406 self.assertNotEqual(wrapper.__name__, _exit.__name__)
407 self.assertIsNone(wrapper.__doc__, _exit.__doc__)
408 self.assertEqual(result, expected)
409
410 def test_push(self):
411 exc_raised = ZeroDivisionError
412 def _expect_exc(exc_type, exc, exc_tb):
413 self.assertIs(exc_type, exc_raised)
414 def _suppress_exc(*exc_details):
415 return True
416 def _expect_ok(exc_type, exc, exc_tb):
417 self.assertIsNone(exc_type)
418 self.assertIsNone(exc)
419 self.assertIsNone(exc_tb)
420 class ExitCM(object):
421 def __init__(self, check_exc):
422 self.check_exc = check_exc
423 def __enter__(self):
424 self.fail("Should not be called!")
425 def __exit__(self, *exc_details):
426 self.check_exc(*exc_details)
427 with ExitStack() as stack:
428 stack.push(_expect_ok)
429 self.assertIs(stack._exit_callbacks[-1], _expect_ok)
430 cm = ExitCM(_expect_ok)
431 stack.push(cm)
432 self.assertIs(stack._exit_callbacks[-1].__self__, cm)
433 stack.push(_suppress_exc)
434 self.assertIs(stack._exit_callbacks[-1], _suppress_exc)
435 cm = ExitCM(_expect_exc)
436 stack.push(cm)
437 self.assertIs(stack._exit_callbacks[-1].__self__, cm)
438 stack.push(_expect_exc)
439 self.assertIs(stack._exit_callbacks[-1], _expect_exc)
440 stack.push(_expect_exc)
441 self.assertIs(stack._exit_callbacks[-1], _expect_exc)
442 1/0
443
444 def test_enter_context(self):
445 class TestCM(object):
446 def __enter__(self):
447 result.append(1)
448 def __exit__(self, *exc_details):
449 result.append(3)
450
451 result = []
452 cm = TestCM()
453 with ExitStack() as stack:
454 @stack.callback # Registered first => cleaned up last
455 def _exit():
456 result.append(4)
457 self.assertIsNotNone(_exit)
458 stack.enter_context(cm)
459 self.assertIs(stack._exit_callbacks[-1].__self__, cm)
460 result.append(2)
461 self.assertEqual(result, [1, 2, 3, 4])
462
463 def test_close(self):
464 result = []
465 with ExitStack() as stack:
466 @stack.callback
467 def _exit():
468 result.append(1)
469 self.assertIsNotNone(_exit)
470 stack.close()
471 result.append(2)
472 self.assertEqual(result, [1, 2])
473
474 def test_pop_all(self):
475 result = []
476 with ExitStack() as stack:
477 @stack.callback
478 def _exit():
479 result.append(3)
480 self.assertIsNotNone(_exit)
481 new_stack = stack.pop_all()
482 result.append(1)
483 result.append(2)
484 new_stack.close()
485 self.assertEqual(result, [1, 2, 3])
486
Nick Coghlanc73e8c22012-05-31 23:49:26 +1000487 def test_exit_raise(self):
488 with self.assertRaises(ZeroDivisionError):
489 with ExitStack() as stack:
490 stack.push(lambda *exc: False)
491 1/0
492
493 def test_exit_suppress(self):
494 with ExitStack() as stack:
495 stack.push(lambda *exc: True)
496 1/0
497
498 def test_exit_exception_chaining_reference(self):
499 # Sanity check to make sure that ExitStack chaining matches
500 # actual nested with statements
501 class RaiseExc:
502 def __init__(self, exc):
503 self.exc = exc
504 def __enter__(self):
505 return self
506 def __exit__(self, *exc_details):
507 raise self.exc
508
Nick Coghlan77452fc2012-06-01 22:48:32 +1000509 class RaiseExcWithContext:
510 def __init__(self, outer, inner):
511 self.outer = outer
512 self.inner = inner
513 def __enter__(self):
514 return self
515 def __exit__(self, *exc_details):
516 try:
517 raise self.inner
518 except:
519 raise self.outer
520
Nick Coghlanc73e8c22012-05-31 23:49:26 +1000521 class SuppressExc:
522 def __enter__(self):
523 return self
524 def __exit__(self, *exc_details):
525 type(self).saved_details = exc_details
526 return True
527
528 try:
529 with RaiseExc(IndexError):
Nick Coghlan77452fc2012-06-01 22:48:32 +1000530 with RaiseExcWithContext(KeyError, AttributeError):
531 with SuppressExc():
532 with RaiseExc(ValueError):
533 1 / 0
Nick Coghlanc73e8c22012-05-31 23:49:26 +1000534 except IndexError as exc:
535 self.assertIsInstance(exc.__context__, KeyError)
536 self.assertIsInstance(exc.__context__.__context__, AttributeError)
537 # Inner exceptions were suppressed
538 self.assertIsNone(exc.__context__.__context__.__context__)
539 else:
540 self.fail("Expected IndexError, but no exception was raised")
541 # Check the inner exceptions
542 inner_exc = SuppressExc.saved_details[1]
543 self.assertIsInstance(inner_exc, ValueError)
544 self.assertIsInstance(inner_exc.__context__, ZeroDivisionError)
545
546 def test_exit_exception_chaining(self):
547 # Ensure exception chaining matches the reference behaviour
548 def raise_exc(exc):
549 raise exc
550
551 saved_details = None
552 def suppress_exc(*exc_details):
553 nonlocal saved_details
554 saved_details = exc_details
555 return True
556
557 try:
558 with ExitStack() as stack:
559 stack.callback(raise_exc, IndexError)
560 stack.callback(raise_exc, KeyError)
561 stack.callback(raise_exc, AttributeError)
562 stack.push(suppress_exc)
563 stack.callback(raise_exc, ValueError)
564 1 / 0
565 except IndexError as exc:
566 self.assertIsInstance(exc.__context__, KeyError)
567 self.assertIsInstance(exc.__context__.__context__, AttributeError)
Nick Coghlan77452fc2012-06-01 22:48:32 +1000568 # Inner exceptions were suppressed
569 self.assertIsNone(exc.__context__.__context__.__context__)
Nick Coghlanc73e8c22012-05-31 23:49:26 +1000570 else:
571 self.fail("Expected IndexError, but no exception was raised")
572 # Check the inner exceptions
573 inner_exc = saved_details[1]
574 self.assertIsInstance(inner_exc, ValueError)
575 self.assertIsInstance(inner_exc.__context__, ZeroDivisionError)
576
Nick Coghlan1a33b2f2013-10-01 23:24:56 +1000577 def test_exit_exception_non_suppressing(self):
578 # http://bugs.python.org/issue19092
579 def raise_exc(exc):
580 raise exc
581
582 def suppress_exc(*exc_details):
583 return True
584
585 try:
586 with ExitStack() as stack:
587 stack.callback(lambda: None)
588 stack.callback(raise_exc, IndexError)
589 except Exception as exc:
590 self.assertIsInstance(exc, IndexError)
591 else:
592 self.fail("Expected IndexError, but no exception was raised")
593
594 try:
595 with ExitStack() as stack:
596 stack.callback(raise_exc, KeyError)
597 stack.push(suppress_exc)
598 stack.callback(raise_exc, IndexError)
599 except Exception as exc:
600 self.assertIsInstance(exc, KeyError)
601 else:
602 self.fail("Expected KeyError, but no exception was raised")
603
604 def test_body_exception_suppress(self):
605 def suppress_exc(*exc_details):
606 return True
607 try:
608 with ExitStack() as stack:
609 stack.push(suppress_exc)
610 1/0
611 except IndexError as exc:
612 self.fail("Expected no exception, got IndexError")
613
Nick Coghlanc73e8c22012-05-31 23:49:26 +1000614 def test_exit_exception_chaining_suppress(self):
615 with ExitStack() as stack:
616 stack.push(lambda *exc: True)
617 stack.push(lambda *exc: 1/0)
618 stack.push(lambda *exc: {}[1])
619
Nick Coghlana5bd2a12012-06-01 00:00:38 +1000620 def test_excessive_nesting(self):
621 # The original implementation would die with RecursionError here
622 with ExitStack() as stack:
623 for i in range(10000):
624 stack.callback(int)
625
Nick Coghlan3267a302012-05-21 22:54:43 +1000626 def test_instance_bypass(self):
627 class Example(object): pass
628 cm = Example()
629 cm.__exit__ = object()
630 stack = ExitStack()
631 self.assertRaises(AttributeError, stack.enter_context, cm)
632 stack.push(cm)
633 self.assertIs(stack._exit_callbacks[-1], cm)
634
Raymond Hettinger1254b402013-10-10 22:39:39 -0700635class TestIgnore(unittest.TestCase):
Raymond Hettingere318a882013-03-10 22:26:51 -0700636
637 def test_no_exception(self):
638
Raymond Hettinger1254b402013-10-10 22:39:39 -0700639 with ignore(ValueError):
Raymond Hettingere318a882013-03-10 22:26:51 -0700640 self.assertEqual(pow(2, 5), 32)
641
642 def test_exact_exception(self):
643
Raymond Hettinger1254b402013-10-10 22:39:39 -0700644 with ignore(TypeError):
Raymond Hettingere318a882013-03-10 22:26:51 -0700645 len(5)
646
647 def test_multiple_exception_args(self):
648
Raymond Hettinger1254b402013-10-10 22:39:39 -0700649 with ignore(ZeroDivisionError, TypeError):
Raymond Hettingere318a882013-03-10 22:26:51 -0700650 len(5)
651
652 def test_exception_hierarchy(self):
653
Raymond Hettinger1254b402013-10-10 22:39:39 -0700654 with ignore(LookupError):
Raymond Hettingere318a882013-03-10 22:26:51 -0700655 'Hello'[50]
656
Raymond Hettinger088cbf22013-10-10 00:46:57 -0700657class TestRedirectStdout(unittest.TestCase):
658
659 def test_redirect_to_string_io(self):
660 f = io.StringIO()
661 with redirect_stdout(f):
662 help(pow)
663 s = f.getvalue()
664 self.assertIn('pow', s)
Nick Coghlan3267a302012-05-21 22:54:43 +1000665
Guido van Rossum1a5e21e2006-02-28 21:57:43 +0000666if __name__ == "__main__":
Brett Cannon3e9a9ae2013-06-12 21:25:59 -0400667 unittest.main()