def start_measurement(self, measurement): """Start a new measurement. """ if self._thread and self._thread.is_alive(): self._state.set('stop_processing') self._thread.join(5) if self._thread.is_alive(): core = self.plugin.workbench.get_plugin('enaml.workbench.core') cmd = 'exopy.app.errors.signal' msg = ("Can't stop the running execution thread. Please " "restart the application and consider reporting this " "as a bug.") core.invoke_command(cmd, dict(kind='error', message=msg)) return if self.continuous_processing: self._state.set('continuous_processing') else: self._state.clear('continuous_processing') deferred_call(setattr, self, 'active', True) self._thread = Thread(target=self._run_measurements, args=(measurement,)) self._thread.daemon = True self._thread.start()
def exit_error_gathering(self): """Upon leaving gathering mode, errors are handled. If error handling should lead to a window display, all widgets are collected and displayed in a single window. As the gathering mode can be requested many times, the errors are only handled when this method has been called as many times as its counterpart. """ self._gathering_counter -= 1 if self._gathering_counter < 1: # Make sure to also gather additional errors signal during errors # handling self._gathering_counter += 1 # Handle all delayed errors errors = {} while self._delayed: delayed = self._delayed.copy() self._delayed.clear() for kind in delayed: res = self._handle(kind, delayed[kind]) if res: errors[kind] = res self._gathering_counter = 0 if errors: dial = ErrorsDialog(errors=errors) deferred_call(dial.exec_)
def _item_closed(self): """ Called by the proxy when the toolkit item is closed. """ # TODO allow the user to veto the close request self.closed() deferred_call(self.destroy)
def update(self, event=None, tab_changed=False): todo = [] if self._x is None: return for pk in self.plot_keys: plot = self.get_plot(pk) key = (self.selected_tab, pk) last_n = self._data_updated.get(key, 0) current_n = self._data_count.get(key, 0) needs_update = current_n >= (last_n + self.n_update) if tab_changed or needs_update: data = self._data_cache.get(key, []) self._data_updated[key] = len(data) if data: x = self._x y = self._y(concat(data, axis='epoch')) else: x = y = np.array([]) if x.shape == y.shape: todo.append((plot.setData, x, y)) def update(): for setter, x, y in todo: setter(x, y) deferred_call(update)
def event_loop_with_timeout(self, repeat=2, timeout=10.0): """Helper function to send all posted events to the event queue and wait for them to be processed. This runs the real event loop and does not emulate it with QApplication.processEvents. Parameters ---------- repeat : int Number of times to process events. Default is 2. timeout: float, optional, keyword only Number of seconds to run the event loop. Default value is 10.0. """ def repeat_loop(condition, repeat): # We sendPostedEvents to ensure that enaml events are processed self.qt_app.sendPostedEvents() repeat = repeat - 1 if repeat <= 0: deferred_call(condition.set) else: deferred_call(repeat_loop, condition=condition, repeat=repeat) condition = threading.Event() deferred_call(repeat_loop, repeat=repeat, condition=condition) self.event_loop_until_condition(condition=condition.is_set, timeout=timeout)
def tearDown(self): with self.event_loop_with_timeout(repeat=5): deferred_call(self.qt_app.closeAllWindows) del self.event_loop_helper self.enaml_app.destroy() del self.enaml_app del self.qt_app
def _insert_new_edition_panel(self, measure): """Handle inserting a new MeasureEditorDockItem in the content. """ template = 'meas_%d' items = self.dock_area.dock_items() test = re.compile('meas\_([0-9]+)$') measure_items = [i for i in items if test.match(i.name)] if not measure_items: name = template % 0 op = InsertItem(item=name, target='meas_exec') else: indexes = [int(test.match(i.name).group(1)) for i in measure_items] indexes.sort() if len(indexes) <= max(indexes): ind = [i for i, x in enumerate(indexes) if i != x][0] else: ind = len(measure_items) name = template % ind op = InsertTab(item=name, target=template % indexes[0]) MeasureEditorDockItem(self.dock_area, workspace=self, measure=measure, name=name) deferred_call(self.dock_area.update_layout, op)
def start(self): """ """ plugin = self.workbench.get_plugin(u'hqc_meas.debug') plugin.workspace = self self.plugin = plugin # Add handler to the root logger to display messages in panel. core = self.workbench.get_plugin(u'enaml.workbench.core') cmd = u'hqc_meas.logging.add_handler' self.log_model = core.invoke_command(cmd, { 'id': LOG_ID, 'mode': 'ui' }, self)[0] # Create content. self.content = DebuggerContent(workspace=self) # Contribute menus. self.workbench.register(DebuggerMenus()) # Add debugger contributions. for debugger in self.plugin.debuggers.values(): if debugger.contribute_workspace: debugger.contribute_workspace(self) # If the workspace was previously opened restore its state. if self.plugin.debugger_instances and self.plugin.workspace_layout: deferred_call(self._restore_debuggers)
def _handle_close(self, result, paths, selected_filter): """ Called by the proxy object when the dialog is closed. Parameters ---------- result : str The result of the dialog; either 'accepted' or 'rejected'. paths : list The list of user selected paths. If the result is 'rejected' this should be an empty list. selected_filter : unicode The user selected name filter. If the result is 'rejected' this should be an empty string. """ self.result = result if result == 'accepted': self.paths = paths self.path = paths[0] if paths else u'' self.selected_filter = selected_filter self.accepted(self.path) else: self.rejected() if self.callback: self.callback(self) self.closed() if self.destroy_on_close: deferred_call(self.destroy)
def set_gui(self, d): """Takes in a dictionary (d) of things to set, where self.key is the parameter to set, and value is what it will be set to. Makes a deferred call to set_dict so that this will happen in the gui thread""" if self.experiment.gui is not None: deferred_call(self.set_dict, d) else: self.set_dict(d)
def event_loop_with_timeout(self, repeat=2, timeout=10.0): """Helper function to send all posted events to the event queue and wait for them to be processed. This runs the real event loop and does not emulate it with QApplication.processEvents. Parameters ---------- repeat : int Number of times to process events. Default is 2. timeout: float, optional, keyword only Number of seconds to run the event loop. Default value is 10.0. """ def repeat_loop(condition, repeat): # We sendPostedEvents to ensure that enaml events are processed self.qt_app.sendPostedEvents() repeat = repeat - 1 if repeat <= 0: deferred_call(condition.set) else: deferred_call(repeat_loop, condition=condition, repeat=repeat) condition = threading.Event() deferred_call(repeat_loop, repeat=repeat, condition=condition) self.event_loop_until_condition( condition=condition.is_set, timeout=timeout)
def start(self): """ """ plugin = self.workbench.get_plugin(u'hqc_meas.debug') plugin.workspace = self self.plugin = plugin # Add handler to the root logger to display messages in panel. core = self.workbench.get_plugin(u'enaml.workbench.core') cmd = u'hqc_meas.logging.add_handler' self.log_model = core.invoke_command(cmd, {'id': LOG_ID, 'mode': 'ui'}, self)[0] # Create content. self.content = DebuggerContent(workspace=self) # Contribute menus. self.workbench.register(DebuggerMenus()) # Add debugger contributions. for debugger in self.plugin.debuggers.values(): if debugger.contribute_workspace: debugger.contribute_workspace(self) # If the workspace was previously opened restore its state. if self.plugin.debugger_instances and self.plugin.workspace_layout: deferred_call(self._restore_debuggers)
def update(self, event=None): lb, ub = self.parent.data_range.current_range current_time = self.parent.data_range.current_time starts = self._rising ends = self._falling if len(starts) == 0 and len(ends) == 1: starts = [0] elif len(starts) == 1 and len(ends) == 0: ends = [current_time] elif len(starts) > 0 and len(ends) > 0: if starts[0] > ends[0]: starts = np.r_[0, starts] if starts[-1] > ends[-1]: ends = np.r_[ends, current_time] try: epochs = np.c_[starts, ends] except ValueError as e: log.exception(e) log.warning('Unable to update %r, starts shape %r, ends shape %r', self, starts, ends) return m = ((epochs >= lb) & (epochs < ub)) | np.isnan(epochs) epochs = epochs[m.any(axis=-1)] path = pg.QtGui.QPainterPath() y_start = self.rect_center - self.rect_height * 0.5 for x_start, x_end in epochs: x_width = x_end - x_start r = pg.QtCore.QRectF(x_start, y_start, x_width, self.rect_height) path.addRect(r) deferred_call(self.plot.setPath, path)
def projectECEFThread(array_model, GRID_ECEF, weights_shape): """Project the ECEF grid on the camera axis. Args: img_array (array): Image (float HDR). GRID_ECEF (array): Grid to project. weights_shape (tuple): Shape of the camera image. """ from enaml.application import deferred_call xs, ys, _ = array_model.projectECEF(GRID_ECEF, filter_fov=False) grid_2D = np.array((ys, xs)).T.astype(np.int) # # Map points outside the fov to 0, 0. # h, w = weights_shape grid_2D[grid_2D < 0] = 0 grid_2D[grid_2D[:, 0] >= h] = 0 grid_2D[grid_2D[:, 1] >= w] = 0 # # Send the results back to the GUI thread. # deferred_call(setattr, array_model, 'grid_2D', grid_2D)
def open(self): """ Open the dialog for user interaction. """ if self.parent is None: raise ValueError('FileDialog cannot be opened without a parent.') content = {} content['title'] = self.title content['mode'] = self.mode content['path'] = self.path content['filters'] = self.filters content['selected_filter'] = self.selected_filter content['native_dialog'] = self.native_dialog # A common dialog idiom is as follows: # # dlg = FileDialog(foo, ...) # dlg.open() # # With this scenario, the dialog will not have been initialized # by the time the `open` method is called, since the child event # of the dialog parent is batched by the Messenger class. The # 'open' action must therefore be deferred in order to allow the # dialog be fully initialized and capable of sending messages. # Otherwise, the 'open' message will be dropped. if self.is_active: self.send_action('open', content) else: deferred_call(self.send_action, 'open', content)
def getDDSDeviceList(self): logger.info('DDS: Requesting device list ...') result = self.send('<LabView><getDDSDeviceList/></LabView>') logger.info('DDS response: {}'.format(result)) deviceListStr = result['DDS/devices'] deferred_call(setattr, self, 'deviceList', deviceListStr.split('\n')) logger.info('DDS: ... done.')
def _handle_close(self): """ Handle the close event from the proxy widget. """ self.visible = False self.closed() deferred_call(self.destroy)
def handle_event(self, event, timestamp=None): # Ensure that we don't attempt to process several events at the same # time. This essentially queues the events such that the next event # doesn't get processed until `_handle_event` finishes processing the # current one. # Only events generated by NI-DAQmx callbacks will have a timestamp. # Since we want all timing information to be in units of the analog # output sample clock, we will capture the value of the sample clock # if a timestamp is not provided. Since there will be some delay # between the time the event occurs and the time we read the analog # clock, the timestamp won't be super-accurate. However, it's not # super-important since these events are not reference points around # which we would do a perievent analysis. Important reference points # would include nose-poke initiation and withdraw, reward contact, # sound onset, lights on, lights off. These reference points will # be tracked via NI-DAQmx or can be calculated (i.e., we know # exactly when the target onset occurs because we precisely specify # the location of the target in the analog output buffer). try: if timestamp is None: timestamp = self.get_ts() log.debug('{} at {}'.format(event, timestamp)) log.trace('Emitting handle_event signal') deferred_call(self._handle_event, event, timestamp) except Exception as e: log.exception(e) raise
def _handle_close(self, result, paths, selected_filter): """ Called by the proxy object when the dialog is closed. Parameters ---------- result : string The result of the dialog; either 'accepted' or 'rejected'. paths : list The list of user selected paths. If the result is 'rejected' this should be an empty list. selected_filter : str The user selected name filter. If the result is 'rejected' this should be an empty string. """ self.result = result if result == 'accepted': self.paths = paths self.path = paths[0] if paths else '' self.selected_filter = selected_filter self.accepted(self.path) else: self.rejected() if self.callback: self.callback(self) self.closed() if self.destroy_on_close: deferred_call(self.destroy)
def start(self): """ """ plugin = self.workbench.get_plugin(u'hqc_meas.measure') plugin.workspace = self self.plugin = plugin # Add handler to the root logger to display messages in panel. core = self.workbench.get_plugin(u'enaml.workbench.core') cmd = u'hqc_meas.logging.add_handler' self.log_model = core.invoke_command(cmd, {'id': LOG_ID, 'mode': 'ui'}, self)[0] # Check whether or not a measure is already being edited. if not plugin.edited_measure: self._new_measure() # Create content. self.content = MeasureContent(workspace=self) # Contribute menus. self.workbench.register(MeasureSpaceMenu()) # Check whether or not an engine can contribute. if plugin.selected_engine: engine = plugin.engines[plugin.selected_engine] deferred_call(engine.contribute_workspace, engine, self) plugin.observe('selected_engine', self._update_engine_contribution)
def start_measure(self, measure): """Start a new measure. """ if self._thread and self._thread.is_alive(): self._state.set('stop_processing') self._thread.join(5) if self._thread.is_alive(): core = self.plugin.workbench.get_plugin('enaml.workbench.core') cmd = 'ecpy.app.errors.signal' msg = ("Can't stop the running execution thread. Please " "restart the application and consider reporting this " "as a bug.") core.invoke_command(cmd, dict(kind='error', message=msg)) return if self.continuous_processing: self._state.set('continuous_processing') else: self._state.clear('continuous_processing') deferred_call(setattr, self, 'active', True) self._thread = Thread(target=self._run_measures, args=(measure, )) self._thread.daemon = True self._thread.start()
def worker(model): p = 0 while p <= 100: deferred_call(setattr, model, 'value', p) p += 1 sleep(0.2) deferred_call(setattr, model, 'busy', False)
def set_background(self, background): """ set models background """ self.bgColor = background if self.view: deferred_call(self.view.render)
def handle_dialog(op='accept', custom=lambda x: x, cls=Dialog): """Automatically close a dialog opened during the context. Parameters ---------- op : {'accept', 'reject'}, optional Whether to accept or reject the dialog. custom : callable, optional Callable taking as only argument the dialog, called before accepting or rejecting the dialog. cls : type, optional """ def close_dialog(): dial = get_window(cls) try: custom(dial) finally: process_app_events() from .conftest import DIALOG_SLEEP sleep(DIALOG_SLEEP) getattr(dial, op)() deferred_call(close_dialog) yield process_app_events()
def _insert_new_edition_panels(self, measurements, update=True, panels=None): """Handle inserting a new MeasurementEditorDockItem in the content. """ if panels is None: template = 'meas_%d' items = self.dock_area.dock_items() test = re.compile('meas\_([0-9]+)$') measurement_items = [i for i in items if test.match(i.name)] ops = [] for measurement in measurements: if not measurement_items: name = template % 0 ops.append(InsertItem(item=name, target='meas_exec')) else: indexes = [ int(test.match(i.name).group(1)) for i in measurement_items ] indexes.sort() if len(indexes) <= max(indexes): ind = [i for i, x in enumerate(indexes) if i != x][0] else: ind = len(measurement_items) name = template % ind ops.append( InsertTab(item=name, target=template % indexes[0])) measurement_items.append( MeasurementEditorDockItem(self.dock_area, workspace=self, measurement=measurement, name=name)) if update: deferred_call(self.dock_area.update_layout, ops) else: for m in measurements: if m not in panels: msg = ('Cannot insert edition panels for measurement %s, ' 'no infos were provided. Panels exists for:\n%s') raise RuntimeError(msg % (m.name + ' (id : %s)' % m.id, ', '.join(m.name for m in panels))) ed_name, t_name = panels[m] MeasurementEditorDockItem(self.dock_area, workspace=self, measurement=m, name=ed_name) if t_name: ToolsEditorDockItem(self.dock_area, measurement=m, name=t_name)
def _observe_factor(self, change): """ observe change in factor """ if change: type_ = change.get("type") if type_ != "create": value = change["value"] self.surface_model.factor = value deferred_call(self.view.render)
def repeat_loop(condition, repeat): # We sendPostedEvents to ensure that enaml events are processed self.qt_app.sendPostedEvents() repeat = repeat - 1 if repeat <= 0: deferred_call(condition.set) else: deferred_call(repeat_loop, condition=condition, repeat=repeat)
def _observe_slice_factor(self, change): """ observe change in factor """ if change: type_ = change.get('type') if type_ != 'create': value = change['value'] self.surface_model.slice_factor = value deferred_call(self.view.render)
def _observe_scale_factor(self, change): """ observe change in scale factor """ if change: type_ = change.get("type") if type_ != "create": value = change["value"] self.surface_model.warp_geometry.SetScaleFactor(value / 100.0) deferred_call(self.view.render)
def stop_experiment(self, skip_errors=False): if self.experiment_state not in ('running', 'paused'): return [] results = self.invoke_actions('experiment_end', self.get_ts(), skip_errors=skip_errors) deferred_call(lambda: setattr(self, 'experiment_state', 'stopped')) return results
def _observe_scale_factor(self, change): """ observe change in scale factor """ if change: type_ = change.get('type') if type_ != 'create': value = change['value'] self.surface_model.warp_geometry.SetScaleFactor(value/100.) deferred_call(self.view.render)
def test_timeout(self): condition = lambda obj: obj.number == 3.0 with self.assertRaises(AssertionError): with self.assertTraitChangesInEventLoop(self.my_class, 'number', condition, timeout=0.5): deferred_call(self._set_trait, 2.0)
def _observe_factor(self, change): """ observe change in factor """ if change: type_ = change.get('type') if type_ != 'create': value = change['value'] self.surface_model.factor = value deferred_call(self.view.render)
def _observe_shrink_factor(self, change): """ observe change in shrink factor """ if change: type_ = change.get('type') if type_ != 'create': value = change['value'] self.extract_model.shrink_geom.SetShrinkFactor(value/100.) deferred_call(self.view.render)
def update(self, database_vals): """ Method updating the value of the entry given the current state of the database. """ # TODO handle evaluation delimited by $ vals = {d: database_vals[d] for d in self.depend_on} new_val = self.formatting.format(**vals) deferred_call(setattr, self, 'value', new_val)
def _observe_radius(self, change): """ observe change in radius """ if change: type_ = change.get('type') if type_ != 'create': value = change['value'] self.extract_model.sphere_geom_1.SetRadius(value/100.) self.extract_model.sphere_geom_2.SetRadius(value/100.) deferred_call(self.view.render)
def start(self): self.content = ExperimentView(workspace=self) plugin = self.workbench.get_plugin('psi.experiment') plugin.setup_toolbar(self) plugin.setup_workspace(self) core = self.workbench.get_plugin('enaml.workbench.core') deferred_call(core.invoke_command, 'psi.get_default_layout') deferred_call(core.invoke_command, 'psi.get_default_preferences')
def _observe_resolution(self, change): """ observe change in resolution """ if change: type_ = change.get('type') if type_ != 'create': value = change['value'] self.surface_model.plane.SetXResolution(value) self.surface_model.plane.SetYResolution(value) deferred_call(self.view.render)
def _observe_resolution(self, change): """ observe change in resolution """ if change: type_ = change.get("type") if type_ != "create": value = change["value"] self.surface_model.plane.SetXResolution(value) self.surface_model.plane.SetYResolution(value) deferred_call(self.view.render)
def init_widget(self): """Initialize the underlying widget.""" super().init_widget() w = self.widget #: Kinda hackish, but when we get the menu back, load it deferred_call(self.init_menu) w.setOnMenuItemClickListener(w.getId()) w.onMenuItemClick.connect(self.on_menu_item_click)
def run(self): while True: try: news = self.queue.get() if news != (None, None): deferred_call(self.monitor.map_news, news) else: break except Queue.Empty: continue
def set_layout(self, layout): ui = self.workbench.get_plugin('enaml.workbench.ui') ui._window.set_geometry(layout['geometry']) self._set_toolbar_layout(ui.workspace.toolbars, layout['toolbars']) ui.workspace.dock_area.layout = layout['dock_layout'] available = [i.name for i in ui.workspace.dock_area.dock_items()] missing = MissingDockLayoutValidator(available)(layout['dock_layout']) for item in missing: log.debug('{} missing from saved dock layout'.format(item)) op = FloatItem(item=item) deferred_call(ui.workspace.dock_area.update_layout, op)
def _popup_closed(self): """ Handle the popup view being closed. This method is called by the proxy object when the toolkit popup view is closed. """ self.visible = False self.closed() deferred_call(self.destroy) PopupView.popup_views.remove(self)
def _wait_for_pause(self): """ Wait for the task paused event to be set. """ stop_sig = self._stop paused_sig = self._meas_paused while not stop_sig.is_set(): if paused_sig.wait(0.1): status = ('PAUSED', 'Measure execution is paused') deferred_call(setattr, self, 'measure_status', status) break
def test_event_loop_until_trait_change(self): with self.assertRaises(AssertionError): with self.event_loop_until_traits_change( self.my_class, 'number', timeout=1.0): pass with reverse_assertion( self.assertRaises(AssertionError), 'Assertion should not be raised'): with self.event_loop_until_traits_change( self.my_class, 'number'): deferred_call(self._set_trait, 5.0)
def test_delete_widget(self): class Widget(QtCore.QObject): destroyed = QtCore.Signal(bool) widget = Widget() with self.assertRaises(AssertionError): with self.delete_widget(widget, timeout=1.0): pass with self.delete_widget(widget, timeout=1.0): deferred_call(widget.destroyed.emit, True)
def _set_measure_state(self, status, infos, measure=None, clear=False): """Set the measure status and infos in the main thread. """ def set_state(processor, status, infos, meas, clear): if meas: processor.running_measure = meas measure = processor.running_measure measure.status = status measure.infos = infos if clear: processor.running_measure = None deferred_call(set_state, self, status, infos, measure, clear)
def _start_timer(self, duration, event): # The duration can be specified as a string naming the context variable # to extract. if isinstance(duration, basestring): duration = self.context.get_value(duration) log.debug('Timer for {} with duration {}'.format(event, duration)) receiver = partial(self.handle_event, event) if duration == 0: deferred_call(receiver) else: self.timer = QTimer() self.timer.timeout.connect(receiver) # set up new callback self.timer.setSingleShot(True) # call only once self.timer.start(duration*1e3)