def create_error_dlg(self, message, info=None, detail=None, ignore_buttons=True): dlg = QMessageBox() dlg.setText(message) if info: dlg.setInformativeText(info) if detail: dlg.setDetailedText(detail) dlg.setWindowTitle(self.name + self.tr(" - Error")) dlg.setIcon(QMessageBox.Critical) if ignore_buttons: dlg.setStandardButtons(QMessageBox.Abort | QMessageBox.Ignore) dlg.btn_ignoreall = dlg.addButton(self.tr("Ignore A&ll"), QMessageBox.ActionRole) dlg.setDefaultButton(QMessageBox.Ignore) else: dlg.setDefaultButton(QMessageBox.NoButton) return dlg
def raise_to_operator(exc, execute=True): """ Utility function to show a Python Exception in QMessageBox The type and representation of the Exception are shown in a pop-up QMessageBox. The entire traceback is available via a drop-down detailed text box in the QMessageBox Parameters ---------- exc: Exception execute: bool, optional Whether to execute the QMessageBox """ # Assemble QMessageBox with Exception details err_msg = QMessageBox() err_msg.setText(f'{exc.__class__.__name__}: {exc}') err_msg.setWindowTitle(type(exc).__name__) err_msg.setIcon(QMessageBox.Critical) # Format traceback as detailed text with io.StringIO() as handle: traceback.print_tb(exc.__traceback__, file=handle) handle.seek(0) err_msg.setDetailedText(handle.read()) if execute: # Execute err_msg.exec_() return err_msg
def delete_patches(self): if self.mainwin.selection.hasSelection(): rows = sorted( [r.row() for r in self.mainwin.selection.selectedRows()]) patches = tuple(self.patches.get_row(r).displayname for r in rows) msg_box = QMessageBox() if len(rows) == 1: msg_box.setText( self.tr("Delete patch '{}'?").format(patches[0])) else: msg_box.setText( self.tr("Delete {} patches?").format(len(rows))) msg_box.setDetailedText('\n'.join(patches)) msg_box.setInformativeText( self.tr("Patches can only be restored by re-importing them.")) msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel) msg_box.setDefaultButton(QMessageBox.Cancel) msg_box.setIcon(QMessageBox.Warning) if msg_box.exec_() == QMessageBox.Yes: with self.session.begin(): for n, row in enumerate(rows): self.patches.removeRows(row - n)
def load_files(self): dial = MultipleLoadDialog(self.load_register, self.settings.get_path_history()) dial.setDirectory( self.settings.get("io.multiple_open_directory", str(Path.home()))) dial.selectNameFilter( self.settings.get("io.multiple_open_filter", next(iter(self.load_register.keys())))) self.error_list = [] if dial.exec_(): result = dial.get_result() load_dir = os.path.dirname(result.load_location[0]) self.settings.set("io.multiple_open_directory", load_dir) self.settings.add_path_history(load_dir) self.settings.set("io.multiple_open_filter", result.selected_filter) dial_fun = ExecuteFunctionDialog( self.execute_load_files, [result], exception_hook=load_data_exception_hook) dial_fun.exec_() if self.error_list: errors_message = QMessageBox() errors_message.setText("There are errors during load files") errors_message.setInformativeText( "During load files cannot found some of files on disc") errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join("File: " + x[0] + "\n" + str(x[1]) for x in self.error_list) errors_message.setDetailedText(text) errors_message.exec_()
def show_failure_msg(self, msg, info, details): self.viz_tab.set_message(msg) msgBox = QMessageBox() msgBox.setIcon(QMessageBox.Critical) msgBox.setText(msg) msgBox.setInformativeText(info) msgBox.setDetailedText(details) msgBox.exec()
def _plotting_error(self, msg, trace): msg_box = QMessageBox(self) msg_box.setIcon(QMessageBox.Critical) msg_box.setText('Plotting Error') msg_box.setInformativeText(msg) msg_box.setDetailedText(trace) msg_box.setStandardButtons(QMessageBox.Close) msg_box.exec_()
def __init__( self, config_folder: Union[str, Path, None] = None, title="PartSeg", settings: Optional[BaseSettings] = None, load_dict: Optional[Register] = None, signal_fun=None, ): if settings is None: if config_folder is None: raise ValueError("wrong config folder") if not os.path.exists(config_folder): import_config() settings: BaseSettings = self.get_setting_class()(config_folder) errors = settings.load() if errors: errors_message = QMessageBox() errors_message.setText("There are errors during start") errors_message.setInformativeText( "During load saved state some of data could not be load properly\n" "The files has prepared backup copies in " " state directory (Help > State directory)") errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join("File: " + x[0] + "\n" + str(x[1]) for x in errors) errors_message.setDetailedText(text) errors_message.exec_() super().__init__() if signal_fun is not None: self.show_signal.connect(signal_fun) self.settings = settings self._load_dict = load_dict self.viewer_list: List[Viewer] = [] self.files_num = 1 self.setAcceptDrops(True) self.setWindowTitle(title) self.title_base = title app = QApplication.instance() if app is not None: app.setStyleSheet(settings.style_sheet) self.settings.theme_changed.connect(self.change_theme) self.channel_info = "" self.multiple_files = None self.settings.request_load_files.connect(self.read_drop) self.recent_file_menu = QMenu("Open recent") self._refresh_recent() self.settings.connect_(FILE_HISTORY, self._refresh_recent) self.settings.napari_settings.appearance.events.theme.connect( self.change_theme) self.settings.set_parent(self) self.console = None self.console_dock = QDockWidget("console", self) self.console_dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.BottomDockWidgetArea) # self.console_dock.setWidget(self.console) self.console_dock.hide() self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock)
def display_message_box(self, title, message, details): msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setText(message) msg.setWindowTitle(title) msg.setDetailedText(details) msg.setStandardButtons(QMessageBox.Ok) msg.setDefaultButton(QMessageBox.Ok) msg.setEscapeButton(QMessageBox.Ok) msg.exec_()
def display_message_box(self, title, message, details): msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setText(message) msg.setWindowTitle(title) msg.setDetailedText(details) msg.setStandardButtons(QMessageBox.Ok) msg.setDefaultButton(QMessageBox.Ok) msg.setEscapeButton(QMessageBox.Ok) msg.exec_()
def errorPopup(self, title, msg, details=None): """ Display an error popup to inform the user. Args: title (str): popup title msg (str): popup message details (str): facultative detailed text """ w = QMessageBox(QMessageBox.Critical, title, msg, QMessageBox.Ok, self) if details: w.setDetailedText(details) w.exec()
def _check_rows(self, rows, only_one=False): """Checks how many items are in ``rows`` and alerts user if not right. Checks the number of indices in ``rows``, alerts the user with a popup box if there are no items in ``rows``. Alternatively if the kwarg ``only_one`` is ``True`` also alerts users that too many rows are selected. Returns ``True`` if the right number(s) of items are in ``rows`` otherwise it returns ``False``. Parameters ---------- rows : [row indices] A list of row indices to be checked. only_one : Bool, optional A boolean that indicates if more than one row is allowed, default is ``False``. Returns ------- Ok : Bool A boolean to indicate if the number of items in row is Ok. """ Ok = True if not rows: # if no cell is selected Ok = False warning = QMessageBox() warning.setIcon(QMessageBox.Information) warning.setWindowTitle('Row(s) must be selected') warning.setText('Action not performed as no row is selected') warning.setDetailedText('This warning generally occurs ' 'because no row is selected, select a row' ' and try again') warning.setStandardButtons(QMessageBox.Ok) warning.exec_() elif len(rows) > 1 and only_one: Ok = False warning = QMessageBox() warning.setIcon(QMessageBox.Information) warning.setWindowTitle('More than one row is selected') warning.setText('Action not performed as more than one row is ' 'selected') warning.setDetailedText('This warning generally occurs ' 'because there are more than one row ' 'selected, unselect some rows and try ' 'again') warning.setStandardButtons(QMessageBox.Ok) warning.exec_() return Ok
def __createMsgBox(self, title, message, details): msg_box = QMessageBox(self.parent()) msg_box.setText(title) msg_box.setInformativeText(message) if len(details) > 0: msg_box.setDetailedText(details) horizontal_spacer = QSpacerItem( 500, 0, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding ) layout = msg_box.layout() layout.addItem(horizontal_spacer, layout.rowCount(), 0, 1, layout.columnCount()) return msg_box
def exception(parent, ex, buttons=QMessageBox.Ok, defaultButton=QMessageBox.NoButton): title = type(ex).__name__ message = str(ex) tb = StringIO() if hasattr(ex, '__traceback__'): exc_traceback = ex.__traceback__ else: exc_traceback = sys.exc_info()[2] traceback.print_tb(exc_traceback, file=tb) msgbox = QMessageBox(QMessageBox.Critical, title, message, buttons, parent) msgbox.setDefaultButton(defaultButton) msgbox.setDetailedText(tb.getvalue()) msgbox.exec_()
def _on_simulation_done(self, failed, failed_msg): self.processing_animation.hide() self.kill_button.setHidden(True) self.done_button.setHidden(False) self.restart_button.setVisible( self._run_model.has_failed_realizations()) self.restart_button.setEnabled(self._run_model.support_restart) self._total_progress_bar.setValue(100) self._total_progress_label.setText( _TOTAL_PROGRESS_TEMPLATE.format( total_progress=100, phase_name=self._run_model.getPhaseName())) if failed: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Simulations failed!".center(100)) msg.setDetailedText(failed_msg) msg.exec_()
def launch(self): if self.prepare.result is None: self.close() return if self.prepare.errors: errors_message = QMessageBox() errors_message.setText("There are errors during start") errors_message.setInformativeText( "During load saved state some of data could not be load properly\n" "The files has prepared backup copies in state directory (Help > State directory)" ) errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.prepare.errors]) errors_message.setDetailedText(text) errors_message.exec() wind = self.prepare.result(title=self.final_title, signal_fun=self.window_shown) wind.show() self.wind = wind
def exceptions(parent, exs, buttons=QMessageBox.Ok, defaultButton=QMessageBox.NoButton): title = 'Exception(s)' message = '\n'.join(map(str, exs)) tracebacks = [] for ex in exs: tb = StringIO() if not hasattr(ex, '__traceback__'): continue exc_traceback = ex.__traceback__ traceback.print_tb(exc_traceback, file=tb) tracebacks.append(tb.getvalue()) msgbox = QMessageBox(QMessageBox.Critical, title, message, buttons, parent) msgbox.setDefaultButton(defaultButton) msgbox.setDetailedText('\n'.join(tracebacks)) msgbox.exec_()
def _export_shape_file(self, *args, **kwargs): # show files msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("You are about to create shape files.") msg.setInformativeText( "Please select an output directory after click \"OK\"\n" "For the list of .edi files (stations) included in the creation, please click \"Show Details\"" ) msg.setWindowTitle("Note") msg.setDetailedText("\n".join([ "{station} ({fn})".format( station=station, fn=self._file_handler.station2ref(station)) for station in self._station_viewer.selected_stations ])) msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) if msg.exec_() == QMessageBox.Ok: dialog = QFileDialog(self) dir_name = None dialog.setWindowTitle("Selecting Output Directory ...") dialog.setFileMode(QFileDialog.DirectoryOnly) while dir_name is None: if dialog.exec_() == QDialog.Accepted: dir_name = dialog.selectedFiles()[0] dir_name = str(dir_name) if not os.path.isdir(dir_name): QMessageBox.information( self, "NOTE", "Please select a directory to save the created shape files." ) dir_name = None # will read again else: break if dir_name is not None: collect = EdiCollection(mt_objs=[ self._file_handler.get_MT_obj( self._file_handler.station2ref(station)) for station in self._station_viewer.selected_stations ]) collect.create_mt_station_gdf(dir_name) QMessageBox.information(self, "Creation Completed", "Output written to %s" % dir_name) webbrowser.open(dir_name)
def __init__( self, config_folder: Optional[str] = None, title="PartSeg", settings: Optional[BaseSettings] = None, signal_fun=None, ): if settings is None: if config_folder is None: raise ValueError("wrong config folder") settings: BaseSettings = self.get_setting_class()(config_folder) if not os.path.exists(config_folder): import_config() errors = settings.load() if errors: errors_message = QMessageBox() errors_message.setText("There are errors during start") errors_message.setInformativeText( "During load saved state some of data could not be load properly\n" "The files has prepared backup copies in " " state directory (Help > State directory)") errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join( ["File: " + x[0] + "\n" + str(x[1]) for x in errors]) errors_message.setDetailedText(text) errors_message.exec() super().__init__() if signal_fun is not None: self.show_signal.connect(signal_fun) self.settings = settings self.viewer_list: List[Viewer] = [] self.files_num = 1 self.setAcceptDrops(True) self.setWindowTitle(title) self.title_base = title app = QApplication.instance() if app is not None: app.setStyleSheet(settings.style_sheet) self.settings.theme_changed.connect(self.change_theme) self.channel_info = ""
def pop_message(parent, message, detailed_message=None, message_type='error'): """ pop up a message with specified message type such as error, warning, info... :param parent: :param message: :param detailed_message: detailed message optionally shown to user :param message_type: str as ['error', 'warning', 'info'] but NOT case sensitive :return: """ message_type = message_type.lower() if message_type not in ['error', 'warning', 'info']: raise TypeError( 'Message type {0} is not supported.'.format(message_type)) # check types checkdatatypes.check_string_variable('(Main) message to show', message) if detailed_message is not None: checkdatatypes.check_string_variable('(Detailed) message to show', detailed_message) # create a QMessageBox msg_box = QMessageBox() # set information type if message_type == 'info': msg_box.setIcon(QMessageBox.Information) elif message_type == 'error': msg_box.setIcon(QMessageBox.Critical) elif message_type == 'warning': msg_box.setIcon(QMessageBox.Warning) # set text msg_box.setText(message) if detailed_message is not None: msg_box.setDetailedText(detailed_message) # another button msg_box.setWindowTitle('PyRS Message') # box msg_box.setStandardButtons(QMessageBox.Ok) ret_val = msg_box.exec_() print('Message box return value: {}'.format(ret_val))
def __on_ws_message(self, msg): ''' Handles messages from the device. :param msg: the message. ''' if msg.startswith('mso '): logger.debug(f"Processing mso {msg}") self.__on_mso(json.loads(msg[4:])) elif msg.startswith('msoupdate '): logger.debug(f"Processing msoupdate {msg}") self.__on_msoupdate(json.loads(msg[10:])) else: logger.warning(f"Unknown message {msg}") msg_box = QMessageBox(QMessageBox.Critical, 'Unknown Message', f"Received unexpected message from {self.ipAddress.text()}") msg_box.setDetailedText(f"<code>{msg}</code>") msg_box.setTextFormat(Qt.RichText) msg_box.exec() if self.__spinner is not None: stop_spinner(self.__spinner, self.syncStatus) self.__spinner = None self.syncStatus.setIcon(qta.icon('fa5s.times', color='red'))
def load_files(self): def exception_hook(exception): from qtpy.QtCore import QMetaObject instance = QApplication.instance() if isinstance(exception, MemoryError): instance.warning = "Open error", f"Not enough memory to read this image: {exception}" QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection) elif isinstance(exception, IOError): instance.warning = "Open error", f"Some problem with reading from disc: {exception}" QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection) elif isinstance(exception, KeyError): instance.warning = "Open error", f"Some problem project file: {exception}" QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection) print(exception, file=sys.stderr) else: raise exception dial = MultipleLoadDialog(self.load_register, self.settings.get_path_history()) dial.setDirectory(self.settings.get("io.multiple_open_directory", str(Path.home()))) dial.selectNameFilter(self.settings.get("io.multiple_open_filter", next(iter(self.load_register.keys())))) self.error_list = [] if dial.exec(): result = dial.get_result() load_dir = os.path.dirname(result.load_location[0]) self.settings.set("io.multiple_open_directory", load_dir) self.settings.add_path_history(load_dir) self.settings.set("io.multiple_open_filter", result.selected_filter) dial_fun = ExecuteFunctionDialog(self.execute_load_files, [result], exception_hook=exception_hook) dial_fun.exec() if self.error_list: errors_message = QMessageBox() errors_message.setText("There are errors during load files") errors_message.setInformativeText("During load files cannot found some of files on disc") errors_message.setStandardButtons(QMessageBox.Ok) text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.error_list]) errors_message.setDetailedText(text) errors_message.exec()
class Console(SpyderPluginWidget): """ Console widget """ CONF_SECTION = 'internal_console' focus_changed = Signal() redirect_stdio = Signal(bool) edit_goto = Signal(str, int, str) def __init__(self, parent=None, namespace=None, commands=[], message=None, exitfunc=None, profile=False, multithreaded=False): SpyderPluginWidget.__init__(self, parent) debug_print(" ..internal console: initializing") self.dialog_manager = DialogManager() # Shell light_background = self.get_option('light_background') self.shell = InternalShell(parent, namespace, commands, message, self.get_option('max_line_count'), self.get_plugin_font(), exitfunc, profile, multithreaded, light_background=light_background) self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0)) self.shell.go_to_error.connect(self.go_to_error) self.shell.focus_changed.connect(lambda: self.focus_changed.emit()) # Redirecting some signals: self.shell.redirect_stdio.connect( lambda state: self.redirect_stdio.emit(state)) # Initialize plugin self.initialize_plugin() # Find/replace widget self.find_widget = FindReplace(self) self.find_widget.set_editor(self.shell) self.find_widget.hide() self.register_widget_shortcuts(self.find_widget) # Main layout btn_layout = QHBoxLayout() btn_layout.setAlignment(Qt.AlignLeft) btn_layout.addStretch() btn_layout.addWidget(self.options_button, Qt.AlignRight) layout = create_plugin_layout(btn_layout) layout.addWidget(self.shell) layout.addWidget(self.find_widget) self.setLayout(layout) # Parameters self.shell.toggle_wrap_mode(self.get_option('wrap')) # Accepting drops self.setAcceptDrops(True) # Traceback MessageBox self.msgbox_traceback = None self.error_traceback = "" #------ Private API -------------------------------------------------------- def set_historylog(self, historylog): """Bind historylog instance to this console Not used anymore since v2.0""" historylog.add_history(self.shell.history_filename) self.shell.append_to_history.connect(historylog.append_to_history) def set_help(self, help_plugin): """Bind help instance to this console""" self.shell.help = help_plugin #------ SpyderPluginWidget API --------------------------------------------- def get_plugin_title(self): """Return widget title""" return _('Internal console') def get_focus_widget(self): """ Return the widget to give focus to when this plugin's dockwidget is raised on top-level """ return self.shell def update_font(self): """Update font from Preferences""" font = self.get_plugin_font() self.shell.set_font(font) def closing_plugin(self, cancelable=False): """Perform actions before parent main window is closed""" self.dialog_manager.close_all() self.shell.exit_interpreter() return True def refresh_plugin(self): pass def get_plugin_actions(self): """Return a list of actions related to plugin""" quit_action = create_action(self, _("&Quit"), icon=ima.icon('exit'), tip=_("Quit"), triggered=self.quit) self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q") run_action = create_action(self, _("&Run..."), None, ima.icon('run_small'), _("Run a Python script"), triggered=self.run_script) environ_action = create_action( self, _("Environment variables..."), icon=ima.icon('environ'), tip=_("Show and edit environment variables" " (for current session)"), triggered=self.show_env) syspath_action = create_action(self, _("Show sys.path contents..."), icon=ima.icon('syspath'), tip=_("Show (read-only) sys.path"), triggered=self.show_syspath) buffer_action = create_action(self, _("Buffer..."), None, tip=_("Set maximum line count"), triggered=self.change_max_line_count) exteditor_action = create_action( self, _("External editor path..."), None, None, _("Set external editor executable path"), triggered=self.change_exteditor) wrap_action = create_action(self, _("Wrap lines"), toggled=self.toggle_wrap_mode) wrap_action.setChecked(self.get_option('wrap')) calltips_action = create_action(self, _("Display balloon tips"), toggled=self.toggle_calltips) calltips_action.setChecked(self.get_option('calltips')) codecompletion_action = create_action( self, _("Automatic code completion"), toggled=self.toggle_codecompletion) codecompletion_action.setChecked( self.get_option('codecompletion/auto')) codecompenter_action = create_action( self, _("Enter key selects completion"), toggled=self.toggle_codecompletion_enter) codecompenter_action.setChecked( self.get_option('codecompletion/enter_key')) option_menu = QMenu(_('Internal console settings'), self) option_menu.setIcon(ima.icon('tooloptions')) add_actions( option_menu, (buffer_action, wrap_action, calltips_action, codecompletion_action, codecompenter_action, exteditor_action)) plugin_actions = [ None, run_action, environ_action, syspath_action, option_menu, MENU_SEPARATOR, quit_action, self.undock_action ] return plugin_actions def register_plugin(self): """Register plugin in Spyder's main window""" self.focus_changed.connect(self.main.plugin_focus_changed) self.main.add_dockwidget(self) # Connecting the following signal once the dockwidget has been created: self.shell.exception_occurred.connect(self.exception_occurred) def exception_occurred(self, text, is_traceback): """Exception ocurred in the internal console. Show a QMessageBox or the internal console to warn the user""" # Skip errors without traceback if not is_traceback and self.msgbox_traceback is None: return if CONF.get('main', 'show_internal_console_if_traceback', False): self.dockwidget.show() self.dockwidget.raise_() else: if self.msgbox_traceback is None: self.msgbox_traceback = QMessageBox( QMessageBox.Critical, _('Error'), _("<b>Spyder has encountered a problem.</b><br>" "Sorry for the inconvenience." "<br><br>" "You can automatically submit this error to our Github " "issues tracker.<br><br>" "<i>Note:</i> You need a Github account for that."), QMessageBox.Ok, parent=self) self.submit_btn = self.msgbox_traceback.addButton( _('Submit to Github'), QMessageBox.YesRole) self.submit_btn.pressed.connect(self.press_submit_btn) self.msgbox_traceback.setWindowModality(Qt.NonModal) self.error_traceback = "" self.msgbox_traceback.show() self.msgbox_traceback.finished.connect(self.close_msg) self.msgbox_traceback.setDetailedText(' ') # open show details (iterate over all buttons and click it) for button in self.msgbox_traceback.buttons(): if (self.msgbox_traceback.buttonRole(button) == QMessageBox.ActionRole): button.click() break self.error_traceback += text self.msgbox_traceback.setDetailedText(self.error_traceback) def close_msg(self): self.msgbox_traceback = None def press_submit_btn(self): self.main.report_issue(self.error_traceback) self.msgbox_traceback = None #------ Public API --------------------------------------------------------- @Slot() def quit(self): """Quit mainwindow""" self.main.close() @Slot() def show_env(self): """Show environment variables""" self.dialog_manager.show(EnvDialog()) @Slot() def show_syspath(self): """Show sys.path""" editor = CollectionsEditor() editor.setup(sys.path, title="sys.path", readonly=True, width=600, icon=ima.icon('syspath')) self.dialog_manager.show(editor) @Slot() def run_script(self, filename=None, silent=False, set_focus=False, args=None): """Run a Python script""" if filename is None: self.shell.interpreter.restore_stds() filename, _selfilter = getopenfilename( self, _("Run Python script"), getcwd_or_home(), _("Python scripts") + " (*.py ; *.pyw ; *.ipy)") self.shell.interpreter.redirect_stds() if filename: os.chdir(osp.dirname(filename)) filename = osp.basename(filename) else: return debug_print(args) filename = osp.abspath(filename) rbs = remove_backslashes command = "runfile('%s', args='%s')" % (rbs(filename), rbs(args)) if set_focus: self.shell.setFocus() if self.dockwidget and not self.ismaximized: self.dockwidget.setVisible(True) self.dockwidget.raise_() self.shell.write(command + '\n') self.shell.run_command(command) def go_to_error(self, text): """Go to error if relevant""" match = get_error_match(to_text_string(text)) if match: fname, lnb = match.groups() self.edit_script(fname, int(lnb)) def edit_script(self, filename=None, goto=-1): """Edit script""" # Called from InternalShell if not hasattr(self, 'main') \ or not hasattr(self.main, 'editor'): self.shell.external_editor(filename, goto) return if filename is not None: self.edit_goto.emit(osp.abspath(filename), goto, '') def execute_lines(self, lines): """Execute lines and give focus to shell""" self.shell.execute_lines(to_text_string(lines)) self.shell.setFocus() @Slot() def change_max_line_count(self): "Change maximum line count" "" mlc, valid = QInputDialog.getInt(self, _('Buffer'), _('Maximum line count'), self.get_option('max_line_count'), 0, 1000000) if valid: self.shell.setMaximumBlockCount(mlc) self.set_option('max_line_count', mlc) @Slot() def change_exteditor(self): """Change external editor path""" path, valid = QInputDialog.getText( self, _('External editor'), _('External editor executable path:'), QLineEdit.Normal, self.get_option('external_editor/path')) if valid: self.set_option('external_editor/path', to_text_string(path)) @Slot(bool) def toggle_wrap_mode(self, checked): """Toggle wrap mode""" self.shell.toggle_wrap_mode(checked) self.set_option('wrap', checked) @Slot(bool) def toggle_calltips(self, checked): """Toggle calltips""" self.shell.set_calltips(checked) self.set_option('calltips', checked) @Slot(bool) def toggle_codecompletion(self, checked): """Toggle automatic code completion""" self.shell.set_codecompletion_auto(checked) self.set_option('codecompletion/auto', checked) @Slot(bool) def toggle_codecompletion_enter(self, checked): """Toggle Enter key for code completion""" self.shell.set_codecompletion_enter(checked) self.set_option('codecompletion/enter_key', checked) #----Drag and drop def dragEnterEvent(self, event): """Reimplement Qt method Inform Qt about the types of data that the widget accepts""" source = event.mimeData() if source.hasUrls(): if mimedata2url(source): event.acceptProposedAction() else: event.ignore() elif source.hasText(): event.acceptProposedAction() def dropEvent(self, event): """Reimplement Qt method Unpack dropped data and handle it""" source = event.mimeData() if source.hasUrls(): pathlist = mimedata2url(source) self.shell.drop_pathlist(pathlist) elif source.hasText(): lines = to_text_string(source.text()) self.shell.set_cursor_position('eof') self.shell.execute_lines(lines) event.acceptProposedAction()
class Console(SpyderPluginWidget): """ Console widget """ CONF_SECTION = 'internal_console' focus_changed = Signal() redirect_stdio = Signal(bool) edit_goto = Signal(str, int, str) def __init__(self, parent=None, namespace=None, commands=[], message=None, exitfunc=None, profile=False, multithreaded=False): SpyderPluginWidget.__init__(self, parent) debug_print(" ..internal console: initializing") self.dialog_manager = DialogManager() # Shell light_background = self.get_option('light_background') self.shell = InternalShell(parent, namespace, commands, message, self.get_option('max_line_count'), self.get_plugin_font(), exitfunc, profile, multithreaded, light_background=light_background) self.shell.status.connect(lambda msg: self.show_message.emit(msg, 0)) self.shell.go_to_error.connect(self.go_to_error) self.shell.focus_changed.connect(lambda: self.focus_changed.emit()) # Redirecting some signals: self.shell.redirect_stdio.connect(lambda state: self.redirect_stdio.emit(state)) # Initialize plugin self.initialize_plugin() # Find/replace widget self.find_widget = FindReplace(self) self.find_widget.set_editor(self.shell) self.find_widget.hide() self.register_widget_shortcuts(self.find_widget) # Main layout layout = QVBoxLayout() layout.addWidget(self.shell) layout.addWidget(self.find_widget) self.setLayout(layout) # Parameters self.shell.toggle_wrap_mode(self.get_option('wrap')) # Accepting drops self.setAcceptDrops(True) # Traceback MessageBox self.msgbox_traceback= None self.error_traceback = "" #------ Private API -------------------------------------------------------- def set_historylog(self, historylog): """Bind historylog instance to this console Not used anymore since v2.0""" historylog.add_history(self.shell.history_filename) self.shell.append_to_history.connect(historylog.append_to_history) def set_help(self, help_plugin): """Bind help instance to this console""" self.shell.help = help_plugin #------ SpyderPluginWidget API --------------------------------------------- def get_plugin_title(self): """Return widget title""" return _('Internal console') def get_focus_widget(self): """ Return the widget to give focus to when this plugin's dockwidget is raised on top-level """ return self.shell def update_font(self): """Update font from Preferences""" font = self.get_plugin_font() self.shell.set_font(font) def closing_plugin(self, cancelable=False): """Perform actions before parent main window is closed""" self.dialog_manager.close_all() self.shell.exit_interpreter() return True def refresh_plugin(self): pass def get_plugin_actions(self): """Return a list of actions related to plugin""" quit_action = create_action(self, _("&Quit"), icon=ima.icon('exit'), tip=_("Quit"), triggered=self.quit) self.register_shortcut(quit_action, "_", "Quit", "Ctrl+Q") run_action = create_action(self, _("&Run..."), None, ima.icon('run_small'), _("Run a Python script"), triggered=self.run_script) environ_action = create_action(self, _("Environment variables..."), icon=ima.icon('environ'), tip=_("Show and edit environment variables" " (for current session)"), triggered=self.show_env) syspath_action = create_action(self, _("Show sys.path contents..."), icon=ima.icon('syspath'), tip=_("Show (read-only) sys.path"), triggered=self.show_syspath) buffer_action = create_action(self, _("Buffer..."), None, tip=_("Set maximum line count"), triggered=self.change_max_line_count) exteditor_action = create_action(self, _("External editor path..."), None, None, _("Set external editor executable path"), triggered=self.change_exteditor) wrap_action = create_action(self, _("Wrap lines"), toggled=self.toggle_wrap_mode) wrap_action.setChecked(self.get_option('wrap')) calltips_action = create_action(self, _("Display balloon tips"), toggled=self.toggle_calltips) calltips_action.setChecked(self.get_option('calltips')) codecompletion_action = create_action(self, _("Automatic code completion"), toggled=self.toggle_codecompletion) codecompletion_action.setChecked(self.get_option('codecompletion/auto')) codecompenter_action = create_action(self, _("Enter key selects completion"), toggled=self.toggle_codecompletion_enter) codecompenter_action.setChecked(self.get_option( 'codecompletion/enter_key')) option_menu = QMenu(_('Internal console settings'), self) option_menu.setIcon(ima.icon('tooloptions')) add_actions(option_menu, (buffer_action, wrap_action, calltips_action, codecompletion_action, codecompenter_action, exteditor_action)) plugin_actions = [None, run_action, environ_action, syspath_action, option_menu, None, quit_action] # Add actions to context menu add_actions(self.shell.menu, plugin_actions) return plugin_actions def register_plugin(self): """Register plugin in Spyder's main window""" self.focus_changed.connect(self.main.plugin_focus_changed) self.main.add_dockwidget(self) # Connecting the following signal once the dockwidget has been created: self.shell.exception_occurred.connect(self.exception_occurred) def exception_occurred(self, text, is_traceback): """Exception ocurred in the internal console. Show a QMessageBox or the internal console to warn the user""" # Skip errors without traceback if not is_traceback and self.msgbox_traceback is None: return if CONF.get('main', 'show_internal_console_if_traceback', False): self.dockwidget.show() self.dockwidget.raise_() else: if self.msgbox_traceback is None: self.msgbox_traceback = QMessageBox( QMessageBox.Critical, _('Error'), _("<b>Spyder has encountered a problem.</b><br>" "Sorry for the inconvenience." "<br><br>" "You can automatically submit this error to our Github " "issues tracker.<br><br>" "<i>Note:</i> You need a Github account for that."), QMessageBox.Ok, parent=self) self.submit_btn = self.msgbox_traceback.addButton( _('Submit to Github'), QMessageBox.YesRole) self.submit_btn.pressed.connect(self.press_submit_btn) self.msgbox_traceback.setWindowModality(Qt.NonModal) self.error_traceback = "" self.msgbox_traceback.show() self.msgbox_traceback.finished.connect(self.close_msg) self.msgbox_traceback.setDetailedText(' ') # open show details (iterate over all buttons and click it) for button in self.msgbox_traceback.buttons(): if (self.msgbox_traceback.buttonRole(button) == QMessageBox.ActionRole): button.click() break self.error_traceback += text self.msgbox_traceback.setDetailedText(self.error_traceback) def close_msg(self): self.msgbox_traceback = None def press_submit_btn(self): self.main.report_issue(self.error_traceback) self.msgbox_traceback = None #------ Public API --------------------------------------------------------- @Slot() def quit(self): """Quit mainwindow""" self.main.close() @Slot() def show_env(self): """Show environment variables""" self.dialog_manager.show(EnvDialog()) @Slot() def show_syspath(self): """Show sys.path""" editor = CollectionsEditor() editor.setup(sys.path, title="sys.path", readonly=True, width=600, icon=ima.icon('syspath')) self.dialog_manager.show(editor) @Slot() def run_script(self, filename=None, silent=False, set_focus=False, args=None): """Run a Python script""" if filename is None: self.shell.interpreter.restore_stds() filename, _selfilter = getopenfilename(self, _("Run Python script"), getcwd(), _("Python scripts")+" (*.py ; *.pyw ; *.ipy)") self.shell.interpreter.redirect_stds() if filename: os.chdir( osp.dirname(filename) ) filename = osp.basename(filename) else: return debug_print(args) filename = osp.abspath(filename) rbs = remove_backslashes command = "runfile('%s', args='%s')" % (rbs(filename), rbs(args)) if set_focus: self.shell.setFocus() if self.dockwidget and not self.ismaximized: self.dockwidget.setVisible(True) self.dockwidget.raise_() self.shell.write(command+'\n') self.shell.run_command(command) def go_to_error(self, text): """Go to error if relevant""" match = get_error_match(to_text_string(text)) if match: fname, lnb = match.groups() self.edit_script(fname, int(lnb)) def edit_script(self, filename=None, goto=-1): """Edit script""" # Called from InternalShell if not hasattr(self, 'main') \ or not hasattr(self.main, 'editor'): self.shell.external_editor(filename, goto) return if filename is not None: self.edit_goto.emit(osp.abspath(filename), goto, '') def execute_lines(self, lines): """Execute lines and give focus to shell""" self.shell.execute_lines(to_text_string(lines)) self.shell.setFocus() @Slot() def change_max_line_count(self): "Change maximum line count""" mlc, valid = QInputDialog.getInt(self, _('Buffer'), _('Maximum line count'), self.get_option('max_line_count'), 0, 1000000) if valid: self.shell.setMaximumBlockCount(mlc) self.set_option('max_line_count', mlc) @Slot() def change_exteditor(self): """Change external editor path""" path, valid = QInputDialog.getText(self, _('External editor'), _('External editor executable path:'), QLineEdit.Normal, self.get_option('external_editor/path')) if valid: self.set_option('external_editor/path', to_text_string(path)) @Slot(bool) def toggle_wrap_mode(self, checked): """Toggle wrap mode""" self.shell.toggle_wrap_mode(checked) self.set_option('wrap', checked) @Slot(bool) def toggle_calltips(self, checked): """Toggle calltips""" self.shell.set_calltips(checked) self.set_option('calltips', checked) @Slot(bool) def toggle_codecompletion(self, checked): """Toggle automatic code completion""" self.shell.set_codecompletion_auto(checked) self.set_option('codecompletion/auto', checked) @Slot(bool) def toggle_codecompletion_enter(self, checked): """Toggle Enter key for code completion""" self.shell.set_codecompletion_enter(checked) self.set_option('codecompletion/enter_key', checked) #----Drag and drop def dragEnterEvent(self, event): """Reimplement Qt method Inform Qt about the types of data that the widget accepts""" source = event.mimeData() if source.hasUrls(): if mimedata2url(source): event.acceptProposedAction() else: event.ignore() elif source.hasText(): event.acceptProposedAction() def dropEvent(self, event): """Reimplement Qt method Unpack dropped data and handle it""" source = event.mimeData() if source.hasUrls(): pathlist = mimedata2url(source) self.shell.drop_pathlist(pathlist) elif source.hasText(): lines = to_text_string(source.text()) self.shell.set_cursor_position('eof') self.shell.execute_lines(lines) event.acceptProposedAction()