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