class ConsoleWidget_embed(RichJupyterWidget, ConsoleWidget): global fit def __init__(self, customBanner=None, *args, **kwargs): super(ConsoleWidget_embed, self).__init__(*args, **kwargs) if customBanner is not None: self.banner = customBanner #self.font_size = 4 self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel(show_banner=True) self.kernel_manager.kernel.gui = 'qt' self.kernel = self.kernel_manager.kernel self.kernel_client = self._kernel_manager.client() self.kernel_client.start_channels() def _abort_queues(kernel): pass self.kernel_manager.kernel._abort_queues = _abort_queues #self._execute("kernel = %s"%fit, False) def stop(): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() self.guisupport.get_app_qt().exit() self.exit_requested.connect(stop) def push_vars(self, variableDict): """ Given a dictionary containing name / value pairs, push those variables to the Jupyter console widget """ self.kernel_manager.kernel.shell.push(variableDict) def clear(self): """ Clears the terminal """ self._control.clear() # self.kernel_manager def print_text(self, text, before_prompt=True): """ Prints some plain text to the console """ self._append_plain_text(text, before_prompt=before_prompt) def execute_command(self, command): """ Execute a command in the frame of the console widget """ self._execute(command, False)
class JupyterWidget(RichJupyterWidget): def __init__(self): super().__init__() if 'asyncio' in sys.modules: self._init_asyncio_patch() self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() # Fix issue with Jupyter 5.0+, see https://github.com/ipython/ipykernel/pull/376 if hasattr(self.kernel_manager.kernel, '_abort_queue'): # noinspection PyProtectedMember self.kernel_manager.kernel._abort_queues = self.kernel_manager.kernel._abort_queue self.exit_requested.connect(self.stop) qApp.aboutToQuit.connect(self.stop) def _init_asyncio_patch(self): """set default asyncio policy to be compatible with tornado Tornado 6 (at least) is not compatible with the default asyncio implementation on Windows Pick the older SelectorEventLoopPolicy on Windows if the known-incompatible default policy is in use. do this as early as possible to make it a low priority and overrideable ref: https://github.com/tornadoweb/tornado/issues/2608 FIXME: if/when tornado supports the defaults in asyncio, remove and bump tornado requirement for py38 """ if sys.platform.startswith("win") and sys.version_info >= ( 3, 8) and tornado.version_info < (6, 1): import asyncio try: from asyncio import ( WindowsProactorEventLoopPolicy, WindowsSelectorEventLoopPolicy, ) except ImportError: pass # not affected else: if type(asyncio.get_event_loop_policy() ) is WindowsProactorEventLoopPolicy: # WindowsProactorEventLoopPolicy is not compatible with tornado 6 # fallback to the pre-3.8 default of Selector asyncio.set_event_loop_policy( WindowsSelectorEventLoopPolicy()) def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() def push(self, **kwargs): self.kernel_manager.kernel.shell.push(kwargs)
class IPythonPlugin(GUIPlugin): name = 'IPython' def __init__(self): # # Enforce global style within the console # with open('xicam/gui/style.stylesheet', 'r') as f: # style = f.read() # style = (qdarkstyle.load_stylesheet() + style) # Setup the kernel self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() kernel = self.kernel_manager.kernel kernel.gui = 'qt' # Push Xi-cam variables into the kernel kernel.shell.push({ plugin.name: plugin for plugin in pluginmanager.get_plugins_of_type("GUIPlugin") + pluginmanager.get_plugins_of_type("EZPlugin") }) # Observe plugin changes pluginmanager.attach(self.pluginsChanged) # Continue kernel setuppluginmanager.getPluginsOfCategory("GUIPlugin") self.kernel_client = self.kernel_manager.client() threads.invoke_in_main_thread(self.kernel_client.start_channels) # Setup console widget def stop(): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() control = RichJupyterWidget() control.kernel_manager = self.kernel_manager threads.invoke_in_main_thread(setattr, control, "kernel_client", self.kernel_client) control.exit_requested.connect(stop) # control.style_sheet = style control.syntax_style = u'monokai' control.set_default_style(colors='Linux') # Setup layout self.stages = {'Terminal': GUILayout(control)} # Save for later self.kernel = kernel super(IPythonPlugin, self).__init__() def pluginsChanged(self): self.kernel.shell.push({ plugin.name: plugin for plugin in pluginmanager.get_plugins_of_type("GUIPlugin") + pluginmanager.get_plugins_of_type("EZPlugin") })
class Ipython(object): def __init__(self, scripts_path=''): self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel sys.stdout = self.kernel.stdout sys.stderr = self.kernel.stderr self.scripts_path = scripts_path self.kernel.gui = 'qt4' self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.control = RichJupyterWidget() self.control.kernel_manager = self.kernel_manager self.control.kernel_client = self.kernel_client self.control.exit_requested.connect(self.stop) self.control.setWindowTitle("IPython shell") self.execute('import numpy as np') self.execute('from matplotlib import pyplot as plt') self.execute('%matplotlib') self.execute('') def __del__(self): self.stop() self.close() def show(self): self.control.show() self.control.setWindowState(self.control.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) self.control.activateWindow() def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() def close(self): self.control.close() def push(self, vardic): self.kernel.shell.push(vardic) def execute(self, cmd): self.control.execute(cmd) def run_script(self, scriptname): scriptpath = os.path.join(self.scripts_path, scriptname) return self.control.execute('run -i %s' % scriptpath)
class IPythonView(RichJupyterWidget): """A view with an IPython console living in the same Python process as the GUI.""" def __init__(self, *args, **kwargs): super(IPythonView, self).__init__(*args, **kwargs) def start_kernel(self): """Start the IPython kernel.""" logger.debug("Starting the kernel.") self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel(show_banner=False) self.kernel_manager.kernel.gui = 'qt' self.kernel = self.kernel_manager.kernel self.shell = self.kernel.shell self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.set_default_style('linux') self.exit_requested.connect(self.stop) def inject(self, **kwargs): """Inject variables into the IPython namespace.""" logger.debug("Injecting variables into the kernel: %s.", ', '.join(kwargs.keys())) self.kernel.shell.push(kwargs) def attach(self, gui, **kwargs): """Add the view to the GUI, start the kernel, and inject the specified variables.""" gui.add_view(self) self.start_kernel() self.inject(gui=gui, **kwargs) try: import numpy self.inject(np=numpy) except ImportError: # pragma: no cover pass try: import matplotlib.pyplot as plt self.inject(plt=plt) except ImportError: # pragma: no cover pass @connect def on_close_view(sender, view): if view == self: self.stop() def stop(self): """Stop the kernel.""" logger.debug("Stopping the kernel.") self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel()
class IPythonConsole: def __init__(self, layout, sim, gui): # Create an in-process kernel # >>> print_process_id() # will print the same process ID as the main process self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel.gui = 'qt4' self.kernel.shell.write("Welcome to AO Sim!") config = sim.config #Pass some useful objects to the user usefulObjects = { "sim": sim, "gui": gui, "config": config, "simConfig": sim.config.sim, "telConfig": sim.config.tel, "atmosConfig": sim.config.atmos } for i in range(sim.config.sim.nGS): usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i] for i in range(sim.config.sim.nDM): usefulObjects["dm{}Config".format(i)] = sim.config.dms[i] for i in range(sim.config.sim.nSci): usefulObjects["sci{}Config".format(i)] = sim.config.scis[i] self.kernel.shell.push(usefulObjects) #kernel.shell.push({'foo': 43, 'print_process_id': print_process_id}) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() control = RichIPythonWidget() control.kernel_manager = self.kernel_manager control.kernel_client = self.kernel_client control.exit_requested.connect(self.stop) layout.addWidget(control) self.kernel.shell.ex("") #control.show() #self.kernel.show def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() def write(self, message): self.kernel.shell.write(message) self.kernel.shell.ex("")
class ConsoleWidget(RichJupyterWidget): """ Convenience class for a live IPython console widget. We can replace the standard banner using the customBanner argument """ def __init__(self, customBanner=None, *args, **kwargs): RichJupyterWidget.__init__(self, *args, **kwargs) if customBanner is not None: self.banner = customBanner self.font_size = 6 self.gui_completion = 'droplist' self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel(show_banner=False) self.kernel_manager.kernel.gui = 'qt' self.kernel_client = kernel_client = self._kernel_manager.client() kernel_client.start_channels() def stop(): kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() # guisupport.get_app_qt().exit() self.exit_requested.connect(stop) def push_vars(self, variableDict): """ Given a dictionary containing name / value pairs, push those variables to the IPython console widget """ self.kernel_manager.kernel.shell.push(variableDict) def clear(self): """ Clears the terminal """ self._control.clear() # self.kernel_manager def print_text(self, text): """ Prints some plain text to the console """ self._append_plain_text(text) def execute_command(self, command): """ Execute a command in the frame of the console widget """ self._execute(command, False)
class IPythonConsole: def __init__(self, layout, sim, gui): # Create an in-process kernel # >>> print_process_id() # will print the same process ID as the main process self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel.gui = 'qt4' self.kernel.shell.write("Welcome to AO Sim!") config = sim.config #Pass some useful objects to the user usefulObjects = { "sim" : sim, "gui" : gui, "config" : config, "simConfig" : sim.config.sim, "telConfig" : sim.config.tel, "atmosConfig" : sim.config.atmos} for i in range(sim.config.sim.nGS): usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i] for i in range(sim.config.sim.nDM): usefulObjects["dm{}Config".format(i)] = sim.config.dms[i] for i in range(sim.config.sim.nSci): usefulObjects["sci{}Config".format(i)] = sim.config.scis[i] self.kernel.shell.push(usefulObjects) #kernel.shell.push({'foo': 43, 'print_process_id': print_process_id}) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() control = RichIPythonWidget() control.kernel_manager = self.kernel_manager control.kernel_client = self.kernel_client control.exit_requested.connect(self.stop) layout.addWidget(control) self.kernel.shell.ex("") #control.show() #self.kernel.show def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() def write(self,message): self.kernel.shell.write(message) self.kernel.shell.ex("")
class IPythonConsole: def __init__(self, layout, sim, gui): # Create an in-process kernel self.kernel_manager = QtInProcessKernelManager() # self.kernel_manager = QtKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel # self.kernel.shell.write("Welcome to AO Sim!\n") config = sim.config #Pass some useful objects to the user usefulObjects = { "sim": sim, "gui": gui, "config": config, "simConfig": sim.config.sim, "telConfig": sim.config.tel, "atmosConfig": sim.config.atmos, "np": numpy, "plt": pyplot } for i in range(sim.config.sim.nGS): usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i] for i in range(sim.config.sim.nDM): usefulObjects["dm{}Config".format(i)] = sim.config.dms[i] for i in range(sim.config.sim.nSci): usefulObjects["sci{}Config".format(i)] = sim.config.scis[i] self.kernel.shell.push(usefulObjects) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() control = RichIPythonWidget() control.kernel_manager = self.kernel_manager control.kernel_client = self.kernel_client control.exit_requested.connect(self.stop) layout.addWidget(control) # self.kernel.shell.ex("") def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() def write(self, message): pass
class ConsoleWidget(RichJupyterWidget): def __init__(self, *args, customBanner=None, myWidget=None, **kwargs): super(ConsoleWidget, self).__init__(*args, **kwargs) if customBanner is not None: self.banner = customBanner self.font_size = 6 self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel(show_banner=False) self.kernel_manager.kernel.gui = 'qt' self.kernel_client = self._kernel_manager.client() self.kernel_client.start_channels() def stop(): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() self.exit_requested.connect(stop) self.kernel_manager.kernel.shell.push({ 'widget': self, 'myWidget': myWidget }) def push_vars(self, variableDict): """ Given a dictionary containing name / value pairs, push those variables to the Jupyter console widget """ self.kernel_manager.kernel.shell.push(variableDict) def clear(self): """ Clears the terminal """ self._control.clear() # self.kernel_manager def print_text(self, text): """ Prints some plain text to the console """ self._append_plain_text(text) def execute_command(self, command): """ Execute a command in the frame of the console widget """ self._execute(command, False)
class IPythonConsole: def __init__(self, layout, sim, gui): # Create an in-process kernel self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel.shell.write("Welcome to AO Sim!\n") config = sim.config #Pass some useful objects to the user usefulObjects = { "sim" : sim, "gui" : gui, "config" : config, "simConfig" : sim.config.sim, "telConfig" : sim.config.tel, "atmosConfig" : sim.config.atmos, "np" : numpy, "plt" : pyplot} for i in range(sim.config.sim.nGS): usefulObjects["wfs{}Config".format(i)] = sim.config.wfss[i] for i in range(sim.config.sim.nDM): usefulObjects["dm{}Config".format(i)] = sim.config.dms[i] for i in range(sim.config.sim.nSci): usefulObjects["sci{}Config".format(i)] = sim.config.scis[i] self.kernel.shell.push(usefulObjects) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() control = RichIPythonWidget() control.kernel_manager = self.kernel_manager control.kernel_client = self.kernel_client control.exit_requested.connect(self.stop) layout.addWidget(control) self.kernel.shell.ex("") def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() def write(self,message): self.kernel.shell.write(message) self.kernel.shell.ex("")
class MainWindow(form_class, QtWidgets.QMainWindow): def __init__(self, *args): super(MainWindow, self).__init__(*args) self.setupUi(self) self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.jupiter_widget.kernel_manager = self.kernel_manager self.jupiter_widget.kernel_client = self.kernel_client self.jupiter_widget.reset() def set_location(self, source_file, line): lexer = pygments.lexers.CppLexer() formatter = pygments.formatters.HtmlFormatter( linenos="inline", linespans="line", hl_lines=[line]) css = formatter.get_style_defs('.highlight') with open(source_file) as f: tokens = lexer.get_tokens(f.read()) source = pygments.format(tokens, formatter) self.code_view.setHtml(code_template.format(css, source)) self.code_view.scrollToAnchor("line-%d" % max(0, line - 10)) def setup_ipython(self, app, window): """ Might break with future versions of IPython, but nobody got time for this! """ shell = self.kernel_client.kernel.shell shell.magic("clear") user_ns = shell.user_ns user_ns["app"] = app user_ns["window"] = self config = shell.config config.TerminalIPythonApp.display_banner = "" shell.register_magics(commands(shell, app, window)) def shutdown_kernel(self): print('Shutting down kernel...') self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel()
class NGSJupyterWidget(QtInProcessRichJupyterWidget): def __init__(self, gui,*args, **kwargs): import ngsolve super().__init__(*args,**kwargs) self.gui = gui self.banner = """NGSolve %s Developed by Joachim Schoeberl at 2010-xxxx Vienna University of Technology 2006-2010 RWTH Aachen University 1996-2006 Johannes Kepler University Linz """ % ngsolve.__version__ multikernel_manager = gui.multikernel_manager if multikernel_manager is not None: self.kernel_id = multikernel_manager.start_kernel() self.kernel_manager = multikernel_manager.get_kernel(self.kernel_id) else: self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_manager.kernel.gui = 'qt' self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() class dummyioloop(): def call_later(self,a,b): return def stop(self): return self.kernel_manager.kernel.io_loop = dummyioloop() def stop(): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() self.exit_requested.connect(stop) @inmain_decorator(wait_for_return=True) def pushVariables(self, varDict): self.kernel_manager.kernel.shell.push(varDict) @inmain_decorator(wait_for_return=True) def clearTerminal(self): self._control.clear()
class IPythonDebugger(RichJupyterWidget): def __init__(self, widget: QWidget): super(IPythonDebugger, self).__init__() # Setup the kernel self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() kernel = self.kernel_manager.kernel kernel.gui = "qt" # Push QWidget to the console kernel.shell.push({"widget": widget}) self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() # Setup console widget def stop(): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() self.exit_requested.connect(stop)
class QIPythonWidget(RichJupyterWidget): def __init__(self, parent=None, custom_banner=None, **kwargs): super(QIPythonWidget, self).__init__(parent=parent, **kwargs) self.plugin = parent if custom_banner is not None: self.banner = custom_banner self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_manager.kernel.gui = 'qt' self.kernel_client = self._kernel_manager.client() self.kernel_client.start_channels() def stop(): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() self.exit_requested.connect(stop) def push_variables(self, variableDict): """ Given a dictionary containing name / value pairs, push those variables to the IPython console widget """ self.kernel_manager.kernel.shell.push(variableDict) def clear_terminal(self): """ Clears the terminal """ self._control.clear() def print_text(self, text): """ Prints some plain text to the console """ self._append_plain_text(text, True) def execute_command(self, command): """ Execute a command in the frame of the console widget """ self._execute(command, False)
class ManagerGui(GUIBase): """This class provides a GUI to the Qudi manager. @signal sigStartAll: sent when all modules should be loaded @signal str str sigStartThis: load a specific module @signal str str sigReloadThis reload a specific module from Python code @signal str str sigStopThis: stop all actions of a module and remove references It supports module loading, reloading, logging and other administrative tasks. """ # status vars consoleFontSize = StatusVar('console_font_size', 10) # signals sigStartAll = QtCore.Signal() sigStartModule = QtCore.Signal(str, str) sigReloadModule = QtCore.Signal(str, str) sigCleanupStatus = QtCore.Signal(str, str) sigStopModule = QtCore.Signal(str, str) sigLoadConfig = QtCore.Signal(str, bool) sigSaveConfig = QtCore.Signal(str) sigRealQuit = QtCore.Signal() def __init__(self, **kwargs): """Create an instance of the module. @param object manager: @param str name: @param dict config: """ super().__init__(**kwargs) self.modlist = list() self.modules = set() def on_activate(self): """ Activation method called on change to active state. This method creates the Manager main window. """ if _has_pyqtgraph: # set background of pyqtgraph testwidget = QWidget() testwidget.ensurePolished() bgcolor = testwidget.palette().color(QPalette.Normal, testwidget.backgroundRole()) # set manually the background color in hex code according to our # color scheme: pg.setConfigOption('background', bgcolor) # opengl usage if 'useOpenGL' in self._manager.tree['global']: pg.setConfigOption('useOpenGL', self._manager.tree['global']['useOpenGL']) self._mw = ManagerMainWindow() self.restoreWindowPos(self._mw) self.errorDialog = ErrorDialog(self) self._about = AboutDialog() version = self.getSoftwareVersion() configFile = self._manager.configFile self._about.label.setText( '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"' ' style=\"color: cyan;\"> {0} </a>, on branch {1}.'.format( version[0], version[1])) self.versionLabel = QtWidgets.QLabel() self.versionLabel.setText( '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"' ' style=\"color: cyan;\"> {0} </a>,' ' on branch {1}, configured from {2}'.format( version[0], version[1], configFile)) self.versionLabel.setOpenExternalLinks(True) self._mw.statusBar().addWidget(self.versionLabel) # Connect up the buttons. self._mw.actionQuit.triggered.connect(self._manager.quit) self._mw.actionLoad_configuration.triggered.connect(self.getLoadFile) self._mw.actionReload_current_configuration.triggered.connect(self.reloadConfig) self._mw.actionSave_configuration.triggered.connect(self.getSaveFile) self._mw.action_Load_all_modules.triggered.connect(self._manager.startAllConfiguredModules) self._mw.actionAbout_Qt.triggered.connect(QtWidgets.QApplication.aboutQt) self._mw.actionAbout_Qudi.triggered.connect(self.showAboutQudi) self._mw.actionReset_to_default_layout.triggered.connect(self.resetToDefaultLayout) self._manager.sigShowManager.connect(self.show) self._manager.sigConfigChanged.connect(self.updateConfigWidgets) self._manager.sigModulesChanged.connect(self.updateConfigWidgets) self._manager.sigShutdownAcknowledge.connect(self.promptForShutdown) # Log widget self._mw.logwidget.setManager(self._manager) for loghandler in logging.getLogger().handlers: if isinstance(loghandler, core.logger.QtLogHandler): loghandler.sigLoggedMessage.connect(self.handleLogEntry) # Module widgets self.sigStartModule.connect(self._manager.startModule) self.sigReloadModule.connect(self._manager.restartModuleRecursive) self.sigCleanupStatus.connect(self._manager.removeStatusFile) self.sigStopModule.connect(self._manager.deactivateModule) self.sigLoadConfig.connect(self._manager.loadConfig) self.sigSaveConfig.connect(self._manager.saveConfig) self.sigRealQuit.connect(self._manager.realQuit) # Module state display self.checkTimer = QtCore.QTimer() self.checkTimer.start(1000) self.updateGUIModuleList() # IPython console widget self.startIPython() self.updateIPythonModuleList() self.startIPythonWidget() # thread widget self._mw.threadWidget.threadListView.setModel(self._manager.tm) # remote widget # hide remote menu item if rpyc is not available self._mw.actionRemoteView.setVisible(self._manager.rm is not None) if (self._manager.rm is not None): self._mw.remoteWidget.remoteModuleListView.setModel(self._manager.rm.remoteModules) if (self._manager.remote_server): self._mw.remoteWidget.hostLabel.setText('Server URL:') self._mw.remoteWidget.portLabel.setText( 'rpyc://{0}:{1}/'.format(self._manager.rm.server.host, self._manager.rm.server.port)) self._mw.remoteWidget.sharedModuleListView.setModel( self._manager.rm.sharedModules) else: self._mw.remoteWidget.hostLabel.setVisible(False) self._mw.remoteWidget.portLabel.setVisible(False) self._mw.remoteWidget.sharedModuleListView.setVisible(False) self._mw.configDisplayDockWidget.hide() self._mw.remoteDockWidget.hide() self._mw.threadDockWidget.hide() self._mw.show() def on_deactivate(self): """Close window and remove connections. """ self.stopIPythonWidget() self.stopIPython() self.checkTimer.stop() if len(self.modlist) > 0: self.checkTimer.timeout.disconnect() self.sigStartModule.disconnect() self.sigReloadModule.disconnect() self.sigStopModule.disconnect() self.sigLoadConfig.disconnect() self.sigSaveConfig.disconnect() self._mw.actionQuit.triggered.disconnect() self._mw.actionLoad_configuration.triggered.disconnect() self._mw.actionSave_configuration.triggered.disconnect() self._mw.action_Load_all_modules.triggered.disconnect() self._mw.actionAbout_Qt.triggered.disconnect() self._mw.actionAbout_Qudi.triggered.disconnect() self.saveWindowPos(self._mw) self._mw.close() def show(self): """Show the window and bring it t the top. """ QtWidgets.QMainWindow.show(self._mw) self._mw.activateWindow() self._mw.raise_() def showAboutQudi(self): """Show a dialog with details about Qudi. """ self._about.show() @QtCore.Slot(bool, bool) def promptForShutdown(self, locked, broken): """ Display a dialog, asking the user to confirm shutdown. """ text = "Some modules are locked right now, really quit?" result = QtWidgets.QMessageBox.question( self._mw, 'Qudi: Really Quit?', text, QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No ) if result == QtWidgets.QMessageBox.Yes: self.sigRealQuit.emit() def resetToDefaultLayout(self): """ Return the dockwidget layout and visibility to its default state """ self._mw.configDisplayDockWidget.setVisible(False) self._mw.consoleDockWidget.setVisible(True) self._mw.remoteDockWidget.setVisible(False) self._mw.threadDockWidget.setVisible(False) self._mw.logDockWidget.setVisible(True) self._mw.actionConfigurationView.setChecked(False) self._mw.actionConsoleView.setChecked(True) self._mw.actionRemoteView.setChecked(False) self._mw.actionThreadsView.setChecked(False) self._mw.actionLogView.setChecked(True) self._mw.configDisplayDockWidget.setFloating(False) self._mw.consoleDockWidget.setFloating(False) self._mw.remoteDockWidget.setFloating(False) self._mw.threadDockWidget.setFloating(False) self._mw.logDockWidget.setFloating(False) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.configDisplayDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(2), self._mw.consoleDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.remoteDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.threadDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.logDockWidget) def handleLogEntry(self, entry): """ Forward log entry to log widget and show an error popup if it is an error message. @param dict entry: Log entry """ self._mw.logwidget.addEntry(entry) if entry['level'] == 'error' or entry['level'] == 'critical': self.errorDialog.show(entry) def startIPython(self): """ Create an IPython kernel manager and kernel. Add modules to its namespace. """ # make sure we only log errors and above from ipython logging.getLogger('ipykernel').setLevel(logging.WARNING) self.log.debug('IPy activation in thread {0}'.format( QtCore.QThread.currentThreadId())) self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.namespace = self.kernel.shell.user_ns self.namespace.update({ 'np': np, 'config': self._manager.tree['defined'], 'manager': self._manager }) if _has_pyqtgraph: self.namespace['pg'] = pg self.updateIPythonModuleList() self.kernel.gui = 'qt4' self.log.info('IPython has kernel {0}'.format( self.kernel_manager.has_kernel)) self.log.info('IPython kernel alive {0}'.format( self.kernel_manager.is_alive())) self._manager.sigModulesChanged.connect(self.updateIPythonModuleList) def startIPythonWidget(self): """ Create an IPython console widget and connect it to an IPython kernel. """ if (_has_pyqtgraph): banner_modules = 'The numpy and pyqtgraph modules have already ' \ 'been imported as ''np'' and ''pg''.' else: banner_modules = 'The numpy module has already been imported ' \ 'as ''np''.' banner = """ This is an interactive IPython console. {0} Configuration is in 'config', the manager is 'manager' and all loaded modules are in this namespace with their configured name. View the current namespace with dir(). Go, play. """.format(banner_modules) self._mw.consolewidget.banner = banner # font size self.consoleSetFontSize(self.consoleFontSize) # settings self._csd = ConsoleSettingsDialog() self._csd.accepted.connect(self.consoleApplySettings) self._csd.rejected.connect(self.consoleKeepSettings) self._csd.buttonBox.button( QtWidgets.QDialogButtonBox.Apply).clicked.connect( self.consoleApplySettings) self._mw.actionConsoleSettings.triggered.connect(self._csd.exec_) self.consoleKeepSettings() self._mw.consolewidget.kernel_manager = self.kernel_manager self._mw.consolewidget.kernel_client = \ self._mw.consolewidget.kernel_manager.client() self._mw.consolewidget.kernel_client.start_channels() # the linux style theme which is basically the monokai theme self._mw.consolewidget.set_default_style(colors='linux') def stopIPython(self): """ Stop the IPython kernel. """ self.log.debug('IPy deactivation: {0}'.format(QtCore.QThread.currentThreadId())) self.kernel_manager.shutdown_kernel() def stopIPythonWidget(self): """ Disconnect the IPython widget from the kernel. """ self._mw.consolewidget.kernel_client.stop_channels() def updateIPythonModuleList(self): """Remove non-existing modules from namespace, add new modules to namespace, update reloaded modules """ currentModules = set() newNamespace = dict() for base in ['hardware', 'logic', 'gui']: for module in self._manager.tree['loaded'][base]: currentModules.add(module) newNamespace[module] = self._manager.tree[ 'loaded'][base][module] discard = self.modules - currentModules self.namespace.update(newNamespace) for module in discard: self.namespace.pop(module, None) self.modules = currentModules def consoleKeepSettings(self): """ Write old values into config dialog. """ self._csd.fontSizeBox.setProperty('value', self.consoleFontSize) def consoleApplySettings(self): """ Apply values from config dialog to console. """ self.consoleSetFontSize(self._csd.fontSizeBox.value()) def consoleSetFontSize(self, fontsize): self._mw.consolewidget.font_size = fontsize self.consoleFontSize = fontsize self._mw.consolewidget.reset_font() def updateConfigWidgets(self): """ Clear and refill the tree widget showing the configuration. """ self.fillTreeWidget(self._mw.treeWidget, self._manager.tree) def updateGUIModuleList(self): """ Clear and refill the module list widget """ # self.clearModuleList(self) self.fillModuleList(self._mw.guilayout, 'gui') self.fillModuleList(self._mw.logiclayout, 'logic') self.fillModuleList(self._mw.hwlayout, 'hardware') def fillModuleList(self, layout, base): """ Fill the module list widget with module widgets for defined gui modules. @param QLayout layout: layout of th module list widget where module widgest should be addad @param str base: module category to fill """ for module in self._manager.tree['defined'][base]: if module not in self._manager.tree['global']['startup']: widget = ModuleListItem(self._manager, base, module) self.modlist.append(widget) layout.addWidget(widget) widget.sigLoadThis.connect(self.sigStartModule) widget.sigReloadThis.connect(self.sigReloadModule) widget.sigDeactivateThis.connect(self.sigStopModule) widget.sigCleanupStatus.connect(self.sigCleanupStatus) self.checkTimer.timeout.connect(widget.checkModuleState) def fillTreeItem(self, item, value): """ Recursively fill a QTreeWidgeItem with the contents from a dictionary. @param QTreeWidgetItem item: the widget item to fill @param (dict, list, etc) value: value to fill in """ item.setExpanded(True) if type(value) is OrderedDict or type(value) is dict: for key in value: child = QtWidgets.QTreeWidgetItem() child.setText(0, key) item.addChild(child) self.fillTreeItem(child, value[key]) elif type(value) is list: for val in value: child = QtWidgets.QTreeWidgetItem() item.addChild(child) if type(val) is dict: child.setText(0, '[dict]') self.fillTreeItem(child, val) elif type(val) is OrderedDict: child.setText(0, '[odict]') self.fillTreeItem(child, val) elif type(val) is list: child.setText(0, '[list]') self.fillTreeItem(child, val) else: child.setText(0, str(val)) child.setExpanded(True) else: child = QtWidgets.QTreeWidgetItem() child.setText(0, str(value)) item.addChild(child) def getSoftwareVersion(self): """ Try to determine the software version in case the program is in a git repository. """ try: repo = Repo(get_main_dir()) branch = repo.active_branch rev = str(repo.head.commit) return (rev, str(branch)) except Exception as e: print('Could not get git repo because:', e) return ('unknown', -1) def fillTreeWidget(self, widget, value): """ Fill a QTreeWidget with the content of a dictionary @param QTreeWidget widget: the tree widget to fill @param dict,OrderedDict value: the dictionary to fill in """ widget.clear() self.fillTreeItem(widget.invisibleRootItem(), value) def reloadConfig(self): """ Reload the current config. """ reply = QtWidgets.QMessageBox.question( self._mw, 'Restart', 'Do you want to restart the current configuration?', QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No ) configFile = self._manager._getConfigFile() restart = (reply == QtWidgets.QMessageBox.Yes) self.sigLoadConfig.emit(configFile, restart) def getLoadFile(self): """ Ask the user for a file where the configuration should be loaded from """ defaultconfigpath = os.path.join(get_main_dir(), 'config') filename = QtWidgets.QFileDialog.getOpenFileName( self._mw, 'Load Configration', defaultconfigpath, 'Configuration files (*.cfg)')[0] if filename != '': reply = QtWidgets.QMessageBox.question( self._mw, 'Restart', 'Do you want to restart to use the configuration?', QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No ) restart = (reply == QtWidgets.QMessageBox.Yes) self.sigLoadConfig.emit(filename, restart) def getSaveFile(self): """ Ask the user for a file where the configuration should be saved to. """ defaultconfigpath = os.path.join(get_main_dir(), 'config') filename = QtWidgets.QFileDialog.getSaveFileName( self._mw, 'Save Configration', defaultconfigpath, 'Configuration files (*.cfg)')[0] if filename != '': self.sigSaveConfig.emit(filename)
class ManagerGui(GUIBase): """This class provides a GUI to the Qudi manager. @signal sigStartAll: sent when all modules should be loaded @signal str str sigStartThis: load a specific module @signal str str sigReloadThis reload a specific module from Python code @signal str str sigStopThis: stop all actions of a module and remove references It supports module loading, reloading, logging and other administrative tasks. """ sigStartAll = QtCore.Signal() sigStartModule = QtCore.Signal(str, str) sigReloadModule = QtCore.Signal(str, str) sigCleanupStatus = QtCore.Signal(str, str) sigStopModule = QtCore.Signal(str, str) sigLoadConfig = QtCore.Signal(str, bool) sigSaveConfig = QtCore.Signal(str) def __init__(self, **kwargs): """Create an instance of the module. @param object manager: @param str name: @param dict config: """ super().__init__(**kwargs) self.modlist = list() self.modules = set() def on_activate(self, e=None): """ Activation method called on change to active state. @param object e: Fysom.event object from Fysom class. An object created by the state machine module Fysom, which is connected to a specific event (have a look in the Base Class). This object contains the passed event, the state before the event happened and the destination of the state which should be reached after the event had happened. This method creates the Manager main window. """ if _has_pyqtgraph: # set background of pyqtgraph testwidget = QWidget() testwidget.ensurePolished() bgcolor = testwidget.palette().color(QPalette.Normal, testwidget.backgroundRole()) # set manually the background color in hex code according to our # color scheme: pg.setConfigOption('background', bgcolor) # opengl usage if 'useOpenGL' in self._manager.tree['global']: pg.setConfigOption('useOpenGL', self._manager.tree['global']['useOpenGL']) self._mw = ManagerMainWindow() self.restoreWindowPos(self._mw) self.errorDialog = ErrorDialog(self) self._about = AboutDialog() version = self.getSoftwareVersion() configFile = self._manager.configFile self._about.label.setText( '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"' ' style=\"color: cyan;\"> {0} </a>, on branch {1}.'.format( version[0], version[1])) self.versionLabel = QtWidgets.QLabel() self.versionLabel.setText( '<a href=\"https://github.com/Ulm-IQO/qudi/commit/{0}\"' ' style=\"color: cyan;\"> {0} </a>,' ' on branch {1}, configured from {2}'.format( version[0], version[1], configFile)) self.versionLabel.setOpenExternalLinks(True) self._mw.statusBar().addWidget(self.versionLabel) # Connect up the buttons. self._mw.actionQuit.triggered.connect(self._manager.quit) self._mw.actionLoad_configuration.triggered.connect(self.getLoadFile) self._mw.actionReload_current_configuration.triggered.connect(self.reloadConfig) self._mw.actionSave_configuration.triggered.connect(self.getSaveFile) self._mw.action_Load_all_modules.triggered.connect(self._manager.startAllConfiguredModules) self._mw.actionAbout_Qt.triggered.connect(QtWidgets.QApplication.aboutQt) self._mw.actionAbout_Qudi.triggered.connect(self.showAboutQudi) self._mw.actionReset_to_default_layout.triggered.connect(self.resetToDefaultLayout) self._manager.sigShowManager.connect(self.show) self._manager.sigConfigChanged.connect(self.updateConfigWidgets) self._manager.sigModulesChanged.connect(self.updateConfigWidgets) # Log widget self._mw.logwidget.setManager(self._manager) for loghandler in logging.getLogger().handlers: if isinstance(loghandler, core.logger.QtLogHandler): loghandler.sigLoggedMessage.connect(self.handleLogEntry) # Module widgets self.sigStartModule.connect(self._manager.startModule) self.sigReloadModule.connect(self._manager.restartModuleSimple) self.sigCleanupStatus.connect(self._manager.removeStatusFile) self.sigStopModule.connect(self._manager.deactivateModule) self.sigLoadConfig.connect(self._manager.loadConfig) self.sigSaveConfig.connect(self._manager.saveConfig) # Module state display self.checkTimer = QtCore.QTimer() self.checkTimer.start(1000) self.updateGUIModuleList() # IPython console widget self.startIPython() self.updateIPythonModuleList() self.startIPythonWidget() # thread widget self._mw.threadWidget.threadListView.setModel(self._manager.tm) # remote widget self._mw.remoteWidget.hostLabel.setText('URL:') self._mw.remoteWidget.portLabel.setText( 'rpyc://{0}:{1}/'.format(self._manager.rm.host, self._manager.rm.server.port)) self._mw.remoteWidget.remoteModuleListView.setModel( self._manager.rm.remoteModules) self._mw.remoteWidget.sharedModuleListView.setModel( self._manager.rm.sharedModules) self._mw.configDisplayDockWidget.hide() self._mw.remoteDockWidget.hide() self._mw.threadDockWidget.hide() self._mw.show() def on_deactivate(self, e): """Close window and remove connections. @param object e: Fysom.event object from Fysom class. A more detailed explanation can be found in the method activation. """ self.stopIPythonWidget() self.stopIPython() self.checkTimer.stop() if len(self.modlist) > 0: self.checkTimer.timeout.disconnect() self.sigStartModule.disconnect() self.sigReloadModule.disconnect() self.sigStopModule.disconnect() self.sigLoadConfig.disconnect() self.sigSaveConfig.disconnect() self._mw.actionQuit.triggered.disconnect() self._mw.actionLoad_configuration.triggered.disconnect() self._mw.actionSave_configuration.triggered.disconnect() self._mw.action_Load_all_modules.triggered.disconnect() self._mw.actionAbout_Qt.triggered.disconnect() self._mw.actionAbout_Qudi.triggered.disconnect() self.saveWindowPos(self._mw) self._mw.close() def show(self): """Show the window and bring it t the top. """ QtWidgets.QMainWindow.show(self._mw) self._mw.activateWindow() self._mw.raise_() def showAboutQudi(self): """Show a dialog with details about Qudi. """ self._about.show() def resetToDefaultLayout(self): """ Return the dockwidget layout and visibility to its default state """ self._mw.configDisplayDockWidget.setVisible(False) self._mw.consoleDockWidget.setVisible(True) self._mw.remoteDockWidget.setVisible(False) self._mw.threadDockWidget.setVisible(False) self._mw.logDockWidget.setVisible(True) self._mw.actionConfigurationView.setChecked(False) self._mw.actionConsoleView.setChecked(True) self._mw.actionRemoteView.setChecked(False) self._mw.actionThreadsView.setChecked(False) self._mw.actionLogView.setChecked(True) self._mw.configDisplayDockWidget.setFloating(False) self._mw.consoleDockWidget.setFloating(False) self._mw.remoteDockWidget.setFloating(False) self._mw.threadDockWidget.setFloating(False) self._mw.logDockWidget.setFloating(False) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.configDisplayDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(2), self._mw.consoleDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.remoteDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.threadDockWidget) self._mw.addDockWidget(QtCore.Qt.DockWidgetArea(8), self._mw.logDockWidget) def handleLogEntry(self, entry): """ Forward log entry to log widget and show an error popup if it is an error message. @param dict entry: Log entry """ self._mw.logwidget.addEntry(entry) if entry['level'] == 'error' or entry['level'] == 'critical': self.errorDialog.show(entry) def startIPython(self): """ Create an IPython kernel manager and kernel. Add modules to its namespace. """ # make sure we only log errors and above from ipython logging.getLogger('ipykernel').setLevel(logging.WARNING) self.log.debug('IPy activation in thread {0}'.format( QtCore.QThread.currentThreadId())) self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.namespace = self.kernel.shell.user_ns self.namespace.update({ 'np': np, 'config': self._manager.tree['defined'], 'manager': self._manager }) if _has_pyqtgraph: self.namespace['pg'] = pg self.updateIPythonModuleList() self.kernel.gui = 'qt4' self.log.info('IPython has kernel {0}'.format( self.kernel_manager.has_kernel)) self.log.info('IPython kernel alive {0}'.format( self.kernel_manager.is_alive())) self._manager.sigModulesChanged.connect(self.updateIPythonModuleList) def startIPythonWidget(self): """ Create an IPython console widget and connect it to an IPython kernel. """ if (_has_pyqtgraph): banner_modules = 'The numpy and pyqtgraph modules have already ' \ 'been imported as ''np'' and ''pg''.' else: banner_modules = 'The numpy module has already been imported ' \ 'as ''np''.' banner = """ This is an interactive IPython console. {0} Configuration is in 'config', the manager is 'manager' and all loaded modules are in this namespace with their configured name. View the current namespace with dir(). Go, play. """.format(banner_modules) self._mw.consolewidget.banner = banner # font size if 'console_font_size' in self._statusVariables: self.consoleSetFontSize(self._statusVariables['console_font_size']) # settings self._csd = ConsoleSettingsDialog() self._csd.accepted.connect(self.consoleApplySettings) self._csd.rejected.connect(self.consoleKeepSettings) self._csd.buttonBox.button( QtWidgets.QDialogButtonBox.Apply).clicked.connect( self.consoleApplySettings) self._mw.actionConsoleSettings.triggered.connect(self._csd.exec_) self.consoleKeepSettings() self._mw.consolewidget.kernel_manager = self.kernel_manager self._mw.consolewidget.kernel_client = \ self._mw.consolewidget.kernel_manager.client() self._mw.consolewidget.kernel_client.start_channels() # the linux style theme which is basically the monokai theme self._mw.consolewidget.set_default_style(colors='linux') def stopIPython(self): """ Stop the IPython kernel. """ self.log.debug('IPy deactivation: {0}'.format(QtCore.QThread.currentThreadId())) self.kernel_manager.shutdown_kernel() def stopIPythonWidget(self): """ Disconnect the IPython widget from the kernel. """ self._mw.consolewidget.kernel_client.stop_channels() def updateIPythonModuleList(self): """Remove non-existing modules from namespace, add new modules to namespace, update reloaded modules """ currentModules = set() newNamespace = dict() for base in ['hardware', 'logic', 'gui']: for module in self._manager.tree['loaded'][base]: currentModules.add(module) newNamespace[module] = self._manager.tree[ 'loaded'][base][module] discard = self.modules - currentModules self.namespace.update(newNamespace) for module in discard: self.namespace.pop(module, None) self.modules = currentModules def consoleKeepSettings(self): """ Write old values into config dialog. """ if 'console_font_size' in self._statusVariables: self._csd.fontSizeBox.setProperty( 'value', self._statusVariables['console_font_size']) else: self._csd.fontSizeBox.setProperty('value', 10) def consoleApplySettings(self): """ Apply values from config dialog to console. """ self.consoleSetFontSize(self._csd.fontSizeBox.value()) def consoleSetFontSize(self, fontsize): self._mw.consolewidget.font_size = fontsize self._statusVariables['console_font_size'] = fontsize self._mw.consolewidget.reset_font() def updateConfigWidgets(self): """ Clear and refill the tree widget showing the configuration. """ self.fillTreeWidget(self._mw.treeWidget, self._manager.tree) def updateGUIModuleList(self): """ Clear and refill the module list widget """ # self.clearModuleList(self) self.fillModuleList(self._mw.guilayout, 'gui') self.fillModuleList(self._mw.logiclayout, 'logic') self.fillModuleList(self._mw.hwlayout, 'hardware') def fillModuleList(self, layout, base): """ Fill the module list widget with module widgets for defined gui modules. @param QLayout layout: layout of th module list widget where module widgest should be addad @param str base: module category to fill """ for module in self._manager.tree['defined'][base]: if not module in self._manager.tree['global']['startup']: widget = ModuleListItem(self._manager, base, module) self.modlist.append(widget) layout.addWidget(widget) widget.sigLoadThis.connect(self.sigStartModule) widget.sigReloadThis.connect(self.sigReloadModule) widget.sigDeactivateThis.connect(self.sigStopModule) widget.sigCleanupStatus.connect(self.sigCleanupStatus) self.checkTimer.timeout.connect(widget.checkModuleState) def fillTreeItem(self, item, value): """ Recursively fill a QTreeWidgeItem with the contents from a dictionary. @param QTreeWidgetItem item: the widget item to fill @param (dict, list, etc) value: value to fill in """ item.setExpanded(True) if type(value) is OrderedDict or type(value) is dict: for key in value: child = QtWidgets.QTreeWidgetItem() child.setText(0, key) item.addChild(child) self.fillTreeItem(child, value[key]) elif type(value) is list: for val in value: child = QtWidgets.QTreeWidgetItem() item.addChild(child) if type(val) is dict: child.setText(0, '[dict]') self.fillTreeItem(child, val) elif type(val) is OrderedDict: child.setText(0, '[odict]') self.fillTreeItem(child, val) elif type(val) is list: child.setText(0, '[list]') self.fillTreeItem(child, val) else: child.setText(0, str(val)) child.setExpanded(True) else: child = QtWidgets.QTreeWidgetItem() child.setText(0, str(value)) item.addChild(child) def getSoftwareVersion(self): """ Try to determine the software version in case the program is in a git repository. """ try: repo = Repo(self.get_main_dir()) branch = repo.active_branch rev = str(repo.head.commit) return (rev, str(branch)) except Exception as e: print('Could not get git repo because:', e) return ('unknown', -1) def fillTreeWidget(self, widget, value): """ Fill a QTreeWidget with the content of a dictionary @param QTreeWidget widget: the tree widget to fill @param dict,OrderedDict value: the dictionary to fill in """ widget.clear() self.fillTreeItem(widget.invisibleRootItem(), value) def reloadConfig(self): """ Reload the current config. """ reply = QtWidgets.QMessageBox.question( self._mw, 'Restart', 'Do you want to restart the current configuration?', QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No ) configFile = self._manager._getConfigFile() restart = (reply == QtWidgets.QMessageBox.Yes) self.sigLoadConfig.emit(configFile, restart) def getLoadFile(self): """ Ask the user for a file where the configuration should be loaded from """ defaultconfigpath = os.path.join(self.get_main_dir(), 'config') filename = QtWidgets.QFileDialog.getOpenFileName( self._mw, 'Load Configration', defaultconfigpath, 'Configuration files (*.cfg)') if filename != '': reply = QtWidgets.QMessageBox.question( self._mw, 'Restart', 'Do you want to restart to use the configuration?', QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No ) restart = (reply == QtWidgets.QMessageBox.Yes) self.sigLoadConfig.emit(filename, restart) def getSaveFile(self): """ Ask the user for a file where the configuration should be saved to. """ defaultconfigpath = os.path.join(self.get_main_dir(), 'config') filename = QtWidgets.QFileDialog.getSaveFileName( self._mw, 'Save Configration', defaultconfigpath, 'Configuration files (*.cfg)') if filename != '': self.sigSaveConfig.emit(filename)
from qtconsole.inprocess import QtInProcessKernelManager from IPython import get_ipython # Check if there is an ipython shell shell = get_ipython() assert shell == None # Start in process kernel manager and client kernel_manager = QtInProcessKernelManager() kernel_manager.start_kernel(show_banner=False) kernel_manager.kernel.gui = 'qt' kernel_client = kernel_manager.client() kernel_client.start_channels() # Shutdown kernel manager and client kernel_client.stop_channels() kernel_manager.shutdown_kernel() # Check there is no longer an ipython shell shell = get_ipython() assert shell == None
class ConsoleWidget(QtGui.QWidget): createdPlot = QtCore.Signal(object) updatedVar = QtCore.Signal() def __init__(self, parent=None): super(ConsoleWidget, self).__init__() self.variable_list = get_variables() self.vbox = QtGui.QVBoxLayout() self.setLayout(self.vbox) self.kernel_manager = None self.kernel_client = None self.kernel = None self.jupyter_widget = None self.values = [] self.display_plots = [] self.shell_vars = {} self.gm_count = {} self.letters = list(string.ascii_uppercase) self.reserved_words = [ 'and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', 'or', 'with', 'assert', 'else', 'if', 'pass', 'yield', 'break', 'except', 'import', 'print', 'class', 'exec', 'in', 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for', 'lambda', 'try' ] # Create ipython widget self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.kernel_client.execute("import vcs, cdms2", silent=True) self.jupyter_widget = RichJupyterWidget() self.jupyter_widget.kernel_manager = self.kernel_manager self.jupyter_widget.kernel_client = self.kernel_client self.jupyter_widget.exit_requested.connect(self.stop) self.jupyter_widget.executed.connect(self.codeExecuted) self.original_ns = dict(self.kernel.shell.user_ns) # Push variableList variables self.variable_list.listUpdated.connect(self.updateVariables) self.updateVariables() self.vbox.addWidget(self.jupyter_widget) def clearShellVars(self): self.gm_count = {} for key, var_dict in self.shell_vars.items(): try: self.kernel.shell.user_ns.pop(self.shell_vars[key]['canvas']) except KeyError: pass try: self.kernel.shell.user_ns.pop(self.shell_vars[key]['gm']) except KeyError: pass try: self.kernel.shell.user_ns.pop(self.shell_vars[key]['template']) except KeyError: pass for var in self.values: self.values.remove(var) try: self.kernel.shell.user_ns.pop(var) except KeyError: pass def updateVariables(self, plot=None): for var in get_variables().values: if var[0] not in self.values: self.values.append(var[0]) self.kernel.shell.push({var[0]: var[1]}) if plot and plot.variables: for var in plot.variables: try: self.kernel.shell.push({var.id: var}) except AttributeError: pass def updateCanvases(self, plot): canvas_var_label = "canvas_{0}{1}".format(plot.row + 1, self.letters[plot.col]) self.shell_vars[plot]['canvas'] = canvas_var_label self.kernel.shell.push({canvas_var_label: plot.canvas}) def updateGMS(self, plot): if plot.graphics_method: gm = plot.graphics_method.name if gm[:2] == '__': gm_prefix = vcs.graphicsmethodtype(plot.graphics_method) gm_prefix = self.fixInvalidVariables(gm_prefix) if gm_prefix not in self.gm_count.keys(): self.gm_count[gm_prefix] = 1 else: self.gm_count[gm_prefix] += 1 gm = "{0}_{1}".format(gm_prefix, self.gm_count[gm_prefix]) else: gm = self.fixInvalidVariables(gm) if gm == 'default': "{0}_default".format( vcs.graphicsmethodtype(plot.graphics_method)) self.shell_vars[plot]['gm'] = gm self.kernel.shell.push({gm: plot.graphics_method}) def updateTemplates(self, plot): if plot.template: tmp = plot.template.name tmp = self.fixInvalidVariables(tmp) if tmp == 'default': tmp = 'temp_default' self.shell_vars[plot]['template'] = tmp self.kernel.shell.push({tmp: plot.template}) def updateAllPlots(self, plots): self.clearShellVars() for plot in plots: self.shell_vars[plot] = {'canvas': '', 'template': '', 'gm': ''} if plot.name() != "(Untitled)": self.updateVariables(plot) self.updateCanvases(plot) self.updateGMS(plot) self.updateTemplates(plot) else: self.updateVariables(plot) self.updateCanvases(plot) def codeExecuted(self, *varargs): namespace = self.kernel.shell.user_ns cur_keys = set(namespace) # get last output out_dict = namespace["Out"] if out_dict: last_line = out_dict[max(out_dict)] else: last_line = None for key in cur_keys - set(self.original_ns): if key[0] == "_": continue value = namespace[key] if isinstance(value, cdms2.dataset.CdmsFile): namespace[key] = FileMetadataWrapper(value) if is_cdms_var(value): cdms_var = value() cdms_var.id = key if not self.variable_list.variable_exists(cdms_var): self.variable_list.add_variable(cdms_var) else: self.variable_list.update_variable(cdms_var, key) self.updatedVar.emit() elif is_displayplot(value) and value not in self.display_plots: self.display_plots.append(value) self.createdPlot.emit(value) if is_displayplot(last_line) and last_line not in self.display_plots: self.display_plots.append(last_line) self.createdPlot.emit(last_line) def fixInvalidVariables(self, var): var = re.sub(' +', '_', var) var = re.sub("[^a-zA-Z0-9_]+", '', var) if var in self.reserved_words or not re.match("^[a-zA-Z_]", var): var = 'cdat_' + var return var def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() app.exit()
class ConsoleWidget(QtGui.QWidget): createdPlot = QtCore.Signal(object) updatedVar = QtCore.Signal() def __init__(self, parent=None): super(ConsoleWidget, self).__init__() self.variable_list = get_variables() self.vbox = QtGui.QVBoxLayout() self.setLayout(self.vbox) self.kernel_manager = None self.kernel_client = None self.kernel = None self.jupyter_widget = None self.values = [] self.display_plots = [] self.shell_vars = {} self.gm_count = {} self.letters = list(string.ascii_uppercase) self.reserved_words = ['and', 'del', 'from', 'not', 'while', 'as', 'elif', 'global', 'or', 'with', 'assert', 'else', 'if', 'pass', 'yield', 'break', 'except', 'import', 'print', 'class', 'exec', 'in', 'raise', 'continue', 'finally', 'is', 'return', 'def', 'for', 'lambda', 'try'] # Create ipython widget self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel = self.kernel_manager.kernel self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.kernel_client.execute("import vcs, cdms2", silent=True) self.jupyter_widget = RichJupyterWidget() self.jupyter_widget.kernel_manager = self.kernel_manager self.jupyter_widget.kernel_client = self.kernel_client self.jupyter_widget.exit_requested.connect(self.stop) self.jupyter_widget.executed.connect(self.codeExecuted) self.original_ns = dict(self.kernel.shell.user_ns) # Push variableList variables self.variable_list.listUpdated.connect(self.updateVariables) self.updateVariables() self.vbox.addWidget(self.jupyter_widget) def clearShellVars(self): self.gm_count = {} for key, var_dict in self.shell_vars.items(): try: self.kernel.shell.user_ns.pop(self.shell_vars[key]['canvas']) except KeyError: pass try: self.kernel.shell.user_ns.pop(self.shell_vars[key]['gm']) except KeyError: pass try: self.kernel.shell.user_ns.pop(self.shell_vars[key]['template']) except KeyError: pass for var in self.values: self.values.remove(var) try: self.kernel.shell.user_ns.pop(var) except KeyError: pass def updateVariables(self, plot=None): for var in get_variables().values: if var[0] not in self.values: self.values.append(var[0]) self.kernel.shell.push({var[0]: var[1]}) if plot and plot.variables: for var in plot.variables: try: self.kernel.shell.push({var.id: var}) except AttributeError: pass def updateCanvases(self, plot): canvas_var_label = "canvas_{0}{1}".format(plot.row + 1, self.letters[plot.col]) self.shell_vars[plot]['canvas'] = canvas_var_label self.kernel.shell.push({canvas_var_label: plot.canvas}) def updateGMS(self, plot): if plot.graphics_method: gm = plot.graphics_method.name if gm[:2] == '__': gm_prefix = vcs.graphicsmethodtype(plot.graphics_method) gm_prefix = self.fixInvalidVariables(gm_prefix) if gm_prefix not in self.gm_count.keys(): self.gm_count[gm_prefix] = 1 else: self.gm_count[gm_prefix] += 1 gm = "{0}_{1}".format(gm_prefix, self.gm_count[gm_prefix]) else: gm = self.fixInvalidVariables(gm) if gm == 'default': "{0}_default".format(vcs.graphicsmethodtype(plot.graphics_method)) self.shell_vars[plot]['gm'] = gm self.kernel.shell.push({gm: plot.graphics_method}) def updateTemplates(self, plot): if plot.template: tmp = plot.template.name tmp = self.fixInvalidVariables(tmp) if tmp == 'default': tmp = 'temp_default' self.shell_vars[plot]['template'] = tmp self.kernel.shell.push({tmp: plot.template}) def updateAllPlots(self, plots): self.clearShellVars() for plot in plots: self.shell_vars[plot] = {'canvas': '', 'template': '', 'gm': ''} if plot.name() != "(Untitled)": self.updateVariables(plot) self.updateCanvases(plot) self.updateGMS(plot) self.updateTemplates(plot) else: self.updateVariables(plot) self.updateCanvases(plot) def codeExecuted(self, *varargs): namespace = self.kernel.shell.user_ns cur_keys = set(namespace) # get last output out_dict = namespace["Out"] if out_dict: last_line = out_dict[max(out_dict)] else: last_line = None for key in cur_keys - set(self.original_ns): if key[0] == "_": continue value = namespace[key] if isinstance(value, cdms2.dataset.CdmsFile): namespace[key] = FileMetadataWrapper(value) if is_cdms_var(value): cdms_var = value() cdms_var.id = key if not self.variable_list.variable_exists(cdms_var): self.variable_list.add_variable(cdms_var) else: self.variable_list.update_variable(cdms_var, key) self.updatedVar.emit() elif is_displayplot(value) and value not in self.display_plots: self.display_plots.append(value) self.createdPlot.emit(value) if is_displayplot(last_line) and last_line not in self.display_plots: self.display_plots.append(last_line) self.createdPlot.emit(last_line) def fixInvalidVariables(self, var): var = re.sub(' +', '_', var) var = re.sub("[^a-zA-Z0-9_]+", '', var) if var in self.reserved_words or not re.match("^[a-zA-Z_]", var): var = 'cdat_' + var return var def stop(self): self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() app.exit()
class QIPythonWidget(RichJupyterWidget): def __init__(self, customBanner=None, colors='lightbg', baseimport=None, *args, **kwargs): """Convenience class for a live IPython console widget. Adapted from the pyQT example Attributes: banner (str): banner on top of the console kernel_client (kernel_manager.client): client for the kernel kernel_manager (QtInProcessKernelManager): kernel manager Args: customBanner (str, optional): Custom banner colors (str, optional): Colorschem for the console: lightbg,linux,nocolor *args: Description **kwargs: Description """ super(QIPythonWidget, self).__init__(*args, **kwargs) if not customBanner is None: self.banner = customBanner # create an Inprocess kernel self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_manager.kernel.gui = 'qt4' self.kernel_client = self._kernel_manager.client() self.kernel_client.start_channels() # set the colorscheme self.set_default_style(colors=colors) # exectute the base import if baseimport is not None: if os.path.isfile(baseimport): with open(baseimport, 'r') as f: cmd = f.readlines() cmd = ''.join(cmd) try: self._execute(cmd, False) except: self.printText('Import of %s failed' % baseimport) self.exit_requested.connect(self.stop) def pushVariables(self, variableDict): """ Given a dictionary containing name / value pairs, push those variables to the IPython console widget Args: variableDict: dict of var {names: value} """ self.kernel_manager.kernel.shell.push(variableDict) def clearTerminal(self): """ Clears the terminal """ self._control.clear() def printText(self, text): """ Prints some plain text to the console. Args: text (str): text to be printed """ self._append_plain_text(text) def executeCommand(self, command, hidden=False, interactive=False): """Execute a command in the frame of the console widget Args: command (str): Command to execute hidden (bool, optional): hid the command or not interactive (bool, optional): Interactive Mode """ self.execute(source=command, hidden=hidden, interactive=interactive) def import_value(self, HDF5Object): """Import the value of a HDF5 object Args: HDF5Object (HDF5 item): Instance of a HDF5 item """ HDF5Object.emitDict.connect(self.get_value) @pyqtSlot(dict) def get_value(self, variableDict): """Get the dict of variables emmitted by the treeview. Note: if the name of variable starts with _ the value is NOT printed in the console. Args: variableDict (dict): dict of variables {name: value} """ # exectute a command keys = list(variableDict.keys()) if keys[0].startswith('exec_cmd'): for k, cmd in variableDict.items(): self._execute(cmd, False) # push a variable in the console # print it if the name doesnt start with _ else: self.pushVariables(variableDict) for k in variableDict: if not k.startswith('_'): self.executeCommand('%s' % k) def stop(): """Stop the kernel.""" self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel() guisupport.get_app_qt4().exit()
class MainWindow(form_class, QtWidgets.QMainWindow): def __init__(self, *args): super(MainWindow, self).__init__(*args) self.setupUi(self) self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.jupiter_widget.kernel_manager = self.kernel_manager self.jupiter_widget.kernel_client = self.kernel_client self.jupiter_widget.reset() self.reg_view.setColumnCount(2) self.reg_view.setHorizontalHeaderLabels(['Name', 'Value']) self.var_view.setColumnCount(4) self.var_view.setHorizontalHeaderLabels( ['Name', 'Type', 'Address', 'Value']) # NOTE: icons are from Google Material Design self.up_button.setIcon( QIcon(str(APP_ROOT.join('frontend/icon/up.png')))) self.up_button.setIconSize(QSize(15, 15)) self.up_button.clicked.connect(self.push_up) self.up_button.setEnabled(False) self.upto_button.setIcon( QIcon(str(APP_ROOT.join('frontend/icon/upto.png')))) self.upto_button.setIconSize(QSize(15, 15)) self.upto_button.clicked.connect(self.push_upto) self.upto_button.setEnabled(False) self.down_button.setIcon( QIcon(str(APP_ROOT.join('frontend/icon/down.png')))) self.down_button.setIconSize(QSize(15, 15)) self.down_button.clicked.connect(self.push_down) self.down_button.setEnabled(False) self.downto_button.setIcon( QIcon(str(APP_ROOT.join('frontend/icon/downto.png')))) self.downto_button.setIconSize(QSize(15, 15)) self.downto_button.clicked.connect(self.push_downto) self.downto_button.setEnabled(False) self.cg_button.clicked.connect(self.push_callgraph) self.cg_button.setEnabled(False) self.info_button.clicked.connect(self.push_info) self.info_button.setEnabled(False) self.switch_button.clicked.connect(self.push_switch) self.switch_button.setEnabled(False) self.time_slider.setEnabled(False) self.file_cache = {} self.file_read_cache = {} self.callgraph = CallGraphManager() self.coredump_constraints = [] def cache_coredump_constraints(self): user_ns = self.kernel_client.kernel.shell.user_ns tracer = user_ns['tracer'] start_state = tracer.start_state active_state = self.states.major_states[-1] coredump = user_ns['coredump'] low = active_state.simstate.regs.rsp MAX_FUNC_FRAME = 0x200 high = start_state.regs.rsp + MAX_FUNC_FRAME try: low_v = active_state.simstate.se.eval(low) except: # very large range low_v = coredump.stack.start try: high_v = start_state.se.eval(high) except: high_v = coredump.stack.stop for addr in range(low_v, high_v): value = active_state.simstate.memory.load(addr, 1, endness='Iend_LE') if value.variables == frozenset(): continue cmem = coredump.stack[addr] self.coredump_constraints.append(value == cmem) def eval_variable(self, active_state, loc, addr, size): # type: (Any, int, Any, int) -> Tuple[str, str] # NOTE: * -> uninitialized / 'E' -> symbolic if not getattr(active_state, 'had_coredump_constraints', False): for c in self.coredump_constraints: old_solver = active_state.simstate.solver._solver.branch() active_state.simstate.se.add(c) if not active_state.simstate.se.satisfiable(): print('Unsatisfiable coredump constraints: ' + str(c)) active_state.simstate.solver._stored_solver = old_solver active_state.had_coredump_constraints = True if loc == 1: mem = active_state.simstate.memory.load(addr, size, endness='Iend_LE') elif loc == 2: mem = getattr(active_state.simstate.regs, addr) elif loc == -1: return 'optimized', 'unknown' else: return 'gdb error', 'unknown' if mem.uninitialized and mem.variables != frozenset() and loc == 1: result = '' for i in range(size): value = active_state.simstate.memory.load(addr + i, 1, endness='Iend_LE') if value.uninitialized: result += '** ' continue try: v = hex(active_state.simstate.se.eval(value))[2:] if len(v) == 1: v = '0' + v except: v = 'Er' result += v + ' ' result = result[:-1] return result, 'array' else: v = self.eval_value(active_state, mem) if v == 'uninitialized' or v == 'symbolic': return v, 'unknown' return v, 'hex' def eval_value(self, active_state, value): # type: (Any, Any) -> str if value.uninitialized: return 'uninitialized' try: v = hex(active_state.simstate.se.eval(value)) except: v = 'symbolic' return v def update_active(self, new_active): # type: (Any) -> None user_ns = self.kernel_client.kernel.shell.user_ns user_ns['active_state'] = new_active user_ns['gdbs'].active_state = new_active # NOTE: gdb c for every operation is slow # user_ns['gdbs'].update_active() addr = new_active.address() self.set_location(*self.addr_map[addr]) def update_active_index(self, active_index): # type: (int) -> None new_state, is_new = self.states[active_index] user_ns = self.kernel_client.kernel.shell.user_ns if is_new: self.callgraph.add_node(new_state, user_ns['tracer']) major_index = self.states.major_index if active_index in major_index: slider_index = len(major_index) - major_index.index( active_index) - 1 self.time_slider.setValue(slider_index) self.update_active(new_state) def push_upto(self): # type: () -> None v = self.time_slider.value() self.time_slider.setValue(min(self.time_slider.maximum(), v + 1)) self.slider_change() def push_downto(self): # type: () -> None v = self.time_slider.value() self.time_slider.setValue(max(self.time_slider.minimum(), v - 1)) self.slider_change() def push_up(self): # type: () -> None user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns['active_state'] state_index = max(0, active_state.index - 1) self.update_active_index(state_index) def push_down(self): # type: () -> None user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns['active_state'] tracer = user_ns['tracer'] state_index = min(len(tracer.trace) - 1, active_state.index + 1) self.update_active_index(state_index) def push_callgraph(self): # type: () -> None self.view = CallGraphView(self.callgraph, self) def push_info(self): # type: () -> None user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns['active_state'] self.set_regs() user_ns['gdbs'].update_active() if self.addr_map[active_state.address()][0] != '??': user_ns['gdbs'].write_request('bt') self.set_variable() else: print("Cannot retrieve variables on unresolvable source code") def push_switch(self): # type: () -> None user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns['active_state'] active_state.is_to_simstate = not active_state.is_to_simstate self.update_active(active_state) def slider_change(self): # type: () -> None v = self.time_slider.value() new_active = self.states.get_major(-(v + 1)) self.update_active(new_active) def set_slider(self, addr_map, states): # type: (List[Union[str, int]], Any) -> None # NOTE: slider is for major states self.addr_map = addr_map self.states = states self.time_slider.setEnabled(True) self.time_slider.setMinimum(0) self.time_slider.setMaximum(states.len_major - 1) self.time_slider.setTickPosition(QtWidgets.QSlider.TicksLeft) self.time_slider.setTickInterval(states.len_major - 1) self.time_slider.setValue(0) self.time_slider.valueChanged.connect(self.slider_change) def set_location(self, source_file, line): # type: (str, int) -> None shell = self.kernel_client.kernel.shell user_ns = shell.user_ns active_state = user_ns['active_state'] insns = active_state.simstate.block().capstone.insns # fmt = QTextCharFormat() # fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline) if source_file != '??': css, source = self.file_cache[source_file][line] if css: self.code_view.setHtml( code_template.format(css, source.encode('utf-8'))) cursor = self.code_view.textCursor() cursor.movePosition(QTextCursor.Start) minl = max(0, line - 30) if self.file_read_cache[source_file][2]: cursor.movePosition(QTextCursor.Down, n=line - minl - 1) else: cursor.movePosition(QTextCursor.Down, n=line - 1) cursor.movePosition(QTextCursor.EndOfLine) cursor.insertText('\t' + str(insns[0])) if not self.file_read_cache[source_file][2]: self.code_view.scrollToAnchor("line-%d" % max(0, line - 10)) else: self.code_view.scrollToAnchor("line-%d" % max(0, line - minl - 10)) else: self.code_view.clear() self.code_view.append("{}:{}".format(source_file, line)) else: self.code_view.clear() self.code_view.append("Unresolved source code") for insn in insns: self.code_view.append('\t' + str(insn)) def set_variable(self): # type: () -> None shell = self.kernel_client.kernel.shell user_ns = shell.user_ns var = user_ns['gdbs'].read_variables() self.var_view.setRowCount(0) i = 0 for v in var: if v['loc'] != -2: self.var_view.insertRow(i) value, value_type = self.eval_variable(user_ns['active_state'], v['loc'], v['addr'], v['size']) self.var_view.set_var(i, v, value, value_type) i += 1 self.var_view.resizeColumnsToContents() def set_regs(self): # type: () -> None def fix_new_regname(rname): # HACK: angr has no access to register like r9w, r8d, r15b for i in range(8, 16): if 'r' + str(i) in rname: return 'r' + str(i) return rname shell = self.kernel_client.kernel.shell user_ns = shell.user_ns active_state = user_ns['active_state'] insns = active_state.simstate.block().capstone.insns insn = insns[0].insn self.reg_view.setRowCount(0) for op in insn.operands: # OP_REG if op.type == 1: rname = insn.reg_name(op.value.reg) rname = fix_new_regname(rname) value = self.eval_value( active_state, getattr(active_state.simstate.regs, rname)) self.reg_view.append_reg(rname, value) # OP_MEM elif op.type == 3: if op.value.mem.base: rname = insn.reg_name(op.value.mem.base) rname = fix_new_regname(rname) value = self.eval_value( active_state, getattr(active_state.simstate.regs, rname)) self.reg_view.append_reg(rname, value) if op.value.mem.index: rname = insn.reg_name(op.value.mem.index) rname = fix_new_regname(rname) value = self.eval_value( active_state, getattr(active_state.simstate.regs, rname)) self.reg_view.append_reg(rname, value) self.reg_view.resizeColumnsToContents() def setup_ipython(self, app, window): # type: (QtWidgets.QApplication, MainWindow) -> None """ Might break with future versions of IPython, but nobody got time for this! """ shell = self.kernel_client.kernel.shell shell.magic("clear") user_ns = shell.user_ns user_ns["app"] = app user_ns["window"] = self config = shell.config config.TerminalIPythonApp.display_banner = "" from . import ipython_extension shell.extension_manager.load_extension(ipython_extension.__name__) def cache_tokens(self, addr_map): for filename, line in addr_map.values(): l.warning('caching file: ' + str(filename) + ' at line: ' + str(line)) if filename != '??': if filename not in self.file_read_cache.keys(): self.file_cache[filename] = {} self.file_read_cache[filename] = {} try: lexer = pygments.lexers.get_lexer_for_filename( str(filename)) formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs('.highlight') with open(str(filename)) as f: content = f.readlines() if len(content) < 1000: content = ''.join(content) tokens = lexer.get_tokens(content) source = pygments.format(tokens, html_formatter) self.file_cache[filename][line] = (css, source) self.file_read_cache[filename] = (lexer, content, False) else: minl = max(0, line - 30) maxl = min(len(content), line + 30) formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs('.highlight') source = pygments.format( lexer.get_tokens(''.join(content[minl:maxl])), html_formatter) self.file_cache[filename][line] = (css, source) self.file_read_cache[filename] = (lexer, content, True) except Exception as e: print(e) self.file_cache[filename][line] = (None, None) self.file_read_cache[filename] = (None, None, False) else: lexer, content, is_largefile = self.file_read_cache[ filename] if content: try: if not is_largefile: formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs( '.highlight') source = pygments.format( lexer.get_tokens(content), html_formatter) self.file_cache[filename][line] = (css, source) else: minl = max(0, line - 30) maxl = min(len(content), line + 30) formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line - minl]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs( '.highlight') source = pygments.format( lexer.get_tokens(''.join( content[minl:maxl])), html_formatter) self.file_cache[filename][line] = (css, source) except Exception as e: print(e) self.file_cache[filename][line] = (None, None) else: self.file_cache[filename][line] = (None, None) def add_states(self, states, tracer): # type: (Any, Any) -> None for s in states.major_states[1:]: self.callgraph.add_node(s, tracer) def clear_viewer(self): # type: () -> None self.code_view.clear() def append_archive(self): # type: () -> None files = DEFAULT_LOG_DIR.listdir() files.sort() self.code_view.append("\nAvailable files:") for f in files: if str(f.basename()).endswith(".tar.gz"): self.code_view.append(str(f.basename())) def enable_buttons(self): # type: () -> None # TODO: maintain a button list self.up_button.setEnabled(True) self.upto_button.setEnabled(True) self.down_button.setEnabled(True) self.downto_button.setEnabled(True) self.cg_button.setEnabled(True) self.info_button.setEnabled(True) self.switch_button.setEnabled(True) def clear_cache(self): self.file_cache = {} self.coredump_constraints = [] self.callgraph.clear_cache() def shutdown_kernel(self): # type: () -> None print('Shutting down kernel...') self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel()
class MainWindow(form_class, QtWidgets.QMainWindow): def __init__(self, *args: Any) -> None: super(MainWindow, self).__init__(*args) self.setupUi(self) self.kernel_manager = QtInProcessKernelManager() self.kernel_manager.start_kernel() self.kernel_client = self.kernel_manager.client() self.kernel_client.start_channels() self.jupiter_widget.kernel_manager = self.kernel_manager self.jupiter_widget.kernel_client = self.kernel_client self.jupiter_widget.reset() self.reg_view.setColumnCount(2) self.reg_view.setHorizontalHeaderLabels(["Name", "Value"]) self.var_view.setColumnCount(4) self.var_view.setHorizontalHeaderLabels( ["Name", "Type", "Address", "Value"]) # NOTE: icons are from Google Material Design self.up_button.setIcon( QIcon(str(APP_ROOT.joinpath("frontend/icon/up.png")))) self.up_button.setIconSize(QSize(15, 15)) self.up_button.clicked.connect(self.push_up) self.up_button.setEnabled(False) self.upto_button.setIcon( QIcon(str(APP_ROOT.joinpath("frontend/icon/upto.png")))) self.upto_button.setIconSize(QSize(15, 15)) self.upto_button.clicked.connect(self.push_upto) self.upto_button.setEnabled(False) self.down_button.setIcon( QIcon(str(APP_ROOT.joinpath("frontend/icon/down.png")))) self.down_button.setIconSize(QSize(15, 15)) self.down_button.clicked.connect(self.push_down) self.down_button.setEnabled(False) self.downto_button.setIcon( QIcon(str(APP_ROOT.joinpath("frontend/icon/downto.png")))) self.downto_button.setIconSize(QSize(15, 15)) self.downto_button.clicked.connect(self.push_downto) self.downto_button.setEnabled(False) self.cg_button.clicked.connect(self.push_callgraph) self.cg_button.setEnabled(False) self.info_button.clicked.connect(self.push_info) self.info_button.setEnabled(False) self.switch_button.clicked.connect(self.push_switch) self.switch_button.setEnabled(False) self.time_slider.setEnabled(False) self.file_cache = ( DefaultDict(dict) ) # type: DefaultDict[str, Dict[int, Tuple[Optional[str], Optional[str]]]] self.file_read_cache = ( {} ) # type: Dict[str, Tuple[Optional[RegexLexer], Optional[Union[str, List[str]]], bool]] # self.callgraph = CallGraphManager() self.coredump_constraints = [] # type:List[claripy.ast.bool.Bool] def cache_coredump_constraints(self) -> None: user_ns = self.kernel_client.kernel.shell.user_ns tracer = user_ns["tracer"] start_state = tracer.start_state active_state = self.states.major_states[-1] coredump = user_ns["coredump"] low = active_state.simstate.regs.rsp MAX_FUNC_FRAME = 0x200 high = start_state.regs.rsp + MAX_FUNC_FRAME try: low_v = active_state.simstate.solver.eval(low) except Exception: # very large range low_v = coredump.stack.start try: high_v = start_state.solver.eval(high) except Exception: high_v = coredump.stack.stop for addr in range(low_v, high_v): value = active_state.simstate.memory.load(addr, 1, endness="Iend_LE") if value.variables == frozenset(): continue cmem = coredump.stack[addr] self.coredump_constraints.append(value == cmem) def eval_variable(self, active_state: State, loc: int, addr: Any, size: int) -> Tuple[str, str]: # NOTE: * -> uninitialized / 'E' -> symbolic if not active_state.had_coredump_constraints: for c in self.coredump_constraints: old_solver = active_state.simstate.solver._solver.branch() active_state.simstate.solver.add(c) if not active_state.simstate.solver.satisfiable(): print("Unsatisfiable coredump constraints: {}".format(c)) active_state.simstate.solver._stored_solver = old_solver active_state.had_coredump_constraints = True if loc == 1: mem = active_state.simstate.memory.load(addr, size, endness="Iend_LE") elif loc == 2: mem = getattr(active_state.simstate.regs, addr) elif loc == -1: return "optimized", "unknown" else: return "gdb error", "unknown" if mem.uninitialized and mem.variables != frozenset() and loc == 1: result = "" for i in range(size): value = active_state.simstate.memory.load(addr + i, 1, endness="Iend_LE") if value.uninitialized: result += "** " continue try: v = hex(active_state.simstate.solver.eval(value))[2:] if len(v) == 1: v = "0" + v except Exception: v = "Er" result += v + " " result = result[:-1] return result, "array" else: v = self.eval_value(active_state, mem) if v == "uninitialized" or v == "symbolic": return v, "unknown" return v, "hex" def eval_value(self, active_state: State, value: Any) -> str: if value.uninitialized: return "uninitialized" try: v = hex(active_state.simstate.solver.eval(value)) except Exception: v = "symbolic" return v def update_active(self, new_active: State) -> None: user_ns = self.kernel_client.kernel.shell.user_ns user_ns["active_state"] = new_active user_ns["gdbs"].active_state = new_active # NOTE: gdb c for every operation is slow # user_ns['gdbs'].update_active() addr = new_active.address() source_file, line = self.addr_map[addr] self.set_location(source_file, line) def update_active_index(self, active_index: int) -> None: new_state, is_new = self.states[active_index] # user_ns = self.kernel_client.kernel.shell.user_ns if is_new: # self.callgraph.add_node(new_state, user_ns['tracer']) pass major_index = self.states.major_index if active_index in major_index: slider_index = len(major_index) - major_index.index( active_index) - 1 self.time_slider.setValue(slider_index) self.update_active(new_state) def push_upto(self) -> None: v = self.time_slider.value() self.time_slider.setValue(min(self.time_slider.maximum(), v + 1)) self.slider_change() def push_downto(self) -> None: v = self.time_slider.value() self.time_slider.setValue(max(self.time_slider.minimum(), v - 1)) self.slider_change() def push_up(self) -> None: user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns["active_state"] state_index = max(0, active_state.index - 1) self.update_active_index(state_index) def push_down(self) -> None: user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns["active_state"] tracer = user_ns["tracer"] state_index = min(len(tracer.trace) - 1, active_state.index + 1) self.update_active_index(state_index) def push_callgraph(self) -> None: pass # self.view = CallGraphView(self.callgraph, self) def push_info(self) -> None: user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns["active_state"] self.set_regs() user_ns["gdbs"].update_active() if self.addr_map[active_state.address()][0] != "??": user_ns["gdbs"].write_request("bt") self.set_variable() else: print("Cannot retrieve variables on unresolvable source code") def push_switch(self) -> None: user_ns = self.kernel_client.kernel.shell.user_ns active_state = user_ns["active_state"] active_state.is_to_simstate = not active_state.is_to_simstate self.update_active(active_state) def slider_change(self) -> None: v = self.time_slider.value() new_active = self.states.get_major(-(v + 1)) self.update_active(new_active) def set_slider(self, addr_map: List[Tuple[str, int]], states: StateManager) -> None: # NOTE: slider is for major states self.addr_map = addr_map self.states = states self.time_slider.setEnabled(True) self.time_slider.setMinimum(0) self.time_slider.setMaximum(states.len_major - 1) self.time_slider.setTickPosition(QtWidgets.QSlider.TicksLeft) self.time_slider.setTickInterval(states.len_major - 1) self.time_slider.setValue(0) self.time_slider.valueChanged.connect(self.slider_change) def set_location(self, source_file: str, line: int) -> None: shell = self.kernel_client.kernel.shell user_ns = shell.user_ns active_state = user_ns["active_state"] insns = active_state.simstate.block().capstone.insns # fmt = QTextCharFormat() # fmt.setUnderlineStyle(QTextCharFormat.SingleUnderline) if source_file != "??": css, source = self.file_cache[source_file][line] if css and source: self.code_view.setHtml(code_template.format(css, source)) cursor = self.code_view.textCursor() cursor.movePosition(QTextCursor.Start) minl = max(0, line - 30) if self.file_read_cache[source_file][2]: cursor.movePosition(QTextCursor.Down, n=line - minl - 1) else: cursor.movePosition(QTextCursor.Down, n=line - 1) cursor.movePosition(QTextCursor.EndOfLine) cursor.insertText("\t" + str(insns[0])) if not self.file_read_cache[source_file][2]: self.code_view.scrollToAnchor("line-%d" % max(0, line - 10)) else: self.code_view.scrollToAnchor("line-%d" % max(0, line - minl - 10)) else: self.code_view.clear() self.code_view.append("{}:{}".format(source_file, line)) else: self.code_view.clear() self.code_view.append("Unresolved source code") for insn in insns: self.code_view.append("\t" + str(insn)) def set_variable(self) -> None: shell = self.kernel_client.kernel.shell user_ns = shell.user_ns var = user_ns["gdbs"].read_variables() self.var_view.setRowCount(0) i = 0 for v in var: if v["loc"] != -2: self.var_view.insertRow(i) value, value_type = self.eval_variable(user_ns["active_state"], v["loc"], v["addr"], v["size"]) self.var_view.set_var(i, v, value, value_type) i += 1 self.var_view.resizeColumnsToContents() def set_regs(self) -> None: def fix_new_regname(rname: str) -> str: # HACK: angr has no access to register like r9w, r8d, r15b for i in range(8, 16): if "r" + str(i) in rname: return "r" + str(i) return rname shell = self.kernel_client.kernel.shell user_ns = shell.user_ns active_state = user_ns["active_state"] insns = active_state.simstate.block().capstone.insns insn = insns[0].insn self.reg_view.setRowCount(0) for op in insn.operands: # OP_REG if op.type == 1: rname = insn.reg_name(op.value.reg) rname = fix_new_regname(rname) value = self.eval_value( active_state, getattr(active_state.simstate.regs, rname)) self.reg_view.append_reg(rname, value) # OP_MEM elif op.type == 3: if op.value.mem.base: rname = insn.reg_name(op.value.mem.base) rname = fix_new_regname(rname) value = self.eval_value( active_state, getattr(active_state.simstate.regs, rname)) self.reg_view.append_reg(rname, value) if op.value.mem.index: rname = insn.reg_name(op.value.mem.index) rname = fix_new_regname(rname) value = self.eval_value( active_state, getattr(active_state.simstate.regs, rname)) self.reg_view.append_reg(rname, value) self.reg_view.resizeColumnsToContents() def setup_ipython(self, app: QtWidgets.QApplication, window: "MainWindow") -> None: """ Might break with future versions of IPython, but nobody got time for this! """ shell = self.kernel_client.kernel.shell shell.magic("clear") user_ns = shell.user_ns user_ns["app"] = app user_ns["window"] = self config = shell.config config.TerminalIPythonApp.display_banner = "" from . import ipython_extension shell.extension_manager.load_extension(ipython_extension.__name__) def fill_read_cache(self, filename: str, line: int) -> None: try: lexer = pygments.lexers.get_lexer_for_filename( str(filename)) # type: RegexLexer formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs(".highlight") with open(str(filename)) as f: lines = f.readlines() if len(lines) < 1000: content = "".join(lines) tokens = lexer.get_tokens(content) source = pygments.format(tokens, html_formatter) self.file_cache[filename][line] = (css, source) self.file_read_cache[filename] = (lexer, content, False) else: minl = max(0, line - 30) maxl = min(len(lines), line + 30) formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs(".highlight") source = pygments.format( lexer.get_tokens("".join(lines[minl:maxl])), html_formatter) self.file_cache[filename][line] = (css, source) self.file_read_cache[filename] = (lexer, lines, True) except Exception as e: l.exception(e) self.file_cache[filename][line] = (None, None) self.file_read_cache[filename] = (None, None, False) def fill_file_cache(self, filename: str, line: int) -> None: lexer, content, is_largefile = self.file_read_cache[filename] if lexer and content: try: if not is_largefile: formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs(".highlight") source = pygments.format(lexer.get_tokens(content), html_formatter) self.file_cache[filename][line] = (css, source) else: minl = max(0, line - 30) maxl = min(len(content), line + 30) formatter_opts = dict(linenos="inline", linespans="line", hl_lines=[line - minl]) html_formatter = pygments.formatters.get_formatter_by_name( "html", **formatter_opts) css = html_formatter.get_style_defs(".highlight") source = pygments.format( lexer.get_tokens("".join(content[minl:maxl])), html_formatter) self.file_cache[filename][line] = (css, source) except Exception as e: l.exception(e) self.file_cache[filename][line] = (None, None) else: self.file_cache[filename][line] = (None, None) def cache_tokens(self, addr_map: Dict[int, Tuple[str, int]]) -> None: for filename, line in addr_map.values(): l.info("caching file: " + str(filename) + " at line: " + str(line)) if filename != "??": if filename in self.file_read_cache.keys(): self.fill_file_cache(filename, line) else: self.fill_read_cache(filename, line) def add_states(self, states: StateManager, tracer: Tracer) -> None: for s in states.major_states[1:]: pass # self.callgraph.add_node(s, tracer) def clear_viewer(self) -> None: self.code_view.clear() def append_archive(self) -> None: files = list(DEFAULT_LOG_DIR.glob("*.tar.gz")) files.sort() self.code_view.append("\nAvailable files:") for f in files: self.code_view.append(f.name) def enable_buttons(self) -> None: # TODO: maintain a button list self.up_button.setEnabled(True) self.upto_button.setEnabled(True) self.down_button.setEnabled(True) self.downto_button.setEnabled(True) # self.cg_button.setEnabled(True) self.info_button.setEnabled(True) self.switch_button.setEnabled(True) def clear_cache(self) -> None: self.file_cache = DefaultDict(dict) self.coredump_constraints = [] # self.callgraph.clear_cache() def shutdown_kernel(self) -> None: print("Shutting down kernel...") self.kernel_client.stop_channels() self.kernel_manager.shutdown_kernel()