/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_cleanup.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-02-14 03:16:54 UTC
  • mfrom: (7479.2.3 no-more-python2)
  • Revision ID: breezy.the.bot@gmail.com-20200214031654-bp1xtv2jr9nmhto3
Drop python2 support.

Merged from https://code.launchpad.net/~jelmer/brz/no-more-python2/+merge/378694

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2009, 2010 Canonical Ltd
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
 
 
19
 
from ..cleanup import (
20
 
    ExitStack,
21
 
    )
22
 
from ..sixish import PY3
23
 
from .. import (
24
 
    tests,
25
 
    )
26
 
 
27
 
from contextlib import contextmanager
28
 
 
29
 
 
30
 
check_exception_chaining = PY3
31
 
 
32
 
 
33
 
# Imported from contextlib2's test_contextlib2.py
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.
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,), {}),
96
 
            ((1, 2), {}),
97
 
            ((), dict(example=1)),
98
 
            ((1,), dict(example=1)),
99
 
            ((1, 2), dict(example=1)),
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)
142
 
            stack.push(_expect_exc)
143
 
            stack.push(_expect_exc)
144
 
            1 / 0
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)
192
 
                1 / 0
193
 
        self.assertRaises(ZeroDivisionError, _raise)
194
 
 
195
 
    def test_exit_suppress(self):
196
 
        with ExitStack() as stack:
197
 
            stack.push(lambda *exc: True)
198
 
            1 / 0
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(
339
 
                    exc.__context__.__context__.__context__.__context__)
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)
376
 
                1 / 0
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)
383
 
            stack.push(lambda *exc: 1 / 0)
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):
393
 
        class Example(object):
394
 
            pass
395
 
        cm = Example()
396
 
        cm.__exit__ = object()
397
 
        stack = ExitStack()
398
 
        self.assertRaises(AttributeError, stack.enter_context, cm)
399
 
        stack.push(cm)
400
 
        # self.assertIs(stack._exit_callbacks[-1], cm)