|
| 1 | +# SyntaxError carries CPython's (msg, filename, lineno, offset, text) attribute |
| 2 | +# set, and the two-argument form is what both Python code and the parser use. |
| 3 | +e = SyntaxError("invalid syntax", ("bad.py", 5, 9, "def foo(:")) |
| 4 | +assert e.args == ("invalid syntax", ("bad.py", 5, 9, "def foo(:")), e.args |
| 5 | +assert e.msg == "invalid syntax", e.msg |
| 6 | +assert e.filename == "bad.py", e.filename |
| 7 | +assert e.lineno == 5, e.lineno |
| 8 | +assert e.offset == 9, e.offset |
| 9 | +assert e.text == "def foo(:", e.text |
| 10 | +assert str(e) == "invalid syntax (bad.py, line 5)", str(e) |
| 11 | + |
| 12 | +# Without an info tuple the location attributes stay None and str() is the message. |
| 13 | +bare = SyntaxError("boom") |
| 14 | +assert bare.args == ("boom",), bare.args |
| 15 | +assert bare.msg == "boom", bare.msg |
| 16 | +assert bare.filename is None, bare.filename |
| 17 | +assert bare.lineno is None, bare.lineno |
| 18 | +assert bare.offset is None, bare.offset |
| 19 | +assert bare.text is None, bare.text |
| 20 | +assert str(bare) == "boom", str(bare) |
| 21 | + |
| 22 | +# With no arguments at all every attribute, msg included, is None. |
| 23 | +empty = SyntaxError() |
| 24 | +assert empty.msg is None, empty.msg |
| 25 | +assert empty.filename is None, empty.filename |
| 26 | +assert empty.lineno is None, empty.lineno |
| 27 | +assert empty.offset is None, empty.offset |
| 28 | +assert empty.text is None, empty.text |
| 29 | + |
| 30 | +# Python 3.9 reports a short info tuple as an IndexError. |
| 31 | +try: |
| 32 | + SyntaxError("x", ("f.py", 1)) |
| 33 | + assert False, "expected IndexError" |
| 34 | +except IndexError as error: |
| 35 | + assert str(error) == "tuple index out of range", str(error) |
| 36 | + |
| 37 | +try: |
| 38 | + SyntaxError("x", foo=1) |
| 39 | + assert False, "expected TypeError" |
| 40 | +except TypeError as error: |
| 41 | + assert str(error) == "SyntaxError() takes no keyword arguments", str(error) |
| 42 | + |
| 43 | +# The attributes are writable, so nothing may assume their type. |
| 44 | +e.lineno = "not an int" |
| 45 | +assert str(e) == "invalid syntax (bad.py)", str(e) |
| 46 | + |
| 47 | +# compile() raises the parser's SyntaxError instead of aborting. |
| 48 | +try: |
| 49 | + compile("def foo(:", "<string>", "exec") |
| 50 | + assert False, "expected SyntaxError" |
| 51 | +except SyntaxError as error: |
| 52 | + assert error.msg == "invalid syntax", error.msg |
| 53 | + assert error.lineno == 1, error.lineno |
| 54 | + assert error.offset == 9, error.offset |
| 55 | + |
| 56 | +# lineno is user-supplied, so out-of-range values are printed, not asserted on. |
| 57 | +negative = SyntaxError("m", ("f.py", -1, 1, "code")) |
| 58 | +assert str(negative) == "m (f.py, line -1)", str(negative) |
| 59 | +huge = SyntaxError("m", ("f.py", 10**30, 1, "code")) |
| 60 | +assert str(huge) == "m (f.py, line 1000000000000000000000000000000)", str(huge) |
0 commit comments