def doInit(self, mode): # import server and serializer class servercls = importString(self.servercls) serialcls = importString(self.serializercls) self._stoprequest = False # the controller represents the internal script execution machinery if self.autosimulate and not config.sandbox_simulation: raise ConfigurationError('autosimulation configured but sandbox' ' deactivated') self._controller = ExecutionController(self.log, self.emit_event, 'startup', self.simmode, self.autosimulate) # cache log messages emitted so far self._messages = [] host, port = parseHostPort(self.server, DEFAULT_PORT) # create server (transport + serializer) self._server = servercls(self, (host, port), serialcls()) self._watch_worker = createThread('daemon watch monitor', self._watch_entry)
def initDataReaders(self): try: # just import to register all default readers # pylint: disable=unused-import import nicos.devices.datasinks except ImportError: pass classes = self.gui_conf.options.get('reader_classes', []) for clsname in classes: try: importString(clsname) except ImportError: pass
def createPanel(item, window, menuwindow, topwindow, log): try: cls = importString(item.clsname) except Exception: log.exception('Could not import class %s to create panel', item.clsname) return None log.debug('creating panel: %s', item.clsname) p = cls(menuwindow, window.client, item.options or {}) window.addPanel(p) topwindow.addPanel(p, False) for toolbar in p.getToolbars(): # this helps for serializing window state toolbar.setObjectName(toolbar.windowTitle()) if hasattr(menuwindow, 'toolBarWindows'): menuwindow.insertToolBar(menuwindow.toolBarWindows, toolbar) else: menuwindow.addToolBar(toolbar) toolbar.setVisible(False) for menu in p.getMenus(): if hasattr(menuwindow, 'menuWindows'): p.actions.update((menuwindow.menuBar().insertMenu( menuwindow.menuWindows.menuAction(), menu), )) else: p.actions.update((menuwindow.menuBar().addMenu(menu), )) p.setCustomStyle(window.user_font, window.user_color) if window.client.isconnected and hasattr(p, 'on_client_connected'): p.on_client_connected() return p
def check_guiconfig_panel_spec(self, spec, context='main window'): # recursively check a panel spec if isinstance( spec, (guicfg.hsplit, guicfg.vsplit, guicfg.hbox, guicfg.vbox)): for child in spec.children: self.check_guiconfig_panel_spec(child, context) elif isinstance(spec, guicfg.tabbed): for child in spec.children: self.check_guiconfig_panel_spec(child[1], context) elif isinstance(spec, guicfg.docked): self.check_guiconfig_panel_spec(spec[0]) for child in spec[1]: if not (isinstance(child, tuple) and len(child) == 2): self.log_error( 'dock item should be a (name, panel) tuple,' ' found %r', child) else: self.check_guiconfig_panel_spec(child[1], context) elif isinstance(spec, guicfg.panel): try: cls = importString(spec.clsname) except Exception as err: self.log_error('class %r for %s not importable: %s', spec.clsname, context, err) else: if qt and not issubclass(cls, Panel): self.log.warning( 'class %r for %s is not a Panel ' 'subclass', spec.clsname, context) self.validate_setup_spec(spec) else: self.log_error('found unsupported panel item %r', spec)
def __init__(self, parent, client, options): LokiPanelBase.__init__(self, parent, client, options) loadUi(self, findResource('nicos_ess/loki/gui/ui_files/scriptbuilder.ui')) self.window = parent self.runBtn.setVisible(False) self.mapping = {} self.expertmode = self.mainwindow.expertmode self._cmdlet = self.sender() self._layout = self.frame.layout() self.index = self._layout.indexOf(self._cmdlet) self.initialise_connection_status_listeners() modules = options.get('modules', []) for module in modules: importString(module) # should register cmdlets for cmdlet in all_cmdlets: def callback(on, cmdlet=cmdlet): inst = cmdlet(self, self.client) inst.cmdletUp.connect(self.on_cmdletUp) inst.cmdletDown.connect(self.on_cmdletDown) inst.cmdletRemove.connect(self.on_cmdletRemove) self.runBtn.setVisible(True) self.frame.layout().insertWidget( self.frame.layout().count() - 2, inst) action = QAction(cmdlet.name, self) action.triggered.connect(callback) self.mapping.setdefault(cmdlet.category, []).append(action) for category in all_categories[::-1]: if category not in self.mapping: return toolbtn = QToolButton(self) toolbtn.setText(category) toolbtn.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) menu.addActions(self.mapping[category]) toolbtn.setMenu(menu) self.btnLayout.insertWidget(1, toolbtn)
def __init__(self, parent, client, options): Panel.__init__(self, parent, client, options) loadUi(self, self.ui) self.window = parent self.mapping = {} self.current_cmdlet = None self.expertmode = self.mainwindow.expertmode # collect values of all cmdlets that have been added # so that the common fields carry over to the next cmdlet self.value_collection = {} self.commandInput.history = self.cmdhistory self.commandInput.completion_callback = self.completeInput self.console = None client.initstatus.connect(self.on_client_initstatus) client.mode.connect(self.on_client_mode) client.simresult.connect(self.on_client_simresult) modules = options.get('modules', []) for module in modules: importString(module) # should register cmdlets for cmdlet in all_cmdlets: action = QAction(cmdlet.name, self) def callback(on, cmdlet=cmdlet): self.selectCmdlet(cmdlet) action.triggered.connect(callback) self.mapping.setdefault(cmdlet.category, []).append(action) for category in all_categories[::-1]: if category not in self.mapping: continue toolbtn = QToolButton(self) toolbtn.setText(category) toolbtn.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) menu.addActions(self.mapping[category]) toolbtn.setMenu(menu) self.btnLayout.insertWidget(1, toolbtn)
def runTool(window, tconfig): """Run a tool from *tconfig* If it is a tool dialog, use *window* as the parent. """ if isinstance(tconfig, tool): try: toolclass = importString(tconfig.clsname) except ImportError: window.showError('Could not import class %r.' % tconfig.clsname) else: dialog = toolclass(window, window.client, **tconfig.options) dialog.setWindowModality(Qt.NonModal) dialog.setAttribute(Qt.WA_DeleteOnClose, True) dialog.show() elif isinstance(tconfig, cmdtool): try: createSubprocess(tconfig.cmdline) except Exception as err: window.showError('Could not execute command: %s' % err)
def check_guiconfig_tool_spec(self, spec): # recursively check a tool spec if not isinstance(spec, (guicfg.tool, guicfg.cmdtool, guicfg.menu)): self.log_error('tool spec %r is not a tool() or cmdtool()', spec) if isinstance(spec, guicfg.menu): for tool in spec.items: self.check_guiconfig_tool_spec(tool) if isinstance(spec, guicfg.tool): try: cls = importString(spec.clsname) except Exception as err: self.log_error('class %r for tool %r not importable: %s', spec.clsname, spec.name, err) else: if qt and not issubclass(cls, (qt.QDialog, qt.QMainWindow)): self.log.warning( 'class %r for tool %r is not a QDialog or' ' QMainWindow', spec.clsname, spec.name) self.validate_setup_spec(spec)
def check_guiconfig_panel_spec(self, spec, context='main window'): qt5_incompatibles = [ 'nicos.clients.gui.panels.liveqwt.LiveDataPanel', ] # recursively check a panel spec if isinstance( spec, (guicfg.hsplit, guicfg.vsplit, guicfg.hbox, guicfg.vbox)): for child in spec.children: self.check_guiconfig_panel_spec(child, context) elif isinstance(spec, guicfg.tabbed): for child in spec.children: self.check_guiconfig_panel_spec(child[1], context) elif isinstance(spec, guicfg.docked): self.check_guiconfig_panel_spec(spec[0]) for child in spec[1]: if not (isinstance(child, tuple) and len(child) == 2): self.log_error( 'dock item should be a (name, panel) tuple,' ' found %r', child) else: self.check_guiconfig_panel_spec(child[1], context) elif isinstance(spec, guicfg.panel): if os.environ.get('NICOS_QT', 4) == '5' and \ spec.clsname in qt5_incompatibles: self.log.warning('%r is not compatible with QT5', spec.clsname) return try: cls = importString(spec.clsname) except Exception as err: self.log_error('class %r for %s not importable: %s', spec.clsname, context, err) else: if qt and not issubclass(cls, Panel): self.log.warning( 'class %r for %s is not a Panel ' 'subclass', spec.clsname, context) self.validate_setup_spec(spec) else: self.log_error('found unsupported panel item %r', spec)
def check(self): # check syntax try: with open(self.filename, encoding='utf-8') as fp: self.code = fp.read() exec(self.code, self.ns) self.ast = ast.parse(self.code) except SyntaxError as e: msg = 'SyntaxError:\t%s' % e.msg msg += '\n|line: %s : %s ' % (e.lineno, e.text.strip() if e.text else '') self.log_error(msg, extra={'line': e.lineno}) return self.good except Exception as e: self.log_exception(e) return self.good self.log.info('syntax ok') self.setup_info[self.setupname] = self.ns if self.is_guiconfig: return self.check_guiconfig() # check for valid group group = self.ns.get('group', 'optional') if group not in SETUP_GROUPS: self.log_error('invalid setup group %r', group, extra=self.find_global('group')) # check for a description description = self.ns.get('description', None) if description in (None, ''): self.log_error('missing user-friendly setup description', extra=self.find_global('description')) self.ns['devices'] = fixup_stacked_devices(self, self.ns.get('devices', {})) # check if devices are duplicated if group != 'special': devs = self.ns.get('devices', {}) for devname in devs: if devname not in self.devs_seen: self.devs_seen[devname] = self.setupname continue # we have a duplicate: it's okay if we exclude the other setup # or if we are both basic setups other = self.devs_seen[devname] self_group = self.ns.get('group', 'optional') other_group = self.setup_info[other].get('group', 'optional') if self_group == 'basic' and other_group == 'basic': continue if other in self.ns.get('excludes', []) or \ self.setupname in self.setup_info[other].get('excludes', []): continue # it's also ok if it is a sample, experiment, or instrument # device if devname in ['Sample', 'Exp'] or \ 'instrument' in devs[devname][1]: continue self.log.warning('device name %s duplicate: also in %s', devname, self.devs_seen[devname], extra=self.find_deventry(devname)) # check for common misspelling of "includes" if 'include' in self.ns: self.log_error("'include' list should be called 'includes'", extra=self.find_global('include')) # check for common misspelling of "excludes" if 'exclude' in self.ns: self.log_error("'exclude' list should be called 'excludes'", extra=self.find_global('exclude')) if os.path.basename(self.filename) == 'startup.py': if self.ns.get('includes', []): self.log_error("The 'includes' in 'startup.py' must be empty!", extra=self.find_global('includes')) # check for types of recognized variables for (vname, vtype) in [ ('description', str), # group is already checked against a fixed list ('sysconfig', dict), ('includes', list), ('excludes', list), ('modules', list), ('devices', dict), ('alias_config', dict), ('startupcode', str), ('extended', dict) ]: if vname in self.ns and not isinstance(self.ns[vname], vtype): self.log_error('%r must be of type %s (but is %s)' % (vname, vtype, type(self.ns[vname])), extra=self.find_global(vname)) # check for importability of modules for module in self.ns.get('modules', []): # try to import the device class try: importString(module) except Exception as err: self.log_error('module %r not importable: %s', module, err, extra=self.find_global('modules')) # check for validity of alias_config aliascfg = self.ns.get('alias_config', {}) if isinstance(aliascfg, dict): # else we complained above already for aliasname, entrydict in aliascfg.items(): if not (isinstance(aliasname, str) and isinstance(entrydict, dict)): self.log_error( 'alias_config entries should map alias ' 'device names to a dictionary', extra=self.find_global('alias_config')) continue for target, prio in entrydict.items(): if not (isinstance(target, str) and isinstance(prio, int) and not isinstance(prio, bool)): self.log_error( 'alias_config entries should map device ' 'names to integer priorities', extra=self.find_global('alias_config')) break if target not in self.ns.get('devices', {}): basedev = target.partition('.')[0] if basedev not in self.ns.get('devices'): self.log_error( 'alias_config device target should ' 'be a device from the current setup', extra=self.find_global('alias_config')) break # check for validity of display_order display_order = self.ns.get('display_order', 50) if not isinstance(display_order, int) or \ not 0 <= display_order <= 100: self.log_error( 'display_order should be an integer between ' '0 and 100', extra=self.find_global('display_order')) # check for validity of extended representative representative = self.ns.get('extended', {}).get('representative') if representative is not None: if representative not in self.ns.get('devices', {}): self.log_error( 'extended["representative"] should be a device ' 'defined in the current setup', extra=self.find_global('extended')) # check for valid device classes (if importable) and parameters for devname, devconfig in self.ns.get('devices', {}).items(): self.check_device(devname, devconfig, group in ('special', 'configdata')) # return overall "ok" flag return self.good
def check_device(self, devname, devconfig, is_special=False): # check for valid name if not nicosdev_re.match(devname): self.log_error('%s: device name is invalid (must be a valid ' 'Python identifier)' % devname, extra=self.find_deventry(devname)) # check for format of config entry if not isinstance(devconfig, tuple) or len(devconfig) != 2: self.log_error('%s: device entry has wrong format (should be ' 'device() or a 2-entry tuple)' % devname, extra=self.find_deventry(devname)) return False # try to import the device class try: cls = importString(devconfig[0]) except (ImportError, RuntimeError) as err: self.log.warning('device class %r for %r not importable: %s', devconfig[0], devname, err, extra=self.find_deventry(devname)) return except Exception as e: self.log_error('could not get device class %r for %r:', devconfig[0], devname, extra=self.find_deventry(devname)) return self.log_exception(e) config = devconfig[1] # check missing attached devices if not hasattr(cls, 'attached_devices'): self.log.warning("%s: class %r has no 'attached_devices'", devname, cls.__name__) else: for aname, ainfo in cls.attached_devices.items(): try: ainfo.check(None, aname, config.get(aname)) except ConfigurationError as err: self.log_error('%s: attached device %s (%s) is ' 'wrongly configured: %s' % (devname, aname, cls.__name__, err), extra=self.find_deventry(devname, aname)) if aname in config: del config[aname] # check missing and unsupported parameter config entries if not hasattr(cls, 'parameters'): self.log.warning("%s: class %r has no 'parameters'", devname, cls.__name__) else: if not (config.get('lowlevel', cls.parameters['lowlevel'].default) or issubclass(cls, DeviceAlias)): if not config.get('description') and not is_special: self.log.warning('%s: device has no description', devname, extra=self.find_deventry(devname)) for pname, pinfo in cls.parameters.items(): if pname in config: if pinfo.internal: self.log_error( "%s: '%s' is configured in a setup file although " "declared as internal parameter", devname, pname, extra=self.find_deventry(devname, pname)) del config[pname] continue try: pinfo.type(config[pname]) except (ValueError, TypeError) as e: self.log_error( '%s: parameter %r value %r is ' 'invalid: %s', devname, pname, config[pname], e, extra=self.find_deventry(devname, pname)) # check value of certain parameters self.check_parameter(devname, pname, config[pname]) del config[pname] elif pinfo.mandatory: self.log_error('%s: mandatory parameter %r missing', devname, pname, extra=self.find_deventry(devname)) if config: onepar = list(config)[0] self.log_error( '%s: configured parameters not accepted by the ' 'device class: %s', devname, ', '.join(config), extra=self.find_deventry(devname, onepar))