source: sasview/src/sas/sasgui/perspectives/calculator/pyconsole.py @ e9f8208

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since e9f8208 was 7673ecd, checked in by Paul Kienzle <pkienzle@…>, 8 years ago

refactor support for sum model; put tracebacks in logging errors

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[ec6c520]1"""
2Console Module display Python console
3"""
4import sys
[5d1c1f4]5import os
[26d6e045]6
7import numpy as np
8
[fb58234]9import wx
[26d6e045]10from wx.lib.dialogs import ScrolledMessageDialog
[fb58234]11import wx.py.editor as editor
[5d1c1f4]12
[49ab5d7]13if sys.platform.count("win32") > 0:
[ec6c520]14    PANEL_WIDTH = 800
[7c8d3093]15    PANEL_HEIGHT = 700
[ec6c520]16    FONT_VARIANT = 0
17else:
18    PANEL_WIDTH = 830
[7c8d3093]19    PANEL_HEIGHT = 730
[ec6c520]20    FONT_VARIANT = 1
[26d6e045]21ID_CHECK_MODEL = wx.NewId()
[49ab5d7]22ID_RUN = wx.NewId()
[5d1c1f4]23
[26d6e045]24def check_model(path):
[5d1c1f4]25    """
[26d6e045]26    Check that the model on the path can run.
[5d1c1f4]27    """
[26d6e045]28    # try running the model
[7673ecd]29    from sasmodels.sasview_model import load_custom_model
30    Model = load_custom_model(path)
31    model = Model()
[26d6e045]32    q =  np.array([0.01, 0.1])
[7673ecd]33    Iq = model.evalDistribution(q)
[26d6e045]34    qx, qy =  np.array([0.01, 0.01]), np.array([0.1, 0.1])
[7673ecd]35    Iqxy = model.evalDistribution([qx, qy])
[26d6e045]36
37    result = """
38    Iq(%s) = %s
39    Iqxy(%s, %s) = %s
40    """%(q, Iq, qx, qy, Iqxy)
41
42    return result
43
44def show_model_output(parent, fname):
45    # Make sure we have a python file; not sure why we care though...
46    if not (fname and os.path.exists(fname) and fname.endswith('.py')):
47        mssg = "\n This is not a python file."
48        wx.MessageBox(str(mssg), 'Error', style=wx.ICON_ERROR)
49        return False
50
[5d1c1f4]51    try:
[26d6e045]52        result, errmsg = check_model(fname), None
53    except Exception:
54        import traceback
[7673ecd]55        result, errmsg = None, traceback.format_exc()
[26d6e045]56
57    parts = ["Running model '%s'..." % os.path.basename(fname)]
58    if errmsg is not None:
59        parts.extend(["", "Error occurred:", errmsg, ""])
60        title, icon = "Error", wx.ICON_ERROR
61    else:
62        parts.extend(["", "Success:", result, ""])
63        title, icon = "Info", wx.ICON_INFORMATION
64    text = "\n".join(parts)
65    dlg = ScrolledMessageDialog(parent, text, title, size=((550, 250)))
66    fnt = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
67    dlg.GetChildren()[0].SetFont(fnt)
68    dlg.GetChildren()[0].SetInsertionPoint(0)
69    dlg.ShowModal()
70    dlg.Destroy()
71    return errmsg is None
[5d1c1f4]72
[fb58234]73class PyConsole(editor.EditorNotebookFrame):
[ec6c520]74    ## Internal nickname for the window, used by the AUI manager
[5d1c1f4]75    window_name = "Custom Model Editor"
[ec6c520]76    ## Name to appear on the window title bar
[5d1c1f4]77    window_caption = "Custom Model Editor"
[ec6c520]78    ## Flag to tell the AUI manager to put this panel in the center pane
79    CENTER_PANE = False
[ae84427]80    def __init__(self, parent=None, base=None, manager=None, panel=None,
[fb58234]81                    title='Python Shell/Editor', filename=None,
[ec6c520]82                    size=(PANEL_WIDTH, PANEL_HEIGHT)):
[fb58234]83        self.config = None
[49ab5d7]84        editor.EditorNotebookFrame.__init__(self, parent=parent,
[ec6c520]85                                        title=title, size=size,
[fb58234]86                                        filename=filename)
[ec6c520]87        self.parent = parent
88        self._manager = manager
[ae84427]89        self.base = base
[5d1c1f4]90        self.panel = panel
91        self._add_menu()
92        if filename != None:
93            dataDir = os.path.dirname(filename)
94        elif self.parent != None:
95            dataDir = self.parent._default_save_location
96        else:
97             dataDir = None
98        self.dataDir = dataDir
[ec6c520]99        self.Centre()
[49ab5d7]100
[7c8d3093]101        self.Bind(wx.EVT_MENU, self.OnNewFile, id=wx.ID_NEW)
[4c5448c]102        self.Bind(wx.EVT_MENU, self.OnOpenFile, id=wx.ID_OPEN)
[5d1c1f4]103        self.Bind(wx.EVT_MENU, self.OnSaveFile, id=wx.ID_SAVE)
104        self.Bind(wx.EVT_MENU, self.OnSaveAsFile, id=wx.ID_SAVEAS)
[26d6e045]105        self.Bind(wx.EVT_MENU, self.OnCheckModel, id=ID_CHECK_MODEL)
[5d1c1f4]106        self.Bind(wx.EVT_MENU, self.OnRun, id=ID_RUN)
[26d6e045]107        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCompileMenu, id=ID_CHECK_MODEL)
[5d1c1f4]108        self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateCompileMenu, id=ID_RUN)
[ae84427]109        self.Bind(wx.EVT_CLOSE, self.on_close)
[7c8d3093]110        if not title.count('Python Shell'):
111            # Delete menu item (open and new) if not python shell
[86be650]112            #self.fileMenu.Delete(wx.ID_NEW)
[7c8d3093]113            self.fileMenu.Delete(wx.ID_OPEN)
[49ab5d7]114
115
[5d1c1f4]116    def _add_menu(self):
[861f8317]117        """
[5d1c1f4]118        Add menu
[861f8317]119        """
[5d1c1f4]120        self.compileMenu = wx.Menu()
[26d6e045]121        self.compileMenu.Append(ID_CHECK_MODEL, 'Check model',
122                 'Loading and run the model')
[5d1c1f4]123        self.compileMenu.AppendSeparator()
[7c8d3093]124        self.compileMenu.Append(ID_RUN, 'Run in Shell',
[5d1c1f4]125                 'Run the file in the Python Shell')
[7c8d3093]126        self.MenuBar.Insert(3, self.compileMenu, '&Run')
[49ab5d7]127
[5d1c1f4]128    def OnHelp(self, event):
129        """
130        Show a help dialog.
131        """
132        import  wx.lib.dialogs
133        title = 'Help on key bindings'
134        text = wx.py.shell.HELP_TEXT
135        dlg = wx.lib.dialogs.ScrolledMessageDialog(self, text, title,
[49ab5d7]136                                                   size=((700, 540)))
[5d1c1f4]137        fnt = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
138        dlg.GetChildren()[0].SetFont(fnt)
139        dlg.GetChildren()[0].SetInsertionPoint(0)
140        dlg.ShowModal()
141        dlg.Destroy()
142
[ec6c520]143    def set_manager(self, manager):
144        """
145        Set the manager of this window
146        """
147        self._manager = manager
[49ab5d7]148
[861f8317]149    def OnAbout(self, event):
150        """
151        On About
152        """
153        message = ABOUT
[b1bda35]154        dial = wx.MessageDialog(self, message, 'About',
[49ab5d7]155                           wx.OK | wx.ICON_INFORMATION)
[861f8317]156        dial.ShowModal()
[49ab5d7]157
[7c8d3093]158    def OnNewFile(self, event):
159        """
[49ab5d7]160        OnFileOpen
[7c8d3093]161        """
162        self.OnFileNew(event)
[4c5448c]163
164    def OnOpenFile(self, event):
165        """
[49ab5d7]166        OnFileOpen
[4c5448c]167        """
168        self.OnFileOpen(event)
169        self.Show(False)
170        self.Show(True)
[49ab5d7]171
[5d1c1f4]172    def OnSaveFile(self, event):
173        """
[49ab5d7]174        OnFileSave overwrite
[5d1c1f4]175        """
176        self.OnFileSave(event)
177        self.Show(False)
178        self.Show(True)
[49ab5d7]179
[5d1c1f4]180    def OnSaveAsFile(self, event):
181        """
[49ab5d7]182        OnFileSaveAs overwrite
[5d1c1f4]183        """
184        self.OnFileSaveAs(event)
185        self.Show(False)
186        self.Show(True)
187
[7c8d3093]188    def bufferOpen(self):
189        """
190        Open file in buffer, bypassing editor bufferOpen
191        """
192        if self.bufferHasChanged():
193            cancel = self.bufferSuggestSave()
194            if cancel:
195                return cancel
196        filedir = ''
197        if self.buffer and self.buffer.doc.filedir:
198            filedir = self.buffer.doc.filedir
[86be650]199        if not filedir:
200            filedir = self.dataDir
[49ab5d7]201        result = editor.openSingle(directory=filedir,
[7c8d3093]202                            wildcard='Python Files (*.py)|*.py')
203        if result.path:
204            self.bufferCreate(result.path)
205        cancel = False
206        return cancel
[49ab5d7]207
[5d1c1f4]208    def bufferSaveAs(self):
209        """
[7c8d3093]210        Save buffer to a new filename: Bypassing editor bufferSaveAs
[5d1c1f4]211        """
212        filedir = ''
213        if self.buffer and self.buffer.doc.filedir:
214            filedir = self.buffer.doc.filedir
[86be650]215        if not filedir:
216            filedir = self.dataDir
[49ab5d7]217        result = editor.saveSingle(directory=filedir,
[7c8d3093]218                                   filename='untitled.py',
219                                   wildcard='Python Files (*.py)|*.py')
[5d1c1f4]220        if result.path:
[f706e09c]221            self.buffer.confirmed = True
[5d1c1f4]222            self.buffer.saveAs(result.path)
223            cancel = False
224        else:
225            cancel = True
226        return cancel
[49ab5d7]227
[5d1c1f4]228    def OnRun(self, event):
229        """
230        Run
231        """
[26d6e045]232        if not self._check_saved():
[5d1c1f4]233            return True
234        if self.buffer and self.buffer.doc.filepath:
235            self.editor.setFocus()
236            # Why we have to do this (Otherwise problems on Windows)?
237            forward_path = self.buffer.doc.filepath.replace('\\', '/')
[49ab5d7]238            self.shell.Execute("execfile('%s')" % forward_path)
[5d1c1f4]239            self.shell.Hide()
240            self.shell.Show(True)
[7c8d3093]241            return self.shell.GetText().split(">>>")[-2]
[5d1c1f4]242        else:
243            mssg = "\n This is not a python file."
244            title = 'Error'
245            icon = wx.ICON_ERROR
246            wx.MessageBox(str(mssg), title, style=icon)
[26d6e045]247            return False
[49ab5d7]248
[26d6e045]249    def OnCheckModel(self, event):
[5d1c1f4]250        """
251        Compile
252        """
[26d6e045]253        if not self._check_saved():
[5d1c1f4]254            return True
[26d6e045]255        fname = self.editor.getStatus()[0]
256        success = show_model_output(self, fname)
257
258        # Update custom model list in fitpage combobox
259        if success and self._manager != None and self.panel != None:
260            self._manager.set_edit_menu_helper(self.parent)
261            wx.CallAfter(self._manager.update_custom_combo)
262
263    def _check_saved(self):
[5d1c1f4]264        """
265        If content was changed, suggest to save it first
266        """
267        if self.bufferHasChanged() and self.buffer.doc.filepath:
268            cancel = self.bufferSuggestSave()
[26d6e045]269            return not cancel
[5d1c1f4]270        return True
[49ab5d7]271
[5d1c1f4]272    def OnUpdateCompileMenu(self, event):
273        """
274        Update Compile menu items based on current tap.
275        """
276        win = wx.Window.FindFocus()
277        id = event.GetId()
278        event.Enable(True)
279        try:
[26d6e045]280            if id == ID_CHECK_MODEL or id == ID_RUN:
[5d1c1f4]281                menu_on = False
282                if self.buffer and self.buffer.doc.filepath:
283                    menu_on = True
284                event.Enable(menu_on)
285        except AttributeError:
286            # This menu option is not supported in the current context.
287            event.Enable(False)
[49ab5d7]288
[ae84427]289    def on_close(self, event):
290        """
291        Close event
292        """
293        if self.base != None:
294            self.base.py_frame = None
295        self.Destroy()
[49ab5d7]296
297ABOUT = "Welcome to Python %s! \n\n" % sys.version.split()[0]
[5d1c1f4]298ABOUT += "This uses Py Shell/Editor in wx (developed by Patrick K. O'Brien).\n"
[861f8317]299ABOUT += "If this is your first time using Python, \n"
300ABOUT += "you should definitely check out the tutorial "
301ABOUT += "on the Internet at http://www.python.org/doc/tut/."
[49ab5d7]302
303
[ec6c520]304if __name__ == "__main__":
[49ab5d7]305
306    app = wx.App()
[ec6c520]307    dlg = PyConsole()
308    dlg.Show()
[49ab5d7]309    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.