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

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since d4881f6a was b963b20, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

pull config out of sas.sasgui so it can be used without reference to wx

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