1from __future__ import with_statement
2
3import sys
4
5def typename(t):
6    name = type(t).__name__
7    if sys.version_info < (2,5):
8        if name == 'classobj' and issubclass(t, MyException):
9            name = 'type'
10        elif name == 'instance' and isinstance(t, MyException):
11            name = 'MyException'
12    return u"<type '%s'>" % name
13
14class MyException(Exception):
15    pass
16
17class ContextManager(object):
18    def __init__(self, value, exit_ret = None):
19        self.value = value
20        self.exit_ret = exit_ret
21
22    def __exit__(self, a, b, tb):
23        print u"exit", typename(a), typename(b), typename(tb)
24        return self.exit_ret
25
26    def __enter__(self):
27        print u"enter"
28        return self.value
29
30def no_as():
31    """
32    >>> no_as()
33    enter
34    hello
35    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
36    """
37    with ContextManager(u"value"):
38        print u"hello"
39
40def basic():
41    """
42    >>> basic()
43    enter
44    value
45    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
46    """
47    with ContextManager(u"value") as x:
48        print x
49
50def with_pass():
51    """
52    >>> with_pass()
53    enter
54    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
55    """
56    with ContextManager(u"value") as x:
57        pass
58
59def with_exception(exit_ret):
60    """
61    >>> with_exception(None)
62    enter
63    value
64    exit <type 'type'> <type 'MyException'> <type 'traceback'>
65    outer except
66    >>> with_exception(True)
67    enter
68    value
69    exit <type 'type'> <type 'MyException'> <type 'traceback'>
70    """
71    try:
72        with ContextManager(u"value", exit_ret=exit_ret) as value:
73            print value
74            raise MyException()
75    except:
76        print u"outer except"
77
78def multitarget():
79    """
80    >>> multitarget()
81    enter
82    1 2 3 4 5
83    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
84    """
85    with ContextManager((1, 2, (3, (4, 5)))) as (a, b, (c, (d, e))):
86        print a, b, c, d, e
87
88def tupletarget():
89    """
90    >>> tupletarget()
91    enter
92    (1, 2, (3, (4, 5)))
93    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
94    """
95    with ContextManager((1, 2, (3, (4, 5)))) as t:
96        print t
97
98def typed():
99    """
100    >>> typed()
101    enter
102    10
103    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
104    """
105    cdef unsigned char i
106    c = ContextManager(255)
107    with c as i:
108        i += 11
109        print i
110
111def multimanager():
112    """
113    >>> multimanager()
114    enter
115    enter
116    enter
117    enter
118    enter
119    enter
120    2
121    value
122    1 2 3 4 5
123    nested
124    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
125    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
126    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
127    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
128    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
129    exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
130    """
131    with ContextManager(1), ContextManager(2) as x, ContextManager(u'value') as y,\
132            ContextManager(3), ContextManager((1, 2, (3, (4, 5)))) as (a, b, (c, (d, e))):
133        with ContextManager(u'nested') as nested:
134            print x
135            print y
136            print a, b, c, d, e
137            print nested
138
139# Tests borrowed from pyregr test_with.py,
140# modified to follow the constraints of Cython.
141import unittest
142
143class Dummy(object):
144    def __init__(self, value=None, gobble=False):
145        if value is None:
146            value = self
147        self.value = value
148        self.gobble = gobble
149        self.enter_called = False
150        self.exit_called = False
151
152    def __enter__(self):
153        self.enter_called = True
154        return self.value
155
156    def __exit__(self, *exc_info):
157        self.exit_called = True
158        self.exc_info = exc_info
159        if self.gobble:
160            return True
161
162class InitRaises(object):
163    def __init__(self): raise RuntimeError()
164
165class EnterRaises(object):
166    def __enter__(self): raise RuntimeError()
167    def __exit__(self, *exc_info): pass
168
169class ExitRaises(object):
170    def __enter__(self): pass
171    def __exit__(self, *exc_info): raise RuntimeError()
172
173class NestedWith(unittest.TestCase):
174    """
175    >>> NestedWith().runTest()
176    """
177
178    def runTest(self):
179        self.testNoExceptions()
180        self.testExceptionInExprList()
181        self.testExceptionInEnter()
182        self.testExceptionInExit()
183        self.testEnterReturnsTuple()
184
185    def testNoExceptions(self):
186        with Dummy() as a, Dummy() as b:
187            self.assertTrue(a.enter_called)
188            self.assertTrue(b.enter_called)
189        self.assertTrue(a.exit_called)
190        self.assertTrue(b.exit_called)
191
192    def testExceptionInExprList(self):
193        try:
194            with Dummy() as a, InitRaises():
195                pass
196        except:
197            pass
198        self.assertTrue(a.enter_called)
199        self.assertTrue(a.exit_called)
200
201    def testExceptionInEnter(self):
202        try:
203            with Dummy() as a, EnterRaises():
204                self.fail('body of bad with executed')
205        except RuntimeError:
206            pass
207        else:
208            self.fail('RuntimeError not reraised')
209        self.assertTrue(a.enter_called)
210        self.assertTrue(a.exit_called)
211
212    def testExceptionInExit(self):
213        body_executed = False
214        with Dummy(gobble=True) as a, ExitRaises():
215            body_executed = True
216        self.assertTrue(a.enter_called)
217        self.assertTrue(a.exit_called)
218        self.assertTrue(body_executed)
219        self.assertNotEqual(a.exc_info[0], None)
220
221    def testEnterReturnsTuple(self):
222        with Dummy(value=(1,2)) as (a1, a2), \
223             Dummy(value=(10, 20)) as (b1, b2):
224            self.assertEqual(1, a1)
225            self.assertEqual(2, a2)
226            self.assertEqual(10, b1)
227            self.assertEqual(20, b2)
228