def update_preview(self, index=None, scheme_name=None): """ Update the color scheme of the preview editor and adds text. Note ---- 'index' is needed, because this is triggered by a signal that sends the selected index. """ text = ('"""A string"""\n\n' '# A comment\n\n' '# %% A cell\n\n' 'class Foo(object):\n' ' def __init__(self):\n' ' bar = 42\n' ' print(bar)\n' ) show_blanks = CONF.get('editor', 'blank_spaces') update_scrollbar = CONF.get('editor', 'scroll_past_end') if scheme_name is None: scheme_name = self.current_scheme self.preview_editor.setup_editor(linenumbers=True, markers=True, tab_mode=False, font=get_font(), show_blanks=show_blanks, color_scheme=scheme_name, scroll_past_end=update_scrollbar) self.preview_editor.set_text(text) self.preview_editor.set_language('Python')
def lsp_manager(qtbot_module, request): """LSP manager instance for tests.""" # Activate pycodestyle and pydocstyle CONF.set('lsp-server', 'pycodestyle', True) CONF.set('lsp-server', 'pydocstyle', True) # Create the manager os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True' manager = LSPManager(parent=MainWindowMock()) # Wait for the client to be started editor = manager.main.editor with qtbot_module.waitSignal(editor.sig_lsp_initialized, timeout=30000): manager.start_client('python') settings = editor.lsp_editor_settings['python'] assert all([option in SERVER_CAPABILITES for option in settings.keys()]) def teardown(): manager.shutdown() os.environ['SPY_TEST_USE_INTROSPECTION'] = 'False' CONF.set('lsp-server', 'pycodestyle', False) CONF.set('lsp-server', 'pydocstyle', False) request.addfinalizer(teardown) return manager
def set_option(self, option, value): """ Set a plugin option in configuration file Use a SIGNAL to call it, e.g.: plugin.sig_option_changed.emit('show_all', checked) """ CONF.set(self.CONF_SECTION, str(option), value)
def argv(self): """Command to start kernels""" # Python interpreter used to start kernels if CONF.get('main_interpreter', 'default'): pyexec = get_python_executable() else: # Avoid IPython adding the virtualenv on which Spyder is running # to the kernel sys.path os.environ.pop('VIRTUAL_ENV', None) pyexec = CONF.get('main_interpreter', 'executable') # Fixes Issue #3427 if os.name == 'nt': dir_pyexec = osp.dirname(pyexec) pyexec_w = osp.join(dir_pyexec, 'pythonw.exe') if osp.isfile(pyexec_w): pyexec = pyexec_w # Command used to start kernels utils_path = osp.join(self.spy_path, 'utils', 'ipython') kernel_cmd = [ pyexec, osp.join("%s" % utils_path, "start_kernel.py"), '-f', '{connection_file}' ] return kernel_cmd
def reset_namespace(self, warning=False, silent=True): """Reset the namespace by removing all names defined by the user.""" reset_str = _("Reset IPython namespace") warn_str = _("All user-defined variables will be removed." "<br>Are you sure you want to reset the namespace?") if warning: box = MessageCheckBox(icon=QMessageBox.Warning, parent=self) box.setWindowTitle(reset_str) box.set_checkbox_text(_("Don't show again.")) box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) box.setDefaultButton(QMessageBox.No) box.set_checked(False) box.set_check_visible(True) box.setText(warn_str) answer = box.exec_() # Update checkbox based on user interaction CONF.set('ipython_console', 'show_reset_namespace_warning', not box.is_checked()) if answer != QMessageBox.Yes: return if self._reading: self.dbg_exec_magic('reset', '-f') else: if silent: self.silent_execute("%reset -f") self.refresh_namespacebrowser() else: self.execute("%reset -f")
def save_connection_settings(self): """Save user's kernel connection settings.""" if not self.save_layout.isChecked(): return is_ssh_key = bool(self.kf_radio.isChecked()) connection_settings = { "json_file_path": self.cf.text(), "is_remote": self.rm_group.isChecked(), "username": self.un.text(), "hostname": self.hn.text(), "port": self.pn.text(), "is_ssh_keyfile": is_ssh_key, "ssh_key_file_path": self.kf.text() } CONF.set("existing-kernel", "settings", connection_settings) try: import keyring if is_ssh_key: keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", self.kfp.text()) else: keyring.set_password("spyder_remote_kernel", "ssh_password", self.pw.text()) except Exception: pass
def delete_scheme(self): """Deletes the currently selected custom color scheme.""" scheme_name = self.current_scheme answer = QMessageBox.warning(self, _("Warning"), _("Are you sure you want to delete " "this scheme?"), QMessageBox.Yes | QMessageBox.No) if answer == QMessageBox.Yes: # Put the combobox in Spyder by default, when deleting a scheme names = self.get_option('names') self.set_scheme('spyder') self.schemes_combobox.setCurrentIndex(names.index('spyder')) self.set_option('selected', 'spyder') # Delete from custom_names custom_names = self.get_option('custom_names', []) if scheme_name in custom_names: custom_names.remove(scheme_name) self.set_option('custom_names', custom_names) # Delete config options for key in syntaxhighlighters.COLOR_SCHEME_KEYS: option = "{0}/{1}".format(scheme_name, key) CONF.remove_option(self.CONF_SECTION, option) CONF.remove_option(self.CONF_SECTION, "{0}/name".format(scheme_name)) self.update_combobox() self.update_preview()
def get_font(section='appearance', option='font', font_size_delta=0): """Get console font properties depending on OS and user options""" font = FONT_CACHE.get((section, option)) if font is None: families = CONF.get(section, option+"/family", None) if families is None: return QFont() family = get_family(families) weight = QFont.Normal italic = CONF.get(section, option+'/italic', False) if CONF.get(section, option+'/bold', False): weight = QFont.Bold size = CONF.get(section, option+'/size', 9) + font_size_delta font = QFont(family, size, weight) font.setItalic(italic) FONT_CACHE[(section, option)] = font size = CONF.get(section, option+'/size', 9) + font_size_delta font.setPointSize(size) return font
def __init__(self, parent=None): QDialog.__init__(self, parent) self.main = parent # Widgets self.pages_widget = QStackedWidget() self.pages_widget.setMinimumWidth(600) self.contents_widget = QListWidget() self.button_reset = QPushButton(_('Reset to defaults')) bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Apply | QDialogButtonBox.Cancel) self.apply_btn = bbox.button(QDialogButtonBox.Apply) # Widgets setup # Destroying the C++ object right after closing the dialog box, # otherwise it may be garbage-collected in another QThread # (e.g. the editor's analysis thread in Spyder), thus leading to # a segmentation fault on UNIX or an application crash on Windows self.setAttribute(Qt.WA_DeleteOnClose) self.setWindowTitle(_('Preferences')) self.setWindowIcon(ima.icon('configure')) self.contents_widget.setMovement(QListView.Static) self.contents_widget.setSpacing(1) self.contents_widget.setCurrentRow(0) self.contents_widget.setMinimumWidth(220) self.contents_widget.setMinimumHeight(400) # Layout hsplitter = QSplitter() hsplitter.addWidget(self.contents_widget) hsplitter.addWidget(self.pages_widget) hsplitter.setStretchFactor(0, 1) hsplitter.setStretchFactor(1, 2) btnlayout = QHBoxLayout() btnlayout.addWidget(self.button_reset) btnlayout.addStretch(1) btnlayout.addWidget(bbox) vlayout = QVBoxLayout() vlayout.addWidget(hsplitter) vlayout.addLayout(btnlayout) self.setLayout(vlayout) # Signals and slots if self.main: self.button_reset.clicked.connect(self.main.reset_spyder) self.pages_widget.currentChanged.connect(self.current_page_changed) self.contents_widget.currentRowChanged.connect( self.pages_widget.setCurrentIndex) bbox.accepted.connect(self.accept) bbox.rejected.connect(self.reject) bbox.clicked.connect(self.button_clicked) # Ensures that the config is present on spyder first run CONF.set('main', 'interface_language', load_lang_conf())
def save_bookmarks(filename, bookmarks): """Save all bookmarks from specific file to config.""" if not osp.isfile(filename): return slots = load_bookmarks_without_file(filename) for slot_num, content in bookmarks.items(): slots[slot_num] = [filename, content[0], content[1]] CONF.set('editor', 'bookmarks', slots)
def set_option(self, option, value): """ Set a plugin option in configuration file. Note: Use sig_option_changed to call it from widgets of the same or another plugin. """ CONF.set(self.CONF_SECTION, str(option), value)
def reset_namespace(self, warning=False, message=False): """Reset the namespace by removing all names defined by the user.""" reset_str = _("Remove all variables") warn_str = _("All user-defined variables will be removed. " "Are you sure you want to proceed?") kernel_env = self.kernel_manager._kernel_spec.env if warning: box = MessageCheckBox(icon=QMessageBox.Warning, parent=self) box.setWindowTitle(reset_str) box.set_checkbox_text(_("Don't show again.")) box.setStandardButtons(QMessageBox.Yes | QMessageBox.No) box.setDefaultButton(QMessageBox.Yes) box.set_checked(False) box.set_check_visible(True) box.setText(warn_str) answer = box.exec_() # Update checkbox based on user interaction CONF.set('ipython_console', 'show_reset_namespace_warning', not box.is_checked()) self.ipyclient.reset_warning = not box.is_checked() if answer != QMessageBox.Yes: return try: if self._reading: self.dbg_exec_magic('reset', '-f') else: if message: self.reset() self._append_html(_("<br><br>Removing all variables..." "\n<hr>"), before_prompt=False) self.silent_execute("%reset -f") if kernel_env.get('SPY_AUTOLOAD_PYLAB_O') == 'True': self.silent_execute("from pylab import *") if kernel_env.get('SPY_SYMPY_O') == 'True': sympy_init = """ from __future__ import division from sympy import * x, y, z, t = symbols('x y z t') k, m, n = symbols('k m n', integer=True) f, g, h = symbols('f g h', cls=Function) init_printing()""" self.silent_execute(dedent(sympy_init)) if kernel_env.get('SPY_RUN_CYTHON') == 'True': self.silent_execute("%reload_ext Cython") self.refresh_namespacebrowser() if not self.external_kernel: self.silent_execute( 'get_ipython().kernel.close_all_mpl_figures()') except AttributeError: pass
def get_user_credentials(self): """Get user credentials with the login dialog.""" password = None token = None (username, remember_me, remember_token) = self._get_credentials_from_settings() valid_py_os = not (PY2 and sys.platform.startswith('linux')) if username and remember_me and valid_py_os: # Get password from keyring try: password = keyring.get_password('github', username) except Exception: # No safe keyring backend if self._show_msgbox: QMessageBox.warning(self.parent_widget, _('Failed to retrieve password'), _('It was not possible to retrieve ' 'your password. Please introduce ' 'it again.')) if remember_token and valid_py_os: # Get token from keyring try: token = keyring.get_password('github', 'token') except Exception: # No safe keyring backend if self._show_msgbox: QMessageBox.warning(self.parent_widget, _('Failed to retrieve token'), _('It was not possible to retrieve ' 'your token. Please introduce it ' 'again.')) if not running_under_pytest(): credentials = DlgGitHubLogin.login(self.parent_widget, username, password, token, remember_me, remember_token) if (credentials['username'] and credentials['password'] and valid_py_os): self._store_credentials(credentials['username'], credentials['password'], credentials['remember']) CONF.set('main', 'report_error/remember_me', credentials['remember']) if credentials['token'] and valid_py_os: self._store_token(credentials['token'], credentials['remember_token']) CONF.set('main', 'report_error/remember_token', credentials['remember_token']) else: return dict(username=username, password=password, token='', remember=remember_me, remember_token=remember_token) return credentials
def _get_credentials_from_settings(self): """Get the stored credentials if any.""" remember_me = CONF.get('main', 'report_error/remember_me') remember_token = CONF.get('main', 'report_error/remember_token') username = CONF.get('main', 'report_error/username', '') if not remember_me: username = '' return username, remember_me, remember_token
def _get_run_configurations(): history_count = CONF.get('run', 'history', 20) try: return [(filename, options) for filename, options in CONF.get('run', 'configurations', []) if osp.isfile(filename)][:history_count] except ValueError: CONF.set('run', 'configurations', []) return []
def update_margins(self): layout = self.layout() if self.default_margins is None: self.default_margins = layout.getContentsMargins() if CONF.get('main', 'use_custom_margin'): margin = CONF.get('main', 'custom_margin') layout.setContentsMargins(*[margin]*4) else: layout.setContentsMargins(*self.default_margins)
def teardown(): """Clear existing-kernel config and keyring passwords.""" CONF.remove_section("existing-kernel") try: import keyring keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", "") keyring.set_password("spyder_remote_kernel", "ssh_password", "") except Exception: pass
def is_dark_interface(): ui_theme = CONF.get('appearance', 'ui_theme') color_scheme = CONF.get('appearance', 'selected') if ui_theme == 'dark': return True elif ui_theme == 'automatic': if not is_dark_font_color(color_scheme): return True else: return False else: return False
def external_editor(self, filename, goto=-1): """Edit in an external editor Recommended: SciTE (e.g. to go to line where an error did occur)""" editor_path = CONF.get("internal_console", "external_editor/path") goto_option = CONF.get("internal_console", "external_editor/gotoline") try: args = [filename] if goto > 0 and goto_option: args.append("%s%d".format(goto_option, goto)) programs.run_program(editor_path, args) except OSError: self.write_error("External editor was not found:" " %s\n" % editor_path)
def argv(self): """Command to start kernels""" # Python interpreter used to start kernels if CONF.get('main_interpreter', 'default'): pyexec = get_python_executable() else: # Avoid IPython adding the virtualenv on which Spyder is running # to the kernel sys.path os.environ.pop('VIRTUAL_ENV', None) pyexec = CONF.get('main_interpreter', 'executable') if not is_python_interpreter(pyexec): pyexec = get_python_executable() CONF.set('main_interpreter', 'executable', '') CONF.set('main_interpreter', 'default', True) CONF.set('main_interpreter', 'custom', False) # Fixes Issue #3427 if os.name == 'nt': dir_pyexec = osp.dirname(pyexec) pyexec_w = osp.join(dir_pyexec, 'pythonw.exe') if osp.isfile(pyexec_w): pyexec = pyexec_w # Command used to start kernels kernel_cmd = [ pyexec, '-m', 'spyder_kernels.console', '-f', '{connection_file}' ] return kernel_cmd
def set_font(font, section='appearance', option='font'): """Set font""" CONF.set(section, option+'/family', to_text_string(font.family())) CONF.set(section, option+'/size', float(font.pointSize())) CONF.set(section, option+'/italic', int(font.italic())) CONF.set(section, option+'/bold', int(font.bold())) FONT_CACHE[(section, option)] = font
def test_ignore_warnings(qtbot, lsp_codeeditor): """Test that the editor is ignoring some warnings.""" editor, manager = lsp_codeeditor # Set text in editor editor.set_text(TEXT) CONF.set('lsp-server', 'pydocstyle/ignore', 'D100') CONF.set('lsp-server', 'pycodestyle/ignore', 'E261') manager.update_server_list() qtbot.wait(2000) # Notify changes with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000): editor.document_did_change() # Get current warnings warnings = editor.get_current_warnings() expected = [['D103: Missing docstring in public function', 1], ['W293 blank line contains whitespace', 2], ["undefined name 's'", 5]] CONF.set('lsp-server', 'pydocstyle/ignore', '') CONF.set('lsp-server', 'pycodestyle/ignore', '') manager.update_server_list() qtbot.wait(2000) assert warnings == expected
def test_editor_docstring_below_def_by_shortcut(qtbot, editor_auto_docstring, text, expected): """Test auto docstring below function definition by shortcut.""" CONF.set('editor', 'docstring_type', 'Numpydoc') editor = editor_auto_docstring editor.set_text(text) cursor = editor.textCursor() cursor.movePosition(QTextCursor.NextBlock) cursor.setPosition(QTextCursor.End, QTextCursor.MoveAnchor) editor.setTextCursor(cursor) editor.writer_docstring.write_docstring_for_shortcut() assert editor.toPlainText() == expected
def test_editor_docstring_with_body_googledoc(qtbot, editor_auto_docstring, text, expected): """Test auto docstring of googledoc when the function body is complex.""" CONF.set('editor', 'docstring_type', 'Googledoc') editor = editor_auto_docstring editor.set_text(text) cursor = editor.textCursor() cursor.setPosition(0, QTextCursor.MoveAnchor) editor.setTextCursor(cursor) writer = editor.writer_docstring writer.write_docstring_for_shortcut() assert editor.toPlainText() == expected
def __init__(self, parent, history_filename, profile=False, initial_message=None, default_foreground_color=None, error_foreground_color=None, traceback_foreground_color=None, prompt_foreground_color=None, background_color=None): """ parent : specifies the parent widget """ ConsoleBaseWidget.__init__(self, parent) SaveHistoryMixin.__init__(self, history_filename) BrowseHistoryMixin.__init__(self) # Prompt position: tuple (line, index) self.current_prompt_pos = None self.new_input_line = True # History assert is_text_string(history_filename) self.history = self.load_history() # Session self.historylog_filename = CONF.get('main', 'historylog_filename', get_conf_path('history.log')) # Context menu self.menu = None self.setup_context_menu() # Simple profiling test self.profile = profile # Buffer to increase performance of write/flush operations self.__buffer = [] if initial_message: self.__buffer.append(initial_message) self.__timestamp = 0.0 self.__flushtimer = QTimer(self) self.__flushtimer.setSingleShot(True) self.__flushtimer.timeout.connect(self.flush) # Give focus to widget self.setFocus() # Cursor width self.setCursorWidth(CONF.get('main', 'cursor/width')) # Adjustments to completion_widget to use it here self.completion_widget.currentRowChanged.disconnect()
def _store_token(self, token, remember=False): """Store token for future use.""" if token and remember: try: keyring.set_password('github', 'token', token) except Exception: if self._show_msgbox: QMessageBox.warning(self.parent_widget, _('Failed to store token'), _('It was not possible to securely ' 'save your token. You will be ' 'prompted for your Github token ' 'next time you want to report ' 'an issue.')) remember = False CONF.set('main', 'report_error/remember_token', remember)
def _load_all_bookmarks(): """Load all bookmarks from config.""" slots = CONF.get('editor', 'bookmarks', {}) for slot_num in list(slots.keys()): if not osp.isfile(slots[slot_num][0]): slots.pop(slot_num) return slots
def update_server_list(self): for language in CONF.options(self.CONF_SECTION): config = {'status': self.STOPPED, 'config': self.get_option(language), 'instance': None} if language not in self.clients: self.clients[language] = config self.register_queue[language] = [] else: logger.debug( self.clients[language]['config'] != config['config']) current_config = self.clients[language]['config'] new_config = config['config'] configuration_diff = (current_config['configurations'] != new_config['configurations']) restart_diff = ['cmd', 'args', 'host', 'port', 'external'] restart = any([current_config[x] != new_config[x] for x in restart_diff]) if restart: if self.clients[language]['status'] == self.STOPPED: self.clients[language] = config elif self.clients[language]['status'] == self.RUNNING: self.close_client(language) self.clients[language] = config self.start_lsp_client(language) else: if configuration_diff: if self.clients[language]['status'] == self.RUNNING: client = self.clients[language]['instance'] client.send_plugin_configurations( new_config['configurations'])
def _create_bot(context, name): sequence = CONF.get('shortcuts', "{}/{}".format(context, name)) shortcut_editor = ShortcutEditor( shorcut_table, context, name, sequence, shortcuts) qtbot.addWidget(shortcut_editor) shortcut_editor.show() return shortcut_editor
def send_args_to_spyder(args): """ Simple socket client used to send the args passed to the Spyder executable to an already running instance. Args can be Python scripts or files with these extensions: .spydata, .mat, .npy, or .h5, which can be imported by the Variable Explorer. """ port = CONF.get('main', 'open_files_port') # Wait ~50 secs for the server to be up # Taken from https://stackoverflow.com/a/4766598/438386 for _x in range(200): try: for arg in args: client = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) client.connect(("127.0.0.1", port)) if is_unicode(arg): arg = arg.encode('utf-8') client.send(osp.abspath(arg)) client.close() except socket.error: time.sleep(0.25) continue break
def reset_to_default(self): """Restore initial values for default color schemes.""" # Checks that this is indeed a default scheme scheme = self.current_scheme names = self.get_option('names') if scheme in names: for key in syntaxhighlighters.COLOR_SCHEME_KEYS: option = "{0}/{1}".format(scheme, key) value = CONF.get_default(self.CONF_SECTION, option) self.set_option(option, value) self.load_from_conf()
def set_spyder_breakpoints(self): self.clear_all_breaks() #------Really deleting all breakpoints: for bp in bdb.Breakpoint.bpbynumber: if bp: bp.deleteMe() bdb.Breakpoint.next = 1 bdb.Breakpoint.bplist = {} bdb.Breakpoint.bpbynumber = [None] #------ from spyder.config.main import CONF CONF.load_from_ini() if CONF.get('run', 'breakpoints/enabled', True): breakpoints = CONF.get('run', 'breakpoints', {}) i = 0 for fname, data in list(breakpoints.items()): for linenumber, condition in data: i += 1 self.set_break(self.canonic(fname), linenumber, cond=condition)
def try_recover_from_autosave(self): """Offer to recover files from autosave.""" if not self.single_instance(): self.recover_files_to_open = [] return autosave_dir = get_conf_path('autosave') autosave_mapping = CONF.get('editor', 'autosave_mapping', {}) dialog = RecoveryDialog(autosave_dir, autosave_mapping, parent=self.editor) dialog.exec_if_nonempty() self.recover_files_to_open = dialog.files_to_open[:]
def __init__(self, parent): QObject.__init__(self) self.main = parent self.lsp_plugins = {} self.clients = {} self.requests = {} self.register_queue = {} # Get configurations for all LSP servers registered through # our Preferences self.configurations_for_servers = CONF.options('lsp-server') # Register languages to create clients for for language in self.configurations_for_servers: self.clients[language] = { 'status': self.STOPPED, 'config': CONF.get('lsp-server', language), 'instance': None } self.register_queue[language] = []
def save_historylog(self): """Save current history log (all text in console)""" title = _("Save history log") self.redirect_stdio.emit(False) filename, _selfilter = getsavefilename( self, title, self.historylog_filename, "%s (*.log)" % _("History logs")) self.redirect_stdio.emit(True) if filename: filename = osp.normpath(filename) try: encoding.write(to_text_string(self.get_text_with_eol()), filename) self.historylog_filename = filename CONF.set('main', 'historylog_filename', filename) except EnvironmentError as error: QMessageBox.critical( self, title, _("<b>Unable to save file '%s'</b>" "<br><br>Error message:<br>%s") % (osp.basename(filename), to_text_string(error)))
def main_window(request): """Main Window fixture""" # Tests assume inline backend CONF.set('ipython_console', 'pylab/backend', 0) # Check if we need to use introspection in a given test # (it's faster and less memory consuming not to use it!) use_introspection = request.node.get_marker('use_introspection') if use_introspection: os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True' else: try: os.environ.pop('SPY_TEST_USE_INTROSPECTION') except KeyError: pass # Only use single_instance mode for tests that require it single_instance = request.node.get_marker('single_instance') if single_instance: CONF.set('main', 'single_instance', True) else: CONF.set('main', 'single_instance', False) # Start the window window = start.main() # Teardown def close_window(): window.close() request.addfinalizer(close_window) return window
def test_runconfig_workdir(main_window, qtbot, tmpdir): """Test runconfig workdir options.""" CONF.set('run', 'configurations', []) # ---- Load test file ---- test_file = osp.join(LOCATION, 'script.py') main_window.editor.load(test_file) code_editor = main_window.editor.get_focus_widget() # --- Use cwd for this file --- rc = RunConfiguration().get() rc['file_dir'] = False rc['cw_dir'] = True config_entry = (test_file, rc) CONF.set('run', 'configurations', [config_entry]) # --- Run test file --- shell = main_window.ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) qtbot.keyClick(code_editor, Qt.Key_F5) qtbot.wait(500) # --- Assert we're in cwd after execution --- with qtbot.waitSignal(shell.executed): shell.execute('import os; current_dir = os.getcwd()') assert shell.get_value('current_dir') == get_home_dir() # --- Use fixed execution dir for test file --- temp_dir = str(tmpdir.mkdir("test_dir")) rc['file_dir'] = False rc['cw_dir'] = False rc['fixed_dir'] = True rc['dir'] = temp_dir config_entry = (test_file, rc) CONF.set('run', 'configurations', [config_entry]) # --- Run test file --- shell = main_window.ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) qtbot.keyClick(code_editor, Qt.Key_F5) qtbot.wait(500) # --- Assert we're in fixed dir after execution --- with qtbot.waitSignal(shell.executed): shell.execute('import os; current_dir = os.getcwd()') assert shell.get_value('current_dir') == temp_dir # ---- Closing test file and resetting config ---- main_window.editor.close_file() CONF.set('run', 'configurations', [])
def wrapper(qtbot_module, request): # Activate pycodestyle and pydocstyle CONF.set('lsp-server', 'pycodestyle', True) CONF.set('lsp-server', 'pydocstyle', True) CONF.set('lsp-server', 'stdio', is_stdio) # Create the manager os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True' manager = LanguageServerPlugin(parent=MainWindowMock()) # Wait for the client to be started editor = manager.main.editor with qtbot_module.waitSignal( editor.sig_lsp_initialized, timeout=30000): manager.start_client('python') settings = editor.lsp_editor_settings['python'] assert all( [option in SERVER_CAPABILITES for option in settings.keys()]) def teardown(): manager.shutdown() os.environ['SPY_TEST_USE_INTROSPECTION'] = 'False' CONF.set('lsp-server', 'pycodestyle', False) CONF.set('lsp-server', 'pydocstyle', False) request.addfinalizer(teardown) return manager
def ipyconsole(qtbot, request): """IPython console fixture.""" # Tests assume inline backend CONF.set('ipython_console', 'pylab/backend', 0) # Test the console with a non-ascii temp dir non_ascii_dir = request.node.get_marker('non_ascii_dir') if non_ascii_dir: test_dir = NON_ASCII_DIR else: test_dir = TEMPDIR # Instruct the console to not use a stderr file no_stderr_file = request.node.get_marker('no_stderr_file') if no_stderr_file: test_no_stderr = True else: test_no_stderr = False # Use the automatic backend if requested auto_backend = request.node.get_marker('auto_backend') if auto_backend: CONF.set('ipython_console', 'pylab/backend', 1) # Create the console and a new client console = IPythonConsole(parent=None, testing=True, test_dir=test_dir, test_no_stderr=test_no_stderr) console.create_new_client() # Close callback def close_console(): console.closing_plugin() console.close() request.addfinalizer(close_console) qtbot.addWidget(console) console.show() return console
def __init__(self, parent=None, namespace=None, commands=[], message=None, max_line_count=300, font=None, exitfunc=None, profile=False, multithreaded=True, light_background=True): PythonShellWidget.__init__(self, parent, get_conf_path('history_internal.py'), profile) self.set_light_background(light_background) self.multithreaded = multithreaded self.setMaximumBlockCount(max_line_count) if font is not None: self.set_font(font) # Allow raw_input support: self.input_loop = None self.input_mode = False # KeyboardInterrupt support self.interrupted = False # used only for not-multithreaded mode self.sig_keyboard_interrupt.connect(self.keyboard_interrupt) # Code completion / calltips getcfg = lambda option: CONF.get('internal_console', option) case_sensitive = getcfg('codecompletion/case_sensitive') self.set_codecompletion_case(case_sensitive) # keyboard events management self.eventqueue = [] # Init interpreter self.exitfunc = exitfunc self.commands = commands self.message = message self.interpreter = None self.start_interpreter(namespace) # Clear status bar self.status.emit('') # Embedded shell -- requires the monitor (which installs the # 'open_in_spyder' function in builtins) if hasattr(builtins, 'open_in_spyder'): self.go_to_error.connect(self.open_with_external_spyder)
def test_set_sequence_to_default(create_shortcut_editor, qtbot): """ Test that clicking on the button 'Default' set the sequence in the Shortcut Editor to the default value as espected. """ shortcut_editor = create_shortcut_editor('editor', 'delete line') default_sequence = CONF.get('shortcuts', "{}/{}".format('editor', 'delete line')) qtbot.mouseClick(shortcut_editor.button_default, Qt.LeftButton) assert shortcut_editor.new_sequence == default_sequence assert shortcut_editor.warning == NO_WARNING assert shortcut_editor.button_ok.isEnabled()
def __init__(self, parent): SpyderPluginWidget.__init__(self, parent) self.options_button.hide() self.lsp_plugins = {} self.clients = {} self.requests = {} self.register_queue = {} for option in CONF.options(self.CONF_SECTION): self.clients[option] = {'status': self.STOPPED, 'config': self.get_option(option), 'instance': None} self.register_queue[option] = []
def test_python_interpreter(tmpdir): """Test the validation of the python interpreter.""" # Set a non existing python interpreter interpreter = str(tmpdir.mkdir('interpreter').join('python')) CONF.set('main_interpreter', 'default', False) CONF.set('main_interpreter', 'custom', True) CONF.set('main_interpreter', 'executable', interpreter) # Create a kernel spec kernel_spec = SpyderKernelSpec() # Assert that the python interprerter is the default one assert interpreter not in kernel_spec.argv assert CONF.get('main_interpreter', 'default') assert not CONF.get('main_interpreter', 'custom')
def test_dedicated_consoles(main_window, qtbot): """Test running code in dedicated consoles.""" # ---- Load test file ---- test_file = osp.join(LOCATION, 'script.py') main_window.editor.load(test_file) code_editor = main_window.editor.get_focus_widget() # --- Set run options for this file --- rc = RunConfiguration().get() # A dedicated console is used when these two options are False rc['current'] = rc['systerm'] = False config_entry = (test_file, rc) CONF.set('run', 'configurations', [config_entry]) # --- Run test file and assert that we get a dedicated console --- qtbot.keyClick(code_editor, Qt.Key_F5) qtbot.wait(500) shell = main_window.ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) nsb = main_window.variableexplorer.get_focus_widget() assert len(main_window.ipyconsole.get_clients()) == 2 assert main_window.ipyconsole.filenames == ['', test_file] assert main_window.ipyconsole.tabwidget.tabText(1) == 'script.py/A' qtbot.wait(500) assert nsb.editor.model.rowCount() == 3 # --- Clean namespace after re-execution --- with qtbot.waitSignal(shell.executed): shell.execute('zz = -1') qtbot.keyClick(code_editor, Qt.Key_F5) qtbot.wait(500) assert not shell.is_defined('zz') # ---- Closing test file and resetting config ---- main_window.editor.close_file() CONF.set('run', 'configurations', [])
def set_spyder_breakpoints(self, force=False): """Set Spyder breakpoints into a debugging session""" if self._reading or force: breakpoints_dict = CONF.get('run', 'breakpoints', {}) # We need to enclose pickled values in a list to be able to # send them to the kernel in Python 2 serialiazed_breakpoints = [ pickle.dumps(breakpoints_dict, protocol=PICKLE_PROTOCOL) ] breakpoints = to_text_string(serialiazed_breakpoints) cmd = u"!get_ipython().kernel._set_spyder_breakpoints({})" self.kernel_client.input(cmd.format(breakpoints))
def create_new_client(self, filename=None, give_focus=True): """Create a new notebook or load a pre-existing one.""" # Generate the notebook name (in case of a new one) if not filename: if not osp.isdir(NOTEBOOK_TMPDIR): os.makedirs(NOTEBOOK_TMPDIR) nb_name = 'untitled' + str(self.untitled_num) + '.ipynb' filename = osp.join(NOTEBOOK_TMPDIR, nb_name) nb_contents = nbformat.v4.new_notebook() nbformat.write(nb_contents, filename) self.untitled_num += 1 # Save spyder_pythonpath before creating a client # because it's needed by our kernel spec. if not self.testing: CONF.set('main', 'spyder_pythonpath', self.main.get_spyder_pythonpath()) # Open the notebook with nbopen and get the url we need to render try: server_info = nbopen(filename) except (subprocess.CalledProcessError, NBServerError): QMessageBox.critical( self, _("Server error"), _("The Jupyter Notebook server failed to start or it is " "taking too much time to do it. Please start it in a " "system terminal with the command 'jupyter notebook' to " "check for errors.")) return client = NotebookClient(self, filename) self.add_tab(client) if NOTEBOOK_TMPDIR not in filename: self.add_to_recent(filename) self.setup_menu_actions() client.register(server_info) client.load_notebook()
def save_connection_settings(self): """Save user's kernel connection settings.""" if not self.save_layout.isChecked(): return is_ssh_key = bool(self.kf_radio.isChecked()) connection_settings = { "json_file_path": self.cf.text(), "is_remote": self.rm_group.isChecked(), "username": self.un.text(), "hostname": self.hn.text(), "port": self.pn.text(), "is_ssh_keyfile": is_ssh_key, "ssh_key_file_path": self.kf.text(), "cmd_jupyter_runtime": self.jupyter_runtime_location_cmd_lineedit.text() } CONF.set("existing-kernel", "settings", connection_settings) try: import keyring if is_ssh_key: keyring.set_password("spyder_remote_kernel", "ssh_key_passphrase", self.kfp.text()) else: keyring.set_password("spyder_remote_kernel", "ssh_password", self.pw.text()) except Exception: pass
def lsp_client(qtbot): config = CONF.get('lsp-server', 'python') lsp_editor = LSPEditor() lsp = LSPClient(None, config['args'], config, config['external'], plugin_configurations=config.get('configurations', {}), language='python') lsp.register_plugin_type(LSPEventTypes.DOCUMENT, lsp_editor.sig_lsp_notification) # qtbot.addWidget(lsp) yield lsp, lsp_editor if os.name != 'nt': lsp.stop()
def test_editor_docstring_delayed_popup(qtbot, editor_auto_docstring, text, expected, key): """Test auto docstring using delayed popup.""" CONF.set('editor', 'docstring_type', 'Numpydoc') editor = editor_auto_docstring editor.set_text(text) cursor = editor.textCursor() cursor.movePosition(QTextCursor.NextBlock) cursor.setPosition(QTextCursor.EndOfLine, QTextCursor.MoveAnchor) editor.setTextCursor(cursor) qtbot.keyPress(editor, Qt.Key_Space) qtbot.keyPress(editor, Qt.Key_Space) qtbot.keyPress(editor, Qt.Key_Space) qtbot.keyPress(editor, Qt.Key_Space) qtbot.keyPress(editor, Qt.Key_QuoteDbl) qtbot.keyPress(editor, Qt.Key_QuoteDbl) qtbot.keyPress(editor, Qt.Key_QuoteDbl) qtbot.wait(1000) qtbot.keyPress(editor.menu_docstring, key) qtbot.wait(1000) assert editor.toPlainText() == expected
def main_window(request): """Main Window fixture""" # Tests assume inline backend CONF.set('ipython_console', 'pylab/backend', 0) # Check if we need to use introspection in a given test # (it's faster and less memory consuming not to use it!) use_introspection = request.node.get_marker('use_introspection') if use_introspection: os.environ['SPY_TEST_USE_INTROSPECTION'] = 'True' else: try: os.environ.pop('SPY_TEST_USE_INTROSPECTION') except KeyError: pass # Start the window app = initialize() options, args = get_options() window = run_spyder(app, options, args) def close_window(): window.close() request.addfinalizer(close_window) return window
def __init__(self, main=None): """Bind widget to a QMainWindow instance.""" super(PluginWidget, self).__init__(main) assert self.CONF_SECTION is not None self.dockwidget = None self.undocked_window = None # Check compatibility check_compatibility, message = self.check_compatibility() if not check_compatibility: self.show_compatibility_message(message) self.PLUGIN_PATH = os.path.dirname(inspect.getfile(self.__class__)) self.main = main self.default_margins = None self.plugin_actions = None self.ismaximized = False self.isvisible = False # Options button and menu self.options_button = create_toolbutton(self, text=_('Options'), icon=ima.icon('tooloptions')) self.options_button.setPopupMode(QToolButton.InstantPopup) # Don't show menu arrow and remove padding if is_dark_interface(): self.options_button.setStyleSheet( ("QToolButton::menu-indicator{image: none;}\n" "QToolButton{padding: 3px;}")) else: self.options_button.setStyleSheet( "QToolButton::menu-indicator{image: none;}") self.options_menu = QMenu(self) # NOTE: Don't use the default option of CONF.get to assign a # None shortcut to plugins that don't have one. That will mess # the creation of our Keyboard Shortcuts prefs page try: self.shortcut = CONF.get('shortcuts', '_/switch to %s' % self.CONF_SECTION) except configparser.NoOptionError: pass # We decided to create our own toggle action instead of using # the one that comes with dockwidget because it's not possible # to raise and focus the plugin with it. self.toggle_view_action = None
def icon(name, resample=False, icon_path=None): theme = CONF.get('appearance', 'icon_theme') if theme == 'spyder 3': if not _resource['loaded']: qta.load_font('spyder', 'spyder.ttf', 'spyder-charmap.json', directory=_resource['directory']) _resource['loaded'] = True args, kwargs = _qtaargs[name] return qta.icon(*args, **kwargs) elif theme == 'spyder 2': icon = get_icon(name + '.png', resample=resample) if icon_path: icon_path = osp.join(icon_path, name + '.png') if osp.isfile(icon_path): icon = QIcon(icon_path) return icon if icon is not None else QIcon()
def set_color_scheme(name, color_scheme, replace=True): """Set syntax color scheme""" section = "color_schemes" names = CONF.get("color_schemes", "names", []) for key in sh.COLOR_SCHEME_KEYS: option = "%s/%s" % (name, key) value = CONF.get(section, option, default=None) if value is None or replace or name not in names: CONF.set(section, option, color_scheme[key]) names.append(to_text_string(name)) CONF.set(section, "names", sorted(list(set(names))))
def __init__(self, fname=None): self.args = None self.args_enabled = None self.wdir = None self.wdir_enabled = None self.current = None self.systerm = None self.interact = None self.post_mortem = None self.python_args = None self.python_args_enabled = None self.clear_namespace = None self.file_dir = None self.cw_dir = None self.fixed_dir = None self.dir = None self.set(CONF.get('run', 'defaultconfiguration', default={}))
def test_ignore_warnings(qtbot, lsp_codeeditor): """Test that the editor is ignoring some warnings.""" editor, manager = lsp_codeeditor # Set text in editor editor.set_text(TEXT) CONF.set('lsp-server', 'pydocstyle/ignore', 'D100') CONF.set('lsp-server', 'pycodestyle/ignore', 'E261') # After this call the manager needs to be reinitialized manager.update_server_list() if os.environ.get('CI', None) is None and sys.platform == 'darwin': # To be able to run local tests on mac this modification is needed editorstack = manager.main.editor with qtbot.waitSignal(editorstack.sig_lsp_initialized, timeout=30000): manager.start_client('python') with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000): editor.document_did_open() else: qtbot.wait(2000) # Notify changes with qtbot.waitSignal(editor.lsp_response_signal, timeout=30000): editor.document_did_change() # Get current warnings warnings = editor.get_current_warnings() expected = [['D103: Missing docstring in public function', 1], ['W293 blank line contains whitespace', 2], ["undefined name 's'", 5]] CONF.set('lsp-server', 'pydocstyle/ignore', '') CONF.set('lsp-server', 'pycodestyle/ignore', '') manager.update_server_list() qtbot.wait(2000) assert warnings == expected
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 load_connection_settings(self): """Load the user's previously-saved kernel connection settings.""" existing_kernel = CONF.get("existing-kernel", "settings", {}) connection_file_path = existing_kernel.get("json_file_path", "") is_remote = existing_kernel.get("is_remote", False) username = existing_kernel.get("username", "") hostname = existing_kernel.get("hostname", "") port = str(existing_kernel.get("port", 22)) is_ssh_kf = existing_kernel.get("is_ssh_keyfile", False) ssh_kf = existing_kernel.get("ssh_key_file_path", "") cmd_jupyter_runtime = existing_kernel.get("cmd_jupyter_runtime") if connection_file_path != "": self.cf.setText(connection_file_path) if username != "": self.un.setText(username) if hostname != "": self.hn.setText(hostname) if ssh_kf != "": self.kf.setText(ssh_kf) if cmd_jupyter_runtime != "": self.jupyter_runtime_location_cmd_lineedit.setText( cmd_jupyter_runtime) self.rm_group.setChecked(is_remote) self.pn.setText(port) self.kf_radio.setChecked(is_ssh_kf) self.pw_radio.setChecked(not is_ssh_kf) try: import keyring ssh_passphrase = keyring.get_password("spyder_remote_kernel", "ssh_key_passphrase") ssh_password = keyring.get_password("spyder_remote_kernel", "ssh_password") if ssh_passphrase: self.kfp.setText(ssh_passphrase) if ssh_password: self.pw.setText(ssh_password) except Exception: pass
def set(self, options): self.args = options.get('args', '') self.args_enabled = options.get('args/enabled', False) self.current = options.get('current', CONF.get('run', CURRENT_INTERPRETER_OPTION, True)) self.systerm = options.get('systerm', CONF.get('run', SYSTERM_INTERPRETER_OPTION, False)) self.interact = options.get('interact', CONF.get('run', 'interact', False)) self.post_mortem = options.get('post_mortem', CONF.get('run', 'post_mortem', False)) self.python_args = options.get('python_args', '') self.python_args_enabled = options.get('python_args/enabled', False) self.clear_namespace = options.get('clear_namespace', CONF.get('run', 'clear_namespace', False)) self.file_dir = options.get('file_dir', CONF.get('run', WDIR_USE_SCRIPT_DIR_OPTION, True)) self.cw_dir = options.get('cw_dir', CONF.get('run', WDIR_USE_CWD_DIR_OPTION, False)) self.fixed_dir = options.get('fixed_dir', CONF.get('run', WDIR_USE_FIXED_DIR_OPTION, False)) self.dir = options.get('dir', '')
def test_get_credentials_from_settings(): b = get_backend() username, remember_me, remember_token = b._get_credentials_from_settings() assert username == '' assert remember_me is False assert remember_token is False CONF.set('main', 'report_error/username', 'user') CONF.set('main', 'report_error/remember_me', True) CONF.set('main', 'report_error/remember_token', True) username, remember_me, remember_token = b._get_credentials_from_settings() assert username == 'user' assert remember_me is True assert remember_token is True
def test_console_coloring(ipyconsole, qtbot): config_options = ipyconsole.config_options() syntax_style = config_options.JupyterWidget.syntax_style style_sheet = config_options.JupyterWidget.style_sheet console_font_color = get_console_font_color(syntax_style) console_background_color = get_console_background_color(style_sheet) selected_color_scheme = CONF.get('color_schemes', 'selected') color_scheme = get_color_scheme(selected_color_scheme) editor_background_color = color_scheme['background'] editor_font_color = color_scheme['normal'][0] console_background_color = console_background_color.replace("'", "") editor_background_color = editor_background_color.replace("'", "") console_font_color = console_font_color.replace("'", "") editor_font_color = editor_font_color.replace("'", "") assert console_background_color.strip() == editor_background_color.strip() assert console_font_color.strip() == editor_font_color.strip()