source: sasview/src/sas/sasview/sasview.py @ 0dde203

ticket-1249
Last change on this file since 0dde203 was 0dde203, checked in by Paul Kienzle <pkienzle@…>, 5 years ago

Fix model editor load/save for wx4. Refs #1260, #1273.

  • Property mode set to 100644
File size: 11.8 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3Base module for loading and running the main SasView application.
4"""
5################################################################################
6# This software was developed by the University of Tennessee as part of the
7# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
8# project funded by the US National Science Foundation.
9#
10# See the license text in license.txt
11#
12# copyright 2009, University of Tennessee
13################################################################################
14import os
15import os.path
16import sys
17import traceback
18import logging
19
20try:
21    reload(sys)
22    sys.setdefaultencoding("iso-8859-1")
23except NameError:
24    # On python 3 sys.setdefaultencoding does nothing, so pass.
25    # We know we are in python 3 at this point since reload is no longer in
26    # builtins, but instead has been moved to importlib, hence the NameError.
27    pass
28
29import sas
30
31APP_NAME = 'SasView'
32PLUGIN_MODEL_DIR = 'plugin_models'
33
34class SasView(object):
35    """
36    Main class for running the SasView application
37    """
38    def __init__(self):
39        """
40        """
41        logger = logging.getLogger(__name__)
42
43        from sas.sasgui.guiframe.gui_manager import SasViewApp
44        from sas.sasgui.guiframe.gui_style import GUIFRAME_ICON
45        self.gui = SasViewApp(0)
46        GUIFRAME_ICON.load_icons()
47        if sys.platform == "darwin":
48            self.check_sasmodels_compiler()
49        # Set the application manager for the GUI
50        self.gui.set_manager(self)
51        # Add perspectives to the basic application
52        # Additional perspectives can still be loaded
53        # dynamically
54        # Note: py2exe can't find dynamically loaded
55        # modules. We load the fitting module here
56        # to ensure a complete Windows executable build.
57
58        # Rebuild .sasview/categories.json.  This triggers a load of sasmodels
59        # and all the plugins.
60        try:
61            from sas.sascalc.fit.models import ModelManager
62            from sas.sasgui.guiframe.CategoryInstaller import CategoryInstaller
63            model_list = ModelManager().cat_model_list()
64            CategoryInstaller.check_install(model_list=model_list)
65        except Exception:
66            logger.error("%s: could not load SasView models")
67            logger.error(traceback.format_exc())
68
69        # Fitting perspective
70        try:
71            import sas.sasgui.perspectives.fitting as module
72            fitting_plug = module.Plugin()
73            self.gui.add_perspective(fitting_plug)
74        except Exception:
75            logger.error("%s: could not find Fitting plug-in module", APP_NAME)
76            logger.error(traceback.format_exc())
77
78        # P(r) perspective
79        try:
80            import sas.sasgui.perspectives.pr as module
81            pr_plug = module.Plugin()
82            self.gui.add_perspective(pr_plug)
83        except Exception:
84            logger.error("%s: could not find P(r) plug-in module", APP_NAME)
85            logger.error(traceback.format_exc())
86
87        # Invariant perspective
88        try:
89            import sas.sasgui.perspectives.invariant as module
90            invariant_plug = module.Plugin()
91            self.gui.add_perspective(invariant_plug)
92        except Exception:
93            logger.error("%s: could not find Invariant plug-in module",
94                         APP_NAME)
95            logger.error(traceback.format_exc())
96
97        # Corfunc perspective
98        try:
99            import sas.sasgui.perspectives.corfunc as module
100            corfunc_plug = module.Plugin()
101            self.gui.add_perspective(corfunc_plug)
102        except Exception:
103            logger.error("Unable to load corfunc module")
104
105        # Calculator perspective
106        try:
107            import sas.sasgui.perspectives.calculator as module
108            calculator_plug = module.Plugin()
109            self.gui.add_perspective(calculator_plug)
110        except Exception:
111            logger.error("%s: could not find Calculator plug-in module",
112                         APP_NAME)
113            logger.error(traceback.format_exc())
114
115        # File converter tool
116        try:
117            import sas.sasgui.perspectives.file_converter as module
118            converter_plug = module.Plugin()
119            self.gui.add_perspective(converter_plug)
120        except Exception:
121            logger.error("%s: could not find File Converter plug-in module",
122                         APP_NAME)
123            logger.error(traceback.format_exc())
124
125        # Add welcome page
126        from .welcome_panel import WelcomePanel
127        self.gui.set_welcome_panel(WelcomePanel)
128
129        # Build the GUI
130        self.gui.build_gui()
131        # delete unused model folder
132        self.gui.clean_plugin_models(PLUGIN_MODEL_DIR)
133        # Start the main loop
134        self.gui.MainLoop()
135
136    def check_sasmodels_compiler(self):
137        """
138        Checking c compiler for sasmodels and raises xcode command line
139        tools for installation
140        """
141        #wx should be importable at this stage
142        import wx
143        import subprocess
144        #Generic message box created becuase standard MessageBox is not moveable
145        class GenericMessageBox(wx.Dialog):
146            def __init__(self, parent, text, title = ''):
147
148                wx.Dialog.__init__(self, parent, -1, title = title,
149                               size = (360,200), pos=(20,60),
150                               style = wx.STAY_ON_TOP | wx.DEFAULT_DIALOG_STYLE)
151                panel = wx.Panel(self, -1)
152                top_row_sizer = wx.BoxSizer(wx.HORIZONTAL)
153
154                error_bitmap = wx.ArtProvider.GetBitmap(
155                    wx.ART_ERROR, wx.ART_MESSAGE_BOX
156                )
157                error_bitmap_ctrl = wx.StaticBitmap(panel, -1)
158                error_bitmap_ctrl.SetBitmap(error_bitmap)
159                label = wx.StaticText(panel, -1, text)
160                top_row_sizer.Add(error_bitmap_ctrl, flag=wx.ALL, border=10)
161                top_row_sizer.Add(label, flag=wx.ALIGN_CENTER_VERTICAL)
162
163                #Create the OK button in the bottom row.
164                ok_button = wx.Button(panel, wx.ID_OK )
165                self.Bind(wx.EVT_BUTTON, self.on_ok, source=ok_button)
166                ok_button.SetFocus()
167                ok_button.SetDefault()
168
169                sizer = wx.BoxSizer(wx.VERTICAL)
170                sizer.Add(top_row_sizer)
171                sizer.Add(ok_button, flag=wx.ALIGN_CENTER | wx.ALL, border=5)
172                panel.SetSizer(sizer)
173
174            def on_ok(self, event):
175                self.Destroy()
176
177        logger = logging.getLogger(__name__)
178        try:
179            subprocess.check_output(["cc","--version"], stderr=subprocess.STDOUT)
180        except subprocess.CalledProcessError as exc:
181            dlg = GenericMessageBox(parent=None,
182            text='No compiler installed. Please install command line\n'
183                'developers tools by clicking \"Install\" in another winodw\n\n'
184                'Alternatively click \"Not Now\" and use OpenCL\n'
185                 'compiler, which can be set up from menu Fitting->OpenCL Options\n\n',
186            title = 'Compiler Info')
187            dlg.Show()
188            logger.error("No compiler installed. %s\n"%(exc))
189            logger.error(traceback.format_exc())
190
191def setup_logging():
192    from sas.logger_config import SetupLogger
193
194    logger = SetupLogger(__name__).config_production()
195    # Log the start of the session
196    logger.info(" --- SasView session started ---")
197    # Log the python version
198    logger.info("Python: %s" % sys.version)
199    return logger
200
201
202def setup_wx():
203    # Allow the dynamic selection of wxPython via an environment variable, when devs
204    # who have multiple versions of the module installed want to pick between them.
205    # This variable does not have to be set of course, and through normal usage will
206    # probably not be, but this can make things a little easier when upgrading to a
207    # new version of wx.
208    logger = logging.getLogger(__name__)
209    WX_ENV_VAR = "SASVIEW_WX_VERSION"
210    if WX_ENV_VAR in os.environ:
211        logger.info("You have set the %s environment variable to %s.",
212                    WX_ENV_VAR, os.environ[WX_ENV_VAR])
213        import wxversion
214        if wxversion.checkInstalled(os.environ[WX_ENV_VAR]):
215            logger.info("Version %s of wxPython is installed, so using that version.",
216                        os.environ[WX_ENV_VAR])
217            wxversion.select(os.environ[WX_ENV_VAR])
218        else:
219            logger.error("Version %s of wxPython is not installed, so using default version.",
220                         os.environ[WX_ENV_VAR])
221    else:
222        logger.info("You have not set the %s environment variable, so using default version of wxPython.",
223                    WX_ENV_VAR)
224
225    import wx
226
227    try:
228        logger.info("Wx version: %s", wx.__version__)
229        logger.info("Wx PlatformInfo: %s", wx.PlatformInfo)
230    except AttributeError:
231        logger.error("Wx version: error reading version")
232
233    # TODO: Do we need the call later fix for wx 3? Or is it wx < 3 only?
234    if "phoenix" in wx.PlatformInfo:
235        #wx.NewId = wx.Window.NewControlId
236        from . import wx4cruft
237        wx4cruft.patch_py_editor()
238    else:
239        from . import wxcruft
240        wxcruft.call_later_fix()
241    #wxcruft.trace_new_id()
242    #Always use private .matplotlib setup to avoid conflicts with other
243    #uses of matplotlib
244
245
246def setup_mpl(backend=None):
247    # Always use private .matplotlib setup to avoid conflicts with other
248    mplconfigdir = os.path.join(sas.get_user_dir(), '.matplotlib')
249    if not os.path.exists(mplconfigdir):
250        os.mkdir(mplconfigdir)
251    os.environ['MPLCONFIGDIR'] = mplconfigdir
252    # Set backend to WXAgg; this overrides matplotlibrc, but shouldn't override
253    # mpl.use().  Note: Don't import matplotlib here since the script that
254    # we are running may not actually need it; also, putting as little on the
255    # path as we can
256    if backend:
257        os.environ['MPLBACKEND'] = backend
258
259    # TODO: ... so much for not importing matplotlib unless we need it...
260    from matplotlib import backend_bases
261    backend_bases.FigureCanvasBase.filetypes.pop('pgf', None)
262
263def setup_sasmodels():
264    """
265    Prepare sasmodels for running within sasview.
266    """
267    # Set SAS_MODELPATH so sasmodels can find our custom models
268    plugin_dir = os.path.join(sas.get_user_dir(), PLUGIN_MODEL_DIR)
269    os.environ['SAS_MODELPATH'] = plugin_dir
270    #Initialize environment variable with custom setting but only if variable not set
271    SAS_OPENCL = sas.get_custom_config().SAS_OPENCL
272    if SAS_OPENCL and "SAS_OPENCL" not in os.environ:
273        os.environ["SAS_OPENCL"] = SAS_OPENCL
274
275def run_gui():
276    """
277    __main__ method for loading and running SasView
278    """
279    from multiprocessing import freeze_support
280    freeze_support()
281    setup_logging()
282    setup_mpl(backend='WXAgg')
283    setup_sasmodels()
284    setup_wx()
285    SasView()
286
287
288def run_cli():
289    from multiprocessing import freeze_support
290    freeze_support()
291    setup_logging()
292    # Use default matplotlib backend on mac/linux, but wx on windows.
293    # The problem on mac is that the wx backend requires pythonw.  On windows
294    # we are sure to wx since it is the shipped with the app.
295    setup_mpl(backend='WXAgg' if os.name == 'nt' else None)
296    setup_sasmodels()
297    if len(sys.argv) == 1 or sys.argv[1] == '-i':
298        # Run sasview as an interactive python interpreter
299        try:
300            from IPython import start_ipython
301            sys.argv = ["ipython", "--pylab"]
302            sys.exit(start_ipython())
303        except ImportError:
304            import code
305            code.interact(local={'exit': sys.exit})
306    elif sys.argv[1] == '-c':
307        exec(sys.argv[2])
308    else:
309        thing_to_run = sys.argv[1]
310        sys.argv = sys.argv[1:]
311        import runpy
312        if os.path.exists(thing_to_run):
313            runpy.run_path(thing_to_run, run_name="__main__")
314        else:
315            runpy.run_module(thing_to_run, run_name="__main__")
316
317
318if __name__ == "__main__":
319    run_gui()
Note: See TracBrowser for help on using the repository browser.