Skip to content

Commit d557fbf

Browse files
authored
Merge pull request #103 from realpython/python-eval-mathrepl
Python eval mathrepl
2 parents e55ef99 + e221e8b commit d557fbf

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

python-eval-mathrepl/mathrepl.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
3+
"""MathREPL, a math expression evaluator using Python's eval() and math."""
4+
5+
import math
6+
7+
__version__ = "1.0"
8+
__author__ = "Leodanis Pozo Ramos"
9+
10+
ALLOWED_NAMES = {
11+
k: v for k, v in math.__dict__.items() if not k.startswith("__")
12+
}
13+
14+
PS1 = "mr>>"
15+
16+
WELCOME = f"""
17+
MathREPL {__version__}, your Python math expressions evaluator!
18+
Enter a valid math expression after the prompt "{PS1}".
19+
Type "help" for more information.
20+
Type "quit" or "exit" to exit.
21+
"""
22+
23+
USAGE = f"""
24+
Usage:
25+
Build math expressions using numeric values and operators.
26+
Use any of the following functions and constants:
27+
28+
{', '.join(ALLOWED_NAMES.keys())}
29+
"""
30+
31+
32+
def evaluate(expression):
33+
"""Evaluate a math expression."""
34+
# Compile the expression eventually raising a SyntaxError
35+
# when the user enters an invalid expression
36+
code = compile(expression, "<string>", "eval")
37+
38+
# Validate allowed names
39+
for name in code.co_names:
40+
if name not in ALLOWED_NAMES:
41+
raise NameError(f"The use of '{name}' is not allowed")
42+
43+
# Evaluate the expression eventually raising a ValueError
44+
# when the user uses a math function with a wrong input value
45+
# e.g. math.sqrt(-10)
46+
return eval(code, {"__builtins__": {}}, ALLOWED_NAMES)
47+
48+
49+
def main():
50+
"""Main loop: Read and evaluate user's input."""
51+
print(WELCOME)
52+
while True:
53+
# Read user's input
54+
try:
55+
expression = input(f"{PS1} ")
56+
except (KeyboardInterrupt, EOFError):
57+
raise SystemExit()
58+
59+
# Handle special commands
60+
if expression.lower() == "help":
61+
print(USAGE)
62+
continue
63+
if expression.lower() in {"quit", "exit"}:
64+
raise SystemExit()
65+
66+
# Evaluate the expression and handle errors
67+
try:
68+
result = evaluate(expression)
69+
except SyntaxError:
70+
# If the user enters an invalid expression
71+
print("Invalid input expression syntax")
72+
continue
73+
except (NameError, ValueError) as err:
74+
# If the user tries to use a name that isn't allowed
75+
# or an invalid value to a given math function
76+
print(err)
77+
continue
78+
79+
# Print the result if no error occurs
80+
print(f"The result is: {result}")
81+
82+
83+
if __name__ == "__main__":
84+
main()

0 commit comments

Comments
 (0)