def instanciatePlugin(self, plugin_info, element, category_name): """ The default behavior is that each plugin is instanciated at load time; the class is thrown away. Add the isSingleton = False attribute to your plugin class to prevent this behavior! """ msg.logMessage(f"Instanciating {plugin_info.name} plugin object.", level=msg.INFO) with load_timer() as elapsed: try: if list(filter(lambda plugin: plugin.name == plugin_info.name, self.category_mapping[category_name])): msg.logMessage(f'A plugin named "{plugin_info.name}" has already been loaded.') return if getattr(element, "isSingleton", True): plugin_info.plugin_object = element() else: plugin_info.plugin_object = element except (Exception, SystemError) as ex: exc_info = sys.exc_info() msg.logMessage("Unable to instanciate plugin: %s" % plugin_info.path, msg.ERROR) msg.logError(ex) msg.notifyMessage( repr(ex), title=f'An error occurred while starting the "{plugin_info.name}" plugin.', level=msg.CRITICAL ) plugin_info.error = exc_info else: plugin_info.categories.append(category_name) self.category_mapping[category_name].append(plugin_info) msg.logMessage(f"{int(elapsed() * 1000)} ms elapsed while instanciating {plugin_info.name}", level=msg.INFO) self.notify()
def __init__(self): self._happi_db_dirs = [happi_site_dir, happi_user_dir] self._device_view = HappiClientTreeView() self._client_model = HappiClientModel() self._device_view.setModel(self._client_model) for db_dir in self._happi_db_dirs: for db_file in Path(db_dir).glob('*.json'): client = Client(path=str(db_file)) self._client_model.add_client(client) try: mongo_client = Client( MongoBackend(host='127.0.0.1', db='happi', collection='labview_static', user=USER_MONGO, pw=PW_MONGO, timeout=None)) self._client_model.add_client(mongo_client) except Exception as e: #TODO catch exception properly msg.logError(e) widget = QWidget() layout = QVBoxLayout() layout.addWidget(self._device_view) widget.setLayout(layout) icon = QIcon(str(static.path('icons/calibrate.png'))) name = "Devices" super(HappiSettingsPlugin, self).__init__(icon, name, widget) self._device_view.expandAll() self.restore()
def appendCatalog(self, run_catalog: BlueskyRun, **kwargs): # catalog.metadata.update(self.schema()) ensemble = Ensemble() ensemble.append_catalog(run_catalog) self.ensemble_model.add_ensemble(ensemble, projection_mapping.values()) try: # Apply nxSTXM projection #add conditional to split xarray from intent xdata = project_all(run_catalog) if isinstance( xdata, list ): # temporary logic to allow for intents to be returned rather than xarray for intent in xdata: if isinstance(intent, ImageIntent): xdata = intent.image break else: raise ValueError("No data returned from ingestion.") self.catalog_viewer.setData( xdata) #, view_dims=('y (μm)', 'x (μm)') except Exception as e: msg.logError(e) msg.showMessage("Unable to display: ", str(e)) self.current_catalog = run_catalog
def pipmain(args): old_env = os.environ.copy() os.environ["PYTHONPATH"] = os.path.join(venvs.current_environment, "Lib/site-packages") os.environ["PYTHONBASE"] = venvs.current_environment old_prefix = sys.prefix sys.prefix = venvs.current_environment r = 1 # (error code) try: # Install the bundled software try: r = pip.main(args) except AttributeError: from pip._internal import main r = main(args) except Exception as ex: msg.logError(ex) finally: os.environ = old_env sys.prefix = old_prefix return r
def run(self, *args, **kwargs): self.cancelled = False self.running = True self.done = False self.exception = None if self.showBusy: invoke_in_main_thread(msg.showBusy) try: for self._result in self._run(*args, **kwargs): if not isinstance(self._result, tuple): self._result = (self._result, ) if self.callback_slot: invoke_in_main_thread(self.callback_slot, *self._result) self.running = False except Exception as ex: self.exception = ex self.sigExcept.emit(ex) msg.logMessage( f'Error in thread: ' f'Method: {self.method.__name__}\n' f'Args: {self.args}\n' f'Kwargs: {self.kwargs}', level=msg.ERROR) msg.logError(ex) else: self.done = True self.sigFinished.emit() finally: invoke_in_main_thread(msg.showReady)
def _load_plugin(self, load_task: PluginTask): entrypoint = load_task.entry_point try: # Load the entrypoint (unless already cached), cache it, and put it on the instantiate queue msg.logMessage( f"Loading entrypoint {entrypoint.name} from module: {entrypoint.module_name}" ) with load_timer() as elapsed: load_task.plugin_class = entrypoint.load() except (Exception, SystemError) as ex: msg.logMessage( f"Unable to load {entrypoint.name} plugin from module: {entrypoint.module_name}", level=msg.ERROR) msg.logError(ex) msg.notifyMessage( repr(ex), title= f'An error occurred while starting the "{entrypoint.name}" plugin.', level=msg.CRITICAL) load_task.status = Status.FailedLoad else: msg.logMessage( f"{int(elapsed() * 1000)} ms elapsed while loading {entrypoint.name}", level=msg.INFO) self._instantiate_queue.put(load_task) load_task.status = Status.InstantiateQueue
def _load_plugin(self, type_name, entrypoint: entrypoints.EntryPoint): # if the entrypoint was already loaded into cache and queued, do nothing if self._load_cache[type_name].get(entrypoint.name, None): return try: # Load the entrypoint (unless already cached), cache it, and put it on the instantiate queue msg.logMessage( f'Loading entrypoint {entrypoint.name} from module: {entrypoint.module_name}' ) with load_timer() as elapsed: plugin_class = self._load_cache[type_name][entrypoint.name] = \ self._load_cache[type_name].get(entrypoint.name, None) or entrypoint.load() except (Exception, SystemError) as ex: msg.logMessage( f"Unable to load {entrypoint.name} plugin from module: {entrypoint.module_name}", msg.ERROR) msg.logError(ex) msg.notifyMessage( repr(ex), title= f'An error occurred while starting the "{entrypoint.name}" plugin.', level=msg.CRITICAL) else: msg.logMessage( f"{int(elapsed() * 1000)} ms elapsed while loading {entrypoint.name}", level=msg.INFO) self._instantiate_queue.put((type_name, entrypoint, plugin_class))
def run(self): while True: try: search_state.process_queries() except Exception as e: msg.logError(e) msg.showMessage("Unable to query: ", str(e))
def process_queries(self): # If there is a backlog, process only the newer query. block = True while True: try: query = self.query_queue.get_nowait() block = False except queue.Empty: if block: query = self.query_queue.get() break log.debug('Submitting query %r', query) try: t0 = time.monotonic() msg.showMessage("Running Query") msg.showBusy() self._results_catalog = self.selected_catalog.search(query) found_new = self.check_for_new_entries() duration = time.monotonic() - t0 log.debug('Query yielded %r results (%.3f s).', len(self._results_catalog), duration) if found_new and self.show_results_event.is_set(): self.new_results_catalog.emit() except Exception as e: msg.logError(e) msg.showMessage("Problem running query") finally: msg.hideBusy()
def flatten_remote_catalogs(self, catalog): from intake.catalog.base import Catalog cat_dict = {} for name in catalog: try: from intake.catalog.base import RemoteCatalog sub_cat = catalog[name] # @TODO remote catalogs are one level too high. This check is # pretty rough. Would rather check that a catalog's children # should be top-level. # This is making the terrible assumption that children # of a RemoteCatalog be treated as top-level. But until # we figure out how to tell that a catalog is a real catalog # with data, it's as good as we can get if isinstance(sub_cat(), RemoteCatalog): for name in sub_cat: cat_dict[name] = sub_cat[name] else: cat_dict[name] = sub_cat except Exception as e: msg.logError(e) msg.showMessage("Unable to query top level catalogs: ", str(e)) return Catalog.from_dict(cat_dict)
def dataChanged(self, start, end): for i in range(self.headermodel.rowCount()): if self.widget(i): if self.widget(i).header == self.headermodel.item(i).header: continue try: newwidget = self.widgetcls(self.headermodel.item(i).header, self.field, **self.kwargs) except Exception as ex: msg.logMessage( f"A widget of type {self.widgetcls} could not be initialized with args: {self.headermodel.item(i).header, self.field, self.kwargs}" ) msg.logError(ex) self.headermodel.removeRow(i) self.dataChanged(0, 0) return self.setCurrentIndex(self.insertTab(i, newwidget, self.headermodel.item(i).text())) for sender, receiver in self.bindings: if isinstance(sender, str): sender = getattr(newwidget, sender) if isinstance(receiver, str): receiver = getattr(newwidget, receiver) sender.connect(receiver) for i in reversed(range(self.headermodel.rowCount(), self.count())): self.removeTab(i)
def __init__(self, **kwargs): super(QRunEngine, self).__init__() self.RE = RunEngine(context_managers=[], during_task=DuringTask(), **kwargs) self.RE.subscribe(self.sigDocumentYield.emit) # TODO: pull from settings plugin from suitcase.mongo_normalized import Serializer #TODO create single databroker db #python-dotenv stores name-value pairs in .env (add to .gitginore) username = os.getenv("USER_MONGO") pw = os.getenv("PASSWD_MONGO") try: self.RE.subscribe( Serializer( f"mongodb://{username}:{pw}@localhost:27017/mds?authsource=mds", f"mongodb://{username}:{pw}@localhost:27017/fs?authsource=fs" )) except OperationFailure as err: msg.notifyMessage("Could not connect to local mongo database.", title="xicam.Acquire Error", level=msg.ERROR) msg.logError(err) self.queue = PriorityQueue() self.process_queue()
def fullReconstruction(self): from xicam.Tomography.widgets.volumeviewer import VolumeViewer volumeviewer = VolumeViewer() self.recontabs.addTab(volumeviewer, '????') currentitem = self.headermodel.item(self.rawtabview.currentIndex()) if not currentitem: msg.showMessage('Error: You must open files before reconstructing.') try: msg.showBusy() msg.showMessage('Running slice reconstruction...', level=msg.INFO) currentheader = self.headermodel.item(self.rawtabview.currentIndex()).header readprocess = self.workflow.processes[0] # hopefully! TODO: require a readprocess first readprocess.path.value = currentheader.startdoc['path'] numofsinograms = currentheader.meta_array('primary').shape[1] executor = DaskExecutor() client = distributed.Client() def chunkiterator(workflow): for i in range(0, int(numofsinograms), int(readprocess.chunksize.value)): readprocess.sinoindex.value = i yield executor.execute(workflow) _reconthread = QThreadFutureIterator(chunkiterator, self.workflow, callback_slot=partial(self.showReconstruction, mode=self.fullrecon), except_slot=self.exceptionCallback) _reconthread.start() except Exception as ex: msg.logError(ex) msg.showReady() msg.clearMessage()
def instanciatePlugin(self, plugin_info, element): """ The default behavior is that each plugin is instanciated at load time; the class is thrown away. Add the isSingleton = False attribute to your plugin class to prevent this behavior! """ msg.logMessage(f"Instanciating {plugin_info.name} plugin object.", level=msg.INFO) with load_timer() as elapsed: try: if getattr(element, "isSingleton", True): plugin_info.plugin_object = element() else: plugin_info.plugin_object = element except (Exception, SystemError) as ex: exc_info = sys.exc_info() msg.logMessage( "Unable to instanciate plugin: %s" % plugin_info.path, msg.ERROR) msg.logError(ex) msg.notifyMessage( repr(ex), title= f'An error occurred while starting the "{plugin_info.name}" plugin.', level=msg.CRITICAL) plugin_info.error = exc_info msg.logMessage( f"{int(elapsed()*1000)} ms elapsed while instanciating {plugin_info.name}", level=msg.INFO) self.notify()
def fullReconstruction(self): from .widgets.volumeviewer import VolumeViewer volumeviewer = VolumeViewer() self.recontabs.addTab(volumeviewer, '????') currentitem = self.headermodel.item(self.rawtabview.currentIndex()) if not currentitem: msg.showMessage( 'Error: You must open files before reconstructing.') try: msg.showBusy() msg.showMessage('Running slice reconstruction...', level=msg.INFO) currentheader = self.headermodel.item( self.rawtabview.currentIndex()).header readprocess = self.workflow.processes[ 0] # hopefully! TODO: require a readprocess first readprocess.path.value = currentheader.startdoc['path'] numofsinograms = currentheader.meta_array('primary').shape[1] self.workflow.execute_all(None, readprocess=range( 0, int(numofsinograms), int(readprocess.chunksize.value))) except Exception as ex: msg.logError(ex) msg.showReady() msg.clearMessage()
def exit_checks(): from xicam.core import msg import threading msg.logMessage('Background threads:', threading.active_count() - 1) # msg.logMessage('Active background threads:', len([thread for thread in threading.enumerate() if not isinstance(thread, threading._DummyThread)])-1) msg.logMessage( 'Active background threads:', len( list( filter( lambda thread: not isinstance(thread, threading. _DummyThread), threading.enumerate()))) - 1) for thread in threading.enumerate(): if thread is threading.current_thread() or isinstance( thread, threading._DummyThread): # or thread.daemon continue msg.logMessage('Waiting for thread:', thread.name) thread.join(timeout=3) msg.logError( TimeoutError( f'Thread named "{thread.name}" took too long to exit as Xi-CAM was closing. ' # 'Please report this.') ))
def appendCatalog(self, run_catalog, **kwargs): self.catalog_viewer.clear() try: msg.showMessage(f"Loading image for {run_catalog.name}") self.catalog_viewer.setCatalog(run_catalog) except Exception as e: msg.logError(e) msg.showMessage("Unable to display: ", str(e))
def restore(self): try: self.fromState(pickle.loads(QSettings().value(self.name()))) except (AttributeError, TypeError, SystemError, KeyError, ModuleNotFoundError) as ex: # No settings saved msg.logError(ex) msg.logMessage( f"Could not restore settings for {self.name} plugin; re-initializing settings...", level=msg.WARNING )
def preview_catalog(self, catalog: BlueskyRun): threads.invoke_in_main_thread(self.setText, "LOADING...") try: stream, field = bluesky_utils.guess_stream_field(catalog) data = bluesky_utils.preview(catalog, stream, field) threads.invoke_in_main_thread(self.setImage, data) except Exception as ex: msg.logError(ex) threads.invoke_in_main_thread(self.imageitem.clear) threads.invoke_in_main_thread(self.setText, "UNKNOWN DATA FORMAT")
def collect_user_plugins(self): files = glob.glob(os.path.join(user_plugin_dir, '*.py')) for file in files: try: spec = importlib.util.spec_from_file_location("xicam.user", file) foo = importlib.util.module_from_spec(spec) spec.loader.exec_module(foo) except Exception as ex: msg.showMessage("An error occured in a user-defined plugin. See log for details.") msg.logError(ex)
def dataChanged(self, topLeft: QModelIndex, bottomRight: QModelIndex, roles=None): """ Listens for dataChanged on an Intent (TreeItem)'s check state. Renders/unrenders according to the check state. Then, defers showing canvases to any derived views (e.g. StackedCanvasView). """ # We only care about the check state changing here (whether to render or unrender) if Qt.CheckStateRole in roles or EnsembleModel.canvas_role in roles: intent_row_start = topLeft.row() intent_row_stop = bottomRight.row() new_intents = set() if topLeft.isValid() and bottomRight.isValid(): for row in range(intent_row_start, intent_row_stop + 1): intent_index = self.model().index(row, 0) intent = intent_index.internalPointer().data( EnsembleModel.object_role) try: canvas = self._canvas_manager.canvas_from_index( intent_index.internalPointer()) try: canvas.sigInteractiveAction.connect( self.sigInteractiveAction, type=Qt.UniqueConnection) except TypeError: # ignore errors from connection already being established pass except Exception as ex: msg.logMessage( f'A error occurred displaying the intent named {intent.name}:', level=msg.ERROR) msg.logError(ex) else: new_intents.add((canvas, intent)) removed_intents = self._last_seen_intents - new_intents added_intents = new_intents - self._last_seen_intents for canvas, intent in removed_intents: if canvas is not None: self.unrender(intent, canvas) for canvas, intent in added_intents: if canvas is not None: self.render(intent, canvas) self._last_seen_intents = new_intents self.show_canvases()
def instanciateLatePlugins(self): if qt_is_safe: for plugin_info in self.getPluginsOfCategory('GUIPlugin'): if callable(plugin_info.plugin_object): try: plugin_info.plugin_object = plugin_info.plugin_object( ) # Force late singleton-ing of GUIPlugins except Exception as ex: msg.notifyMessage( f'The "{plugin_info.name}" plugin could not be loaded. {repr(ex)}', level=msg.CRITICAL) msg.logError(ex)
def _from_dict(metadata: Iterable, excludedkeys=None): if isinstance(metadata, Sequence): metadata = OrderedDict(enumerate(metadata)) metadata = MetadataView._strip_reserved(metadata, excludedkeys) children = [] for key, value in metadata.items(): subchildren = [] if typemap.get(type(value), None) in ["group", "lazygroup"]: subchildren = MetadataView._from_dict(value) key = f"{str(key)} {type(value)}" value = None param_type = None if type(value) in typemap: param_type = type(value) if param_type is None: for map_type in typemap: if isinstance(value, map_type): param_type = map_type break if param_type is None and value: msg.logError(TypeError(f'An embedded value of type {type(value)} could not be mapped to a Parameter: {value}')) return children try: children.append( Parameter.create( name=str(key), value=value, type=typemap[param_type], children=subchildren, expanded=False, readonly=True, ) ) except Exception as ex: msg.logMessage("Error during parameterizing metadata:") msg.logError(ex) children.append( Parameter.create( name=str(key), value=repr(value), type=typemap[str], children=subchildren, expanded=False, readonly=True, ) ) return children
def load_element(self, element, candidate_infofile, plugin_info): """ Parameters ---------- element candidate_infofile plugin_info Returns ------- bool True if the element matched a category, and will be accepted as a plugin """ target_plugin_info = None for category_name in self.categories_interfaces: try: is_correct_subclass = issubclass( element, self.categories_interfaces[category_name]) except Exception: continue if is_correct_subclass and element is not self.categories_interfaces[ category_name]: current_category = category_name if candidate_infofile not in self._category_file_mapping[ current_category]: # we found a new plugin: initialise it and search for the next one try: threads.invoke_in_main_thread(self.instanciatePlugin, plugin_info, element, current_category) except Exception as ex: exc_info = sys.exc_info() msg.logError(ex) msg.logMessage("Unable to create plugin object: %s" % plugin_info.path) plugin_info.error = exc_info # break # If it didn't work once it wont again msg.logError( RuntimeError( "An error occurred while loading plugin: %s" % plugin_info.path)) else: # plugin_info.categories.append(current_category) # self.category_mapping[current_category].append(plugin_info) self._category_file_mapping[current_category].append( candidate_infofile) return True
def _update_thread(self, update_action:Callable): while True: if not self.passive.isChecked(): break if self.visibleRegion().isEmpty(): time.sleep(1 / self.maxfps) continue try: if not self.device.connected: with msg.busyContext(): msg.showMessage('Connecting to device...') self.device.wait_for_connection() update_action() except (RuntimeError, CaprotoTimeoutError, ConnectionTimeoutError, TimeoutError) as ex: threads.invoke_in_main_thread(self.error_text.setText, 'An error occurred communicating with this device.') msg.logError(ex) except Exception as e: threads.invoke_in_main_thread(self.error_text.setText, 'Unknown error occurred when attempting to communicate with device.') msg.logError(e) num_exposures_counter = self.device.cam.num_exposures_counter.get() num_exposures = self.device.cam.num_exposures.get() num_captured = self.device.hdf5.num_captured.get() num_capture = self.device.hdf5.num_capture.get() capturing = self.device.hdf5.capture.get() if capturing: current = num_exposures_counter + num_captured * num_exposures total = num_exposures * num_capture elif num_exposures == 1: # Show 'busy' for just one exposure current = 0 total = 0 else: current = num_exposures_counter total = num_exposures threads.invoke_in_main_thread(self._update_progress, current, total) while self.getting_frame: time.sleep(.01) t = time.time() max_period = 1 / self.maxfps current_elapsed = t - self._last_timestamp if current_elapsed < max_period: time.sleep(max_period - current_elapsed) self._last_timestamp = time.time()
def __setitem__(self, key, value): self.mapping[key] = value if self.operation: if self.operation._parameter: group_parameter = self.operation._parameter() if group_parameter: try: group_parameter.child(key).setOpts( **{self._opts_key: value}) # group_parameter.child(key).setValue(value, # blockSignal=self._operation._set_value) except Exception as e: msg.logError(e)
def preview_catalog(self, catalog: BlueskyRun): threads.invoke_in_main_thread(self.setText, "LOADING...") try: stream, field = self.guess_stream_field(catalog) data = getattr(catalog, stream).to_dask()[field].squeeze() for i in range(len(data.shape) - 2): data = data[0] threads.invoke_in_main_thread(self.setImage, np.asarray(data.compute())) except Exception as ex: msg.logError(ex) threads.invoke_in_main_thread(self.imageitem.clear) threads.invoke_in_main_thread(self.setText, "UNKNOWN DATA FORMAT")
def event(self, event): try: if hasattr(event.fn, 'signal'): # check if invoking a signal or a callable event.fn.emit(*event.args, *event.kwargs.values()) else: event.fn(*event.args, **event.kwargs) return True except Exception as ex: msg.logMessage('QThreadFuture callback could not be invoked.', level=msg.ERROR) msg.logError(ex) return False
def field(self): if not self._field: fields = list(self.header.fields()) if len(fields) > 1: msg.logError( ValueError( "Unspecified field for document stream with >1 field. Potentially unexpected behavior.") ) self.field = next(iter(self.header.eventdocs[0]["data"].keys())) else: self.field = fields[0] return self._field
def _instantiate_plugin(self): if not self._instantiate_queue.empty(): type_name, entrypoint, plugin_class = self._instantiate_queue.get() # if this plugin was already instantiated earlier, skip it; mark done if self.type_mapping[type_name].get(entrypoint.name, None) is None: # inject the entrypoint name into the class plugin_class._name = entrypoint.name success = False # ... and instantiate it (as long as its supposed to be singleton) try: if getattr(plugin_class, "is_singleton", False): msg.logMessage(f"Instantiating {entrypoint.name} plugin object.", level=msg.INFO) with load_timer() as elapsed: self.type_mapping[type_name][entrypoint.name] = plugin_class() msg.logMessage( f"{int(elapsed() * 1000)} ms elapsed while instantiating {entrypoint.name}", level=msg.INFO ) else: self.type_mapping[type_name][entrypoint.name] = plugin_class success = True except (Exception, SystemError) as ex: msg.logMessage( f"Unable to instantiate {entrypoint.name} plugin from module: {entrypoint.module_name}", msg.ERROR ) msg.logError(ex) msg.notifyMessage(repr(ex), title=f'An error occurred while starting the "{entrypoint.name}" plugin.') if success: msg.logMessage(f"Successfully collected {entrypoint.name} plugin.", level=msg.INFO) msg.showProgress(self._progress_count(), maxval=self._entrypoint_count()) self._notify(Filters.UPDATE) # mark it as completed self._instantiate_queue.task_done() # If this was the last plugin if self._load_queue.empty() and self._instantiate_queue.empty() and self.state in [State.INSTANTIATING, State.READY]: self.state = State.READY msg.logMessage("Plugin collection completed!") msg.hideProgress() self._notify(Filters.COMPLETE) if not self.state == State.READY: # if we haven't reached the last task, but there's nothing queued threads.invoke_as_event(self._instantiate_plugin) # return to the event loop, but come back soon