quick python expression evaluator
Kragen Sitaker
kragen at pobox.com
Thu Apr 22 21:11:50 EDT 2004
This evaluates expressions and displays their results as you type
them. It's like some hack I posted a year ago, except that it doesn't
look quite as ugly and it has noticeably better updating behavior.
Still, it doesn't limit the time to evaluate an expression, and
doesn't effectively let you define functions.
This is yet another a prototype for the "functional programming for
amateurs in an outliner" goal.
#!/usr/bin/python
"""Functional outline -- at least, eventually. No outlining yet.
This is "one to throw away."
To do:
D bring up a window
D add an exit button
D add "add row" button
D make its focus behavior sensible
D fix shitty colors
- remove "select all on focus" behavior
- make entry fields' "relief" change on focus? No relief for now.
- fix packing
- remove empty rows? Rearrange rows? Gravy...
- build f2c
D add f
D add c (in Python), and value
- add re-evaluation
D store all definitions in one object
D start by recalculating everything in dumb order on any change, then...
- topologically sort
- use compile(expr, varname, 'eval').co_names to find dependencies. Maybe display them?
- add "valid" bit.
- Before setting new value, set to invalid; propagate this to dependents.
- after setting new value, set to valid.
- For display, maybe get new value for everything invalid that wants display
- add K
- add f2c
- add hierarchy --- expand/collapse
- add ability to *call* f2c
- build something recursive
- how about factorial?
- add persistence
"""
import Tkinter, sys
bgcolor='white'
mainwin = Tkinter.Tk()
mainwin.title('quickfunc')
mainwin['background'] = bgcolor
varrows = Tkinter.Frame(mainwin, background=bgcolor)
varrows.pack(side='top')
def leftwidget(parent, ctor=Tkinter.Entry, **args):
rv = ctor(parent, background=bgcolor, **args)
rv.pack(side='left', fill='both')
return rv
class namespace:
def __init__(self):
self.variables = []
self.values = {}
self.exceptions = {}
def add_var(self, namevar, exprvar, value_widget):
self.variables.append((namevar, exprvar, value_widget))
def recalculate_everything(self, *stupid_tcl_vars):
self.values.clear()
for namevar, exprvar, widget in self.variables:
name = namevar.get()
try:
value = eval(exprvar.get(), self.values)
self.values[name] = value
widget['text'] = repr(value)
widget['background'] = bgcolor
except:
self.exceptions[name] = sys.exc_info()
widget['background'] = 'red'
def row(name, expr, env):
f = Tkinter.Frame(varrows, background=bgcolor)
f.pack(fill='both')
fnamevar = Tkinter.Variable()
fnamevar.set(name)
fname = leftwidget(f, relief='flat', textvariable=fnamevar, width=8, justify='right', highlightthickness=0)
equal = leftwidget(f, Tkinter.Label, text=':')
exprvar = Tkinter.Variable()
fexpr = leftwidget(f, relief='flat', textvariable=exprvar, highlightthickness=0)
fvalue = leftwidget(f, Tkinter.Label)
env.add_var(namevar=fnamevar, exprvar=exprvar, value_widget=fvalue)
exprvar.trace('w', env.recalculate_everything)
fnamevar.trace('w', env.recalculate_everything)
exprvar.set(expr)
fexpr.focus()
return f
env = namespace()
f = row('f', '212', env)
c = row('c', '(f - 32) * 5 / 9', env)
def addrow_cmd():
row('', '', env)
addrow = Tkinter.Button(mainwin, text="New row", command=addrow_cmd)
addrow.pack(side='left')
exit = Tkinter.Button(mainwin, text="Exit", command=mainwin.quit)
exit.pack(side='left')
Tkinter.mainloop()
More information about the Kragen-hacks
mailing list