r20471 - gnucash/trunk - Add code to start up a Python console during Py module init, but disabled by default.
Christian Stimming
cstim at code.gnucash.org
Thu Mar 24 16:10:46 EDT 2011
Author: cstim
Date: 2011-03-24 16:10:45 -0400 (Thu, 24 Mar 2011)
New Revision: 20471
Trac: http://svn.gnucash.org/trac/changeset/20471
Added:
gnucash/trunk/src/python/pycons/
gnucash/trunk/src/python/pycons/Makefile.am
gnucash/trunk/src/python/pycons/__init__.py
gnucash/trunk/src/python/pycons/console.py
gnucash/trunk/src/python/pycons/ishell.py
gnucash/trunk/src/python/pycons/pycons
gnucash/trunk/src/python/pycons/setup.py
gnucash/trunk/src/python/pycons/shell.py
gnucash/trunk/src/python/pycons/simple_plot.py
Modified:
gnucash/trunk/configure.ac
gnucash/trunk/src/python/Makefile.am
gnucash/trunk/src/python/init.py
Log:
Add code to start up a Python console during Py module init, but disabled by default.
If a python console is wanted, change the last section
of src/python/init.py to "if True:".
From: Andy Clayton <q3aiml at gmail.com>
Modified: gnucash/trunk/configure.ac
===================================================================
--- gnucash/trunk/configure.ac 2011-03-24 19:47:47 UTC (rev 20470)
+++ gnucash/trunk/configure.ac 2011-03-24 20:10:45 UTC (rev 20471)
@@ -1388,6 +1388,7 @@
src/optional/python-bindings/tests/Makefile
src/pixmaps/Makefile
src/python/Makefile
+ src/python/pycons/Makefile
src/quotes/Makefile
src/register/Makefile
src/register/ledger-core/Makefile
Modified: gnucash/trunk/src/python/Makefile.am
===================================================================
--- gnucash/trunk/src/python/Makefile.am 2011-03-24 19:47:47 UTC (rev 20470)
+++ gnucash/trunk/src/python/Makefile.am 2011-03-24 20:10:45 UTC (rev 20471)
@@ -1,4 +1,4 @@
-SUBDIRS = .
+SUBDIRS = . pycons
#test
pkglib_LTLIBRARIES = libgncmod-python.la
Modified: gnucash/trunk/src/python/init.py
===================================================================
--- gnucash/trunk/src/python/init.py 2011-03-24 19:47:47 UTC (rev 20470)
+++ gnucash/trunk/src/python/init.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -2,6 +2,12 @@
import _sw_app_utils
from gnucash import *
+import gtk
+import os
+sys.path.append(os.path.dirname(__file__))
+print "woop", os.path.dirname(__file__)
+import pycons.console as cons
+
print "Hello from python!"
print "test", sys.modules.keys()
@@ -19,5 +25,66 @@
#print acct.GetBalance()
#print acct.GetSplitList()
+
#print "test2", dir(gnucash.gnucash_core_c)
+class Console (cons.Console):
+ """ GTK python console """
+
+ def __init__(self, argv=[], shelltype='python', banner=[],
+ filename=None, size=100):
+ cons.Console.__init__(self, argv, shelltype, banner, filename, size)
+ self.buffer.create_tag('center',
+ justification=gtk.JUSTIFY_CENTER,
+ font='Mono 4')
+ self.figures = []
+ self.callbacks = []
+ self.last_figure = None
+ self.active_canvas = None
+ self.view.connect ('key-press-event', self.key_press_event)
+ self.view.connect ('button-press-event', self.button_press_event)
+ self.view.connect ('scroll-event', self.scroll_event)
+
+
+ def key_press_event (self, widget, event):
+ """ Handle key press event """
+
+ if self.active_canvas:
+ self.active_canvas.emit ('key-press-event', event)
+ return True
+ return cons.Console.key_press_event (self, widget, event)
+
+ def scroll_event (self, widget, event):
+ """ Scroll event """
+ if self.active_canvas:
+ return True
+ return False
+
+ def button_press_event (self, widget, event):
+ """ Button press event """
+ return self.refresh()
+
+ def refresh (self):
+ """ Refresh drawing """
+ for fig in self.figures:
+ figure, canvas, anchor = fig
+ canvas.draw()
+ return False
+
+
+# Change this to "if True:" to switch on a python console at gnucash
+# startup:
+if False:
+ console = Console(argv = [], shelltype = 'python', banner = [['woop', 'title']], size = 100)
+
+ window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ window.set_position(gtk.WIN_POS_CENTER)
+ window.set_default_size(800,600)
+ window.set_border_width(0)
+ # Hm. gtk.main_quit will kill gnucash without closing the file
+ # properly. That's kinda bad.
+ window.connect('destroy-event', gtk.main_quit)
+ window.connect('delete-event', gtk.main_quit)
+ window.add (console)
+ window.show_all()
+ console.grab_focus()
Added: gnucash/trunk/src/python/pycons/Makefile.am
===================================================================
--- gnucash/trunk/src/python/pycons/Makefile.am (rev 0)
+++ gnucash/trunk/src/python/pycons/Makefile.am 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,14 @@
+SUBDIRS = .
+
+pyconsdir = ${GNC_SHAREDIR}/python/pycons/
+pycons_DATA = \
+ console.py \
+ __init__.py \
+ ishell.py \
+ pycons \
+ setup.py \
+ shell.py \
+ simple_plot.py
+
+EXTRA_DIST = ${pycons_DATA}
+
Added: gnucash/trunk/src/python/pycons/__init__.py
===================================================================
--- gnucash/trunk/src/python/pycons/__init__.py (rev 0)
+++ gnucash/trunk/src/python/pycons/__init__.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,27 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2008, Nicolas Rougier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Added: gnucash/trunk/src/python/pycons/console.py
===================================================================
--- gnucash/trunk/src/python/pycons/console.py (rev 0)
+++ gnucash/trunk/src/python/pycons/console.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,443 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2008, Nicolas Rougier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+import re
+import tempfile
+import readline
+import gobject
+import gtk
+import pango
+from StringIO import StringIO
+import shell
+try: import ishell
+except: pass
+
+ansi_colors = {'0;30': '#2E3436',
+ '0;31': '#CC0000',
+ '0;32': '#4E9A06',
+ '0;33': '#C4A000',
+ '0;34': '#3465A4',
+ '0;35': '#75507B',
+ '0;36': '#06989A',
+ '0;37': '#D3D7CF',
+ '1;30': '#555753',
+ '1;31': '#EF2929',
+ '1;32': '#8AE234',
+ '1;33': '#FCE94F',
+ '1;34': '#729FCF',
+ '1;35': '#AD7FA8',
+ '1;36': '#34E2E2',
+ '1;37': '#EEEEEC'}
+
+# ------------------------------------------------------------- class ConsoleOut
+class ConsoleOut:
+ """
+ A fake output file object. It sends output to the console widget,
+ and if asked for a file number, returns one set on instance creation
+ """
+
+ def __init__(self, console, fn=-1, style=None):
+ self.fn = fn
+ self.console = console
+ self.style = style
+ def close(self): pass
+ flush = close
+ def fileno(self): return self.fn
+ def isatty(self): return False
+ def read(self, a): return ''
+ def readline(self): return ''
+ def readlines(self): return []
+ def write(self, s):
+ self.console.write (s, self.style)
+ def writelines(self, l):
+ for s in l:
+ self.console.write (s, self.style)
+ def seek(self, a): raise IOError, (29, 'Illegal seek')
+ def tell(self): raise IOError, (29, 'Illegal seek')
+ truncate = tell
+
+
+# -------------------------------------------------------------- class ConsoleIn
+class ConsoleIn:
+ """
+ A fake input file object. It receives input from a GTK TextView widget,
+ and if asked for a file number, returns one set on instance creation
+ """
+ def __init__(self, console, fn=-1):
+ self.fn = fn
+ self.console = console
+ def close(self): pass
+ flush = close
+ def fileno(self): return self.fn
+ def isatty(self): return False
+ def read(self, a): return self.readline()
+ def readline(self):
+ self.console.input_mode = True
+ buffer = self.console.buffer
+ #console.write('\n')
+ iter = buffer.get_iter_at_mark(buffer.get_insert())
+ buffer.move_mark (buffer.get_mark('linestart'), iter)
+ while self.console.input_mode:
+ #while gtk.events_pending():
+ gtk.main_iteration()
+ s = self.console.input
+ self.console.input = ''
+ return s+'\n'
+ def readlines(self): return []
+ def write(self, s): return None
+ def writelines(self, l): return None
+ def seek(self, a): raise IOError, (29, 'Illegal seek')
+ def tell(self): raise IOError, (29, 'Illegal seek')
+ truncate = tell
+
+
+# ---------------------------------------------------------------- class Console
+class Console (gtk.ScrolledWindow):
+ """ GTK python console """
+
+ def __init__(self, argv=[], shelltype='python', banner=[],
+ filename=None, size=100):
+
+ """ Console interface building + initialization"""
+
+ # GTK interface
+ self.do_quit = False
+ gtk.ScrolledWindow.__init__(self)
+ self.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.set_shadow_type (gtk.SHADOW_NONE)
+ self.set_border_width(0)
+ self.view = gtk.TextView()
+ self.view.modify_font (pango.FontDescription("Mono 10"))
+ self.view.set_editable (True)
+ self.view.set_wrap_mode(True)
+ self.view.set_left_margin(0)
+ self.view.set_right_margin(0)
+ self.buffer = self.view.get_buffer()
+ self.buffer.create_tag ('title',
+ indent = 2,
+ weight=pango.WEIGHT_BOLD,
+ foreground='blue',
+ font='Mono 12')
+ self.buffer.create_tag ('subtitle',
+ indent = 2,
+ foreground='blue',
+ font='Mono 8')
+ self.buffer.create_tag ('output',
+ foreground = 'blue',
+ font='Mono 10')
+ self.buffer.create_tag ('error',
+ foreground='red',
+ style=pango.STYLE_OBLIQUE,
+ font='Mono 10')
+ self.buffer.create_tag ('prompt',
+ foreground='blue',
+ weight=pango.WEIGHT_BOLD,
+ font='Mono 10')
+ self.buffer.create_tag('0')
+ self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
+ for code in ansi_colors:
+ self.buffer.create_tag(code,
+ foreground=ansi_colors[code],
+ weight=700)
+ for text, style in banner:
+ self.write (text, style)
+ iter = self.buffer.get_iter_at_mark(self.buffer.get_insert())
+ self.buffer.create_mark ('linestart', iter, True)
+ self.view.add_events(gtk.gdk.KEY_PRESS_MASK)
+ self.view.connect ('key-press-event', self.key_press_event)
+ self.add(self.view)
+ self.show_all()
+ self.killbuffer = None
+
+ # Console stuff
+ self.argv = argv
+ self.history_init(filename, size)
+ self.cout = StringIO()
+ self.cout.truncate(0)
+ if shelltype=='ipython':
+ self.shell = ishell.Shell(argv,locals(),globals(),
+ cout=self.cout, cerr=self.cout,
+ input_func=self.raw_input)
+ else:
+ self.shell = shell.Shell(locals(),globals())
+ self.interrupt = False
+ self.input_mode = False
+ self.input = None
+ self.stdout = ConsoleOut (self, sys.stdout.fileno(), 'output')
+ self.stderr = ConsoleOut (self, sys.stderr.fileno(), 'error')
+ self.stdin = ConsoleIn (self, sys.stdin.fileno())
+
+ # Create a named pipe for system stdout/stderr redirection
+ self.fifoname = tempfile.mktemp()
+ if not os.path.exists (self.fifoname):
+ os.mkfifo (self.fifoname)
+ self.piperead = os.open (self.fifoname, os.O_RDONLY | os.O_NONBLOCK)
+ self.pipewrite = os.open (self.fifoname, os.O_WRONLY | os.O_NONBLOCK)
+ self.shell.eval(self)
+ self.cout.truncate(0)
+
+ def history_init(self, filename, size):
+ self.history_file = filename
+ self.history_size = size
+ if filename and os.path.exists(filename):
+ readline.read_history_file(filename)
+ readline.set_history_length(size)
+ self.history_reset()
+
+ def history_save(self):
+ if self.history_file:
+ readline.write_history_file(self.history_file)
+
+ def history_add(self, item):
+ if len(item):
+ readline.add_history (item)
+ self.history_reset()
+
+ def history_reset(self):
+ self.history_index = readline.get_current_history_length()+1
+
+ def history_next(self):
+ self.history_index += 1
+ if self.history_index <= readline.get_current_history_length():
+ return '' or readline.get_history_item (self.history_index)
+ self.history_index = readline.get_current_history_length()+1
+ return ''
+
+ def history_prev(self):
+ if self.history_index > 1:
+ self.history_index -= 1
+ else:
+ self.history_index = 1
+ return '' or readline.get_history_item (self.history_index)
+
+ def raw_input(self, prompt=''):
+ if self.interrupt:
+ self.interrupt = False
+ raise KeyboardInterrupt
+ return self.last_line()
+
+ def grab_focus (self):
+ """ Give focus to the TextView """
+
+ self.view.grab_focus()
+
+ def write (self, text, style=None):
+ """ Write text using given style (if any) """
+ segments = self.color_pat.split(text)
+ segment = segments.pop(0)
+ start,end = self.buffer.get_bounds()
+ if style==None:
+ self.buffer.insert(end, segment)
+ else:
+ self.buffer.insert_with_tags_by_name(end, segment, style)
+ if segments:
+ ansi_tags = self.color_pat.findall(text)
+ for tag in ansi_tags:
+ i = segments.index(tag)
+ self.buffer.insert_with_tags_by_name(self.buffer.get_end_iter(),
+ segments[i+1], tag)
+ segments.pop(i)
+ self.view.scroll_mark_onscreen(self.buffer.get_insert())
+
+ def overwrite (self, text, style=None):
+ """ Overwrite text after prompt with text """
+
+ mark = self.buffer.get_mark('linestart')
+ start = self.buffer.get_iter_at_mark(mark)
+ end = self.buffer.get_end_iter()
+ self.buffer.delete (start,end)
+ self.write (text, style)
+
+ def last_line (self):
+ """ Get last line (without prompt) """
+
+ mark = self.buffer.get_mark('linestart')
+ start = self.buffer.get_iter_at_mark(mark)
+ end = self.buffer.get_end_iter()
+ return self.buffer.get_text (start,end,True)
+
+
+ def prompt (self, style=None):
+ """ Display prompt """
+
+ iter = self.buffer.get_end_iter()
+ self.buffer.place_cursor (iter)
+ self.write (self.shell.prompt, style)
+ iter = self.buffer.get_iter_at_mark(self.buffer.get_insert())
+ self.buffer.move_mark (self.buffer.get_mark('linestart'), iter)
+ self.history_reset()
+ self.view.scroll_mark_onscreen(self.buffer.get_insert())
+ while gtk.events_pending():
+ gtk.main_iteration()
+
+ def key_press_event (self, widget, event):
+ """ Handle key press event """
+
+ keyname = gtk.gdk.keyval_name (event.keyval)
+
+ # New command
+ if keyname in ['Return', 'KP_Enter']:
+ line = self.last_line()
+ self.history_add (line)
+ if self.input_mode:
+ self.input_mode = False
+ self.input = self.last_line()
+ self.write('\n')
+ else:
+ self.execute()
+ return True
+
+ # Prevent cursor to go back past prompt
+ elif keyname in ['Left', 'BackSpace']:
+ mark = self.buffer.get_mark('linestart')
+ linestart = self.buffer.get_iter_at_mark(mark)
+ iter = self.buffer.get_iter_at_mark(self.buffer.get_insert())
+ if iter.compare(linestart) <= 0:
+ return True
+
+ elif keyname == 'Right':
+ return False
+
+ # Next history item
+ elif keyname == 'Down':
+ self.overwrite (self.history_next())
+ return True
+
+ # Previous history item
+ elif keyname == 'Up':
+ self.overwrite (self.history_prev())
+ return True
+
+ # Move cursor just after prompt
+ elif keyname == 'Home':
+ mark = self.buffer.get_mark('linestart')
+ linestart = self.buffer.get_iter_at_mark(mark)
+ self.buffer.place_cursor (linestart)
+ return True
+
+ # Completion if line not empty
+ elif keyname == 'Tab':
+ line = self.last_line()
+ if not line.strip():
+ return False
+ completed, possibilities = self.shell.complete(line)
+ if len(possibilities) > 1:
+ slice = line
+ self.write('\n')
+ for symbol in possibilities:
+ self.write(symbol+'\n')
+ self.prompt('prompt')
+ self.overwrite(completed or slice)
+ return True
+
+ # Controls
+ elif event.state & gtk.gdk.CONTROL_MASK:
+ if keyname in ['a','A']:
+ mark = self.buffer.get_mark('linestart')
+ linestart = self.buffer.get_iter_at_mark(mark)
+ self.buffer.place_cursor (linestart)
+ return True
+ elif keyname in ['e','E']:
+ end = self.buffer.get_end_iter()
+ self.buffer.place_cursor (end)
+ return True
+ elif keyname in ['k','K']:
+ start = self.buffer.get_iter_at_mark (self.buffer.get_insert())
+ end = self.buffer.get_end_iter()
+ self.killbuffer = self.buffer.get_text(start,end)
+ self.buffer.delete(start,end)
+ return True
+ elif keyname in ['y','Y']:
+ if self.killbuffer:
+ iter = self.buffer.get_iter_at_mark (self.buffer.get_insert())
+ self.buffer.insert(iter, self.killbuffer)
+ return True
+ elif keyname in ['l', 'L']:
+ start = self.buffer.get_start_iter()
+ end = self.buffer.get_end_iter()
+ end.backward_sentence_start()
+ self.buffer.delete (start,end)
+ elif keyname in ['d', 'D']:
+ if not len(self.last_line().strip()):
+ self.quit()
+
+ # Editing before prompt is forbidden
+ else:
+ mark = self.buffer.get_mark('linestart')
+ linestart = self.buffer.get_iter_at_mark(mark)
+ iter = self.buffer.get_iter_at_mark(self.buffer.get_insert())
+ if iter.compare(linestart) < 0:
+ iter = self.buffer.get_end_iter()
+ self.buffer.place_cursor (iter)
+ return False
+
+
+ def execute (self):
+ # Python stdout, stderr, stdin redirection
+ sys.stdout, self.stdout = self.stdout, sys.stdout
+ sys.stderr, self.stderr = self.stderr, sys.stderr
+ sys.stdin, self.stdin = self.stdin, sys.stdin
+
+ # System stdout, stderr redirection
+ sys_stdout = os.dup(1)
+ sys_stderr = os.dup(2)
+ os.dup2 (self.pipewrite, 1)
+ os.dup2 (self.pipewrite, 2)
+
+ self.shell.eval(self)
+ self.view.scroll_mark_onscreen(self.buffer.get_insert())
+ while gtk.events_pending():
+ gtk.main_iteration()
+
+ # Get system output and remove system redirection
+ os.dup2 (sys_stdout, 1)
+ os.dup2 (sys_stderr, 2)
+ os.close (sys_stdout)
+ os.close (sys_stderr)
+
+ # Remove python redirection
+ sys.stdout, self.stdout = self.stdout, sys.stdout
+ sys.stderr, self.stderr = self.stderr, sys.stderr
+ sys.stdin, self.stdin = self.stdin, sys.stdin
+
+
+ def quit(self):
+ """ Quit console """
+
+ gtk.main_quit()
+ self.history_save()
+ try:
+ os.close (self.piperead)
+ os.close (self.pipewrite)
+ except:
+ pass
+ if os.path.exists (self.fifoname):
+ os.remove (self.fifoname)
+ self.do_quit = True
Added: gnucash/trunk/src/python/pycons/ishell.py
===================================================================
--- gnucash/trunk/src/python/pycons/ishell.py (rev 0)
+++ gnucash/trunk/src/python/pycons/ishell.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,134 @@
+#! /usr/bin/env python
+#
+# Adapted from:
+#
+# Backend to the console plugin.
+# @author: Eitan Isaacson
+# @organization: IBM Corporation
+# @copyright: Copyright (c) 2007 IBM Corporation
+# @license: BSD
+#
+# All rights reserved. This program and the accompanying materials are made
+# available under the terms of the BSD which accompanies this distribution, and
+# is available at U{http://www.opensource.org/licenses/bsd-license.php}
+#
+
+import os
+import sys
+import re
+from StringIO import StringIO
+try:
+ import IPython
+ from IPython import ipapi
+except Exception,e:
+ raise "Error importing IPython (%s)" % str(e)
+
+
+# ------------------------------------------------------------------ class Shell
+class Shell:
+ """ """
+
+ def __init__(self,argv=None,user_ns=None,user_global_ns=None,
+ cin=None, cout=None,cerr=None, input_func=None):
+ """ """
+ if input_func:
+ IPython.iplib.raw_input_original = input_func
+ if cin:
+ IPython.Shell.Term.cin = cin
+ if cout:
+ IPython.Shell.Term.cout = cout
+ if cerr:
+ IPython.Shell.Term.cerr = cerr
+ if argv is None:
+ argv=[]
+ IPython.iplib.raw_input = lambda x: None
+ self.term = IPython.genutils.IOTerm(cin=cin, cout=cout, cerr=cerr)
+ os.environ['TERM'] = 'dumb'
+ excepthook = sys.excepthook
+ self.IP = IPython.Shell.make_IPython(argv,
+ user_ns=user_ns,
+ user_global_ns=user_global_ns,
+ embedded=True,
+ shell_class=IPython.Shell.InteractiveShell)
+ self.IP.system = lambda cmd: self.shell(self.IP.var_expand(cmd),
+ header='IPython system call: ',
+ verbose=self.IP.rc.system_verbose)
+ # Get a hold of the public IPython API object and use it
+ self.ip = ipapi.get()
+ self.ip.magic('colors LightBG')
+ sys.excepthook = excepthook
+ self.iter_more = 0
+ self.complete_sep = re.compile('[\s\{\}\[\]\(\)]')
+
+
+ def namespace(self):
+ return self.IP.user_ns
+
+ def eval(self, console):
+ console.write ('\n')
+ orig_stdout = sys.stdout
+ sys.stdout = IPython.Shell.Term.cout
+ try:
+ line = self.IP.raw_input(None, self.iter_more)
+ if self.IP.autoindent:
+ self.IP.readline_startup_hook(None)
+ except KeyboardInterrupt:
+ self.IP.write('\nKeyboardInterrupt\n')
+ self.IP.resetbuffer()
+ self.IP.outputcache.prompt_count -= 1
+ if self.IP.autoindent:
+ self.IP.indent_current_nsp = 0
+ self.iter_more = 0
+ except:
+ self.IP.showtraceback()
+ else:
+ self.iter_more = self.IP.push(line)
+ if (self.IP.SyntaxTB.last_syntax_error and self.IP.rc.autoedit_syntax):
+ self.IP.edit_syntax_error()
+ if self.iter_more:
+ self.prompt = str(self.IP.outputcache.prompt2).strip()
+ if self.IP.autoindent:
+ self.IP.readline_startup_hook(self.IP.pre_readline)
+ else:
+ self.prompt = str(self.IP.outputcache.prompt1).strip()
+ sys.stdout = orig_stdout
+
+ # System output (if any)
+ while True:
+ try:
+ buf = os.read(console.piperead, 256)
+ except:
+ break
+ else:
+ console.write (buf)
+ if len(buf) < 256: break
+
+ # Command output
+ rv = console.cout.getvalue()
+ if rv:
+ rv = rv.strip('\n')
+ console.write (rv)
+ if rv:
+ console.write ('\n')
+ console.cout.truncate(0)
+ console.prompt()
+
+ def complete(self, line):
+ split_line = self.complete_sep.split(line)
+ possibilities = self.IP.complete(split_line[-1])
+ if possibilities:
+ common_prefix = os.path.commonprefix (possibilities)
+ completed = line[:-len(split_line[-1])]+common_prefix
+ else:
+ completed = line
+ return completed, possibilities
+
+ def shell(self, cmd,verbose=0,debug=0,header=''):
+ stat = 0
+ if verbose or debug: print header+cmd
+ if not debug:
+ input, output = os.popen4(cmd)
+ print output.read()
+ output.close()
+ input.close()
+
Added: gnucash/trunk/src/python/pycons/pycons
===================================================================
--- gnucash/trunk/src/python/pycons/pycons (rev 0)
+++ gnucash/trunk/src/python/pycons/pycons 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,398 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2008, Nicolas Rougier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+""" Interactive Python/IPython/Pylab console
+
+This console implements a python (or ipython) shell within a GTK window and
+handles python stdin/stderr/stdout redirection and system wide stdout/stderr
+redirection (using a pipe), provides history based on the GNU readline package
+and automatic completion. It is also able to display matplotlib figures
+inline. Each call to the show functions actually produces a FigureCanvasGTKAgg
+that is inserted within the console.
+
+Usage: ./pycons [--ipython] [--pylab] [--toolbar] file
+
+You can refresh all active figures by calling the refresh() method and replot
+the last figures using the replot() method. You can also zoom(), pan(), home(),
+back(), forward() and save() active figure.
+"""
+
+import os
+import sys
+import gc
+import gobject
+import gtk
+import pango
+
+pylab_available = True
+try:
+ import matplotlib
+ matplotlib.use('GtkAgg')
+ from matplotlib.backends.backend_gtkagg \
+ import FigureCanvasGTKAgg as Canvas
+ from matplotlib.backends.backend_gtkagg \
+ import NavigationToolbar2GTKAgg as NavigationToolbar
+ import matplotlib.backends.backend_gtkagg as backend_gtkagg
+ def draw_if_interactive():
+ """ Is called after every pylab drawing command """
+ show(console)
+ backend_gtkagg.draw_if_interactive = draw_if_interactive
+ import pylab
+ import matplotlib.pylab
+ from matplotlib._pylab_helpers import Gcf
+except:
+ pylab_available = False
+
+ipython_available = True
+try:
+ import IPython
+except:
+ ipython_available = False
+
+try:
+ from functools import partial
+except ImportError:
+ def partial(func, *args, **keywords):
+ def newfunc(*fargs, **fkeywords):
+ newkeywords = keywords.copy()
+ newkeywords.update(fkeywords)
+ return func(*(args + fargs), **newkeywords)
+ newfunc.func = func
+ newfunc.args = args
+ newfunc.keywords = keywords
+ return newfunc
+
+import pycons.console as cons
+
+
+# ---------------------------------------------------------------------- replace
+def replace (console, canvas, anchor):
+ """ Replaces a given canvas with a static image replica """
+
+ figures = console.figures
+ view = console.view
+ canvas.draw()
+ w, h = canvas.get_size_request()
+ pixbuf = gtk.gdk.pixbuf_new_from_data (
+ canvas.buffer_rgba(0,0), gtk.gdk.COLORSPACE_RGB, True,8,w,h,w*4)
+ image = gtk.Image()
+ image.set_from_pixbuf (pixbuf)
+ widget = anchor.get_widgets()
+ for widget in anchor.get_widgets():
+ for child in widget.get_children():
+ widget.remove (child)
+ view.add_child_at_anchor(image, anchor)
+ image.show()
+ #gc.collect()
+ return widget
+
+# ----------------------------------------------------------------------- refresh
+def refresh(console):
+ """ Refreshs all active canvas """
+
+ figures = console.figures
+ for fig in figures:
+ figure, canvas, anchor = fig
+ canvas.draw()
+ while gtk.events_pending():
+ gtk.main_iteration()
+
+# ----------------------------------------------------------------------- refresh
+def figure_enter(widget, event, console):
+ """ Change cursor to an arrow """
+
+ watch = gtk.gdk.Cursor(gtk.gdk.TOP_LEFT_ARROW)
+ widget.window.set_cursor (watch)
+ widget.grab_focus()
+ console.active_canvas = widget.get_child()
+
+# ----------------------------------------------------------------------- refresh
+def figure_leave(widget, event, console):
+ """ Change cursor to text cursor """
+
+ cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
+ widget.window.set_cursor (cursor)
+ console.grab_focus()
+ console.active_canvas = None
+
+# ----------------------------------------------------------------------- insert
+def insert (console, figure):
+ """ Inserts a new canvas for the given figure """
+
+ figures = console.figures
+ last_figure = console.last_figure
+ figure.set_facecolor ('w')
+ view = console.view
+ buffer = console.buffer
+
+ # Compute size of the canvas according to current console visible area
+ x,y,width,height = console.get_allocation()
+ dpi = figure.get_dpi()
+ figwidth = figure.get_figwidth() * dpi
+ figheight = figure.get_figheight() * dpi
+ w = int (width*.75)
+ h = int ( (w/figwidth)*figheight)
+ if h > height*.75:
+ h = int (height*.75)
+ w = int ( (h/figheight)*figwidth)
+ figure.set_figwidth (w/dpi)
+ figure.set_figheight (h/dpi)
+ canvas = Canvas(figure)
+ for s,func in console.callbacks:
+ canvas.mpl_connect(s,func)
+ canvas.set_size_request (w,h)
+ canvas.show_all()
+ console.write ('\n')
+ console.write (' ', 'center')
+ iter = buffer.get_iter_at_mark(buffer.get_mark('insert'))
+ anchor = buffer.create_child_anchor(iter)
+ console.write (' ', 'center')
+
+ if console.use_toolbar:
+ boxout = gtk.EventBox()
+ boxout.set_border_width(0)
+ boxin = gtk.EventBox()
+ boxin.set_border_width(1)
+ boxout.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#cccccc"))
+ boxout.add (boxin)
+
+ vbox = gtk.VBox()
+ box = gtk.EventBox()
+ box.add(canvas)
+ box.connect ('enter-notify-event', figure_enter, console)
+ box.connect ('leave-notify-event', figure_leave, console)
+ vbox.add(box)
+ toolbar = NavigationToolbar(canvas, None)
+ vbox.add(toolbar)
+
+ if console.use_toolbar:
+ boxin.add(vbox)
+ boxout.show_all()
+ vbox.show()
+ box.show()
+ view.add_child_at_anchor(boxout, anchor)
+ else:
+ vbox.show_all()
+ toolbar.hide()
+ view.add_child_at_anchor(vbox, anchor)
+
+ console.shell.namespace()['pan'] = toolbar.pan
+ console.shell.namespace()['zoom'] = toolbar.zoom
+ console.shell.namespace()['back'] = toolbar.back
+ console.shell.namespace()['forward'] = toolbar.forward
+ console.shell.namespace()['home'] = toolbar.forward
+ console.shell.namespace()['save'] = partial(toolbar.save_figure,1)
+ console.write ('\n')
+ figures.append ( (figure, canvas, anchor) )
+ console.last_figure = figure
+
+# ----------------------------------------------------------------------- refresh
+def refresh(console):
+ """ Refreshs all active canvas """
+ figures = console.figures
+ for fig in figures:
+ figure, canvas, anchor = fig
+ canvas.draw()
+
+# ----------------------------------------------------------------------- replot
+def replot (console):
+ """
+ Produces a replot of the last figure and insert it within console. Previous
+ figure, if it exists, is transformed into a static image replica and
+ inserted in place of the previous figure.
+ """
+
+ figures = console.figures
+ last_figure = console.last_figure
+ if not figures:
+ if last_figure:
+ insert (console, last_figure)
+ return
+ else:
+ return
+ figure, canvas, anchor = figures[-1]
+ if not anchor.get_deleted():
+ replace (console, canvas, anchor)
+ figures.remove ( (figure, canvas, anchor) )
+ # insert (console, figure, canvas)
+ insert (console, figure)
+ else:
+ console.figures = console.figures[0:-1]
+ insert (console, figure)
+ console.view.scroll_mark_onscreen(console.buffer.get_insert())
+ while gtk.events_pending():
+ gtk.main_iteration()
+
+
+# ---------------------------------------------------------------------- connect
+def connect (console, s, func):
+ """ Append callback to the list of callbacks (to be connected later) """
+
+ console.callbacks.append([s,func])
+
+
+# ------------------------------------------------------------------------- show
+def show (console):
+ """ Insert pending figures within console """
+
+ figures = console.figures
+ last_figure = console.last_figure
+ for manager in Gcf.get_all_fig_managers():
+ found = False
+ for fig in figures:
+ figure, canvas, anchor = fig
+ if figure == manager.canvas.figure:
+ canvas.draw()
+ found = True
+ break
+ if not found:
+ insert (console, manager.canvas.figure)
+
+# ---------------------------------------------------------------- class Console
+class Console (cons.Console):
+ """ GTK python console """
+
+ def __init__(self, argv=[], shelltype='python', banner=[],
+ filename=None, size=100):
+ cons.Console.__init__(self, argv, shelltype, banner, filename, size)
+ self.buffer.create_tag('center',
+ justification=gtk.JUSTIFY_CENTER,
+ font='Mono 4')
+ self.figures = []
+ self.callbacks = []
+ self.last_figure = None
+ self.active_canvas = None
+ self.view.connect ('key-press-event', self.key_press_event)
+ self.view.connect ('button-press-event', self.button_press_event)
+ self.view.connect ('scroll-event', self.scroll_event)
+
+
+ def key_press_event (self, widget, event):
+ """ Handle key press event """
+
+ if self.active_canvas:
+ self.active_canvas.emit ('key-press-event', event)
+ return True
+ return cons.Console.key_press_event (self, widget, event)
+
+ def scroll_event (self, widget, event):
+ """ Scroll event """
+ if self.active_canvas:
+ return True
+ return False
+
+ def button_press_event (self, widget, event):
+ """ Button press event """
+ return self.refresh()
+
+ def refresh (self):
+ """ Refresh drawing """
+ for fig in self.figures:
+ figure, canvas, anchor = fig
+ canvas.draw()
+ return False
+
+
+if __name__ == "__main__":
+ from optparse import OptionParser
+ try:
+ import IPython
+ except:
+ pass
+
+ usage = "Usage: %pycons [options] file"
+ parser = OptionParser(usage=usage, version="%prog 1.0")
+ parser.add_option("", "--ipython", action="store_true", dest="ipython",
+ help="Use IPython as shell (if available)")
+ parser.add_option("", "--pylab", action="store_true", dest="pylab",
+ help="Use Pylab integration (if available)")
+ parser.add_option("", "--toolbar", action="store_true", dest="toolbar",
+ help="Use Pylab toolbar")
+ (options, args) = parser.parse_args()
+
+ filename = os.path.expanduser("~/.pyhistory")
+ p = 'Python %s' % sys.version.split(' ')[0]
+ l = 'matplotlib %s' % matplotlib.__version__
+ shelltype = 'python'
+ if (options.ipython and ipython_available) is True:
+ p = 'IPython %s' % IPython.__version__
+ shelltype = 'ipython'
+ if not pylab_available or not options.pylab:
+ banner = [
+ ['GTK Python console\n', 'title'],
+ [' Using %s\n' % p,'subtitle'],
+ [' Type "help", "copyright", "credits" or "license" for more information.\n',
+ 'subtitle']
+ ]
+ else:
+ banner = [
+ ['GTK Pylab console\n', 'title'],
+ [' Using %s and %s\n' % (p,l),'subtitle'],
+ [' Extra commands: "replot", "refresh", "pan", "zoom", "back", "forward", "home"\n',
+ 'subtitle']
+ ]
+ console = Console(argv=args, shelltype=shelltype,
+ banner=banner, filename=filename, size=100)
+ if options.toolbar:
+ console.use_toolbar = True
+ else:
+ console.use_toolbar = False
+ window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ window.set_position(gtk.WIN_POS_CENTER)
+ window.set_default_size(800,600)
+ window.set_border_width(0)
+ window.connect('destroy-event', gtk.main_quit)
+ window.connect('delete-event', gtk.main_quit)
+ window.add (console)
+ window.show_all()
+ console.grab_focus()
+
+ if pylab_available and options.pylab:
+ console.write ("from pylab import *")
+ console.execute()
+ pylab.show = partial (show, console)
+ matplotlib.pylab.show = pylab.show
+ matplotlib.pyplot.show = pylab.show
+ pylab.connect = partial (connect, console)
+ matplotlib.pylab.connect = pylab.connect
+ console.shell.namespace()['replot'] = partial (replot, console)
+ console.shell.namespace()['refresh'] = partial (refresh, console)
+
+ def execfiles(console):
+ console.write ('execfile("%s")' % args[0])
+ # execfile(console.argv[0], console.shell.namespace())
+ console.execute()
+ return False
+ if len(args):
+ gobject.timeout_add(50, execfiles, console)
+
+
+ # Prevent external commands/scripts to quit
+ while console.do_quit == False:
+ gtk.main()
+
Added: gnucash/trunk/src/python/pycons/setup.py
===================================================================
--- gnucash/trunk/src/python/pycons/setup.py (rev 0)
+++ gnucash/trunk/src/python/pycons/setup.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,40 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2008, Nicolas Rougier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from distutils.core import setup
+
+setup(name='PyCons',
+ version='1.0.1',
+ description='IPython/Python/Pylab GTK Console',
+ author='Nicolas Rougier',
+ author_email='Nicolas.Rougier at loria.fr',
+ url='http://www.loria.fr/~rougier/pycons.html',
+ packages=['pycons'],
+ package_dir = {'pycons': '.'},
+ scripts=['pycons']
+ )
Added: gnucash/trunk/src/python/pycons/shell.py
===================================================================
--- gnucash/trunk/src/python/pycons/shell.py (rev 0)
+++ gnucash/trunk/src/python/pycons/shell.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,173 @@
+#! /usr/bin/env python
+#
+# Copyright (c) 2008, Nicolas Rougier
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the University of California, Berkeley nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+import re
+import rlcompleter
+import traceback
+import tempfile
+
+if not hasattr(sys, 'ps1'): sys.ps1 = '>>> '
+if not hasattr(sys, 'ps2'): sys.ps2 = '... '
+
+
+class Shell:
+ """ """
+
+ def __init__(self, ns_globals={}, ns_locals={}):
+ """ """
+
+ self.completer = rlcompleter.Completer (ns_globals)
+ self.command = ''
+ self.globals = ns_globals
+ self.locals = ns_locals
+ self.complete_sep = re.compile('[\s\{\}\[\]\(\)]')
+ self.prompt = sys.ps1
+
+
+ def namespace(self):
+ return self.globals
+
+ def is_balanced (self, line):
+ """ Checks line balance for brace, bracket, parenthese and string quote
+
+ This helper function checks for the balance of brace, bracket,
+ parenthese and string quote. Any unbalanced line means to wait until
+ some other lines are fed to the console.
+ """
+
+ s = line
+ s = filter(lambda x: x in '()[]{}"\'', s)
+ s = s.replace ("'''", "'")
+ s = s.replace ('"""', '"')
+ instring = False
+ brackets = {'(':')', '[':']', '{':'}', '"':'"', '\'':'\''}
+ stack = []
+ while len(s):
+ if not instring:
+ if s[0] in ')]}':
+ if stack and brackets[stack[-1]] == s[0]:
+ del stack[-1]
+ else:
+ return False
+ elif s[0] in '"\'':
+ if stack and brackets[stack[-1]] == s[0]:
+ del stack[-1]
+ instring = False
+ else:
+ stack.append(s[0])
+ instring = True
+ else:
+ stack.append(s[0])
+ else:
+ if s[0] in '"\'' and stack and brackets[stack[-1]] == s[0]:
+ del stack[-1]
+ instring = False
+ s = s[1:]
+ return len(stack) == 0
+
+
+ def complete(self, line):
+ split_line = self.complete_sep.split(line)
+ possibilities = []
+ i = 0
+ c = self.completer.complete (split_line[-1], i)
+ while c:
+ possibilities.append(c)
+ i = i+1
+ c = self.completer.complete (split_line[-1], i)
+ if possibilities:
+ common_prefix = os.path.commonprefix (possibilities)
+ completed = line[:-len(split_line[-1])]+common_prefix
+ else:
+ completed = line
+ return completed, possibilities
+
+
+ def eval (self, console):
+ line = console.last_line()
+ console.write ('\n')
+ if line == '':
+ self.execute (console)
+ self.command = ''
+ self.prompt = sys.ps1
+ console.prompt('prompt')
+ return
+ self.command = self.command + line + '\n'
+ if not self.is_balanced (self.command):
+ self.prompt = sys.ps2
+ console.prompt('prompt')
+ return
+ line = line.rstrip()
+ if len(line) > 0:
+ if line[-1] == ':' or line[-1] == '\\' or line[0] in ' \11':
+ self.prompt = sys.ps2
+ console.prompt('prompt')
+ return
+ self.execute (console)
+ self.command = ''
+ self.prompt = sys.ps1
+ console.prompt('prompt')
+
+
+ def execute (self, console):
+ if not self.command:
+ return
+ try:
+ try:
+ r = eval (self.command, self.globals, self.locals)
+ if r is not None:
+ # System output (if any)
+ while True:
+ try:
+ buf = os.read(console.piperead, 256)
+ except:
+ break
+ else:
+ console.write (buf, 'output')
+ if len(buf) < 256: break
+ # Command output
+ print `r`
+ except SyntaxError:
+ exec self.command in self.globals
+ except:
+ if hasattr (sys, 'last_type') and sys.last_type == SystemExit:
+ console.quit()
+ elif hasattr (sys, 'exc_type') and sys.exc_type == SystemExit:
+ console.quit()
+ else:
+ try:
+ tb = sys.exc_traceback
+ if tb:
+ tb=tb.tb_next
+ traceback.print_exception (sys.exc_type, sys.exc_value, tb)
+ except:
+ sys.stderr, console.stderr = console.stderr, sys.stderr
+ traceback.print_exc()
+
Added: gnucash/trunk/src/python/pycons/simple_plot.py
===================================================================
--- gnucash/trunk/src/python/pycons/simple_plot.py (rev 0)
+++ gnucash/trunk/src/python/pycons/simple_plot.py 2011-03-24 20:10:45 UTC (rev 20471)
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+"""
+Example: simple line plot.
+Show how to make and save a simple line plot with labels, title and grid
+"""
+from pylab import *
+
+figure()
+t = arange(0.0, 1.0+0.01, 0.01)
+s = cos(2*2*pi*t)
+plot(t, s, '-', lw=2)
+
+xlabel('time (s)')
+ylabel('voltage (mV)')
+title('About as simple as it gets, folks')
+grid(True)
+show()
More information about the gnucash-changes
mailing list