Skip to content

Commit ddcd360

Browse files
committed
Materials for Python 3.14 Preview: Better Syntax Error Messages
1 parent 5704140 commit ddcd360

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

python314-preview-errors/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Python 3.14 Preview: Better Syntax Error Messages
2+
3+
The materials contained in this folder are designed to complement the Real Python tutorial [Python 3.14 Preview: Better Syntax Error Messages](https://realpython.com/python314-error-messages/).

python314-preview-errors/errors.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import sys
2+
import textwrap
3+
4+
MAX_WIDTH = 80
5+
6+
7+
def main() -> None:
8+
for title, snippets in get_scenarios().items():
9+
print_headline(title)
10+
for snippet in snippets:
11+
execute(snippet)
12+
13+
14+
def get_scenarios() -> dict[str, list[str]]:
15+
return {
16+
"Keyword Typos": [
17+
"forr i in range(5):",
18+
"why True:",
19+
],
20+
"Strict elif After else": [
21+
"""
22+
if x > 0:
23+
print("positive")
24+
else:
25+
print("not positive")
26+
elif x == 0: # This is invalid
27+
print("zero")
28+
""",
29+
],
30+
"Conditional Expressions": ["1 if True else pass"],
31+
"String Closures": [
32+
'message = "She said "Hello" to everyone"',
33+
],
34+
"String Prefix Combinations": ['text = fb"Binary {text}"'],
35+
"Unpacking Assignments": [
36+
'dog, age, city, hobbies = ["Frieda", 8, "Berlin"]',
37+
'dog, age = ["Frieda", 8, "Berlin"]',
38+
],
39+
"Aliases": ["import sys as [alias]"],
40+
"Unhashable Types": ['grid = {[0, 0]: "Label", [0, 1]: "Input"}'],
41+
"Math Domain": [
42+
"""
43+
import math
44+
math.sqrt(-1)
45+
"""
46+
],
47+
"Context Managers": [
48+
"""
49+
import asyncio
50+
async def process_data():
51+
with asyncio.TaskGroup() as tg:
52+
pass
53+
54+
asyncio.run(process_data())
55+
""",
56+
"""
57+
import asyncio
58+
async def read_file():
59+
async with open(__file__) as f:
60+
return f.read()
61+
62+
asyncio.run(read_file())
63+
""",
64+
],
65+
}
66+
67+
68+
def print_headline(text: str, width: int = MAX_WIDTH) -> None:
69+
print(f" {text} ".center(width, "="))
70+
71+
72+
def execute(source_code: str) -> None:
73+
raw_source_code = dedent(source_code)
74+
try:
75+
print(with_repl_prompts(raw_source_code))
76+
exec(raw_source_code, globals())
77+
except (SyntaxError, ValueError, TypeError) as e:
78+
sys.excepthook(type(e), e, e.__traceback__)
79+
finally:
80+
print()
81+
82+
83+
def with_repl_prompts(source_code: str) -> str:
84+
return "\n".join(
85+
(">>> " if i == 0 else "... ") + line
86+
for i, line in enumerate(source_code.splitlines())
87+
)
88+
89+
90+
def dedent(source_code: str) -> str:
91+
return textwrap.dedent(source_code).strip("\n")
92+
93+
94+
if __name__ == "__main__":
95+
main()

0 commit comments

Comments
 (0)