source: sasview/src/sas/sasgui/guiframe/local_perspectives/data_loader/data_loader.py @ 7f75a3f

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 7f75a3f was 7f75a3f, checked in by krzywon, 7 years ago

More explicit error messages when file loading fails. see #889

  • Property mode set to 100644
File size: 10.3 KB
Line 
1
2"""
3plugin DataLoader responsible of loading data
4"""
5import os
6import sys
7import wx
8import logging
9
10from sas.sascalc.dataloader.loader import Loader
11from sas.sascalc.dataloader.loader_exceptions import NoKnownLoaderException
12from sas.sasgui.guiframe.plugin_base import PluginBase
13from sas.sasgui.guiframe.events import StatusEvent
14from sas.sasgui.guiframe.gui_style import GUIFRAME
15from sas.sasgui.guiframe.gui_manager import DEFAULT_OPEN_FOLDER
16try:
17    # Try to find a local config
18    import imp
19    path = os.getcwd()
20    if(os.path.isfile("%s/%s.py" % (path, 'local_config'))) or \
21        (os.path.isfile("%s/%s.pyc" % (path, 'local_config'))):
22        fObj, path, descr = imp.find_module('local_config', [path])
23        config = imp.load_module('local_config', fObj, path, descr)
24    else:
25        # Try simply importing local_config
26        import local_config as config
27except:
28    # Didn't find local config, load the default
29    import sas.sasgui.guiframe.config as config
30
31if config is None:
32    import sas.sasgui.guiframe.config as config
33
34
35extension_list = []
36if config.APPLICATION_STATE_EXTENSION is not None:
37    extension_list.append(config.APPLICATION_STATE_EXTENSION)
38EXTENSIONS = config.PLUGIN_STATE_EXTENSIONS + extension_list
39PLUGINS_WLIST = config.PLUGINS_WLIST
40APPLICATION_WLIST = config.APPLICATION_WLIST
41
42
43class Plugin(PluginBase):
44
45    def __init__(self):
46        PluginBase.__init__(self, name="DataLoader")
47        # Default location
48        self._default_save_location = DEFAULT_OPEN_FOLDER
49        self.loader = Loader()
50        self._data_menu = None
51
52    def populate_file_menu(self):
53        """
54        get a menu item and append it under file menu of the application
55        add load file menu item and load folder item
56        """
57        # menu for data files
58        data_file_hint = "load one or more data in the application"
59        menu_list = [('&Load Data File(s)', data_file_hint, self.load_data)]
60        gui_style = self.parent.get_style()
61        style = gui_style & GUIFRAME.MULTIPLE_APPLICATIONS
62        if style == GUIFRAME.MULTIPLE_APPLICATIONS:
63            # menu for data from folder
64            data_folder_hint = "load multiple data in the application"
65            menu_list.append(('&Load Data Folder', data_folder_hint,
66                              self._load_folder))
67        return menu_list
68
69    def load_data(self, event):
70        """
71        Load data
72        """
73        path = None
74        self._default_save_location = self.parent._default_save_location
75        if self._default_save_location == None:
76            self._default_save_location = os.getcwd()
77
78        cards = self.loader.get_wildcards()
79        temp = [APPLICATION_WLIST] + PLUGINS_WLIST
80        for item in temp:
81            if item in cards:
82                cards.remove(item)
83        wlist = '|'.join(cards)
84        style = wx.OPEN | wx.FD_MULTIPLE
85        dlg = wx.FileDialog(self.parent,
86                            "Choose a file",
87                            self._default_save_location, "",
88                            wlist,
89                            style=style)
90        if dlg.ShowModal() == wx.ID_OK:
91            file_list = dlg.GetPaths()
92            if len(file_list) >= 0 and not file_list[0] is None:
93                self._default_save_location = os.path.dirname(file_list[0])
94                path = self._default_save_location
95        dlg.Destroy()
96
97        if path is None or not file_list or file_list[0] is None:
98            return
99        self.parent._default_save_location = self._default_save_location
100        self.get_data(file_list)
101
102    def can_load_data(self):
103        """
104        if return True, then call handler to laod data
105        """
106        return True
107
108    def _load_folder(self, event):
109        """
110        Load entire folder
111        """
112        path = None
113        self._default_save_location = self.parent._default_save_location
114        if self._default_save_location is None:
115            self._default_save_location = os.getcwd()
116        dlg = wx.DirDialog(self.parent, "Choose a directory",
117                           self._default_save_location,
118                           style=wx.DD_DEFAULT_STYLE)
119        if dlg.ShowModal() == wx.ID_OK:
120            path = dlg.GetPath()
121            self._default_save_location = path
122        dlg.Destroy()
123        if path is not None:
124            self._default_save_location = os.path.dirname(path)
125        else:
126            return
127        file_list = self.get_file_path(path)
128        self.get_data(file_list)
129        self.parent._default_save_location = self._default_save_location
130
131    def load_error(self, error=None):
132        """
133        Pop up an error message.
134
135        :param error: details error message to be displayed
136        """
137        if error is not None or str(error).strip() != "":
138            dial = wx.MessageDialog(self.parent, str(error),
139                                    'Error Loading File',
140                                    wx.OK | wx.ICON_EXCLAMATION)
141            dial.ShowModal()
142
143    def get_file_path(self, path):
144        """
145        Receive a list containing folder then return a list of file
146        """
147        if os.path.isdir(path):
148            return [os.path.join(os.path.abspath(path), filename) for filename
149                    in os.listdir(path)]
150
151    def _process_data_and_errors(self, item, p_file, output, message):
152        """
153        Check to see if data set loaded with any errors. If so, append to
154            error message to be sure user knows the issue.
155        """
156        data_error = False
157        if hasattr(item, 'errors'):
158            for error_data in item.errors:
159                data_error = True
160                message += "\tError: {0}\n".format(error_data)
161        else:
162            logging.error("Loader returned an invalid object:\n %s" % str(item))
163            data_error = True
164
165        data = self.parent.create_gui_data(item, p_file)
166        output[data.id] = data
167        return output, message, data_error
168
169    def get_data(self, path, format=None):
170        """
171        """
172        file_errors = {}
173        output = {}
174        exception_occurred = False
175
176        for p_file in path:
177            basename = os.path.basename(p_file)
178            # Skip files that start with a period
179            if basename.startswith("."):
180                msg = "The folder included a potential hidden file - %s." \
181                      % basename
182                msg += " Do you wish to load this file as data?"
183                msg_box = wx.MessageDialog(None, msg, 'Warning',
184                                           wx.OK | wx.CANCEL)
185                if msg_box.ShowModal() == wx.ID_CANCEL:
186                    continue
187            _, extension = os.path.splitext(basename)
188            if extension.lower() in EXTENSIONS:
189                log_msg = "Data Loader cannot "
190                log_msg += "load: {}\n".format(str(p_file))
191                log_msg += "Please try to open that file from \"open project\""
192                log_msg += "or \"open analysis\" menu."
193                logging.info(log_msg)
194                file_errors[basename] = [log_msg]
195                continue
196
197            try:
198                message = "Loading {}...\n".format(p_file)
199                self.load_update(output=output, message=message, info="info")
200                temp = self.loader.load(p_file, format)
201                if not isinstance(temp, list):
202                    temp = [temp]
203                for item in temp:
204                    error_message = ""
205                    output, error_message, data_error = \
206                        self._process_data_and_errors(item,
207                                                      p_file,
208                                                      output,
209                                                      error_message)
210                    if data_error:
211                        if basename in file_errors.keys():
212                            file_errors[basename] += [error_message]
213                        else:
214                            file_errors[basename] = [error_message]
215                        self.load_update(output=output,
216                            message=error_message, info="warning")
217
218                self.load_update(output=output,
219                message="Loaded {}\n".format(p_file),
220                info="info")
221
222            except NoKnownLoaderException as e:
223                logging.error(e.message)
224                self.load_update(output=None, message=e.message, info="warning")
225                self.load_complete(output=None,
226                                   message="Loading data failed!",
227                                   info="warning")
228            except:
229                logging.error(sys.exc_value)
230
231                error_message = "The Data file you selected could not be "
232                error_message += "loaded.\nMake sure the content of your file"
233                error_message += " is properly formatted.\n"
234                error_message += "When contacting the SasView team, mention the"
235                error_message += " following:\n"
236                error_message += "Error: " + str(sys.exc_info()[1])
237                file_errors[basename] = [error_message]
238                self.load_update(output=output, message=error_message,
239                                 info="warning")
240
241        if len(file_errors) > 0:
242            error_message = ""
243            for filename, error_array in file_errors.iteritems():
244                error_message += "The following errors occured whilst "
245                error_message += "loading {}:\n".format(filename)
246                for message in error_array:
247                    error_message += message + "\n"
248                error_message += "\n"
249            self.load_update(output=output, message=error_message, info="error")
250
251        self.load_complete(output=output, message="Loading data complete!",
252                           info="info")
253
254    def load_update(self, output=None, message="", info="warning"):
255        """
256        print update on the status bar
257        """
258        if message != "":
259            wx.PostEvent(self.parent, StatusEvent(status=message, info=info,
260                                                  type="progress"))
261
262    def load_complete(self, output, message="", info="warning"):
263        """
264         post message to status bar and return list of data
265        """
266        wx.PostEvent(self.parent, StatusEvent(status=message, info=info,
267                                              type="stop"))
268        self.parent.add_data(data_list=output)
Note: See TracBrowser for help on using the repository browser.