scriptutils.py :  » Windows » pyExcelerator » pywin32-214 » pythonwin » pywin » framework » 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 » Windows » pyExcelerator 
pyExcelerator » pywin32 214 » pythonwin » pywin » framework » scriptutils.py
"""
Various utilities for running/importing a script
"""
import sys
import win32ui
import win32api
import win32con
import __main__
from pywin.mfc import dialog
from pywin.mfc.docview import TreeView
import os
import string
import traceback
import linecache
import bdb

from cmdline import ParseArgs

RS_DEBUGGER_NONE=0 # Dont run under the debugger.
RS_DEBUGGER_STEP=1 # Start stepping under the debugger
RS_DEBUGGER_GO=2 # Just run under the debugger, stopping only at break-points.
RS_DEBUGGER_PM=3 # Dont run under debugger, but do post-mortem analysis on exception.

debugging_options = """No debugging
Step-through in the debugger
Run in the debugger
Post-Mortem of unhandled exceptions""".split("\n")

byte_cr = "\r".encode("ascii")
byte_lf = "\n".encode("ascii")
byte_crlf = "\r\n".encode("ascii")

# A dialog box for the "Run Script" command.
class DlgRunScript(dialog.Dialog):
  "A class for the 'run script' dialog"
  def __init__(self, bHaveDebugger):
    dialog.Dialog.__init__(self, win32ui.IDD_RUN_SCRIPT )
    self.AddDDX(win32ui.IDC_EDIT1, "script")
    self.AddDDX(win32ui.IDC_EDIT2, "args")
    self.AddDDX(win32ui.IDC_COMBO1, "debuggingType", "i")
    self.HookCommand(self.OnBrowse, win32ui.IDC_BUTTON2)
    self.bHaveDebugger = bHaveDebugger
  def OnInitDialog(self):
    rc = dialog.Dialog.OnInitDialog(self)
    cbo = self.GetDlgItem(win32ui.IDC_COMBO1)
    for o in debugging_options:
      cbo.AddString(o)
    cbo.SetCurSel(self['debuggingType'])
    if not self.bHaveDebugger:
      cbo.EnableWindow(0)

  def OnBrowse(self, id, cmd):
    openFlags = win32con.OFN_OVERWRITEPROMPT|win32con.OFN_FILEMUSTEXIST
    dlg = win32ui.CreateFileDialog(1,None,None,openFlags, "Python Scripts (*.py)|*.py||", self)
    dlg.SetOFNTitle("Run Script")
    if dlg.DoModal()!=win32con.IDOK:
      return 0
    self['script'] = dlg.GetPathName()
    self.UpdateData(0)
    return 0

def GetDebugger():
  """Get the default Python debugger.  Returns the debugger, or None.
  
  It is assumed the debugger has a standard "pdb" defined interface.
  Currently always returns the 'pywin.debugger' debugger, or None
  (pdb is _not_ returned as it is not effective in this GUI environment)
  """
  try:
    import pywin.debugger
    return pywin.debugger
  except ImportError:
    return None

def IsOnPythonPath(path):
  "Given a path only, see if it is on the Pythonpath.  Assumes path is a full path spec."
  # must check that the command line arg's path is in sys.path
  for syspath in sys.path:
    try:
      # Python 1.5 and later allows an empty sys.path entry.
      if syspath and win32ui.FullPath(syspath)==path:
        return 1
    except win32ui.error, details:
      print "Warning: The sys.path entry '%s' is invalid\n%s" % (syspath, details)
  return 0

def GetPackageModuleName(fileName):
  """Given a filename, return (module name, new path).
     eg - given "c:\a\b\c\my.py", return ("b.c.my",None) if "c:\a" is on sys.path.
     If no package found, will return ("my", "c:\a\b\c")
  """
  path, fname = os.path.split(fileName)
  path=origPath=win32ui.FullPath(path)
  fname = os.path.splitext(fname)[0]
  modBits = []
  newPathReturn = None
  if not IsOnPythonPath(path):
    # Module not directly on the search path - see if under a package.
    while len(path)>3: # ie 'C:\'
      path, modBit = os.path.split(path)
      modBits.append(modBit)
      # If on path, _and_ existing package of that name loaded.
      if IsOnPythonPath(path) and modBit in sys.modules and \
        ( os.path.exists(os.path.join(path, '__init__.py')) or \
        os.path.exists(os.path.join(path, '__init__.pyc')) or \
        os.path.exists(os.path.join(path, '__init__.pyo')) \
        ):
        modBits.reverse()
        return ".".join(modBits) + "." + fname, newPathReturn
      # Not found - look a level higher
    else:
      newPathReturn = origPath
    
  return fname, newPathReturn

def GetActiveView():
  """Gets the edit control (eg, EditView) with the focus, or None
  """
  try:
    childFrame, bIsMaximised = win32ui.GetMainFrame().MDIGetActive()
    return childFrame.GetActiveView()
  except win32ui.error:
    return None

def GetActiveEditControl():
  view = GetActiveView()
  if view is None: return None
  if hasattr(view, "SCIAddText"): # Is it a scintilla control?
    return view
  try:
    return view.GetRichEditCtrl()
  except AttributeError:
    pass
  try:
    return view.GetEditCtrl()
  except AttributeError:
    pass

def GetActiveEditorDocument():
  """Returns the active editor document and view, or (None,None) if no
  active document or its not an editor document.
  """
  view = GetActiveView()
  if view is None or isinstance(view, TreeView):
    return (None, None)
  doc = view.GetDocument()
  if hasattr(doc, "MarkerAdd"): # Is it an Editor document?
    return doc, view
  return (None, None)

def GetActiveFileName(bAutoSave = 1):
  """Gets the file name for the active frame, saving it if necessary.
  
  Returns None if it cant be found, or raises KeyboardInterrupt.
  """
  pathName = None
  active = GetActiveView()
  if active is None:
    return None
  try:
    doc = active.GetDocument()
    pathName = doc.GetPathName()

    if bAutoSave and \
      (len(pathName)>0 or \
      doc.GetTitle()[:8]=="Untitled" or \
      doc.GetTitle()[:6]=="Script"): # if not a special purpose window
      if doc.IsModified():
        try:
          doc.OnSaveDocument(pathName)
          pathName = doc.GetPathName()
          
          # clear the linecache buffer
          linecache.clearcache()

        except win32ui.error:
          raise KeyboardInterrupt

  except (win32ui.error, AttributeError):
    pass
  if not pathName:
    return None
  return pathName

lastScript = ''
lastArgs = ''
lastDebuggingType = RS_DEBUGGER_NONE

def RunScript(defName=None, defArgs=None, bShowDialog = 1, debuggingType=None):
  global lastScript, lastArgs, lastDebuggingType
  _debugger_stop_frame_ = 1 # Magic variable so the debugger will hide me!

  # Get the debugger - may be None!
  debugger = GetDebugger()

  if defName is None:
    try:
      pathName = GetActiveFileName()
    except KeyboardInterrupt:
      return # User cancelled save.
  else:
    pathName = defName
  if not pathName:
    pathName = lastScript
  if defArgs is None:
    args = ''
    if pathName==lastScript:
      args = lastArgs
  else:
    args = defArgs
  if debuggingType is None: debuggingType = lastDebuggingType

  if not pathName or bShowDialog:
    dlg = DlgRunScript(debugger is not None)
    dlg['script'] = pathName
    dlg['args'] = args
    dlg['debuggingType'] = debuggingType
    if dlg.DoModal() != win32con.IDOK:
      return
    script=dlg['script']
    args=dlg['args']
    debuggingType = dlg['debuggingType']
    if not script: return
    if debuggingType == RS_DEBUGGER_GO and debugger is not None:
      # This may surprise users - they select "Run under debugger", but
      # it appears not to!  Only warn when they pick from the dialog!
      # First - ensure the debugger is activated to pickup any break-points
      # set in the editor.
      try:
        # Create the debugger, but _dont_ init the debugger GUI.
        rd = debugger._GetCurrentDebugger()
      except AttributeError:
        rd = None
      if rd is not None and len(rd.breaks)==0:
        msg = "There are no active break-points.\r\n\r\nSelecting this debug option without any\r\nbreak-points is unlikely to have the desired effect\r\nas the debugger is unlikely to be invoked..\r\n\r\nWould you like to step-through in the debugger instead?"
        rc = win32ui.MessageBox(msg, win32ui.LoadString(win32ui.IDR_DEBUGGER), win32con.MB_YESNOCANCEL | win32con.MB_ICONINFORMATION)
        if rc == win32con.IDCANCEL:
          return
        if rc == win32con.IDYES:
          debuggingType = RS_DEBUGGER_STEP

    lastDebuggingType = debuggingType
    lastScript = script
    lastArgs = args
  else:
    script = pathName

  # try and open the script.
  if len(os.path.splitext(script)[1])==0:  # check if no extension supplied, and give one.
      script = script + '.py'
  # If no path specified, try and locate the file
  path, fnameonly = os.path.split(script)
  if len(path)==0:
    try:
      os.stat(fnameonly) # See if it is OK as is...
      script = fnameonly
    except os.error:
      fullScript = LocatePythonFile(script)
      if fullScript is None:
        win32ui.MessageBox("The file '%s' can not be located" % script )
        return
      script = fullScript
  else:
    path = win32ui.FullPath(path)
    if not IsOnPythonPath(path): sys.path.append(path)

  # py3k fun: If we use text mode to open the file, we get \r\n
  # translated so Python allows the syntax (good!), but we get back
  # text already decoded from the default encoding (bad!) and Python
  # ignores any encoding decls (bad!).  If we use binary mode we get
  # the raw bytes and Python looks at the encoding (good!) but \r\n
  # chars stay in place so Python throws a syntax error (bad!).
  # So: so the binary thing and manually normalize \r\n.
  try:
    f = open(script, 'rb')
  except IOError, exc:
    win32ui.MessageBox("The file could not be opened - %s (%d)" % (exc.strerror, exc.errno))
    return

  # Get the source-code - as above, normalize \r\n
  code = f.read().replace(byte_crlf, byte_lf).replace(byte_cr, byte_lf) + byte_lf

  # Remember and hack sys.argv for the script.
  oldArgv = sys.argv
  sys.argv = ParseArgs(args)
  sys.argv.insert(0, script)
  # sys.path[0] is the path of the script
  oldPath0 = sys.path[0]
  newPath0 = os.path.split(script)[0]
  if not oldPath0: # if sys.path[0] is empty
    sys.path[0] = newPath0
    insertedPath0 = 0
  else:
    sys.path.insert(0, newPath0)
    insertedPath0 = 1
  bWorked = 0
  win32ui.DoWaitCursor(1)
  base = os.path.split(script)[1]
  # Allow windows to repaint before starting.
  win32ui.PumpWaitingMessages()
  win32ui.SetStatusText('Running script %s...' % base,1 )
  exitCode = 0
  from pywin.framework import interact
  # Check the debugger flags
  if debugger is None and (debuggingType != RS_DEBUGGER_NONE):
    win32ui.MessageBox("No debugger is installed.  Debugging options have been ignored!")
    debuggingType = RS_DEBUGGER_NONE

  # Get a code object - ignore the debugger for this, as it is probably a syntax error
  # at this point
  try:
    codeObject = compile(code, script, "exec")
  except:
    # Almost certainly a syntax error!
    _HandlePythonFailure("run script", script)
    # No code object which to run/debug.
    return
  try:
    if debuggingType == RS_DEBUGGER_STEP:
      debugger.run(codeObject, __main__.__dict__, start_stepping=1)
    elif debuggingType == RS_DEBUGGER_GO:
      debugger.run(codeObject, __main__.__dict__, start_stepping=0)
    else:
      # Post mortem or no debugging
      exec codeObject in __main__.__dict__
    bWorked = 1
  except bdb.BdbQuit:
    # Dont print tracebacks when the debugger quit, but do print a message.
    print "Debugging session cancelled."
    exitCode = 1
    bWorked = 1
  except SystemExit, code:
    exitCode = code
    bWorked = 1
  except KeyboardInterrupt:
    # Consider this successful, as we dont want the debugger.
    # (but we do want a traceback!)
    if interact.edit and interact.edit.currentView:
      interact.edit.currentView.EnsureNoPrompt()
    traceback.print_exc()
    if interact.edit and interact.edit.currentView:
      interact.edit.currentView.AppendToPrompt([])
    bWorked = 1
  except:
    if interact.edit and interact.edit.currentView:
      interact.edit.currentView.EnsureNoPrompt()
    traceback.print_exc()
    if interact.edit and interact.edit.currentView:
      interact.edit.currentView.AppendToPrompt([])
    if debuggingType == RS_DEBUGGER_PM:
      debugger.pm()
  sys.argv = oldArgv
  if insertedPath0:
    del sys.path[0]
  else:
    sys.path[0] = oldPath0
  f.close()
  if bWorked:
    win32ui.SetStatusText("Script '%s' returned exit code %s" %(script, exitCode))
  else:
    win32ui.SetStatusText('Exception raised while running script  %s' % base)
  try:
    sys.stdout.flush()
  except AttributeError:
    pass

  win32ui.DoWaitCursor(0)

def ImportFile():
  """ This code looks for the current window, and determines if it can be imported.  If not,
  it will prompt for a file name, and allow it to be imported. """
  try:
    pathName = GetActiveFileName()
  except KeyboardInterrupt:
    pathName = None

  if pathName is not None:
    if os.path.splitext(pathName)[1].lower() != ".py":
      pathName = None

  if pathName is None:
    openFlags = win32con.OFN_OVERWRITEPROMPT|win32con.OFN_FILEMUSTEXIST
    dlg = win32ui.CreateFileDialog(1,None,None,openFlags, "Python Scripts (*.py)|*.py||")
    dlg.SetOFNTitle("Import Script")
    if dlg.DoModal()!=win32con.IDOK:
      return 0

    pathName = dlg.GetPathName()
    
  # If already imported, dont look for package
  path, modName = os.path.split(pathName)
  modName, modExt = os.path.splitext(modName)
  newPath = None
  for key, mod in sys.modules.iteritems():
    if hasattr(mod, '__file__'):
      fname = mod.__file__
      base, ext = os.path.splitext(fname)
      if ext.lower() in ['.pyo', '.pyc']:
        ext = '.py'
      fname = base + ext
      if win32ui.ComparePath(fname, pathName):
        modName = key
        break
  else: # for not broken
    modName, newPath = GetPackageModuleName(pathName)
    if newPath: sys.path.append(newPath)

  if modName in sys.modules:
    bNeedReload = 1
    what = "reload"
  else:
    what = "import"
    bNeedReload = 0
  
  win32ui.SetStatusText(what.capitalize()+'ing module...',1)
  win32ui.DoWaitCursor(1)
#  win32ui.GetMainFrame().BeginWaitCursor()

  try:
    # always do an import, as it is cheap if it's already loaded.  This ensures
    # it is in our name space.
    codeObj = compile('import '+modName,'<auto import>','exec')
  except SyntaxError:
    win32ui.SetStatusText('Invalid filename for import: "' +modName+'"')
    return
  try:
    exec codeObj in __main__.__dict__
    if bNeedReload:
      try:
        ## The interpreter sees this import as a local assignment, so Python 2.x throws
        ##  UnboundLocalError: local variable 'reload' referenced before assignment
        ## when you try to use reload after this fails
        from imp import reload
        my_reload = reload # reload a builtin in py2k
      my_reload(sys.modules[modName])
    win32ui.SetStatusText('Successfully ' + what + "ed module '"+modName+"'")
  except:
    _HandlePythonFailure(what)
  win32ui.DoWaitCursor(0)

def CheckFile():
  """ This code looks for the current window, and gets Python to check it
  without actually executing any code (ie, by compiling only)
  """
  try:
    pathName = GetActiveFileName()
  except KeyboardInterrupt:
    return

  what = "check"  
  win32ui.SetStatusText(what.capitalize()+'ing module...',1)
  win32ui.DoWaitCursor(1)
  try:
    f = open(pathName)
  except IOError, details:
    print "Cant open file '%s' - %s" % (pathName, details)
    return
  try:
    code = f.read() + "\n"
  finally:
    f.close()
  try:
    codeObj = compile(code, pathName,'exec')
    if RunTabNanny(pathName):
      win32ui.SetStatusText("Python and the TabNanny successfully checked the file '"+os.path.basename(pathName)+"'")
  except SyntaxError:
    _HandlePythonFailure(what, pathName)
  except:
    traceback.print_exc()
    _HandlePythonFailure(what)
  win32ui.DoWaitCursor(0)

def RunTabNanny(filename):
  import cStringIO as io
  tabnanny = FindTabNanny()
  if tabnanny is None:
    win32ui.MessageBox("The TabNanny is not around, so the children can run amok!" )
    return
    
  # Capture the tab-nanny output
  newout = io.StringIO()
  old_out = sys.stderr, sys.stdout
  sys.stderr = sys.stdout = newout
  try:
    tabnanny.check(filename)
  finally:
    # Restore output
    sys.stderr, sys.stdout = old_out
  data = newout.getvalue()
  if data:
    try:
      lineno = data.split()[1]
      lineno = int(lineno)
      _JumpToPosition(filename, lineno)
      try: # Try and display whitespace
        GetActiveEditControl().SCISetViewWS(1)
      except:
        pass
      win32ui.SetStatusText("The TabNanny found trouble at line %d" % lineno)
    except (IndexError, TypeError, ValueError):
      print "The tab nanny complained, but I cant see where!"
      print data
    return 0
  return 1

def _JumpToPosition(fileName, lineno, col = 1):
  JumpToDocument(fileName, lineno, col)

def JumpToDocument(fileName, lineno=0, col = 1, nChars = 0, bScrollToTop = 0):
  # Jump to the position in a file.
  # If lineno is <= 0, dont move the position - just open/restore.
  # if nChars > 0, select that many characters.
  # if bScrollToTop, the specified line will be moved to the top of the window
  #  (eg, bScrollToTop should be false when jumping to an error line to retain the
  #  context, but true when jumping to a method defn, where we want the full body.
  doc = win32ui.GetApp().OpenDocumentFile(fileName)
  if doc is None: return 0
  frame = doc.GetFirstView().GetParentFrame()
  try:
    view = frame.GetEditorView()
    if frame.GetActiveView() != view:
      frame.SetActiveView(view)
    frame.AutoRestore()
  except AttributeError: # Not an editor frame??
    view = doc.GetFirstView()
  if lineno > 0:
    charNo = view.LineIndex(lineno-1)
    start = charNo + col - 1
    size = view.GetTextLength()
    try:
      view.EnsureCharsVisible(charNo)
    except AttributeError:
      print "Doesnt appear to be one of our views?"
    view.SetSel(min(start, size), min(start + nChars, size))
  if bScrollToTop:
    curTop = view.GetFirstVisibleLine()
    nScroll = (lineno-1) - curTop
    view.LineScroll(nScroll, 0)
  view.SetFocus()
  return 1

def _HandlePythonFailure(what, syntaxErrorPathName = None):
  typ, details, tb = sys.exc_info()
  if isinstance(details, SyntaxError):
    try:
      msg, (fileName, line, col, text) = details
      if (not fileName or fileName =="<string>") and syntaxErrorPathName:
        fileName = syntaxErrorPathName
      _JumpToPosition(fileName, line, col)
    except (TypeError, ValueError):
      msg = str(details)
    win32ui.SetStatusText('Failed to ' + what + ' - syntax error - %s' % msg)
  else:  
    traceback.print_exc()
    win32ui.SetStatusText('Failed to ' + what + ' - ' + str(details) )
  tb = None # Clean up a cycle.

# Find the Python TabNanny in either the standard library or the Python Tools/Scripts directory.
def FindTabNanny():
  try:
    return __import__("tabnanny")
  except ImportError:
    pass
  # OK - not in the standard library - go looking.
  filename = "tabnanny.py"
  try:
    path = win32api.RegQueryValue(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%s\\InstallPath" % (sys.winver))
  except win32api.error:
    print "WARNING - The Python registry does not have an 'InstallPath' setting"
    print "          The file '%s' can not be located" % (filename)
    return None
  fname = os.path.join(path, "Tools\\Scripts\\%s" % filename)
  try:
    os.stat(fname)
  except os.error:
    print "WARNING - The file '%s' can not be located in path '%s'" % (filename, path)
    return None

  tabnannyhome, tabnannybase = os.path.split(fname)
  tabnannybase = os.path.splitext(tabnannybase)[0]
  # Put tab nanny at the top of the path.
  sys.path.insert(0, tabnannyhome)
  try:
    return __import__(tabnannybase)
  finally:
    # remove the tab-nanny from the path
    del sys.path[0]
    
def LocatePythonFile( fileName, bBrowseIfDir = 1 ):
  " Given a file name, return a fully qualified file name, or None "
  # first look for the exact file as specified
  if not os.path.isfile(fileName):
    # Go looking!
    baseName = fileName
    for path in sys.path:
      fileName = os.path.abspath(os.path.join(path, baseName))
      if os.path.isdir(fileName):
        if bBrowseIfDir:
          d=win32ui.CreateFileDialog(1, "*.py", None, 0, "Python Files (*.py)|*.py|All files|*.*")
          d.SetOFNInitialDir(fileName)
          rc=d.DoModal()
          if rc==win32con.IDOK:
            fileName = d.GetPathName()
            break
          else:
            return None
      else:
        fileName = fileName + ".py"
        if os.path.isfile(fileName):
          break # Found it!

    else:  # for not broken out of
      return None
  return win32ui.FullPath(fileName)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.