diff options
-rw-r--r-- | Demo/parser/unparse.py | 316 | ||||
-rw-r--r-- | Lib/test/contextmanager.py | 66 | ||||
-rw-r--r-- | Lib/test/nested.py | 80 | ||||
-rw-r--r-- | Lib/test/test_ast.py | 356 | ||||
-rw-r--r-- | Lib/test/test_with.py | 1120 |
5 files changed, 969 insertions, 969 deletions
diff --git a/Demo/parser/unparse.py b/Demo/parser/unparse.py index 53b57b3..72691b5 100644 --- a/Demo/parser/unparse.py +++ b/Demo/parser/unparse.py @@ -1,158 +1,158 @@ -"Usage: unparse.py <path to source file>"
-import sys
-
-class Unparser:
- """Methods in this class recursively traverse an AST and
- output source code for the abstract syntax; original formatting
- is disregarged. """
-
- def __init__(self, tree, file = sys.stdout):
- """Unparser(tree, file=sys.stdout) -> None.
- Print the source for tree to file."""
- self.f = file
- self._indent = 0
- self.dispatch(tree)
- self.f.flush()
-
- def fill(self, text = ""):
- "Indent a piece of text, according to the current indentation level"
- self.f.write("\n"+" "*self._indent + text)
-
- def write(self, text):
- "Append a piece of text to the current line."
- self.f.write(text)
-
- def enter(self):
- "Print ':', and increase the indentation."
- self.write(":")
- self._indent += 1
-
- def leave(self):
- "Decrease the indentation level."
- self._indent -= 1
-
- def dispatch(self, tree):
- "Dispatcher function, dispatching tree type T to method _T."
- if isinstance(tree, list):
- for t in tree:
- self.dispatch(t)
- return
- meth = getattr(self, "_"+tree.__class__.__name__)
- meth(tree)
-
-
- ############### Unparsing methods ######################
- # There should be one method per concrete grammar type #
- # Constructors should be grouped by sum type. Ideally, #
- # this would follow the order in the grammar, but #
- # currently doesn't. #
- ########################################################
-
- def _Module(self, tree):
- for stmt in tree.body:
- self.dispatch(stmt)
-
- # stmt
- def _Expr(self, tree):
- self.fill()
- self.dispatch(tree.value)
-
- def _Import(self, t):
- self.fill("import ")
- first = True
- for a in t.names:
- if first:
- first = False
- else:
- self.write(", ")
- self.write(a.name)
- if a.asname:
- self.write(" as "+a.asname)
-
- def _Assign(self, t):
- self.fill()
- for target in t.targets:
- self.dispatch(target)
- self.write(" = ")
- self.dispatch(t.value)
-
- def _ClassDef(self, t):
- self.write("\n")
- self.fill("class "+t.name)
- if t.bases:
- self.write("(")
- for a in t.bases:
- self.dispatch(a)
- self.write(", ")
- self.write(")")
- self.enter()
- self.dispatch(t.body)
- self.leave()
-
- def _FunctionDef(self, t):
- self.write("\n")
- self.fill("def "+t.name + "(")
- self.dispatch(t.args)
- self.enter()
- self.dispatch(t.body)
- self.leave()
-
- def _If(self, t):
- self.fill("if ")
- self.dispatch(t.test)
- self.enter()
- # XXX elif?
- self.dispatch(t.body)
- self.leave()
- if t.orelse:
- self.fill("else")
- self.enter()
- self.dispatch(t.orelse)
- self.leave()
-
- # expr
- def _Str(self, tree):
- self.write(repr(tree.s))
-
- def _Name(self, t):
- self.write(t.id)
-
- def _List(self, t):
- self.write("[")
- for e in t.elts:
- self.dispatch(e)
- self.write(", ")
- self.write("]")
-
- unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"}
- def _UnaryOp(self, t):
- self.write(self.unop[t.op.__class__.__name__])
- self.write("(")
- self.dispatch(t.operand)
- self.write(")")
-
- # others
- def _arguments(self, t):
- first = True
- # XXX t.defaults
- for a in t.args:
- if first:first = False
- else: self.write(", ")
- self.dispatch(a)
- if t.vararg:
- if first:first = False
- else: self.write(", ")
- self.write("*"+t.vararg)
- if t.kwarg:
- if first:first = False
- else: self.write(", ")
- self.write("**"+self.kwarg)
- self.write(")")
-
-def roundtrip(filename):
- source = open(filename).read()
- tree = compile(source, filename, "exec", 0x400)
- Unparser(tree)
-
-if __name__=='__main__':
- roundtrip(sys.argv[1])
+"Usage: unparse.py <path to source file>" +import sys + +class Unparser: + """Methods in this class recursively traverse an AST and + output source code for the abstract syntax; original formatting + is disregarged. """ + + def __init__(self, tree, file = sys.stdout): + """Unparser(tree, file=sys.stdout) -> None. + Print the source for tree to file.""" + self.f = file + self._indent = 0 + self.dispatch(tree) + self.f.flush() + + def fill(self, text = ""): + "Indent a piece of text, according to the current indentation level" + self.f.write("\n"+" "*self._indent + text) + + def write(self, text): + "Append a piece of text to the current line." + self.f.write(text) + + def enter(self): + "Print ':', and increase the indentation." + self.write(":") + self._indent += 1 + + def leave(self): + "Decrease the indentation level." + self._indent -= 1 + + def dispatch(self, tree): + "Dispatcher function, dispatching tree type T to method _T." + if isinstance(tree, list): + for t in tree: + self.dispatch(t) + return + meth = getattr(self, "_"+tree.__class__.__name__) + meth(tree) + + + ############### Unparsing methods ###################### + # There should be one method per concrete grammar type # + # Constructors should be grouped by sum type. Ideally, # + # this would follow the order in the grammar, but # + # currently doesn't. # + ######################################################## + + def _Module(self, tree): + for stmt in tree.body: + self.dispatch(stmt) + + # stmt + def _Expr(self, tree): + self.fill() + self.dispatch(tree.value) + + def _Import(self, t): + self.fill("import ") + first = True + for a in t.names: + if first: + first = False + else: + self.write(", ") + self.write(a.name) + if a.asname: + self.write(" as "+a.asname) + + def _Assign(self, t): + self.fill() + for target in t.targets: + self.dispatch(target) + self.write(" = ") + self.dispatch(t.value) + + def _ClassDef(self, t): + self.write("\n") + self.fill("class "+t.name) + if t.bases: + self.write("(") + for a in t.bases: + self.dispatch(a) + self.write(", ") + self.write(")") + self.enter() + self.dispatch(t.body) + self.leave() + + def _FunctionDef(self, t): + self.write("\n") + self.fill("def "+t.name + "(") + self.dispatch(t.args) + self.enter() + self.dispatch(t.body) + self.leave() + + def _If(self, t): + self.fill("if ") + self.dispatch(t.test) + self.enter() + # XXX elif? + self.dispatch(t.body) + self.leave() + if t.orelse: + self.fill("else") + self.enter() + self.dispatch(t.orelse) + self.leave() + + # expr + def _Str(self, tree): + self.write(repr(tree.s)) + + def _Name(self, t): + self.write(t.id) + + def _List(self, t): + self.write("[") + for e in t.elts: + self.dispatch(e) + self.write(", ") + self.write("]") + + unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"} + def _UnaryOp(self, t): + self.write(self.unop[t.op.__class__.__name__]) + self.write("(") + self.dispatch(t.operand) + self.write(")") + + # others + def _arguments(self, t): + first = True + # XXX t.defaults + for a in t.args: + if first:first = False + else: self.write(", ") + self.dispatch(a) + if t.vararg: + if first:first = False + else: self.write(", ") + self.write("*"+t.vararg) + if t.kwarg: + if first:first = False + else: self.write(", ") + self.write("**"+self.kwarg) + self.write(")") + +def roundtrip(filename): + source = open(filename).read() + tree = compile(source, filename, "exec", 0x400) + Unparser(tree) + +if __name__=='__main__': + roundtrip(sys.argv[1]) diff --git a/Lib/test/contextmanager.py b/Lib/test/contextmanager.py index e8b0894..07fe61c 100644 --- a/Lib/test/contextmanager.py +++ b/Lib/test/contextmanager.py @@ -1,33 +1,33 @@ -class GeneratorContextManager(object):
- def __init__(self, gen):
- self.gen = gen
-
- def __context__(self):
- return self
-
- def __enter__(self):
- try:
- return self.gen.next()
- except StopIteration:
- raise RuntimeError("generator didn't yield")
-
- def __exit__(self, type, value, traceback):
- if type is None:
- try:
- self.gen.next()
- except StopIteration:
- return
- else:
- raise RuntimeError("generator didn't stop")
- else:
- try:
- self.gen.throw(type, value, traceback)
- except (type, StopIteration):
- return
- else:
- raise RuntimeError("generator caught exception")
-
-def contextmanager(func):
- def helper(*args, **kwds):
- return GeneratorContextManager(func(*args, **kwds))
- return helper
+class GeneratorContextManager(object): + def __init__(self, gen): + self.gen = gen + + def __context__(self): + return self + + def __enter__(self): + try: + return self.gen.next() + except StopIteration: + raise RuntimeError("generator didn't yield") + + def __exit__(self, type, value, traceback): + if type is None: + try: + self.gen.next() + except StopIteration: + return + else: + raise RuntimeError("generator didn't stop") + else: + try: + self.gen.throw(type, value, traceback) + except (type, StopIteration): + return + else: + raise RuntimeError("generator caught exception") + +def contextmanager(func): + def helper(*args, **kwds): + return GeneratorContextManager(func(*args, **kwds)) + return helper diff --git a/Lib/test/nested.py b/Lib/test/nested.py index a20cf43..b5030e0 100644 --- a/Lib/test/nested.py +++ b/Lib/test/nested.py @@ -1,40 +1,40 @@ -import sys
-from collections import deque
-
-
-class nested(object):
- def __init__(self, *contexts):
- self.contexts = contexts
- self.entered = None
-
- def __context__(self):
- return self
-
- def __enter__(self):
- if self.entered is not None:
- raise RuntimeError("Context is not reentrant")
- self.entered = deque()
- vars = []
- try:
- for context in self.contexts:
- mgr = context.__context__()
- vars.append(mgr.__enter__())
- self.entered.appendleft(mgr)
- except:
- self.__exit__(*sys.exc_info())
- raise
- return vars
-
- def __exit__(self, *exc_info):
- # Behave like nested with statements
- # first in, last out
- # New exceptions override old ones
- ex = exc_info
- for mgr in self.entered:
- try:
- mgr.__exit__(*ex)
- except:
- ex = sys.exc_info()
- self.entered = None
- if ex is not exc_info:
- raise ex[0], ex[1], ex[2]
+import sys +from collections import deque + + +class nested(object): + def __init__(self, *contexts): + self.contexts = contexts + self.entered = None + + def __context__(self): + return self + + def __enter__(self): + if self.entered is not None: + raise RuntimeError("Context is not reentrant") + self.entered = deque() + vars = [] + try: + for context in self.contexts: + mgr = context.__context__() + vars.append(mgr.__enter__()) + self.entered.appendleft(mgr) + except: + self.__exit__(*sys.exc_info()) + raise + return vars + + def __exit__(self, *exc_info): + # Behave like nested with statements + # first in, last out + # New exceptions override old ones + ex = exc_info + for mgr in self.entered: + try: + mgr.__exit__(*ex) + except: + ex = sys.exc_info() + self.entered = None + if ex is not exc_info: + raise ex[0], ex[1], ex[2] diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index f83dc92..82bb140 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,178 +1,178 @@ -import sys, itertools
-
-def to_tuple(t):
- if t is None or isinstance(t, (basestring, int, long, complex)):
- return t
- elif isinstance(t, list):
- return [to_tuple(e) for e in t]
- result = [t.__class__.__name__]
- if t._fields is None:
- return tuple(result)
- for f in t._fields:
- result.append(to_tuple(getattr(t, f)))
- return tuple(result)
-
-# These tests are compiled through "exec"
-# There should be atleast one test per statement
-exec_tests = [
- # FunctionDef
- "def f(): pass",
- # ClassDef
- "class C:pass",
- # Return
- "def f():return 1",
- # Delete
- "del v",
- # Assign
- "v = 1",
- # AugAssign
- "v += 1",
- # Print
- "print >>f, 1, ",
- # For
- "for v in v:pass",
- # While
- "while v:pass",
- # If
- "if v:pass",
- # Raise
- "raise Exception, 'string'",
- # TryExcept
- "try:\n pass\nexcept Exception:\n pass",
- # TryFinally
- "try:\n pass\nfinally:\n pass",
- # Assert
- "assert v",
- # Import
- "import sys",
- # ImportFrom
- "from sys import v",
- # Exec
- "exec 'v'",
- # Global
- "global v",
- # Expr
- "1",
- # Pass,
- "pass",
- # Break
- "break",
- # Continue
- "continue",
-]
-
-# These are compiled through "single"
-# because of overlap with "eval", it just tests what
-# can't be tested with "eval"
-single_tests = [
- "1+2"
-]
-
-# These are compiled through "eval"
-# It should test all expressions
-eval_tests = [
- # BoolOp
- "a and b",
- # BinOp
- "a + b",
- # UnaryOp
- "not v",
- # Lambda
- "lambda:None",
- # Dict
- "{ 1:2 }",
- # ListComp
- "[a for b in c if d]",
- # GeneratorExp
- "(a for b in c if d)",
- # Yield - yield expressions can't work outside a function
- #
- # Compare
- "1 < 2 < 3",
- # Call
- "f(1,2,c=3,*d,**e)",
- # Repr
- "`v`",
- # Num
- "10L",
- # Str
- "'string'",
- # Attribute
- "a.b",
- # Subscript
- "a[b:c]",
- # Name
- "v",
- # List
- "[1,2,3]",
- # Tuple
- "1,2,3"
-]
-
-# TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension
-# excepthandler, arguments, keywords, alias
-
-if __name__=='__main__' and sys.argv[1:] == ['-g']:
- for statements, kind in ((exec_tests, "exec"), (single_tests, "single"), (eval_tests, "eval")):
- print kind+"_results = ["
- for s in statements:
- print repr(to_tuple(compile(s, "?", kind, 0x400)))+","
- print "]"
- print "run_tests()"
- raise SystemExit
-
-def run_tests():
- for input, output, kind in ((exec_tests, exec_results, "exec"),
- (single_tests, single_results, "single"),
- (eval_tests, eval_results, "eval")):
- for i, o in itertools.izip(input, output):
- assert to_tuple(compile(i, "?", kind, 0x400)) == o
-
-#### EVERYTHING BELOW IS GENERATED #####
-exec_results = [
-('Module', [('FunctionDef', 'f', ('arguments', [], None, None, []), [('Pass',)], [])]),
-('Module', [('ClassDef', 'C', [], [('Pass',)])]),
-('Module', [('FunctionDef', 'f', ('arguments', [], None, None, []), [('Return', ('Num', 1))], [])]),
-('Module', [('Delete', [('Name', 'v', ('Del',))])]),
-('Module', [('Assign', [('Name', 'v', ('Store',))], ('Num', 1))]),
-('Module', [('AugAssign', ('Name', 'v', ('Load',)), ('Add',), ('Num', 1))]),
-('Module', [('Print', ('Name', 'f', ('Load',)), [('Num', 1)], False)]),
-('Module', [('For', ('Name', 'v', ('Store',)), ('Name', 'v', ('Load',)), [('Pass',)], [])]),
-('Module', [('While', ('Name', 'v', ('Load',)), [('Pass',)], [])]),
-('Module', [('If', ('Name', 'v', ('Load',)), [('Pass',)], [])]),
-('Module', [('Raise', ('Name', 'Exception', ('Load',)), ('Str', 'string'), None)]),
-('Module', [('TryExcept', [('Pass',)], [('excepthandler', ('Name', 'Exception', ('Load',)), None, [('Pass',)])], [])]),
-('Module', [('TryFinally', [('Pass',)], [('Pass',)])]),
-('Module', [('Assert', ('Name', 'v', ('Load',)), None)]),
-('Module', [('Import', [('alias', 'sys', None)])]),
-('Module', [('ImportFrom', 'sys', [('alias', 'v', None)], 0)]),
-('Module', [('Exec', ('Str', 'v'), None, None)]),
-('Module', [('Global', ['v'])]),
-('Module', [('Expr', ('Num', 1))]),
-('Module', [('Pass',)]),
-('Module', [('Break',)]),
-('Module', [('Continue',)]),
-]
-single_results = [
-('Interactive', [('Expr', ('BinOp', ('Num', 1), ('Add',), ('Num', 2)))]),
-]
-eval_results = [
-('Expression', ('BoolOp', ('And',), [('Name', 'a', ('Load',)), ('Name', 'b', ('Load',))])),
-('Expression', ('BinOp', ('Name', 'a', ('Load',)), ('Add',), ('Name', 'b', ('Load',)))),
-('Expression', ('UnaryOp', ('Not',), ('Name', 'v', ('Load',)))),
-('Expression', ('Lambda', ('arguments', [], None, None, []), ('Name', 'None', ('Load',)))),
-('Expression', ('Dict', [('Num', 1)], [('Num', 2)])),
-('Expression', ('ListComp', ('Name', 'a', ('Load',)), [('comprehension', ('Name', 'b', ('Store',)), ('Name', 'c', ('Load',)), [('Name', 'd', ('Load',))])])),
-('Expression', ('GeneratorExp', ('Name', 'a', ('Load',)), [('comprehension', ('Name', 'b', ('Store',)), ('Name', 'c', ('Load',)), [('Name', 'd', ('Load',))])])),
-('Expression', ('Compare', ('Num', 1), [('Lt',), ('Lt',)], [('Num', 2), ('Num', 3)])),
-('Expression', ('Call', ('Name', 'f', ('Load',)), [('Num', 1), ('Num', 2)], [('keyword', 'c', ('Num', 3))], ('Name', 'd', ('Load',)), ('Name', 'e', ('Load',)))),
-('Expression', ('Repr', ('Name', 'v', ('Load',)))),
-('Expression', ('Num', 10L)),
-('Expression', ('Str', 'string')),
-('Expression', ('Attribute', ('Name', 'a', ('Load',)), 'b', ('Load',))),
-('Expression', ('Subscript', ('Name', 'a', ('Load',)), ('Slice', ('Name', 'b', ('Load',)), ('Name', 'c', ('Load',)), None), ('Load',))),
-('Expression', ('Name', 'v', ('Load',))),
-('Expression', ('List', [('Num', 1), ('Num', 2), ('Num', 3)], ('Load',))),
-('Expression', ('Tuple', [('Num', 1), ('Num', 2), ('Num', 3)], ('Load',))),
-]
-run_tests()
+import sys, itertools + +def to_tuple(t): + if t is None or isinstance(t, (basestring, int, long, complex)): + return t + elif isinstance(t, list): + return [to_tuple(e) for e in t] + result = [t.__class__.__name__] + if t._fields is None: + return tuple(result) + for f in t._fields: + result.append(to_tuple(getattr(t, f))) + return tuple(result) + +# These tests are compiled through "exec" +# There should be atleast one test per statement +exec_tests = [ + # FunctionDef + "def f(): pass", + # ClassDef + "class C:pass", + # Return + "def f():return 1", + # Delete + "del v", + # Assign + "v = 1", + # AugAssign + "v += 1", + # Print + "print >>f, 1, ", + # For + "for v in v:pass", + # While + "while v:pass", + # If + "if v:pass", + # Raise + "raise Exception, 'string'", + # TryExcept + "try:\n pass\nexcept Exception:\n pass", + # TryFinally + "try:\n pass\nfinally:\n pass", + # Assert + "assert v", + # Import + "import sys", + # ImportFrom + "from sys import v", + # Exec + "exec 'v'", + # Global + "global v", + # Expr + "1", + # Pass, + "pass", + # Break + "break", + # Continue + "continue", +] + +# These are compiled through "single" +# because of overlap with "eval", it just tests what +# can't be tested with "eval" +single_tests = [ + "1+2" +] + +# These are compiled through "eval" +# It should test all expressions +eval_tests = [ + # BoolOp + "a and b", + # BinOp + "a + b", + # UnaryOp + "not v", + # Lambda + "lambda:None", + # Dict + "{ 1:2 }", + # ListComp + "[a for b in c if d]", + # GeneratorExp + "(a for b in c if d)", + # Yield - yield expressions can't work outside a function + # + # Compare + "1 < 2 < 3", + # Call + "f(1,2,c=3,*d,**e)", + # Repr + "`v`", + # Num + "10L", + # Str + "'string'", + # Attribute + "a.b", + # Subscript + "a[b:c]", + # Name + "v", + # List + "[1,2,3]", + # Tuple + "1,2,3" +] + +# TODO: expr_context, slice, boolop, operator, unaryop, cmpop, comprehension +# excepthandler, arguments, keywords, alias + +if __name__=='__main__' and sys.argv[1:] == ['-g']: + for statements, kind in ((exec_tests, "exec"), (single_tests, "single"), (eval_tests, "eval")): + print kind+"_results = [" + for s in statements: + print repr(to_tuple(compile(s, "?", kind, 0x400)))+"," + print "]" + print "run_tests()" + raise SystemExit + +def run_tests(): + for input, output, kind in ((exec_tests, exec_results, "exec"), + (single_tests, single_results, "single"), + (eval_tests, eval_results, "eval")): + for i, o in itertools.izip(input, output): + assert to_tuple(compile(i, "?", kind, 0x400)) == o + +#### EVERYTHING BELOW IS GENERATED ##### +exec_results = [ +('Module', [('FunctionDef', 'f', ('arguments', [], None, None, []), [('Pass',)], [])]), +('Module', [('ClassDef', 'C', [], [('Pass',)])]), +('Module', [('FunctionDef', 'f', ('arguments', [], None, None, []), [('Return', ('Num', 1))], [])]), +('Module', [('Delete', [('Name', 'v', ('Del',))])]), +('Module', [('Assign', [('Name', 'v', ('Store',))], ('Num', 1))]), +('Module', [('AugAssign', ('Name', 'v', ('Load',)), ('Add',), ('Num', 1))]), +('Module', [('Print', ('Name', 'f', ('Load',)), [('Num', 1)], False)]), +('Module', [('For', ('Name', 'v', ('Store',)), ('Name', 'v', ('Load',)), [('Pass',)], [])]), +('Module', [('While', ('Name', 'v', ('Load',)), [('Pass',)], [])]), +('Module', [('If', ('Name', 'v', ('Load',)), [('Pass',)], [])]), +('Module', [('Raise', ('Name', 'Exception', ('Load',)), ('Str', 'string'), None)]), +('Module', [('TryExcept', [('Pass',)], [('excepthandler', ('Name', 'Exception', ('Load',)), None, [('Pass',)])], [])]), +('Module', [('TryFinally', [('Pass',)], [('Pass',)])]), +('Module', [('Assert', ('Name', 'v', ('Load',)), None)]), +('Module', [('Import', [('alias', 'sys', None)])]), +('Module', [('ImportFrom', 'sys', [('alias', 'v', None)], 0)]), +('Module', [('Exec', ('Str', 'v'), None, None)]), +('Module', [('Global', ['v'])]), +('Module', [('Expr', ('Num', 1))]), +('Module', [('Pass',)]), +('Module', [('Break',)]), +('Module', [('Continue',)]), +] +single_results = [ +('Interactive', [('Expr', ('BinOp', ('Num', 1), ('Add',), ('Num', 2)))]), +] +eval_results = [ +('Expression', ('BoolOp', ('And',), [('Name', 'a', ('Load',)), ('Name', 'b', ('Load',))])), +('Expression', ('BinOp', ('Name', 'a', ('Load',)), ('Add',), ('Name', 'b', ('Load',)))), +('Expression', ('UnaryOp', ('Not',), ('Name', 'v', ('Load',)))), +('Expression', ('Lambda', ('arguments', [], None, None, []), ('Name', 'None', ('Load',)))), +('Expression', ('Dict', [('Num', 1)], [('Num', 2)])), +('Expression', ('ListComp', ('Name', 'a', ('Load',)), [('comprehension', ('Name', 'b', ('Store',)), ('Name', 'c', ('Load',)), [('Name', 'd', ('Load',))])])), +('Expression', ('GeneratorExp', ('Name', 'a', ('Load',)), [('comprehension', ('Name', 'b', ('Store',)), ('Name', 'c', ('Load',)), [('Name', 'd', ('Load',))])])), +('Expression', ('Compare', ('Num', 1), [('Lt',), ('Lt',)], [('Num', 2), ('Num', 3)])), +('Expression', ('Call', ('Name', 'f', ('Load',)), [('Num', 1), ('Num', 2)], [('keyword', 'c', ('Num', 3))], ('Name', 'd', ('Load',)), ('Name', 'e', ('Load',)))), +('Expression', ('Repr', ('Name', 'v', ('Load',)))), +('Expression', ('Num', 10L)), +('Expression', ('Str', 'string')), +('Expression', ('Attribute', ('Name', 'a', ('Load',)), 'b', ('Load',))), +('Expression', ('Subscript', ('Name', 'a', ('Load',)), ('Slice', ('Name', 'b', ('Load',)), ('Name', 'c', ('Load',)), None), ('Load',))), +('Expression', ('Name', 'v', ('Load',))), +('Expression', ('List', [('Num', 1), ('Num', 2), ('Num', 3)], ('Load',))), +('Expression', ('Tuple', [('Num', 1), ('Num', 2), ('Num', 3)], ('Load',))), +] +run_tests() diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index 3f32830..8423ee1 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -1,560 +1,560 @@ -#!/usr/bin/env python
-
-"""Unit tests for the with statement specified in PEP 343."""
-
-__author__ = "Mike Bland"
-__email__ = "mbland at acm dot org"
-
-import unittest
-from test.contextmanager import GeneratorContextManager
-from test.nested import nested
-from test.test_support import run_unittest
-
-
-class MockContextManager(GeneratorContextManager):
- def __init__(self, gen):
- GeneratorContextManager.__init__(self, gen)
- self.context_called = False
- self.enter_called = False
- self.exit_called = False
- self.exit_args = None
-
- def __context__(self):
- self.context_called = True
- return GeneratorContextManager.__context__(self)
-
- def __enter__(self):
- self.enter_called = True
- return GeneratorContextManager.__enter__(self)
-
- def __exit__(self, type, value, traceback):
- self.exit_called = True
- self.exit_args = (type, value, traceback)
- return GeneratorContextManager.__exit__(self, type, value, traceback)
-
-
-def mock_contextmanager(func):
- def helper(*args, **kwds):
- return MockContextManager(func(*args, **kwds))
- return helper
-
-
-class MockResource(object):
- def __init__(self):
- self.yielded = False
- self.stopped = False
-
-
-@mock_contextmanager
-def mock_contextmanager_generator():
- mock = MockResource()
- try:
- mock.yielded = True
- yield mock
- finally:
- mock.stopped = True
-
-
-class MockNested(nested):
- def __init__(self, *contexts):
- nested.__init__(self, *contexts)
- self.context_called = False
- self.enter_called = False
- self.exit_called = False
- self.exit_args = None
-
- def __context__(self):
- self.context_called = True
- return nested.__context__(self)
-
- def __enter__(self):
- self.enter_called = True
- return nested.__enter__(self)
-
- def __exit__(self, *exc_info):
- self.exit_called = True
- self.exit_args = exc_info
- return nested.__exit__(self, *exc_info)
-
-
-class FailureTestCase(unittest.TestCase):
- def testNameError(self):
- def fooNotDeclared():
- with foo: pass
- self.assertRaises(NameError, fooNotDeclared)
-
- def testContextAttributeError(self):
- class LacksContext(object):
- def __enter__(self):
- pass
-
- def __exit__(self, type, value, traceback):
- pass
-
- def fooLacksContext():
- foo = LacksContext()
- with foo: pass
- self.assertRaises(AttributeError, fooLacksContext)
-
- def testEnterAttributeError(self):
- class LacksEnter(object):
- def __context__(self):
- pass
-
- def __exit__(self, type, value, traceback):
- pass
-
- def fooLacksEnter():
- foo = LacksEnter()
- with foo: pass
- self.assertRaises(AttributeError, fooLacksEnter)
-
- def testExitAttributeError(self):
- class LacksExit(object):
- def __context__(self):
- pass
-
- def __enter__(self):
- pass
-
- def fooLacksExit():
- foo = LacksExit()
- with foo: pass
- self.assertRaises(AttributeError, fooLacksExit)
-
- def assertRaisesSyntaxError(self, codestr):
- def shouldRaiseSyntaxError(s):
- compile(s, '', 'single')
- self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr)
-
- def testAssignmentToNoneError(self):
- self.assertRaisesSyntaxError('with mock as None:\n pass')
- self.assertRaisesSyntaxError(
- 'with mock as (None):\n'
- ' pass')
-
- def testAssignmentToEmptyTupleError(self):
- self.assertRaisesSyntaxError(
- 'with mock as ():\n'
- ' pass')
-
- def testAssignmentToTupleOnlyContainingNoneError(self):
- self.assertRaisesSyntaxError('with mock as None,:\n pass')
- self.assertRaisesSyntaxError(
- 'with mock as (None,):\n'
- ' pass')
-
- def testAssignmentToTupleContainingNoneError(self):
- self.assertRaisesSyntaxError(
- 'with mock as (foo, None, bar):\n'
- ' pass')
-
- def testContextThrows(self):
- class ContextThrows(object):
- def __context__(self):
- raise RuntimeError("Context threw")
-
- def shouldThrow():
- ct = ContextThrows()
- self.foo = None
- with ct as self.foo:
- pass
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertEqual(self.foo, None)
-
- def testEnterThrows(self):
- class EnterThrows(object):
- def __context__(self):
- return self
-
- def __enter__(self):
- raise RuntimeError("Context threw")
-
- def __exit__(self, *args):
- pass
-
- def shouldThrow():
- ct = EnterThrows()
- self.foo = None
- with ct as self.foo:
- pass
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertEqual(self.foo, None)
-
- def testExitThrows(self):
- class ExitThrows(object):
- def __context__(self):
- return self
- def __enter__(self):
- return
- def __exit__(self, *args):
- raise RuntimeError(42)
- def shouldThrow():
- with ExitThrows():
- pass
- self.assertRaises(RuntimeError, shouldThrow)
-
-class ContextmanagerAssertionMixin(object):
- TEST_EXCEPTION = RuntimeError("test exception")
-
- def assertInWithManagerInvariants(self, mock_manager):
- self.assertTrue(mock_manager.context_called)
- self.assertTrue(mock_manager.enter_called)
- self.assertFalse(mock_manager.exit_called)
- self.assertEqual(mock_manager.exit_args, None)
-
- def assertAfterWithManagerInvariants(self, mock_manager, exit_args):
- self.assertTrue(mock_manager.context_called)
- self.assertTrue(mock_manager.enter_called)
- self.assertTrue(mock_manager.exit_called)
- self.assertEqual(mock_manager.exit_args, exit_args)
-
- def assertAfterWithManagerInvariantsNoError(self, mock_manager):
- self.assertAfterWithManagerInvariants(mock_manager,
- (None, None, None))
-
- def assertInWithGeneratorInvariants(self, mock_generator):
- self.assertTrue(mock_generator.yielded)
- self.assertFalse(mock_generator.stopped)
-
- def assertAfterWithGeneratorInvariantsNoError(self, mock_generator):
- self.assertTrue(mock_generator.yielded)
- self.assertTrue(mock_generator.stopped)
-
- def raiseTestException(self):
- raise self.TEST_EXCEPTION
-
- def assertAfterWithManagerInvariantsWithError(self, mock_manager):
- self.assertTrue(mock_manager.context_called)
- self.assertTrue(mock_manager.enter_called)
- self.assertTrue(mock_manager.exit_called)
- self.assertEqual(mock_manager.exit_args[0], RuntimeError)
- self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION)
-
- def assertAfterWithGeneratorInvariantsWithError(self, mock_generator):
- self.assertTrue(mock_generator.yielded)
- self.assertTrue(mock_generator.stopped)
-
-
-class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
- def testInlineGeneratorSyntax(self):
- with mock_contextmanager_generator():
- pass
-
- def testUnboundGenerator(self):
- mock = mock_contextmanager_generator()
- with mock:
- pass
- self.assertAfterWithManagerInvariantsNoError(mock)
-
- def testInlineGeneratorBoundSyntax(self):
- with mock_contextmanager_generator() as foo:
- self.assertInWithGeneratorInvariants(foo)
- # FIXME: In the future, we'll try to keep the bound names from leaking
- self.assertAfterWithGeneratorInvariantsNoError(foo)
-
- def testInlineGeneratorBoundToExistingVariable(self):
- foo = None
- with mock_contextmanager_generator() as foo:
- self.assertInWithGeneratorInvariants(foo)
- self.assertAfterWithGeneratorInvariantsNoError(foo)
-
- def testInlineGeneratorBoundToDottedVariable(self):
- with mock_contextmanager_generator() as self.foo:
- self.assertInWithGeneratorInvariants(self.foo)
- self.assertAfterWithGeneratorInvariantsNoError(self.foo)
-
- def testBoundGenerator(self):
- mock = mock_contextmanager_generator()
- with mock as foo:
- self.assertInWithGeneratorInvariants(foo)
- self.assertInWithManagerInvariants(mock)
- self.assertAfterWithGeneratorInvariantsNoError(foo)
- self.assertAfterWithManagerInvariantsNoError(mock)
-
- def testNestedSingleStatements(self):
- mock_a = mock_contextmanager_generator()
- with mock_a as foo:
- mock_b = mock_contextmanager_generator()
- with mock_b as bar:
- self.assertInWithManagerInvariants(mock_a)
- self.assertInWithManagerInvariants(mock_b)
- self.assertInWithGeneratorInvariants(foo)
- self.assertInWithGeneratorInvariants(bar)
- self.assertAfterWithManagerInvariantsNoError(mock_b)
- self.assertAfterWithGeneratorInvariantsNoError(bar)
- self.assertInWithManagerInvariants(mock_a)
- self.assertInWithGeneratorInvariants(foo)
- self.assertAfterWithManagerInvariantsNoError(mock_a)
- self.assertAfterWithGeneratorInvariantsNoError(foo)
-
-
-class NestedNonexceptionalTestCase(unittest.TestCase,
- ContextmanagerAssertionMixin):
- def testSingleArgInlineGeneratorSyntax(self):
- with nested(mock_contextmanager_generator()):
- pass
-
- def testSingleArgUnbound(self):
- mock_contextmanager = mock_contextmanager_generator()
- mock_nested = MockNested(mock_contextmanager)
- with mock_nested:
- self.assertInWithManagerInvariants(mock_contextmanager)
- self.assertInWithManagerInvariants(mock_nested)
- self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
- self.assertAfterWithManagerInvariantsNoError(mock_nested)
-
- def testSingleArgBoundToNonTuple(self):
- m = mock_contextmanager_generator()
- # This will bind all the arguments to nested() into a single list
- # assigned to foo.
- with nested(m) as foo:
- self.assertInWithManagerInvariants(m)
- self.assertAfterWithManagerInvariantsNoError(m)
-
- def testSingleArgBoundToSingleElementParenthesizedList(self):
- m = mock_contextmanager_generator()
- # This will bind all the arguments to nested() into a single list
- # assigned to foo.
- # FIXME: what should this do: with nested(m) as (foo,):
- with nested(m) as (foo):
- self.assertInWithManagerInvariants(m)
- self.assertAfterWithManagerInvariantsNoError(m)
-
- def testSingleArgBoundToMultipleElementTupleError(self):
- def shouldThrowValueError():
- with nested(mock_contextmanager_generator()) as (foo, bar):
- pass
- self.assertRaises(ValueError, shouldThrowValueError)
-
- def testSingleArgUnbound(self):
- mock_contextmanager = mock_contextmanager_generator()
- mock_nested = MockNested(mock_contextmanager)
- with mock_nested:
- self.assertInWithManagerInvariants(mock_contextmanager)
- self.assertInWithManagerInvariants(mock_nested)
- self.assertAfterWithManagerInvariantsNoError(mock_contextmanager)
- self.assertAfterWithManagerInvariantsNoError(mock_nested)
-
- def testMultipleArgUnbound(self):
- m = mock_contextmanager_generator()
- n = mock_contextmanager_generator()
- o = mock_contextmanager_generator()
- mock_nested = MockNested(m, n, o)
- with mock_nested:
- self.assertInWithManagerInvariants(m)
- self.assertInWithManagerInvariants(n)
- self.assertInWithManagerInvariants(o)
- self.assertInWithManagerInvariants(mock_nested)
- self.assertAfterWithManagerInvariantsNoError(m)
- self.assertAfterWithManagerInvariantsNoError(n)
- self.assertAfterWithManagerInvariantsNoError(o)
- self.assertAfterWithManagerInvariantsNoError(mock_nested)
-
- def testMultipleArgBound(self):
- mock_nested = MockNested(mock_contextmanager_generator(),
- mock_contextmanager_generator(), mock_contextmanager_generator())
- with mock_nested as (m, n, o):
- self.assertInWithGeneratorInvariants(m)
- self.assertInWithGeneratorInvariants(n)
- self.assertInWithGeneratorInvariants(o)
- self.assertInWithManagerInvariants(mock_nested)
- self.assertAfterWithGeneratorInvariantsNoError(m)
- self.assertAfterWithGeneratorInvariantsNoError(n)
- self.assertAfterWithGeneratorInvariantsNoError(o)
- self.assertAfterWithManagerInvariantsNoError(mock_nested)
-
-
-class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin):
- def testSingleResource(self):
- cm = mock_contextmanager_generator()
- def shouldThrow():
- with cm as self.resource:
- self.assertInWithManagerInvariants(cm)
- self.assertInWithGeneratorInvariants(self.resource)
- self.raiseTestException()
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertAfterWithManagerInvariantsWithError(cm)
- self.assertAfterWithGeneratorInvariantsWithError(self.resource)
-
- def testNestedSingleStatements(self):
- mock_a = mock_contextmanager_generator()
- mock_b = mock_contextmanager_generator()
- def shouldThrow():
- with mock_a as self.foo:
- with mock_b as self.bar:
- self.assertInWithManagerInvariants(mock_a)
- self.assertInWithManagerInvariants(mock_b)
- self.assertInWithGeneratorInvariants(self.foo)
- self.assertInWithGeneratorInvariants(self.bar)
- self.raiseTestException()
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertAfterWithManagerInvariantsWithError(mock_a)
- self.assertAfterWithManagerInvariantsWithError(mock_b)
- self.assertAfterWithGeneratorInvariantsWithError(self.foo)
- self.assertAfterWithGeneratorInvariantsWithError(self.bar)
-
- def testMultipleResourcesInSingleStatement(self):
- cm_a = mock_contextmanager_generator()
- cm_b = mock_contextmanager_generator()
- mock_nested = MockNested(cm_a, cm_b)
- def shouldThrow():
- with mock_nested as (self.resource_a, self.resource_b):
- self.assertInWithManagerInvariants(cm_a)
- self.assertInWithManagerInvariants(cm_b)
- self.assertInWithManagerInvariants(mock_nested)
- self.assertInWithGeneratorInvariants(self.resource_a)
- self.assertInWithGeneratorInvariants(self.resource_b)
- self.raiseTestException()
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertAfterWithManagerInvariantsWithError(cm_a)
- self.assertAfterWithManagerInvariantsWithError(cm_b)
- self.assertAfterWithManagerInvariantsWithError(mock_nested)
- self.assertAfterWithGeneratorInvariantsWithError(self.resource_a)
- self.assertAfterWithGeneratorInvariantsWithError(self.resource_b)
-
- def testNestedExceptionBeforeInnerStatement(self):
- mock_a = mock_contextmanager_generator()
- mock_b = mock_contextmanager_generator()
- self.bar = None
- def shouldThrow():
- with mock_a as self.foo:
- self.assertInWithManagerInvariants(mock_a)
- self.assertInWithGeneratorInvariants(self.foo)
- self.raiseTestException()
- with mock_b as self.bar:
- pass
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertAfterWithManagerInvariantsWithError(mock_a)
- self.assertAfterWithGeneratorInvariantsWithError(self.foo)
-
- # The inner statement stuff should never have been touched
- self.assertEqual(self.bar, None)
- self.assertFalse(mock_b.context_called)
- self.assertFalse(mock_b.enter_called)
- self.assertFalse(mock_b.exit_called)
- self.assertEqual(mock_b.exit_args, None)
-
- def testNestedExceptionAfterInnerStatement(self):
- mock_a = mock_contextmanager_generator()
- mock_b = mock_contextmanager_generator()
- def shouldThrow():
- with mock_a as self.foo:
- with mock_b as self.bar:
- self.assertInWithManagerInvariants(mock_a)
- self.assertInWithManagerInvariants(mock_b)
- self.assertInWithGeneratorInvariants(self.foo)
- self.assertInWithGeneratorInvariants(self.bar)
- self.raiseTestException()
- self.assertRaises(RuntimeError, shouldThrow)
- self.assertAfterWithManagerInvariantsWithError(mock_a)
- self.assertAfterWithManagerInvariantsNoError(mock_b)
- self.assertAfterWithGeneratorInvariantsWithError(self.foo)
- self.assertAfterWithGeneratorInvariantsNoError(self.bar)
-
-
-class NonLocalFlowControlTestCase(unittest.TestCase):
-
- def testWithBreak(self):
- counter = 0
- while True:
- counter += 1
- with mock_contextmanager_generator():
- counter += 10
- break
- counter += 100 # Not reached
- self.assertEqual(counter, 11)
-
- def testWithContinue(self):
- counter = 0
- while True:
- counter += 1
- if counter > 2:
- break
- with mock_contextmanager_generator():
- counter += 10
- continue
- counter += 100 # Not reached
- self.assertEqual(counter, 12)
-
- def testWithReturn(self):
- def foo():
- counter = 0
- while True:
- counter += 1
- with mock_contextmanager_generator():
- counter += 10
- return counter
- counter += 100 # Not reached
- self.assertEqual(foo(), 11)
-
- def testWithYield(self):
- def gen():
- with mock_contextmanager_generator():
- yield 12
- yield 13
- x = list(gen())
- self.assertEqual(x, [12, 13])
-
- def testWithRaise(self):
- counter = 0
- try:
- counter += 1
- with mock_contextmanager_generator():
- counter += 10
- raise RuntimeError
- counter += 100 # Not reached
- except RuntimeError:
- self.assertEqual(counter, 11)
- else:
- self.fail("Didn't raise RuntimeError")
-
-
-class AssignmentTargetTestCase(unittest.TestCase):
-
- def testSingleComplexTarget(self):
- targets = {1: [0, 1, 2]}
- with mock_contextmanager_generator() as targets[1][0]:
- self.assertEqual(targets.keys(), [1])
- self.assertEqual(targets[1][0].__class__, MockResource)
- with mock_contextmanager_generator() as targets.values()[0][1]:
- self.assertEqual(targets.keys(), [1])
- self.assertEqual(targets[1][1].__class__, MockResource)
- with mock_contextmanager_generator() as targets[2]:
- keys = targets.keys()
- keys.sort()
- self.assertEqual(keys, [1, 2])
- class C: pass
- blah = C()
- with mock_contextmanager_generator() as blah.foo:
- self.assertEqual(hasattr(blah, "foo"), True)
-
- def testMultipleComplexTargets(self):
- class C:
- def __context__(self): return self
- def __enter__(self): return 1, 2, 3
- def __exit__(self, *a): pass
- targets = {1: [0, 1, 2]}
- with C() as (targets[1][0], targets[1][1], targets[1][2]):
- self.assertEqual(targets, {1: [1, 2, 3]})
- with C() as (targets.values()[0][2], targets.values()[0][1], targets.values()[0][0]):
- self.assertEqual(targets, {1: [3, 2, 1]})
- with C() as (targets[1], targets[2], targets[3]):
- self.assertEqual(targets, {1: 1, 2: 2, 3: 3})
- class B: pass
- blah = B()
- with C() as (blah.one, blah.two, blah.three):
- self.assertEqual(blah.one, 1)
- self.assertEqual(blah.two, 2)
- self.assertEqual(blah.three, 3)
-
-
-def test_main():
- run_unittest(FailureTestCase, NonexceptionalTestCase,
- NestedNonexceptionalTestCase, ExceptionalTestCase,
- NonLocalFlowControlTestCase,
- AssignmentTargetTestCase)
-
-
-if __name__ == '__main__':
- test_main()
+#!/usr/bin/env python + +"""Unit tests for the with statement specified in PEP 343.""" + +__author__ = "Mike Bland" +__email__ = "mbland at acm dot org" + +import unittest +from test.contextmanager import GeneratorContextManager +from test.nested import nested +from test.test_support import run_unittest + + +class MockContextManager(GeneratorContextManager): + def __init__(self, gen): + GeneratorContextManager.__init__(self, gen) + self.context_called = False + self.enter_called = False + self.exit_called = False + self.exit_args = None + + def __context__(self): + self.context_called = True + return GeneratorContextManager.__context__(self) + + def __enter__(self): + self.enter_called = True + return GeneratorContextManager.__enter__(self) + + def __exit__(self, type, value, traceback): + self.exit_called = True + self.exit_args = (type, value, traceback) + return GeneratorContextManager.__exit__(self, type, value, traceback) + + +def mock_contextmanager(func): + def helper(*args, **kwds): + return MockContextManager(func(*args, **kwds)) + return helper + + +class MockResource(object): + def __init__(self): + self.yielded = False + self.stopped = False + + +@mock_contextmanager +def mock_contextmanager_generator(): + mock = MockResource() + try: + mock.yielded = True + yield mock + finally: + mock.stopped = True + + +class MockNested(nested): + def __init__(self, *contexts): + nested.__init__(self, *contexts) + self.context_called = False + self.enter_called = False + self.exit_called = False + self.exit_args = None + + def __context__(self): + self.context_called = True + return nested.__context__(self) + + def __enter__(self): + self.enter_called = True + return nested.__enter__(self) + + def __exit__(self, *exc_info): + self.exit_called = True + self.exit_args = exc_info + return nested.__exit__(self, *exc_info) + + +class FailureTestCase(unittest.TestCase): + def testNameError(self): + def fooNotDeclared(): + with foo: pass + self.assertRaises(NameError, fooNotDeclared) + + def testContextAttributeError(self): + class LacksContext(object): + def __enter__(self): + pass + + def __exit__(self, type, value, traceback): + pass + + def fooLacksContext(): + foo = LacksContext() + with foo: pass + self.assertRaises(AttributeError, fooLacksContext) + + def testEnterAttributeError(self): + class LacksEnter(object): + def __context__(self): + pass + + def __exit__(self, type, value, traceback): + pass + + def fooLacksEnter(): + foo = LacksEnter() + with foo: pass + self.assertRaises(AttributeError, fooLacksEnter) + + def testExitAttributeError(self): + class LacksExit(object): + def __context__(self): + pass + + def __enter__(self): + pass + + def fooLacksExit(): + foo = LacksExit() + with foo: pass + self.assertRaises(AttributeError, fooLacksExit) + + def assertRaisesSyntaxError(self, codestr): + def shouldRaiseSyntaxError(s): + compile(s, '', 'single') + self.assertRaises(SyntaxError, shouldRaiseSyntaxError, codestr) + + def testAssignmentToNoneError(self): + self.assertRaisesSyntaxError('with mock as None:\n pass') + self.assertRaisesSyntaxError( + 'with mock as (None):\n' + ' pass') + + def testAssignmentToEmptyTupleError(self): + self.assertRaisesSyntaxError( + 'with mock as ():\n' + ' pass') + + def testAssignmentToTupleOnlyContainingNoneError(self): + self.assertRaisesSyntaxError('with mock as None,:\n pass') + self.assertRaisesSyntaxError( + 'with mock as (None,):\n' + ' pass') + + def testAssignmentToTupleContainingNoneError(self): + self.assertRaisesSyntaxError( + 'with mock as (foo, None, bar):\n' + ' pass') + + def testContextThrows(self): + class ContextThrows(object): + def __context__(self): + raise RuntimeError("Context threw") + + def shouldThrow(): + ct = ContextThrows() + self.foo = None + with ct as self.foo: + pass + self.assertRaises(RuntimeError, shouldThrow) + self.assertEqual(self.foo, None) + + def testEnterThrows(self): + class EnterThrows(object): + def __context__(self): + return self + + def __enter__(self): + raise RuntimeError("Context threw") + + def __exit__(self, *args): + pass + + def shouldThrow(): + ct = EnterThrows() + self.foo = None + with ct as self.foo: + pass + self.assertRaises(RuntimeError, shouldThrow) + self.assertEqual(self.foo, None) + + def testExitThrows(self): + class ExitThrows(object): + def __context__(self): + return self + def __enter__(self): + return + def __exit__(self, *args): + raise RuntimeError(42) + def shouldThrow(): + with ExitThrows(): + pass + self.assertRaises(RuntimeError, shouldThrow) + +class ContextmanagerAssertionMixin(object): + TEST_EXCEPTION = RuntimeError("test exception") + + def assertInWithManagerInvariants(self, mock_manager): + self.assertTrue(mock_manager.context_called) + self.assertTrue(mock_manager.enter_called) + self.assertFalse(mock_manager.exit_called) + self.assertEqual(mock_manager.exit_args, None) + + def assertAfterWithManagerInvariants(self, mock_manager, exit_args): + self.assertTrue(mock_manager.context_called) + self.assertTrue(mock_manager.enter_called) + self.assertTrue(mock_manager.exit_called) + self.assertEqual(mock_manager.exit_args, exit_args) + + def assertAfterWithManagerInvariantsNoError(self, mock_manager): + self.assertAfterWithManagerInvariants(mock_manager, + (None, None, None)) + + def assertInWithGeneratorInvariants(self, mock_generator): + self.assertTrue(mock_generator.yielded) + self.assertFalse(mock_generator.stopped) + + def assertAfterWithGeneratorInvariantsNoError(self, mock_generator): + self.assertTrue(mock_generator.yielded) + self.assertTrue(mock_generator.stopped) + + def raiseTestException(self): + raise self.TEST_EXCEPTION + + def assertAfterWithManagerInvariantsWithError(self, mock_manager): + self.assertTrue(mock_manager.context_called) + self.assertTrue(mock_manager.enter_called) + self.assertTrue(mock_manager.exit_called) + self.assertEqual(mock_manager.exit_args[0], RuntimeError) + self.assertEqual(mock_manager.exit_args[1], self.TEST_EXCEPTION) + + def assertAfterWithGeneratorInvariantsWithError(self, mock_generator): + self.assertTrue(mock_generator.yielded) + self.assertTrue(mock_generator.stopped) + + +class NonexceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin): + def testInlineGeneratorSyntax(self): + with mock_contextmanager_generator(): + pass + + def testUnboundGenerator(self): + mock = mock_contextmanager_generator() + with mock: + pass + self.assertAfterWithManagerInvariantsNoError(mock) + + def testInlineGeneratorBoundSyntax(self): + with mock_contextmanager_generator() as foo: + self.assertInWithGeneratorInvariants(foo) + # FIXME: In the future, we'll try to keep the bound names from leaking + self.assertAfterWithGeneratorInvariantsNoError(foo) + + def testInlineGeneratorBoundToExistingVariable(self): + foo = None + with mock_contextmanager_generator() as foo: + self.assertInWithGeneratorInvariants(foo) + self.assertAfterWithGeneratorInvariantsNoError(foo) + + def testInlineGeneratorBoundToDottedVariable(self): + with mock_contextmanager_generator() as self.foo: + self.assertInWithGeneratorInvariants(self.foo) + self.assertAfterWithGeneratorInvariantsNoError(self.foo) + + def testBoundGenerator(self): + mock = mock_contextmanager_generator() + with mock as foo: + self.assertInWithGeneratorInvariants(foo) + self.assertInWithManagerInvariants(mock) + self.assertAfterWithGeneratorInvariantsNoError(foo) + self.assertAfterWithManagerInvariantsNoError(mock) + + def testNestedSingleStatements(self): + mock_a = mock_contextmanager_generator() + with mock_a as foo: + mock_b = mock_contextmanager_generator() + with mock_b as bar: + self.assertInWithManagerInvariants(mock_a) + self.assertInWithManagerInvariants(mock_b) + self.assertInWithGeneratorInvariants(foo) + self.assertInWithGeneratorInvariants(bar) + self.assertAfterWithManagerInvariantsNoError(mock_b) + self.assertAfterWithGeneratorInvariantsNoError(bar) + self.assertInWithManagerInvariants(mock_a) + self.assertInWithGeneratorInvariants(foo) + self.assertAfterWithManagerInvariantsNoError(mock_a) + self.assertAfterWithGeneratorInvariantsNoError(foo) + + +class NestedNonexceptionalTestCase(unittest.TestCase, + ContextmanagerAssertionMixin): + def testSingleArgInlineGeneratorSyntax(self): + with nested(mock_contextmanager_generator()): + pass + + def testSingleArgUnbound(self): + mock_contextmanager = mock_contextmanager_generator() + mock_nested = MockNested(mock_contextmanager) + with mock_nested: + self.assertInWithManagerInvariants(mock_contextmanager) + self.assertInWithManagerInvariants(mock_nested) + self.assertAfterWithManagerInvariantsNoError(mock_contextmanager) + self.assertAfterWithManagerInvariantsNoError(mock_nested) + + def testSingleArgBoundToNonTuple(self): + m = mock_contextmanager_generator() + # This will bind all the arguments to nested() into a single list + # assigned to foo. + with nested(m) as foo: + self.assertInWithManagerInvariants(m) + self.assertAfterWithManagerInvariantsNoError(m) + + def testSingleArgBoundToSingleElementParenthesizedList(self): + m = mock_contextmanager_generator() + # This will bind all the arguments to nested() into a single list + # assigned to foo. + # FIXME: what should this do: with nested(m) as (foo,): + with nested(m) as (foo): + self.assertInWithManagerInvariants(m) + self.assertAfterWithManagerInvariantsNoError(m) + + def testSingleArgBoundToMultipleElementTupleError(self): + def shouldThrowValueError(): + with nested(mock_contextmanager_generator()) as (foo, bar): + pass + self.assertRaises(ValueError, shouldThrowValueError) + + def testSingleArgUnbound(self): + mock_contextmanager = mock_contextmanager_generator() + mock_nested = MockNested(mock_contextmanager) + with mock_nested: + self.assertInWithManagerInvariants(mock_contextmanager) + self.assertInWithManagerInvariants(mock_nested) + self.assertAfterWithManagerInvariantsNoError(mock_contextmanager) + self.assertAfterWithManagerInvariantsNoError(mock_nested) + + def testMultipleArgUnbound(self): + m = mock_contextmanager_generator() + n = mock_contextmanager_generator() + o = mock_contextmanager_generator() + mock_nested = MockNested(m, n, o) + with mock_nested: + self.assertInWithManagerInvariants(m) + self.assertInWithManagerInvariants(n) + self.assertInWithManagerInvariants(o) + self.assertInWithManagerInvariants(mock_nested) + self.assertAfterWithManagerInvariantsNoError(m) + self.assertAfterWithManagerInvariantsNoError(n) + self.assertAfterWithManagerInvariantsNoError(o) + self.assertAfterWithManagerInvariantsNoError(mock_nested) + + def testMultipleArgBound(self): + mock_nested = MockNested(mock_contextmanager_generator(), + mock_contextmanager_generator(), mock_contextmanager_generator()) + with mock_nested as (m, n, o): + self.assertInWithGeneratorInvariants(m) + self.assertInWithGeneratorInvariants(n) + self.assertInWithGeneratorInvariants(o) + self.assertInWithManagerInvariants(mock_nested) + self.assertAfterWithGeneratorInvariantsNoError(m) + self.assertAfterWithGeneratorInvariantsNoError(n) + self.assertAfterWithGeneratorInvariantsNoError(o) + self.assertAfterWithManagerInvariantsNoError(mock_nested) + + +class ExceptionalTestCase(unittest.TestCase, ContextmanagerAssertionMixin): + def testSingleResource(self): + cm = mock_contextmanager_generator() + def shouldThrow(): + with cm as self.resource: + self.assertInWithManagerInvariants(cm) + self.assertInWithGeneratorInvariants(self.resource) + self.raiseTestException() + self.assertRaises(RuntimeError, shouldThrow) + self.assertAfterWithManagerInvariantsWithError(cm) + self.assertAfterWithGeneratorInvariantsWithError(self.resource) + + def testNestedSingleStatements(self): + mock_a = mock_contextmanager_generator() + mock_b = mock_contextmanager_generator() + def shouldThrow(): + with mock_a as self.foo: + with mock_b as self.bar: + self.assertInWithManagerInvariants(mock_a) + self.assertInWithManagerInvariants(mock_b) + self.assertInWithGeneratorInvariants(self.foo) + self.assertInWithGeneratorInvariants(self.bar) + self.raiseTestException() + self.assertRaises(RuntimeError, shouldThrow) + self.assertAfterWithManagerInvariantsWithError(mock_a) + self.assertAfterWithManagerInvariantsWithError(mock_b) + self.assertAfterWithGeneratorInvariantsWithError(self.foo) + self.assertAfterWithGeneratorInvariantsWithError(self.bar) + + def testMultipleResourcesInSingleStatement(self): + cm_a = mock_contextmanager_generator() + cm_b = mock_contextmanager_generator() + mock_nested = MockNested(cm_a, cm_b) + def shouldThrow(): + with mock_nested as (self.resource_a, self.resource_b): + self.assertInWithManagerInvariants(cm_a) + self.assertInWithManagerInvariants(cm_b) + self.assertInWithManagerInvariants(mock_nested) + self.assertInWithGeneratorInvariants(self.resource_a) + self.assertInWithGeneratorInvariants(self.resource_b) + self.raiseTestException() + self.assertRaises(RuntimeError, shouldThrow) + self.assertAfterWithManagerInvariantsWithError(cm_a) + self.assertAfterWithManagerInvariantsWithError(cm_b) + self.assertAfterWithManagerInvariantsWithError(mock_nested) + self.assertAfterWithGeneratorInvariantsWithError(self.resource_a) + self.assertAfterWithGeneratorInvariantsWithError(self.resource_b) + + def testNestedExceptionBeforeInnerStatement(self): + mock_a = mock_contextmanager_generator() + mock_b = mock_contextmanager_generator() + self.bar = None + def shouldThrow(): + with mock_a as self.foo: + self.assertInWithManagerInvariants(mock_a) + self.assertInWithGeneratorInvariants(self.foo) + self.raiseTestException() + with mock_b as self.bar: + pass + self.assertRaises(RuntimeError, shouldThrow) + self.assertAfterWithManagerInvariantsWithError(mock_a) + self.assertAfterWithGeneratorInvariantsWithError(self.foo) + + # The inner statement stuff should never have been touched + self.assertEqual(self.bar, None) + self.assertFalse(mock_b.context_called) + self.assertFalse(mock_b.enter_called) + self.assertFalse(mock_b.exit_called) + self.assertEqual(mock_b.exit_args, None) + + def testNestedExceptionAfterInnerStatement(self): + mock_a = mock_contextmanager_generator() + mock_b = mock_contextmanager_generator() + def shouldThrow(): + with mock_a as self.foo: + with mock_b as self.bar: + self.assertInWithManagerInvariants(mock_a) + self.assertInWithManagerInvariants(mock_b) + self.assertInWithGeneratorInvariants(self.foo) + self.assertInWithGeneratorInvariants(self.bar) + self.raiseTestException() + self.assertRaises(RuntimeError, shouldThrow) + self.assertAfterWithManagerInvariantsWithError(mock_a) + self.assertAfterWithManagerInvariantsNoError(mock_b) + self.assertAfterWithGeneratorInvariantsWithError(self.foo) + self.assertAfterWithGeneratorInvariantsNoError(self.bar) + + +class NonLocalFlowControlTestCase(unittest.TestCase): + + def testWithBreak(self): + counter = 0 + while True: + counter += 1 + with mock_contextmanager_generator(): + counter += 10 + break + counter += 100 # Not reached + self.assertEqual(counter, 11) + + def testWithContinue(self): + counter = 0 + while True: + counter += 1 + if counter > 2: + break + with mock_contextmanager_generator(): + counter += 10 + continue + counter += 100 # Not reached + self.assertEqual(counter, 12) + + def testWithReturn(self): + def foo(): + counter = 0 + while True: + counter += 1 + with mock_contextmanager_generator(): + counter += 10 + return counter + counter += 100 # Not reached + self.assertEqual(foo(), 11) + + def testWithYield(self): + def gen(): + with mock_contextmanager_generator(): + yield 12 + yield 13 + x = list(gen()) + self.assertEqual(x, [12, 13]) + + def testWithRaise(self): + counter = 0 + try: + counter += 1 + with mock_contextmanager_generator(): + counter += 10 + raise RuntimeError + counter += 100 # Not reached + except RuntimeError: + self.assertEqual(counter, 11) + else: + self.fail("Didn't raise RuntimeError") + + +class AssignmentTargetTestCase(unittest.TestCase): + + def testSingleComplexTarget(self): + targets = {1: [0, 1, 2]} + with mock_contextmanager_generator() as targets[1][0]: + self.assertEqual(targets.keys(), [1]) + self.assertEqual(targets[1][0].__class__, MockResource) + with mock_contextmanager_generator() as targets.values()[0][1]: + self.assertEqual(targets.keys(), [1]) + self.assertEqual(targets[1][1].__class__, MockResource) + with mock_contextmanager_generator() as targets[2]: + keys = targets.keys() + keys.sort() + self.assertEqual(keys, [1, 2]) + class C: pass + blah = C() + with mock_contextmanager_generator() as blah.foo: + self.assertEqual(hasattr(blah, "foo"), True) + + def testMultipleComplexTargets(self): + class C: + def __context__(self): return self + def __enter__(self): return 1, 2, 3 + def __exit__(self, *a): pass + targets = {1: [0, 1, 2]} + with C() as (targets[1][0], targets[1][1], targets[1][2]): + self.assertEqual(targets, {1: [1, 2, 3]}) + with C() as (targets.values()[0][2], targets.values()[0][1], targets.values()[0][0]): + self.assertEqual(targets, {1: [3, 2, 1]}) + with C() as (targets[1], targets[2], targets[3]): + self.assertEqual(targets, {1: 1, 2: 2, 3: 3}) + class B: pass + blah = B() + with C() as (blah.one, blah.two, blah.three): + self.assertEqual(blah.one, 1) + self.assertEqual(blah.two, 2) + self.assertEqual(blah.three, 3) + + +def test_main(): + run_unittest(FailureTestCase, NonexceptionalTestCase, + NestedNonexceptionalTestCase, ExceptionalTestCase, + NonLocalFlowControlTestCase, + AssignmentTargetTestCase) + + +if __name__ == '__main__': + test_main() |