"""
Console Module display Python console
"""
import sys
import os
import numpy as np
import wx
from wx.lib.dialogs import ScrolledMessageDialog
from wx.lib import layoutf
import wx.py.editor as editor
if sys.platform.count("win32") > 0:
PANEL_WIDTH = 800
PANEL_HEIGHT = 700
FONT_VARIANT = 0
else:
PANEL_WIDTH = 830
PANEL_HEIGHT = 730
FONT_VARIANT = 1
ID_CHECK_MODEL = wx.NewId()
ID_RUN = wx.NewId()
[docs]def check_model(path):
"""
Check that the model on the path can run.
"""
# TODO: fix model caching
# model_test.run_one() is directly forcing a reload of the module, but
# sasview_model is caching models that have already been loaded.
# If the sasview load happens before the test, then the module is
# reloaded out from under it, which causes the global variables in
# the model function definitions to be cleared (at least in python 2.7).
# To fix the proximal problem of models failing on test, perform the
# run_one() tests first. To fix the deeper problem we should either
# remove caching from sasmodels.sasview_model.load_custom_model() or
# add caching to sasmodels.custom.load_custom_kernel_module(). Another
# option is to add a runTests method to SasviewModel which runs the
# test suite directly from the model info structure. Probably some
# combination of options:
# (1) have this function (check_model) operate on a loaded model
# so that caching isn't needed in sasview_models.load_custom_model
# (2) add the runTests method to SasviewModel so that tests can
# be run on a loaded module.
#
# Also, note that the model test suite runs the equivalent of the
# "try running the model" block below, and doesn't need to be run
# twice. The reason for duplicating the block here is to generate
# an exception that show_model_output can catch. Need to write the
# runTests method so that it returns success flag as well as output
# string so that the extra test is not necessary.
# check the model's unit tests run
from sasmodels.model_test import run_one
result = run_one(path)
# remove cached version of the model, if any
from sasmodels import sasview_model
sasview_model.MODEL_BY_PATH.pop(path, None)
# try running the model
Model = sasview_model.load_custom_model(path)
model = Model()
q = np.array([0.01, 0.1])
Iq = model.evalDistribution(q)
qx, qy = np.array([0.01, 0.01]), np.array([0.1, 0.1])
Iqxy = model.evalDistribution([qx, qy])
return result
[docs]def show_model_output(parent, fname):
# Make sure we have a python file; not sure why we care though...
if not (fname and os.path.exists(fname) and fname.endswith('.py')):
mssg = "\n This is not a python file."
wx.MessageBox(str(mssg), 'Error', style=wx.ICON_ERROR)
return False
try:
result, errmsg = check_model(fname), None
except Exception:
import traceback
result, errmsg = None, traceback.format_exc()
parts = ["Running model '%s'..." % os.path.basename(fname)]
if errmsg is not None:
parts.extend(["", "Error occurred:", errmsg, ""])
title, icon = "Error", wx.ICON_ERROR
else:
parts.extend(["", "Success:", result, ""])
title, icon = "Info", wx.ICON_INFORMATION
text = "\n".join(parts)
dlg = ResizableScrolledMessageDialog(parent, text, title, size=((550, 250)))
fnt = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
dlg.GetChildren()[0].SetFont(fnt)
dlg.GetChildren()[0].SetInsertionPoint(0)
dlg.ShowModal()
dlg.Destroy()
return errmsg is None
[docs]class PyConsole(editor.EditorNotebookFrame):
## Internal nickname for the window, used by the AUI manager
window_name = "Custom Model Editor"
## Name to appear on the window title bar
window_caption = "Plugin Model Editor"
## Flag to tell the AUI manager to put this panel in the center pane
CENTER_PANE = False
def __init__(self, parent=None, base=None, manager=None, panel=None,
title='Python Shell/Editor', filename=None,
size=(PANEL_WIDTH, PANEL_HEIGHT)):
self.config = None
editor.EditorNotebookFrame.__init__(self, parent=parent,
title=title, size=size)
self.parent = parent
self._manager = manager
self.base = base
self.panel = panel
self._add_menu()
if filename is not None:
dataDir = os.path.dirname(filename)
elif self.parent is not None:
dataDir = self.parent._default_save_location
else:
dataDir = None
self.dataDir = dataDir
self.Centre()
# See if there is a corresponding C file
if filename is not None:
c_filename = os.path.splitext(filename)[0] + ".c"
if os.path.isfile(c_filename):
self.bufferCreate(c_filename)
# If not, just open the requested .py, if any.
# Needs to be after the C file so the tab focus is correct.
if os.path.isfile(filename):
self.bufferCreate(filename)
self.Bind(wx.EVT_MENU, self.OnNewFile, id=wx.ID_NEW)
self.Bind(wx.EVT_MENU, self.OnOpenFile, id=wx.ID_OPEN)
self.Bind(wx.EVT_MENU, self.OnSaveFile, id=wx.ID_SAVE)
self.Bind(wx.EVT_MENU, self.OnSaveAsFile, id=wx.ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnCheckModel, id=ID_CHECK_MODEL)
self.Bind(wx.EVT_MENU, self.OnRun, id=ID_RUN)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCompileMenu, id=ID_CHECK_MODEL)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCompileMenu, id=ID_RUN)
self.Bind(wx.EVT_CLOSE, self.on_close)
if not title.count('Python Shell'):
# Delete menu item (open and new) if not python shell
#self.fileMenu.Delete(wx.ID_NEW)
self.fileMenu.Delete(wx.ID_OPEN)
def _add_menu(self):
"""
Add menu
"""
self.compileMenu = wx.Menu()
self.compileMenu.Append(ID_CHECK_MODEL, 'Check model',
'Loading and run the model')
self.compileMenu.AppendSeparator()
self.compileMenu.Append(ID_RUN, 'Run in Shell',
'Run the file in the Python Shell')
self.MenuBar.Insert(3, self.compileMenu, '&Run')
[docs] def OnHelp(self, event):
"""
Show a help dialog.
"""
import wx.lib.dialogs
title = 'Help on key bindings'
text = wx.py.shell.HELP_TEXT
dlg = wx.lib.dialogs.ScrolledMessageDialog(self, text, title,
size=((700, 540)))
fnt = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
dlg.GetChildren()[0].SetFont(fnt)
dlg.GetChildren()[0].SetInsertionPoint(0)
dlg.ShowModal()
dlg.Destroy()
[docs] def set_manager(self, manager):
"""
Set the manager of this window
"""
self._manager = manager
[docs] def OnAbout(self, event):
"""
On About
"""
message = ABOUT
dial = wx.MessageDialog(self, message, 'About',
wx.OK | wx.ICON_INFORMATION)
dial.ShowModal()
[docs] def OnNewFile(self, event):
"""
OnFileOpen
"""
self.OnFileNew(event)
[docs] def OnOpenFile(self, event):
"""
OnFileOpen
"""
self.OnFileOpen(event)
self.Show(False)
self.Show(True)
[docs] def OnSaveFile(self, event):
"""
OnFileSave overwrite
"""
self.OnFileSave(event)
self.Show(False)
self.Show(True)
[docs] def OnSaveAsFile(self, event):
"""
OnFileSaveAs overwrite
"""
self.OnFileSaveAs(event)
self.Show(False)
self.Show(True)
[docs] def bufferOpen(self):
"""
Open file in buffer, bypassing editor bufferOpen
"""
if self.bufferHasChanged():
cancel = self.bufferSuggestSave()
if cancel:
return cancel
filedir = ''
if self.buffer and self.buffer.doc.filedir:
filedir = self.buffer.doc.filedir
if not filedir:
filedir = self.dataDir
result = editor.openSingle(directory=filedir,
wildcard='Python Files (*.py)|*.py')
if result.path:
self.bufferCreate(result.path)
# See if there is a corresponding C file
if result.path is not None:
c_filename = os.path.splitext(result.path)[0] + ".c"
if os.path.isfile(c_filename):
self.bufferCreate(c_filename)
cancel = False
return cancel
[docs] def bufferSaveAs(self):
"""
Save buffer to a new filename: Bypassing editor bufferSaveAs
"""
filedir = ''
if self.buffer and self.buffer.doc.filedir:
filedir = self.buffer.doc.filedir
if not filedir:
filedir = self.dataDir
result = editor.saveSingle(directory=filedir,
filename='untitled.py',
wildcard='Python Files (*.py)|*.py')
if result.path:
self.buffer.confirmed = True
self.buffer.saveAs(result.path)
cancel = False
else:
cancel = True
return cancel
[docs] def OnRun(self, event):
"""
Run
"""
if not self._check_saved():
return True
if self.buffer and self.buffer.doc.filepath:
self.editor.setFocus()
# Why we have to do this (Otherwise problems on Windows)?
forward_path = self.buffer.doc.filepath.replace('\\', '/')
self.shell.Execute("execfile('%s')" % forward_path)
self.shell.Hide()
self.shell.Show(True)
return self.shell.GetText().split(">>>")[-2]
else:
mssg = "\n This is not a python file."
title = 'Error'
icon = wx.ICON_ERROR
wx.MessageBox(str(mssg), title, style=icon)
return False
[docs] def OnCheckModel(self, event):
"""
Compile
"""
if not self._check_saved():
return True
fname = self.editor.getStatus()[0]
success = show_model_output(self, fname)
# Update plugin model list in fitpage combobox
if success and self._manager is not None and self.panel is not None:
self._manager.set_edit_menu_helper(self.parent)
wx.CallAfter(self._manager.update_custom_combo)
def _check_saved(self):
"""
If content was changed, suggest to save it first
"""
if self.bufferHasChanged() and self.buffer.doc.filepath:
cancel = self.bufferSuggestSave()
return not cancel
return True
[docs] def on_close(self, event):
"""
Close event
"""
if self.base is not None:
self.base.py_frame = None
self.Destroy()
ABOUT = "Welcome to Python %s! \n\n" % sys.version.split()[0]
ABOUT += "This uses Py Shell/Editor in wx (developed by Patrick K. O'Brien).\n"
ABOUT += "If this is your first time using Python, \n"
ABOUT += "you should definitely check out the tutorial "
ABOUT += "on the Internet at http://www.python.org/doc/tut/."
if __name__ == "__main__":
app = wx.App()
dlg = PyConsole()
dlg.Show()
app.MainLoop()