return Nodes.PassStatNode(pos)
def p_with_statement(s):
- pos = s.position()
s.next() # 'with'
-# if s.sy == 'IDENT' and s.systring in ('gil', 'nogil'):
+ if s.systring == 'template':
+ node = p_with_template(s)
+ else:
+ node = p_with_items(s)
+ return node
+
+def p_with_items(s):
+ pos = s.position()
if s.sy == 'IDENT' and s.systring == 'nogil':
state = s.systring
s.next()
- body = p_suite(s)
- return Nodes.GILStatNode(pos, state = state, body = body)
- elif s.systring == 'template':
- templates = []
- s.next()
- s.expect('[')
- #s.next()
- templates.append(s.systring)
- s.next()
- while s.systring == ',':
- s.next()
- templates.append(s.systring)
- s.next()
- s.expect(']')
- if s.sy == ':':
+ if s.sy == ',':
s.next()
- s.expect_newline("Syntax error in template function declaration")
- s.expect_indent()
- body_ctx = Ctx()
- body_ctx.templates = templates
- func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
- s.expect_dedent()
- return func_or_var
+ body = p_with_items(s)
else:
- error(pos, "Syntax error in template function declaration")
+ body = p_suite(s)
+ return Nodes.GILStatNode(pos, state = state, body = body)
else:
manager = p_test(s)
target = None
if s.sy == 'IDENT' and s.systring == 'as':
s.next()
- allow_multi = (s.sy == '(')
- target = p_target(s, ':')
- if not allow_multi and isinstance(target, ExprNodes.TupleNode):
- s.error("Multiple with statement target values not allowed without paranthesis")
- body = p_suite(s)
+ target = p_starred_expr(s)
+ if s.sy == ',':
+ s.next()
+ body = p_with_items(s)
+ else:
+ body = p_suite(s)
return Nodes.WithStatNode(pos, manager = manager,
target = target, body = body)
-
+
+def p_with_template(s):
+ pos = s.position()
+ templates = []
+ s.next()
+ s.expect('[')
+ templates.append(s.systring)
+ s.next()
+ while s.systring == ',':
+ s.next()
+ templates.append(s.systring)
+ s.next()
+ s.expect(']')
+ if s.sy == ':':
+ s.next()
+ s.expect_newline("Syntax error in template function declaration")
+ s.expect_indent()
+ body_ctx = Ctx()
+ body_ctx.templates = templates
+ func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
+ s.expect_dedent()
+ return func_or_var
+ else:
+ error(pos, "Syntax error in template function declaration")
+
def p_simple_statement(s, first_statement = 0):
#print "p_simple_statement:", s.sy, s.systring ###
if s.sy == 'global':
with c as i:
i += 11
print i
+
+def multimanager():
+ """
+ >>> multimanager()
+ enter
+ enter
+ enter
+ enter
+ enter
+ enter
+ 2
+ value
+ 1 2 3 4 5
+ nested
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ """
+ with ContextManager(1), ContextManager(2) as x, ContextManager(u'value') as y,\
+ ContextManager(3), ContextManager((1, 2, (3, (4, 5)))) as (a, b, (c, (d, e))):
+ with ContextManager(u'nested') as nested:
+ print x
+ print y
+ print a, b, c, d, e
+ print nested
+
+# Tests borrowed from pyregr test_with.py,
+# modified to follow the constraints of Cython.
+import unittest
+
+class Dummy(object):
+ def __init__(self, value=None, gobble=False):
+ if value is None:
+ value = self
+ self.value = value
+ self.gobble = gobble
+ self.enter_called = False
+ self.exit_called = False
+
+ def __enter__(self):
+ self.enter_called = True
+ return self.value
+
+ def __exit__(self, *exc_info):
+ self.exit_called = True
+ self.exc_info = exc_info
+ if self.gobble:
+ return True
+
+class InitRaises(object):
+ def __init__(self): raise RuntimeError()
+
+class EnterRaises(object):
+ def __enter__(self): raise RuntimeError()
+ def __exit__(self, *exc_info): pass
+
+class ExitRaises(object):
+ def __enter__(self): pass
+ def __exit__(self, *exc_info): raise RuntimeError()
+
+class NestedWith(unittest.TestCase):
+ """
+ >>> NestedWith().runTest()
+ """
+
+ def runTest(self):
+ self.testNoExceptions()
+ self.testExceptionInExprList()
+ self.testExceptionInEnter()
+ self.testExceptionInExit()
+ self.testEnterReturnsTuple()
+
+ def testNoExceptions(self):
+ with Dummy() as a, Dummy() as b:
+ self.assertTrue(a.enter_called)
+ self.assertTrue(b.enter_called)
+ self.assertTrue(a.exit_called)
+ self.assertTrue(b.exit_called)
+
+ def testExceptionInExprList(self):
+ try:
+ with Dummy() as a, InitRaises():
+ pass
+ except:
+ pass
+ self.assertTrue(a.enter_called)
+ self.assertTrue(a.exit_called)
+
+ def testExceptionInEnter(self):
+ try:
+ with Dummy() as a, EnterRaises():
+ self.fail('body of bad with executed')
+ except RuntimeError:
+ pass
+ else:
+ self.fail('RuntimeError not reraised')
+ self.assertTrue(a.enter_called)
+ self.assertTrue(a.exit_called)
+
+ def testExceptionInExit(self):
+ body_executed = False
+ with Dummy(gobble=True) as a, ExitRaises():
+ body_executed = True
+ self.assertTrue(a.enter_called)
+ self.assertTrue(a.exit_called)
+ self.assertTrue(body_executed)
+ self.assertNotEqual(a.exc_info[0], None)
+
+ def testEnterReturnsTuple(self):
+ with Dummy(value=(1,2)) as (a1, a2), \
+ Dummy(value=(10, 20)) as (b1, b2):
+ self.assertEquals(1, a1)
+ self.assertEquals(2, a2)
+ self.assertEquals(10, b1)
+ self.assertEquals(20, b2)