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

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalcmagnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 60a7820 was 759a8ab, checked in by Paul Kienzle <pkienzle@…>, 7 years ago

Merge branch 'master' into ticket-887-reorg

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