Reinteract
Reinteract is a system for interactive experimentation with python. You enter Python code and expressions and immediately see the results. What distinguishes Reinteract from a shell (such as IPython or the builtin interactive mode) is that you can go back and edit expressions you entered earlier and the results will flow through the part of the worksheet after the changed portion.
Obviously, going back and changing previously edited expressions works better for some things than others. If your code already wrote something to a file, it can't be unwritten. Things that Reinteract works well for include numerical experimentation, lightweight signal processing and data analysis, and just plain playing around with the Python language.
Reinteract has a fair bit of intelligence for editing Python code; it does syntax highlighting, audo-indentation, and highlighting of matching parentheses. I'd like to extend it in the future to do completion as well.
Reinteract supports custom formatting of results. If an expression
returns a subclass of reinteract.CustomResult
, then the result gets to
control how it will be displayed in the worksheet. Custom result types
currently in reinteract are line graphs and images via matplotlib, and
a "play" result which displays as a button that can be clicked to play
an array of data as a sound.
What it looks like
Screencast (5 minutes)
Trying it out
Information about checking it out from source control and trying it out can be found on the project site.
Dependencies
- pygtk
- Replot is written the pygtk bindings to the GTK+ user interface toolkit. These bindings should be present on most current Linux distributions. GTK+ and pygtk also work well on Windows, and it's probably even possible to get them to work on OS X. But I haven't done any testing other than on Linux. I've been using GTK+-2.10 and GTK+-2.12, though reinteract might work with older versions. There is one bug fix scheduled for 2.12.2 that fixes a misbehavior when deleting multiple statements at once.
- numpy
- The examples and replot/replay modules use numpy, though the core should work without it.
- matplotlib
- The plot() and imshow() commands in the replot module are based on matplotlib.
- sox
- The play() command in the replay module uses sox for output. sox should be present on just about every Linux system. (It would be really simple to use a more inherently portable Python module like pymedia if someone was interested in getting it to work on Windows.)
- Multiple worksheets in a notebook.
- Data libraries. Allow management of a library of sound snippets and numerical data sets.
- Completion. Reinteract knows a lot about the symbols in the current scope and the syntax of the expression being edited, so it will be easy to offer completion to available names or the attributes of a particular name.
- A normal shell. Reinteract has a lot of intelligence in it that would be useful for a more normal Python shell without the "reinteractive" features.
Ideas for future development
How it works
The basic idea of reinteract is that reinteract saves a copy of the scope dictionary after every statement. If it needs to recompile starting from a particular statement, it then has the right scope to execute that statement in.
# scope: { a: 1, l: [1,2,3,4] } b = a + 1 # scope: { a: 1, b: 2, l: [1,2,3,4] }
This is pretty efficient because variables that stay the same
can be shared between successive scopes, so the only memory
used is for the scope dictionaries themselves. However, if
reinteract detects that a statement modifies a variable, then
it makes a shallow copy of the variable using copy.copy()
# scope: { a: 1, l: [1,2,3,4] } # reinteract does scope['l'] = copy.copy(scope['l']) l[0] = 5 # scope: { a: 1, l: [5,2,3,4] }
Some types of modification are easy to detect, like the slice assignment above or assigning to an attribute. However, some modifications are harder to detect. Compare:
l.append(2) # modifies l l.count(2) # no modification
The rule that reinteract uses is that a bare method call like the ones is probably a modification, and it conservatively makes a copy in that case. You can avoid a copy by using a temporary variable or explicitly printing the result.
print l.count(2) # no copy c = l.count(2); c # no copy