|
1 ========================= |
|
2 Mock Library Comparison |
|
3 ========================= |
|
4 |
|
5 |
|
6 .. testsetup:: |
|
7 |
|
8 def assertEqual(a, b): |
|
9 assert a == b, ("%r != %r" % (a, b)) |
|
10 |
|
11 def assertRaises(Exc, func): |
|
12 try: |
|
13 func() |
|
14 except Exc: |
|
15 return |
|
16 assert False, ("%s not raised" % Exc) |
|
17 |
|
18 sys.modules['somemodule'] = somemodule = mock.Mock(name='somemodule') |
|
19 class SomeException(Exception): |
|
20 some_method = method1 = method2 = None |
|
21 some_other_object = SomeObject = SomeException |
|
22 |
|
23 |
|
24 A side-by-side comparison of how to accomplish some basic tasks with mock and |
|
25 some other popular Python mocking libraries and frameworks. |
|
26 |
|
27 These are: |
|
28 |
|
29 * `flexmock <http://pypi.python.org/pypi/flexmock>`_ |
|
30 * `mox <http://pypi.python.org/pypi/mox>`_ |
|
31 * `Mocker <http://niemeyer.net/mocker>`_ |
|
32 * `dingus <http://pypi.python.org/pypi/dingus>`_ |
|
33 * `fudge <http://pypi.python.org/pypi/fudge>`_ |
|
34 |
|
35 Popular python mocking frameworks not yet represented here include |
|
36 `MiniMock <http://pypi.python.org/pypi/MiniMock>`_. |
|
37 |
|
38 `pMock <http://pmock.sourceforge.net/>`_ (last release 2004 and doesn't import |
|
39 in recent versions of Python) and |
|
40 `python-mock <http://python-mock.sourceforge.net/>`_ (last release 2005) are |
|
41 intentionally omitted. |
|
42 |
|
43 .. note:: |
|
44 |
|
45 A more up to date, and tested for all mock libraries (only the mock |
|
46 examples on this page can be executed as doctests) version of this |
|
47 comparison is maintained by Gary Bernhardt: |
|
48 |
|
49 * `Python Mock Library Comparison |
|
50 <http://garybernhardt.github.com/python-mock-comparison/>`_ |
|
51 |
|
52 This comparison is by no means complete, and also may not be fully idiomatic |
|
53 for all the libraries represented. *Please* contribute corrections, missing |
|
54 comparisons, or comparisons for additional libraries to the `mock issue |
|
55 tracker <https://code.google.com/p/mock/issues/list>`_. |
|
56 |
|
57 This comparison page was originally created by the `Mox project |
|
58 <https://code.google.com/p/pymox/wiki/MoxComparison>`_ and then extended for |
|
59 `flexmock and mock <http://has207.github.com/flexmock/compare.html>`_ by |
|
60 Herman Sheremetyev. Dingus examples written by `Gary Bernhadt |
|
61 <http://garybernhardt.github.com/python-mock-comparison/>`_. fudge examples |
|
62 provided by `Kumar McMillan <http://farmdev.com/>`_. |
|
63 |
|
64 .. note:: |
|
65 |
|
66 The examples tasks here were originally created by Mox which is a mocking |
|
67 *framework* rather than a library like mock. The tasks shown naturally |
|
68 exemplify tasks that frameworks are good at and not the ones they make |
|
69 harder. In particular you can take a `Mock` or `MagicMock` object and use |
|
70 it in any way you want with no up-front configuration. The same is also |
|
71 true for Dingus. |
|
72 |
|
73 The examples for mock here assume version 0.7.0. |
|
74 |
|
75 |
|
76 Simple fake object |
|
77 ~~~~~~~~~~~~~~~~~~ |
|
78 |
|
79 .. doctest:: |
|
80 |
|
81 >>> # mock |
|
82 >>> my_mock = mock.Mock() |
|
83 >>> my_mock.some_method.return_value = "calculated value" |
|
84 >>> my_mock.some_attribute = "value" |
|
85 >>> assertEqual("calculated value", my_mock.some_method()) |
|
86 >>> assertEqual("value", my_mock.some_attribute) |
|
87 |
|
88 :: |
|
89 |
|
90 # Flexmock |
|
91 mock = flexmock(some_method=lambda: "calculated value", some_attribute="value") |
|
92 assertEqual("calculated value", mock.some_method()) |
|
93 assertEqual("value", mock.some_attribute) |
|
94 |
|
95 # Mox |
|
96 mock = mox.MockAnything() |
|
97 mock.some_method().AndReturn("calculated value") |
|
98 mock.some_attribute = "value" |
|
99 mox.Replay(mock) |
|
100 assertEqual("calculated value", mock.some_method()) |
|
101 assertEqual("value", mock.some_attribute) |
|
102 |
|
103 # Mocker |
|
104 mock = mocker.mock() |
|
105 mock.some_method() |
|
106 mocker.result("calculated value") |
|
107 mocker.replay() |
|
108 mock.some_attribute = "value" |
|
109 assertEqual("calculated value", mock.some_method()) |
|
110 assertEqual("value", mock.some_attribute) |
|
111 |
|
112 :: |
|
113 |
|
114 >>> # Dingus |
|
115 >>> my_dingus = dingus.Dingus(some_attribute="value", |
|
116 ... some_method__returns="calculated value") |
|
117 >>> assertEqual("calculated value", my_dingus.some_method()) |
|
118 >>> assertEqual("value", my_dingus.some_attribute) |
|
119 |
|
120 :: |
|
121 |
|
122 >>> # fudge |
|
123 >>> my_fake = (fudge.Fake() |
|
124 ... .provides('some_method') |
|
125 ... .returns("calculated value") |
|
126 ... .has_attr(some_attribute="value")) |
|
127 ... |
|
128 >>> assertEqual("calculated value", my_fake.some_method()) |
|
129 >>> assertEqual("value", my_fake.some_attribute) |
|
130 |
|
131 |
|
132 Simple mock |
|
133 ~~~~~~~~~~~ |
|
134 |
|
135 .. doctest:: |
|
136 |
|
137 >>> # mock |
|
138 >>> my_mock = mock.Mock() |
|
139 >>> my_mock.some_method.return_value = "value" |
|
140 >>> assertEqual("value", my_mock.some_method()) |
|
141 >>> my_mock.some_method.assert_called_once_with() |
|
142 |
|
143 :: |
|
144 |
|
145 # Flexmock |
|
146 mock = flexmock() |
|
147 mock.should_receive("some_method").and_return("value").once |
|
148 assertEqual("value", mock.some_method()) |
|
149 |
|
150 # Mox |
|
151 mock = mox.MockAnything() |
|
152 mock.some_method().AndReturn("value") |
|
153 mox.Replay(mock) |
|
154 assertEqual("value", mock.some_method()) |
|
155 mox.Verify(mock) |
|
156 |
|
157 # Mocker |
|
158 mock = mocker.mock() |
|
159 mock.some_method() |
|
160 mocker.result("value") |
|
161 mocker.replay() |
|
162 assertEqual("value", mock.some_method()) |
|
163 mocker.verify() |
|
164 |
|
165 :: |
|
166 |
|
167 >>> # Dingus |
|
168 >>> my_dingus = dingus.Dingus(some_method__returns="value") |
|
169 >>> assertEqual("value", my_dingus.some_method()) |
|
170 >>> assert my_dingus.some_method.calls().once() |
|
171 |
|
172 :: |
|
173 |
|
174 >>> # fudge |
|
175 >>> @fudge.test |
|
176 ... def test(): |
|
177 ... my_fake = (fudge.Fake() |
|
178 ... .expects('some_method') |
|
179 ... .returns("value") |
|
180 ... .times_called(1)) |
|
181 ... |
|
182 >>> test() |
|
183 Traceback (most recent call last): |
|
184 ... |
|
185 AssertionError: fake:my_fake.some_method() was not called |
|
186 |
|
187 |
|
188 Creating partial mocks |
|
189 ~~~~~~~~~~~~~~~~~~~~~~ |
|
190 |
|
191 .. doctest:: |
|
192 |
|
193 >>> # mock |
|
194 >>> SomeObject.some_method = mock.Mock(return_value='value') |
|
195 >>> assertEqual("value", SomeObject.some_method()) |
|
196 |
|
197 :: |
|
198 |
|
199 # Flexmock |
|
200 flexmock(SomeObject).should_receive("some_method").and_return('value') |
|
201 assertEqual("value", mock.some_method()) |
|
202 |
|
203 # Mox |
|
204 mock = mox.MockObject(SomeObject) |
|
205 mock.some_method().AndReturn("value") |
|
206 mox.Replay(mock) |
|
207 assertEqual("value", mock.some_method()) |
|
208 mox.Verify(mock) |
|
209 |
|
210 # Mocker |
|
211 mock = mocker.mock(SomeObject) |
|
212 mock.Get() |
|
213 mocker.result("value") |
|
214 mocker.replay() |
|
215 assertEqual("value", mock.some_method()) |
|
216 mocker.verify() |
|
217 |
|
218 :: |
|
219 |
|
220 >>> # Dingus |
|
221 >>> object = SomeObject |
|
222 >>> object.some_method = dingus.Dingus(return_value="value") |
|
223 >>> assertEqual("value", object.some_method()) |
|
224 |
|
225 :: |
|
226 |
|
227 >>> # fudge |
|
228 >>> fake = fudge.Fake().is_callable().returns("<fudge-value>") |
|
229 >>> with fudge.patched_context(SomeObject, 'some_method', fake): |
|
230 ... s = SomeObject() |
|
231 ... assertEqual("<fudge-value>", s.some_method()) |
|
232 ... |
|
233 |
|
234 |
|
235 Ensure calls are made in specific order |
|
236 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
237 |
|
238 .. doctest:: |
|
239 |
|
240 >>> # mock |
|
241 >>> my_mock = mock.Mock(spec=SomeObject) |
|
242 >>> my_mock.method1() |
|
243 <Mock name='mock.method1()' id='...'> |
|
244 >>> my_mock.method2() |
|
245 <Mock name='mock.method2()' id='...'> |
|
246 >>> assertEqual(my_mock.mock_calls, [call.method1(), call.method2()]) |
|
247 |
|
248 :: |
|
249 |
|
250 # Flexmock |
|
251 mock = flexmock(SomeObject) |
|
252 mock.should_receive('method1').once.ordered.and_return('first thing') |
|
253 mock.should_receive('method2').once.ordered.and_return('second thing') |
|
254 |
|
255 # Mox |
|
256 mock = mox.MockObject(SomeObject) |
|
257 mock.method1().AndReturn('first thing') |
|
258 mock.method2().AndReturn('second thing') |
|
259 mox.Replay(mock) |
|
260 mox.Verify(mock) |
|
261 |
|
262 # Mocker |
|
263 mock = mocker.mock() |
|
264 with mocker.order(): |
|
265 mock.method1() |
|
266 mocker.result('first thing') |
|
267 mock.method2() |
|
268 mocker.result('second thing') |
|
269 mocker.replay() |
|
270 mocker.verify() |
|
271 |
|
272 :: |
|
273 |
|
274 >>> # Dingus |
|
275 >>> my_dingus = dingus.Dingus() |
|
276 >>> my_dingus.method1() |
|
277 <Dingus ...> |
|
278 >>> my_dingus.method2() |
|
279 <Dingus ...> |
|
280 >>> assertEqual(['method1', 'method2'], [call.name for call in my_dingus.calls]) |
|
281 |
|
282 :: |
|
283 |
|
284 >>> # fudge |
|
285 >>> @fudge.test |
|
286 ... def test(): |
|
287 ... my_fake = (fudge.Fake() |
|
288 ... .remember_order() |
|
289 ... .expects('method1') |
|
290 ... .expects('method2')) |
|
291 ... my_fake.method2() |
|
292 ... my_fake.method1() |
|
293 ... |
|
294 >>> test() |
|
295 Traceback (most recent call last): |
|
296 ... |
|
297 AssertionError: Call #1 was fake:my_fake.method2(); Expected: #1 fake:my_fake.method1(), #2 fake:my_fake.method2(), end |
|
298 |
|
299 |
|
300 Raising exceptions |
|
301 ~~~~~~~~~~~~~~~~~~ |
|
302 |
|
303 .. doctest:: |
|
304 |
|
305 >>> # mock |
|
306 >>> my_mock = mock.Mock() |
|
307 >>> my_mock.some_method.side_effect = SomeException("message") |
|
308 >>> assertRaises(SomeException, my_mock.some_method) |
|
309 |
|
310 :: |
|
311 |
|
312 # Flexmock |
|
313 mock = flexmock() |
|
314 mock.should_receive("some_method").and_raise(SomeException("message")) |
|
315 assertRaises(SomeException, mock.some_method) |
|
316 |
|
317 # Mox |
|
318 mock = mox.MockAnything() |
|
319 mock.some_method().AndRaise(SomeException("message")) |
|
320 mox.Replay(mock) |
|
321 assertRaises(SomeException, mock.some_method) |
|
322 mox.Verify(mock) |
|
323 |
|
324 # Mocker |
|
325 mock = mocker.mock() |
|
326 mock.some_method() |
|
327 mocker.throw(SomeException("message")) |
|
328 mocker.replay() |
|
329 assertRaises(SomeException, mock.some_method) |
|
330 mocker.verify() |
|
331 |
|
332 :: |
|
333 |
|
334 >>> # Dingus |
|
335 >>> my_dingus = dingus.Dingus() |
|
336 >>> my_dingus.some_method = dingus.exception_raiser(SomeException) |
|
337 >>> assertRaises(SomeException, my_dingus.some_method) |
|
338 |
|
339 :: |
|
340 |
|
341 >>> # fudge |
|
342 >>> my_fake = (fudge.Fake() |
|
343 ... .is_callable() |
|
344 ... .raises(SomeException("message"))) |
|
345 ... |
|
346 >>> my_fake() |
|
347 Traceback (most recent call last): |
|
348 ... |
|
349 SomeException: message |
|
350 |
|
351 |
|
352 Override new instances of a class |
|
353 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
354 |
|
355 .. doctest:: |
|
356 |
|
357 >>> # mock |
|
358 >>> with mock.patch('somemodule.Someclass') as MockClass: |
|
359 ... MockClass.return_value = some_other_object |
|
360 ... assertEqual(some_other_object, somemodule.Someclass()) |
|
361 ... |
|
362 |
|
363 |
|
364 :: |
|
365 |
|
366 # Flexmock |
|
367 flexmock(some_module.SomeClass, new_instances=some_other_object) |
|
368 assertEqual(some_other_object, some_module.SomeClass()) |
|
369 |
|
370 # Mox |
|
371 # (you will probably have mox.Mox() available as self.mox in a real test) |
|
372 mox.Mox().StubOutWithMock(some_module, 'SomeClass', use_mock_anything=True) |
|
373 some_module.SomeClass().AndReturn(some_other_object) |
|
374 mox.ReplayAll() |
|
375 assertEqual(some_other_object, some_module.SomeClass()) |
|
376 |
|
377 # Mocker |
|
378 instance = mocker.mock() |
|
379 klass = mocker.replace(SomeClass, spec=None) |
|
380 klass('expected', 'args') |
|
381 mocker.result(instance) |
|
382 |
|
383 :: |
|
384 |
|
385 >>> # Dingus |
|
386 >>> MockClass = dingus.Dingus(return_value=some_other_object) |
|
387 >>> with dingus.patch('somemodule.SomeClass', MockClass): |
|
388 ... assertEqual(some_other_object, somemodule.SomeClass()) |
|
389 ... |
|
390 |
|
391 :: |
|
392 |
|
393 >>> # fudge |
|
394 >>> @fudge.patch('somemodule.SomeClass') |
|
395 ... def test(FakeClass): |
|
396 ... FakeClass.is_callable().returns(some_other_object) |
|
397 ... assertEqual(some_other_object, somemodule.SomeClass()) |
|
398 ... |
|
399 >>> test() |
|
400 |
|
401 |
|
402 Call the same method multiple times |
|
403 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
404 |
|
405 .. note:: |
|
406 |
|
407 You don't need to do *any* configuration to call `mock.Mock()` methods |
|
408 multiple times. Attributes like `call_count`, `call_args_list` and |
|
409 `method_calls` provide various different ways of making assertions about |
|
410 how the mock was used. |
|
411 |
|
412 .. doctest:: |
|
413 |
|
414 >>> # mock |
|
415 >>> my_mock = mock.Mock() |
|
416 >>> my_mock.some_method() |
|
417 <Mock name='mock.some_method()' id='...'> |
|
418 >>> my_mock.some_method() |
|
419 <Mock name='mock.some_method()' id='...'> |
|
420 >>> assert my_mock.some_method.call_count >= 2 |
|
421 |
|
422 :: |
|
423 |
|
424 # Flexmock # (verifies that the method gets called at least twice) |
|
425 flexmock(some_object).should_receive('some_method').at_least.twice |
|
426 |
|
427 # Mox |
|
428 # (does not support variable number of calls, so you need to create a new entry for each explicit call) |
|
429 mock = mox.MockObject(some_object) |
|
430 mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) |
|
431 mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) |
|
432 mox.Replay(mock) |
|
433 mox.Verify(mock) |
|
434 |
|
435 # Mocker |
|
436 # (TODO) |
|
437 |
|
438 :: |
|
439 |
|
440 >>> # Dingus |
|
441 >>> my_dingus = dingus.Dingus() |
|
442 >>> my_dingus.some_method() |
|
443 <Dingus ...> |
|
444 >>> my_dingus.some_method() |
|
445 <Dingus ...> |
|
446 >>> assert len(my_dingus.calls('some_method')) == 2 |
|
447 |
|
448 :: |
|
449 |
|
450 >>> # fudge |
|
451 >>> @fudge.test |
|
452 ... def test(): |
|
453 ... my_fake = fudge.Fake().expects('some_method').times_called(2) |
|
454 ... my_fake.some_method() |
|
455 ... |
|
456 >>> test() |
|
457 Traceback (most recent call last): |
|
458 ... |
|
459 AssertionError: fake:my_fake.some_method() was called 1 time(s). Expected 2. |
|
460 |
|
461 |
|
462 Mock chained methods |
|
463 ~~~~~~~~~~~~~~~~~~~~ |
|
464 |
|
465 .. doctest:: |
|
466 |
|
467 >>> # mock |
|
468 >>> my_mock = mock.Mock() |
|
469 >>> method3 = my_mock.method1.return_value.method2.return_value.method3 |
|
470 >>> method3.return_value = 'some value' |
|
471 >>> assertEqual('some value', my_mock.method1().method2().method3(1, 2)) |
|
472 >>> method3.assert_called_once_with(1, 2) |
|
473 |
|
474 :: |
|
475 |
|
476 # Flexmock |
|
477 # (intermediate method calls are automatically assigned to temporary fake objects |
|
478 # and can be called with any arguments) |
|
479 flexmock(some_object).should_receive( |
|
480 'method1.method2.method3' |
|
481 ).with_args(arg1, arg2).and_return('some value') |
|
482 assertEqual('some_value', some_object.method1().method2().method3(arg1, arg2)) |
|
483 |
|
484 :: |
|
485 |
|
486 # Mox |
|
487 mock = mox.MockObject(some_object) |
|
488 mock2 = mox.MockAnything() |
|
489 mock3 = mox.MockAnything() |
|
490 mock.method1().AndReturn(mock1) |
|
491 mock2.method2().AndReturn(mock2) |
|
492 mock3.method3(arg1, arg2).AndReturn('some_value') |
|
493 self.mox.ReplayAll() |
|
494 assertEqual("some_value", some_object.method1().method2().method3(arg1, arg2)) |
|
495 self.mox.VerifyAll() |
|
496 |
|
497 # Mocker |
|
498 # (TODO) |
|
499 |
|
500 :: |
|
501 |
|
502 >>> # Dingus |
|
503 >>> my_dingus = dingus.Dingus() |
|
504 >>> method3 = my_dingus.method1.return_value.method2.return_value.method3 |
|
505 >>> method3.return_value = 'some value' |
|
506 >>> assertEqual('some value', my_dingus.method1().method2().method3(1, 2)) |
|
507 >>> assert method3.calls('()', 1, 2).once() |
|
508 |
|
509 :: |
|
510 |
|
511 >>> # fudge |
|
512 >>> @fudge.test |
|
513 ... def test(): |
|
514 ... my_fake = fudge.Fake() |
|
515 ... (my_fake |
|
516 ... .expects('method1') |
|
517 ... .returns_fake() |
|
518 ... .expects('method2') |
|
519 ... .returns_fake() |
|
520 ... .expects('method3') |
|
521 ... .with_args(1, 2) |
|
522 ... .returns('some value')) |
|
523 ... assertEqual('some value', my_fake.method1().method2().method3(1, 2)) |
|
524 ... |
|
525 >>> test() |
|
526 |
|
527 |
|
528 Mocking a context manager |
|
529 ~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
530 |
|
531 Examples for mock, Dingus and fudge only (so far): |
|
532 |
|
533 .. doctest:: |
|
534 |
|
535 >>> # mock |
|
536 >>> my_mock = mock.MagicMock() |
|
537 >>> with my_mock: |
|
538 ... pass |
|
539 ... |
|
540 >>> my_mock.__enter__.assert_called_with() |
|
541 >>> my_mock.__exit__.assert_called_with(None, None, None) |
|
542 |
|
543 :: |
|
544 |
|
545 |
|
546 >>> # Dingus (nothing special here; all dinguses are "magic mocks") |
|
547 >>> my_dingus = dingus.Dingus() |
|
548 >>> with my_dingus: |
|
549 ... pass |
|
550 ... |
|
551 >>> assert my_dingus.__enter__.calls() |
|
552 >>> assert my_dingus.__exit__.calls('()', None, None, None) |
|
553 |
|
554 :: |
|
555 |
|
556 >>> # fudge |
|
557 >>> my_fake = fudge.Fake().provides('__enter__').provides('__exit__') |
|
558 >>> with my_fake: |
|
559 ... pass |
|
560 ... |
|
561 |
|
562 |
|
563 Mocking the builtin open used as a context manager |
|
564 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
565 |
|
566 Example for mock only (so far): |
|
567 |
|
568 .. doctest:: |
|
569 |
|
570 >>> # mock |
|
571 >>> my_mock = mock.MagicMock() |
|
572 >>> with mock.patch('__builtin__.open', my_mock): |
|
573 ... manager = my_mock.return_value.__enter__.return_value |
|
574 ... manager.read.return_value = 'some data' |
|
575 ... with open('foo') as h: |
|
576 ... data = h.read() |
|
577 ... |
|
578 >>> data |
|
579 'some data' |
|
580 >>> my_mock.assert_called_once_with('foo') |
|
581 |
|
582 *or*: |
|
583 |
|
584 .. doctest:: |
|
585 |
|
586 >>> # mock |
|
587 >>> with mock.patch('__builtin__.open') as my_mock: |
|
588 ... my_mock.return_value.__enter__ = lambda s: s |
|
589 ... my_mock.return_value.__exit__ = mock.Mock() |
|
590 ... my_mock.return_value.read.return_value = 'some data' |
|
591 ... with open('foo') as h: |
|
592 ... data = h.read() |
|
593 ... |
|
594 >>> data |
|
595 'some data' |
|
596 >>> my_mock.assert_called_once_with('foo') |
|
597 |
|
598 :: |
|
599 |
|
600 >>> # Dingus |
|
601 >>> my_dingus = dingus.Dingus() |
|
602 >>> with dingus.patch('__builtin__.open', my_dingus): |
|
603 ... file_ = open.return_value.__enter__.return_value |
|
604 ... file_.read.return_value = 'some data' |
|
605 ... with open('foo') as h: |
|
606 ... data = f.read() |
|
607 ... |
|
608 >>> data |
|
609 'some data' |
|
610 >>> assert my_dingus.calls('()', 'foo').once() |
|
611 |
|
612 :: |
|
613 |
|
614 >>> # fudge |
|
615 >>> from contextlib import contextmanager |
|
616 >>> from StringIO import StringIO |
|
617 >>> @contextmanager |
|
618 ... def fake_file(filename): |
|
619 ... yield StringIO('sekrets') |
|
620 ... |
|
621 >>> with fudge.patch('__builtin__.open') as fake_open: |
|
622 ... fake_open.is_callable().calls(fake_file) |
|
623 ... with open('/etc/password') as f: |
|
624 ... data = f.read() |
|
625 ... |
|
626 fake:__builtin__.open |
|
627 >>> data |
|
628 'sekrets' |