/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4797.32.2 by John Arbash Meinel
merge 2.1, resolving NEWS conflict.
1
# Copyright (C) 2009, 2010 Canonical Ltd
4634.85.1 by Andrew Bennetts
Begin defining cleanup helpers and their tests.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
import re
18
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
19
from ..cleanup import (
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
20
    ExitStack,
4634.85.3 by Andrew Bennetts
Lots more tests.
21
    )
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
22
from ..sixish import PY3
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
23
from .. import (
6770.3.1 by Martin
Fix test_cleanup on Python 3
24
    tests,
4634.85.5 by Andrew Bennetts
Add unit test for -Dcleanup behaviour.
25
    )
4634.85.3 by Andrew Bennetts
Lots more tests.
26
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
27
from contextlib import contextmanager
28
29
30
check_exception_chaining = PY3
31
32
33
# Imported from contextlib2's test_contextlib2.py
7356.1.6 by Jelmer Vernooij
Add copyright for contextlib code.
34
# Copyright: Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
35
#   2009, 2010, 2011 Python Software Foundation
36
#
37
# PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
38
# --------------------------------------------
39
# .
40
# 1. This LICENSE AGREEMENT is between the Python Software Foundation
41
# ("PSF"), and the Individual or Organization ("Licensee") accessing and
42
# otherwise using this software ("Python") in source or binary form and
43
# its associated documentation.
44
# .
45
# 2. Subject to the terms and conditions of this License Agreement, PSF hereby
46
# grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
47
# analyze, test, perform and/or display publicly, prepare derivative works,
48
# distribute, and otherwise use Python alone or in any derivative version,
49
# provided, however, that PSF's License Agreement and PSF's notice of copyright,
50
# i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
51
# 2011 Python Software Foundation; All Rights Reserved" are retained in Python
52
# alone or in any derivative version prepared by Licensee.
53
# .
54
# 3. In the event Licensee prepares a derivative work that is based on
55
# or incorporates Python or any part thereof, and wants to make
56
# the derivative work available to others as provided herein, then
57
# Licensee hereby agrees to include in any such work a brief summary of
58
# the changes made to Python.
59
# .
60
# 4. PSF is making Python available to Licensee on an "AS IS"
61
# basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
62
# IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
63
# DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
64
# FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
65
# INFRINGE ANY THIRD PARTY RIGHTS.
66
# .
67
# 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
68
# FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
69
# A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
70
# OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
71
# .
72
# 6. This License Agreement will automatically terminate upon a material
73
# breach of its terms and conditions.
74
# .
75
# 7. Nothing in this License Agreement shall be deemed to create any
76
# relationship of agency, partnership, or joint venture between PSF and
77
# Licensee.  This License Agreement does not grant permission to use PSF
78
# trademarks or trade name in a trademark sense to endorse or promote
79
# products or services of Licensee, or any third party.
80
# .
81
# 8. By copying, installing or otherwise using Python, Licensee
82
# agrees to be bound by the terms and conditions of this License
83
# Agreement.
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
84
85
86
class TestExitStack(tests.TestCase):
87
88
    def test_no_resources(self):
89
        with ExitStack():
90
            pass
91
92
    def test_callback(self):
93
        expected = [
94
            ((), {}),
95
            ((1,), {}),
7356.1.3 by Jelmer Vernooij
Fix tests.
96
            ((1, 2), {}),
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
97
            ((), dict(example=1)),
98
            ((1,), dict(example=1)),
7356.1.3 by Jelmer Vernooij
Fix tests.
99
            ((1, 2), dict(example=1)),
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
100
        ]
101
        result = []
102
        def _exit(*args, **kwds):
103
            """Test metadata propagation"""
104
            result.append((args, kwds))
105
        with ExitStack() as stack:
106
            for args, kwds in reversed(expected):
107
                if args and kwds:
108
                    f = stack.callback(_exit, *args, **kwds)
109
                elif args:
110
                    f = stack.callback(_exit, *args)
111
                elif kwds:
112
                    f = stack.callback(_exit, **kwds)
113
                else:
114
                    f = stack.callback(_exit)
115
                self.assertIs(f, _exit)
116
        self.assertEqual(result, expected)
117
118
    def test_push(self):
119
        exc_raised = ZeroDivisionError
120
        def _expect_exc(exc_type, exc, exc_tb):
121
            self.assertIs(exc_type, exc_raised)
122
        def _suppress_exc(*exc_details):
123
            return True
124
        def _expect_ok(exc_type, exc, exc_tb):
125
            self.assertIsNone(exc_type)
126
            self.assertIsNone(exc)
127
            self.assertIsNone(exc_tb)
128
        class ExitCM(object):
129
            def __init__(self, check_exc):
130
                self.check_exc = check_exc
131
            def __enter__(self):
132
                self.fail("Should not be called!")
133
            def __exit__(self, *exc_details):
134
                self.check_exc(*exc_details)
135
        with ExitStack() as stack:
136
            stack.push(_expect_ok)
137
            cm = ExitCM(_expect_ok)
138
            stack.push(cm)
139
            stack.push(_suppress_exc)
140
            cm = ExitCM(_expect_exc)
141
            stack.push(cm)
7356.1.3 by Jelmer Vernooij
Fix tests.
142
            stack.push(_expect_exc)
143
            stack.push(_expect_exc)
144
            1 / 0
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
145
146
    def test_enter_context(self):
147
        class TestCM(object):
148
            def __enter__(self):
149
                result.append(1)
150
            def __exit__(self, *exc_details):
151
                result.append(3)
152
153
        result = []
154
        cm = TestCM()
155
        with ExitStack() as stack:
156
            @stack.callback  # Registered first => cleaned up last
157
            def _exit():
158
                result.append(4)
159
            self.assertIsNotNone(_exit)
160
            stack.enter_context(cm)
161
            result.append(2)
162
        self.assertEqual(result, [1, 2, 3, 4])
163
164
    def test_close(self):
165
        result = []
166
        with ExitStack() as stack:
167
            @stack.callback
168
            def _exit():
169
                result.append(1)
170
            self.assertIsNotNone(_exit)
171
            stack.close()
172
            result.append(2)
173
        self.assertEqual(result, [1, 2])
174
175
    def test_pop_all(self):
176
        result = []
177
        with ExitStack() as stack:
178
            @stack.callback
179
            def _exit():
180
                result.append(3)
181
            self.assertIsNotNone(_exit)
182
            new_stack = stack.pop_all()
183
            result.append(1)
184
        result.append(2)
185
        new_stack.close()
186
        self.assertEqual(result, [1, 2, 3])
187
188
    def test_exit_raise(self):
189
        def _raise():
190
            with ExitStack() as stack:
191
                stack.push(lambda *exc: False)
7356.1.3 by Jelmer Vernooij
Fix tests.
192
                1 / 0
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
193
        self.assertRaises(ZeroDivisionError, _raise)
194
195
    def test_exit_suppress(self):
196
        with ExitStack() as stack:
197
            stack.push(lambda *exc: True)
7356.1.3 by Jelmer Vernooij
Fix tests.
198
            1 / 0
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
199
200
    def test_exit_exception_chaining_reference(self):
201
        # Sanity check to make sure that ExitStack chaining matches
202
        # actual nested with statements
203
        class RaiseExc:
204
            def __init__(self, exc):
205
                self.exc = exc
206
            def __enter__(self):
207
                return self
208
            def __exit__(self, *exc_details):
209
                raise self.exc
210
211
        class RaiseExcWithContext:
212
            def __init__(self, outer, inner):
213
                self.outer = outer
214
                self.inner = inner
215
            def __enter__(self):
216
                return self
217
            def __exit__(self, *exc_details):
218
                try:
219
                    raise self.inner
220
                except:
221
                    raise self.outer
222
223
        class SuppressExc:
224
            def __enter__(self):
225
                return self
226
            def __exit__(self, *exc_details):
227
                self.__class__.saved_details = exc_details
228
                return True
229
230
        try:
231
            with RaiseExc(IndexError):
232
                with RaiseExcWithContext(KeyError, AttributeError):
233
                    with SuppressExc():
234
                        with RaiseExc(ValueError):
235
                            1 / 0
236
        except IndexError as exc:
237
            if check_exception_chaining:
238
                self.assertIsInstance(exc.__context__, KeyError)
239
                self.assertIsInstance(exc.__context__.__context__, AttributeError)
240
                # Inner exceptions were suppressed
241
                self.assertIsNone(exc.__context__.__context__.__context__)
242
        else:
243
            self.fail("Expected IndexError, but no exception was raised")
244
        # Check the inner exceptions
245
        inner_exc = SuppressExc.saved_details[1]
246
        self.assertIsInstance(inner_exc, ValueError)
247
        if check_exception_chaining:
248
            self.assertIsInstance(inner_exc.__context__, ZeroDivisionError)
249
250
    def test_exit_exception_chaining(self):
251
        # Ensure exception chaining matches the reference behaviour
252
        def raise_exc(exc):
253
            raise exc
254
255
        saved_details = [None]
256
        def suppress_exc(*exc_details):
257
            saved_details[0] = exc_details
258
            return True
259
260
        try:
261
            with ExitStack() as stack:
262
                stack.callback(raise_exc, IndexError)
263
                stack.callback(raise_exc, KeyError)
264
                stack.callback(raise_exc, AttributeError)
265
                stack.push(suppress_exc)
266
                stack.callback(raise_exc, ValueError)
267
                1 / 0
268
        except IndexError as exc:
269
            if check_exception_chaining:
270
                self.assertIsInstance(exc.__context__, KeyError)
271
                self.assertIsInstance(exc.__context__.__context__, AttributeError)
272
                # Inner exceptions were suppressed
273
                self.assertIsNone(exc.__context__.__context__.__context__)
274
        else:
275
            self.fail("Expected IndexError, but no exception was raised")
276
        # Check the inner exceptions
277
        inner_exc = saved_details[0][1]
278
        self.assertIsInstance(inner_exc, ValueError)
279
        if check_exception_chaining:
280
            self.assertIsInstance(inner_exc.__context__, ZeroDivisionError)
281
282
    def test_exit_exception_non_suppressing(self):
283
        # http://bugs.python.org/issue19092
284
        def raise_exc(exc):
285
            raise exc
286
287
        def suppress_exc(*exc_details):
288
            return True
289
290
        try:
291
            with ExitStack() as stack:
292
                stack.callback(lambda: None)
293
                stack.callback(raise_exc, IndexError)
294
        except Exception as exc:
295
            self.assertIsInstance(exc, IndexError)
296
        else:
297
            self.fail("Expected IndexError, but no exception was raised")
298
299
        try:
300
            with ExitStack() as stack:
301
                stack.callback(raise_exc, KeyError)
302
                stack.push(suppress_exc)
303
                stack.callback(raise_exc, IndexError)
304
        except Exception as exc:
305
            self.assertIsInstance(exc, KeyError)
306
        else:
307
            self.fail("Expected KeyError, but no exception was raised")
308
309
    def test_exit_exception_with_correct_context(self):
310
        # http://bugs.python.org/issue20317
311
        @contextmanager
312
        def gets_the_context_right(exc):
313
            try:
314
                yield
315
            finally:
316
                raise exc
317
318
        exc1 = Exception(1)
319
        exc2 = Exception(2)
320
        exc3 = Exception(3)
321
        exc4 = Exception(4)
322
323
        # The contextmanager already fixes the context, so prior to the
324
        # fix, ExitStack would try to fix it *again* and get into an
325
        # infinite self-referential loop
326
        try:
327
            with ExitStack() as stack:
328
                stack.enter_context(gets_the_context_right(exc4))
329
                stack.enter_context(gets_the_context_right(exc3))
330
                stack.enter_context(gets_the_context_right(exc2))
331
                raise exc1
332
        except Exception as exc:
333
            self.assertIs(exc, exc4)
334
            if check_exception_chaining:
335
                self.assertIs(exc.__context__, exc3)
336
                self.assertIs(exc.__context__.__context__, exc2)
337
                self.assertIs(exc.__context__.__context__.__context__, exc1)
338
                self.assertIsNone(
7356.1.3 by Jelmer Vernooij
Fix tests.
339
                    exc.__context__.__context__.__context__.__context__)
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
340
341
    def test_exit_exception_with_existing_context(self):
342
        # Addresses a lack of test coverage discovered after checking in a
343
        # fix for issue 20317 that still contained debugging code.
344
        def raise_nested(inner_exc, outer_exc):
345
            try:
346
                raise inner_exc
347
            finally:
348
                raise outer_exc
349
        exc1 = Exception(1)
350
        exc2 = Exception(2)
351
        exc3 = Exception(3)
352
        exc4 = Exception(4)
353
        exc5 = Exception(5)
354
        try:
355
            with ExitStack() as stack:
356
                stack.callback(raise_nested, exc4, exc5)
357
                stack.callback(raise_nested, exc2, exc3)
358
                raise exc1
359
        except Exception as exc:
360
            self.assertIs(exc, exc5)
361
            if check_exception_chaining:
362
                self.assertIs(exc.__context__, exc4)
363
                self.assertIs(exc.__context__.__context__, exc3)
364
                self.assertIs(exc.__context__.__context__.__context__, exc2)
365
                self.assertIs(
366
                    exc.__context__.__context__.__context__.__context__, exc1)
367
                self.assertIsNone(
368
                    exc.__context__.__context__.__context__.__context__.__context__)
369
370
    def test_body_exception_suppress(self):
371
        def suppress_exc(*exc_details):
372
            return True
373
        try:
374
            with ExitStack() as stack:
375
                stack.push(suppress_exc)
7356.1.3 by Jelmer Vernooij
Fix tests.
376
                1 / 0
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
377
        except IndexError as exc:
378
            self.fail("Expected no exception, got IndexError")
379
380
    def test_exit_exception_chaining_suppress(self):
381
        with ExitStack() as stack:
382
            stack.push(lambda *exc: True)
7356.1.3 by Jelmer Vernooij
Fix tests.
383
            stack.push(lambda *exc: 1 / 0)
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
384
            stack.push(lambda *exc: {}[1])
385
386
    def test_excessive_nesting(self):
387
        # The original implementation would die with RecursionError here
388
        with ExitStack() as stack:
389
            for i in range(10000):
390
                stack.callback(int)
391
392
    def test_instance_bypass(self):
7356.1.3 by Jelmer Vernooij
Fix tests.
393
        class Example(object):
394
            pass
7356.1.1 by Jelmer Vernooij
Use ExitStack context rather than brz-specific OperationWithCleanup.
395
        cm = Example()
396
        cm.__exit__ = object()
397
        stack = ExitStack()
398
        self.assertRaises(AttributeError, stack.enter_context, cm)
399
        stack.push(cm)
7356.1.3 by Jelmer Vernooij
Fix tests.
400
        # self.assertIs(stack._exit_callbacks[-1], cm)