python.py :  » Mobile » Python-for-PalmOS » Python-1.5.2+reduced-1.0 » Demo » stdwin » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Mobile » Python for PalmOS 
Python for PalmOS » Python 1.5.2 reduced 1.0 » Demo » stdwin » python.py
#! /usr/bin/env python

# A STDWIN-based front end for the Python interpreter.
#
# This is useful if you want to avoid console I/O and instead
# use text windows to issue commands to the interpreter.
#
# It supports multiple interpreter windows, each with its own context.
#
# BUGS AND CAVEATS:
#
# This was written long ago as a demonstration, and slightly hacked to
# keep it up-to-date, but never as an industry-strength alternative
# interface to Python.  It should be rewritten using more classes, and
# merged with something like wdb.
#
# Although this supports multiple windows, the whole application
# is deaf and dumb when a command is running in one window.
#
# Interrupt is (ab)used to signal EOF on input requests.
#
# On UNIX (using X11), interrupts typed in the window will not be
# seen until the next input or output operation.  When you are stuck
# in an infinite loop, try typing ^C in the shell window where you
# started this interpreter.  (On the Mac, interrupts work normally.)


import sys
import stdwin
from stdwinevents import *
import rand
import mainloop
import os


# Stack of windows waiting for [raw_]input().
# Element [0] is the top.
# If there are multiple windows waiting for input, only the
# one on top of the stack can accept input, because the way
# raw_input() is implemented (using recursive mainloop() calls).
#
inputwindows = []


# Exception raised when input is available
#
InputAvailable = 'input available for raw_input (not an error)'


# Main program -- create the window and call the mainloop
#
def main():
  # Hack so 'import python' won't load another copy
  # of this if we were loaded though 'python python.py'.
  # (Should really look at sys.argv[0]...)
  if 'inputwindows' in dir(sys.modules['__main__']) and \
      sys.modules['__main__'].inputwindows is inputwindows:
    sys.modules['python'] = sys.modules['__main__']
  #
  win = makewindow()
  mainloop.mainloop()


# Create a new window
#
def makewindow():
  # stdwin.setdefscrollbars(0, 1) # Not in Python 0.9.1
  # stdwin.setfont('monaco') # Not on UNIX! and not Python 0.9.1
  # width, height = stdwin.textwidth('in')*40, stdwin.lineheight()*24
  # stdwin.setdefwinsize(width, height)
  win = stdwin.open('Python interpreter ready')
  win.editor = win.textcreate((0,0), win.getwinsize())
  win.globals = {}    # Dictionary for user's globals
  win.command = ''    # Partially read command
  win.busy = 0      # Ready to accept a command
  win.auto = 1      # [CR] executes command
  win.insertOutput = 1    # Insert output at focus
  win.insertError = 1    # Insert error output at focus
  win.setwincursor('ibeam')
  win.filename = ''    # Empty if no file for this window
  makefilemenu(win)
  makeeditmenu(win)
  win.dispatch = pdispatch  # Event dispatch function
  mainloop.register(win)
  return win


# Make a 'File' menu
#
def makefilemenu(win):
  win.filemenu = mp = win.menucreate('File')
  mp.callback = []
  additem(mp, 'New', 'N', do_new)
  additem(mp, 'Open...', 'O', do_open)
  additem(mp, '', '',  None)
  additem(mp, 'Close', 'W', do_close)
  additem(mp, 'Save', 'S', do_save)
  additem(mp, 'Save as...', '', do_saveas)
  additem(mp, '', '', None)
  additem(mp, 'Quit', 'Q', do_quit)


# Make an 'Edit' menu
#
def makeeditmenu(win):
  win.editmenu = mp = win.menucreate('Edit')
  mp.callback = []
  additem(mp, 'Cut', 'X', do_cut)
  additem(mp, 'Copy', 'C', do_copy)
  additem(mp, 'Paste', 'V', do_paste)
  additem(mp, 'Clear', '',  do_clear)
  additem(mp, '', '', None)
  win.iauto = len(mp.callback)
  additem(mp, 'Autoexecute', '', do_auto)
  mp.check(win.iauto, win.auto)
  win.insertOutputNum = len(mp.callback)
  additem(mp, 'Insert Output', '', do_insertOutputOption)
  win.insertErrorNum = len(mp.callback)
  additem(mp, 'Insert Error', '', do_insertErrorOption)
  additem(mp, 'Exec', '\r', do_exec)


# Helper to add a menu item and callback function
#
def additem(mp, text, shortcut, handler):
  if shortcut:
    mp.additem(text, shortcut)
  else:
    mp.additem(text)
  mp.callback.append(handler)


# Dispatch a single event to the interpreter.
# Resize events cause a resize of the editor.
# Some events are treated specially.
# Most other events are passed directly to the editor.
#
def pdispatch(event):
  type, win, detail = event
  if not win:
    win = stdwin.getactive()
    if not win: return
  if type == WE_CLOSE:
    do_close(win)
    return
  elif type == WE_SIZE:
    win.editor.move((0, 0), win.getwinsize())
  elif type == WE_COMMAND and detail == WC_RETURN:
    if win.auto:
      do_exec(win)
    else:
      void = win.editor.event(event)
  elif type == WE_COMMAND and detail == WC_CANCEL:
    if win.busy:
      raise KeyboardInterrupt
    else:
      win.command = ''
      settitle(win)
  elif type == WE_MENU:
    mp, item = detail
    mp.callback[item](win)
  else:
    void = win.editor.event(event)
  if win in mainloop.windows:
    # May have been deleted by close...
    win.setdocsize(0, win.editor.getrect()[1][1])
    if type in (WE_CHAR, WE_COMMAND):
      win.editor.setfocus(win.editor.getfocus())


# Helper to set the title of the window
#
def settitle(win):
  if win.filename == '':
    win.settitle('Python interpreter ready')
  else:
    win.settitle(win.filename)


# Helper to replace the text of the focus
#
def replace(win, text):
  win.editor.replace(text)
  # Resize the window to display the text
  win.setdocsize(0, win.editor.getrect()[1][1]) # update the size before
  win.editor.setfocus(win.editor.getfocus()) # move focus to the change


# File menu handlers
#
def do_new(win):
  win = makewindow()
#
def do_open(win):
  try:
    filename = stdwin.askfile('Open file', '', 0)
    win = makewindow()
    win.filename = filename
    win.editor.replace(open(filename, 'r').read())
    win.editor.setfocus(0, 0)
    win.settitle(win.filename)
    #
  except KeyboardInterrupt:
    pass      # Don't give an error on cancel
#
def do_save(win):
  try:
    if win.filename == '':
      win.filename = stdwin.askfile('Open file', '', 1)
    f = open(win.filename, 'w')
    f.write(win.editor.gettext())
    #
  except KeyboardInterrupt:
    pass      # Don't give an error on cancel
  
def do_saveas(win):
  currentFilename = win.filename
  win.filename = ''
  do_save(win)    # Use do_save with empty filename
  if win.filename == '':  # Restore the name if do_save did not set it
    win.filename = currentFilename
#
def do_close(win):
  if win.busy:
    stdwin.message('Can\'t close busy window')
    return    # need to fail if quitting??
  win.editor = None # Break circular reference
  #del win.editmenu  # What about the filemenu??
  mainloop.unregister(win)
  win.close()
#
def do_quit(win):
  # Call win.dispatch instead of do_close because there
  # may be 'alien' windows in the list.
  for win in mainloop.windows[:]:
    mainloop.dispatch((WE_CLOSE, win, None))
    # need to catch failed close


# Edit menu handlers
#
def do_cut(win):
  text = win.editor.getfocustext()
  if not text:
    stdwin.fleep()
    return
  stdwin.setcutbuffer(0, text)
  replace(win, '')
#
def do_copy(win):
  text = win.editor.getfocustext()
  if not text:
    stdwin.fleep()
    return
  stdwin.setcutbuffer(0, text)
#
def do_paste(win):
  text = stdwin.getcutbuffer(0)
  if not text:
    stdwin.fleep()
    return
  replace(win, text)
#
def do_clear(win):
  replace(win, '')


# These would be better in a preferences dialog:
#
def do_auto(win):
  win.auto = (not win.auto)
  win.editmenu.check(win.iauto, win.auto)
#
def do_insertOutputOption(win):
  win.insertOutput = (not win.insertOutput)
  title = ['Append Output', 'Insert Output'][win.insertOutput]
  win.editmenu.setitem(win.insertOutputNum, title)
#
def do_insertErrorOption(win):
  win.insertError = (not win.insertError)
  title = ['Error Dialog', 'Insert Error'][win.insertError]
  win.editmenu.setitem(win.insertErrorNum, title)


# Extract a command from the editor and execute it, or pass input to
# an interpreter waiting for it.
# Incomplete commands are merely placed in the window's command buffer.
# All exceptions occurring during the execution are caught and reported.
# (Tracebacks are currently not possible, as the interpreter does not
# save the traceback pointer until it reaches its outermost level.)
#
def do_exec(win):
  if win.busy:
    if win not in inputwindows:
      stdwin.message('Can\'t run recursive commands')
      return
    if win <> inputwindows[0]:
      stdwin.message('Please complete recursive input first')
      return
  #
  # Set text to the string to execute.
  a, b = win.editor.getfocus()
  alltext = win.editor.gettext()
  n = len(alltext)
  if a == b:
    # There is no selected text, just an insert point;
    # so execute the current line.
    while 0 < a and alltext[a-1] <> '\n': # Find beginning of line
      a = a-1
    while b < n and alltext[b] <> '\n': # Find end of line after b
      b = b+1
    text = alltext[a:b] + '\n'
  else:
    # Execute exactly the selected text.
    text = win.editor.getfocustext()
    if text[-1:] <> '\n': # Make sure text ends with \n
      text = text + '\n'
    while b < n and alltext[b] <> '\n': # Find end of line after b
      b = b+1
  #
  # Set the focus to expect the output, since there is always something.
  # Output will be inserted at end of line after current focus,
  # or appended to the end of the text.
  b = [n, b][win.insertOutput]
  win.editor.setfocus(b, b)
  #
  # Make sure there is a preceeding newline.
  if alltext[b-1:b] <> '\n':
    win.editor.replace('\n')
  #
  #
  if win.busy:
    # Send it to raw_input() below
    raise InputAvailable, text
  #
  # Like the real Python interpreter, we want to execute
  # single-line commands immediately, but save multi-line
  # commands until they are terminated by a blank line.
  # Unlike the real Python interpreter, we don't do any syntax
  # checking while saving up parts of a multi-line command.
  #
  # The current heuristic to determine whether a command is
  # the first line of a multi-line command simply checks whether
  # the command ends in a colon (followed by a newline).
  # This is not very robust (comments and continuations will
  # confuse it), but it is usable, and simple to implement.
  # (It even has the advantage that single-line loops etc.
  # don't need te be terminated by a blank line.)
  #
  if win.command:
    # Already continuing
    win.command = win.command + text
    if win.command[-2:] <> '\n\n':
      win.settitle('Unfinished command...')
      return # Need more...
  else:
    # New command
    win.command = text
    if text[-2:] == ':\n':
      win.settitle('Unfinished command...')
      return
  command = win.command
  win.command = ''
  win.settitle('Executing command...')
  #
  # Some hacks:
  # - The standard files are replaced by an IOWindow instance.
  # - A 2nd argument to exec() is used to specify the directory
  #   holding the user's global variables.  (If this wasn't done,
  #   the exec would be executed in the current local environment,
  #   and the user's assignments to globals would be lost...)
  #
  save_stdin = sys.stdin
  save_stdout = sys.stdout
  save_stderr = sys.stderr
  try:
    sys.stdin = sys.stdout = sys.stderr = IOWindow(win)
    win.busy = 1
    try:
      exec(command, win.globals)
    except KeyboardInterrupt:
      print '[Interrupt]'
    except:
      if type(sys.exc_type) == type(''):
        msg = sys.exc_type
      else: msg = sys.exc_type.__name__
      if sys.exc_value <> None:
        msg = msg + ': ' + `sys.exc_value`
      if win.insertError:
        stdwin.fleep()
        replace(win, msg + '\n')
      else:
        win.settitle('Unhandled exception')
        stdwin.message(msg)
  finally:
    # Restore redirected I/O in *all* cases
    win.busy = 0
    sys.stderr = save_stderr
    sys.stdout = save_stdout
    sys.stdin = save_stdin
    settitle(win)


# Class emulating file I/O from/to a window
#
class IOWindow:
  #
  def __init__(self, win):
    self.win = win
  #
  def readline(self, *unused_args):
    n = len(inputwindows)
    save_title = self.win.gettitle()
    title = n*'(' + 'Requesting input...' + ')'*n
    self.win.settitle(title)
    inputwindows.insert(0, self.win)
    try:
      try:
        mainloop.mainloop()
      finally:
        del inputwindows[0]
        self.win.settitle(save_title)
    except InputAvailable, val: # See do_exec above
      return val
    except KeyboardInterrupt:
      raise EOFError # Until we have a "send EOF" key
    # If we didn't catch InputAvailable, something's wrong...
    raise EOFError
  #
  def write(self, text):
    mainloop.check()
    replace(self.win, text)
    mainloop.check()


# Currently unused function to test a command's syntax without executing it
#
def testsyntax(s):
  import string
  lines = string.splitfields(s, '\n')
  for i in range(len(lines)): lines[i] = '\t' + lines[i]
  lines.insert(0, 'if 0:')
  lines.append('')
  exec(string.joinfields(lines, '\n'))


# Call the main program
#
main()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.