1 # -*- coding: utf-8 -*- 2 import py 3 from pyparser import pyparse 4 from pyparser.pygram import syms 5 from pyparser.error import SyntaxError, IndentationError 6 from pyparser import consts 7 8 9 class TestPythonParser: 10 11 def setup_class(self): 12 self.parser = pyparse.PythonParser() 13 14 def parse(self, source, mode="exec", info=None): 15 if info is None: 16 info = pyparse.CompileInfo("<test>", mode) 17 return self.parser.parse_source(source, info) 18 19 def test_with_and_as(self): 20 py.test.raises(SyntaxError, self.parse, "with = 23") 21 py.test.raises(SyntaxError, self.parse, "as = 2") 22 23 def test_dont_imply_dedent(self): 24 info = pyparse.CompileInfo("<test>", "single", 25 consts.PyCF_DONT_IMPLY_DEDENT) 26 self.parse('if 1:\n x\n', info=info) 27 self.parse('x = 5 ', info=info) 28 29 def test_clear_state(self): 30 assert self.parser.root is None 31 tree = self.parse("name = 32") 32 assert self.parser.root is None 33 34 def test_encoding(self): 35 info = pyparse.CompileInfo("<test>", "exec") 36 tree = self.parse("""# coding: latin-1 37 stuff = "nothing" 38 """, info=info) 39 assert tree.type == syms["encoding_decl"] 40 assert tree.encoding == "iso-8859-1" 41 assert info.encoding == "iso-8859-1" 42 sentence = u"u'Die M??nner ??rgen sich!'" 43 input = (u"# coding: utf-7\nstuff = %s" % (sentence,)).encode("utf-7") 44 tree = self.parse(input, info=info) 45 assert info.encoding == "utf-7" 46 input = "# coding: iso-8859-15\nx" 47 self.parse(input, info=info) 48 assert info.encoding == "iso-8859-15" 49 input = "\xEF\xBB\xBF# coding: utf-8\nx" 50 self.parse(input, info=info) 51 assert info.encoding == "utf-8" 52 input = "# coding: utf-8\nx" 53 info.flags |= consts.PyCF_SOURCE_IS_UTF8 54 exc = py.test.raises(SyntaxError, self.parse, input, info=info).value 55 info.flags &= ~consts.PyCF_SOURCE_IS_UTF8 56 assert exc.msg == "coding declaration in unicode string" 57 input = "\xEF\xBB\xBF# coding: latin-1\nx" 58 exc = py.test.raises(SyntaxError, self.parse, input).value 59 assert exc.msg == "UTF-8 BOM with latin-1 coding cookie" 60 input = "# coding: not-here" 61 exc = py.test.raises(SyntaxError, self.parse, input).value 62 assert exc.msg == "Unknown encoding: not-here" 63 input = u"# coding: ascii\n\xe2".encode('utf-8') 64 exc = py.test.raises(SyntaxError, self.parse, input).value 65 assert exc.msg == ("'ascii' codec can't decode byte 0xc3 " 66 "in position 16: ordinal not in range(128)") 67 68 def test_non_unicode_codec(self): 69 exc = py.test.raises(SyntaxError, self.parse, """\ 70 # coding: string-escape 71 \x70\x72\x69\x6e\x74\x20\x32\x2b\x32\x0a 72 """).value 73 assert exc.msg == "codec did not return a unicode object" 74 75 def test_syntax_error(self): 76 parse = self.parse 77 exc = py.test.raises(SyntaxError, parse, "name another for").value 78 assert exc.msg == "invalid syntax" 79 assert exc.lineno == 1 80 assert exc.offset == 5 81 assert exc.text.startswith("name another for") 82 exc = py.test.raises(SyntaxError, parse, "x = \"blah\n\n\n").value 83 assert exc.msg == "EOL while scanning string literal" 84 assert exc.lineno == 1 85 assert exc.offset == 5 86 exc = py.test.raises(SyntaxError, parse, "x = '''\n\n\n").value 87 assert exc.msg == "EOF while scanning triple-quoted string literal" 88 assert exc.lineno == 1 89 assert exc.offset == 5 90 assert exc.lastlineno == 3 91 for input in ("())", "(()", "((", "))"): 92 py.test.raises(SyntaxError, parse, input) 93 exc = py.test.raises(SyntaxError, parse, "x = (\n\n(),\n(),").value 94 assert exc.msg == "parenthesis is never closed" 95 assert exc.lineno == 1 96 assert exc.offset == 5 97 assert exc.lastlineno == 5 98 exc = py.test.raises(SyntaxError, parse, "abc)").value 99 assert exc.msg == "unmatched ')'" 100 assert exc.lineno == 1 101 assert exc.offset == 4 102 103 def test_is(self): 104 self.parse("x is y") 105 self.parse("x is not y") 106 107 def test_indentation_error(self): 108 parse = self.parse 109 input = """ 110 def f(): 111 pass""" 112 exc = py.test.raises(IndentationError, parse, input).value 113 assert exc.msg == "expected an indented block" 114 assert exc.lineno == 3 115 assert exc.text.startswith("pass") 116 assert exc.offset == 0 117 input = "hi\n indented" 118 exc = py.test.raises(IndentationError, parse, input).value 119 assert exc.msg == "unexpected indent" 120 input = "def f():\n pass\n next_stmt" 121 exc = py.test.raises(IndentationError, parse, input).value 122 assert exc.msg == "unindent does not match any outer indentation level" 123 assert exc.lineno == 3 124 125 def test_mac_newline(self): 126 self.parse("this_is\ra_mac\rfile") 127 128 def test_mode(self): 129 assert self.parse("x = 43*54").type == syms["file_input"] 130 tree = self.parse("43**54", "eval") 131 assert tree.type == syms["eval_input"] 132 py.test.raises(SyntaxError, self.parse, "x = 54", "eval") 133 tree = self.parse("x = 43", "single") 134 assert tree.type == syms["single_input"] 135 136 def test_multiline_string(self): 137 self.parse("''' \n '''") 138 self.parse("r''' \n '''") 139 140 def test_bytes_literal(self): 141 self.parse('b" "') 142 self.parse('br" "') 143 self.parse('b""" """') 144 self.parse("b''' '''") 145 self.parse("br'\\\n'") 146 147 py.test.raises(SyntaxError, self.parse, "b'a\\n") 148 149 def test_new_octal_literal(self): 150 self.parse('0777') 151 self.parse('0o777') 152 self.parse('0o777L') 153 py.test.raises(SyntaxError, self.parse, "0o778") 154 155 def test_new_binary_literal(self): 156 self.parse('0b1101') 157 self.parse('0b0l') 158 py.test.raises(SyntaxError, self.parse, "0b112") 159 160 def test_universal_newlines(self): 161 fmt = 'stuff = """hello%sworld"""' 162 expected_tree = self.parse(fmt % '\n') 163 for linefeed in ["\r\n","\r"]: 164 tree = self.parse(fmt % linefeed) 165 assert expected_tree == tree