Skip to content

Commit

Permalink
Merge branch '5.x' into issue-19003
Browse files Browse the repository at this point in the history
  • Loading branch information
ccordoba12 committed Aug 15, 2022
2 parents a79910e + 9d485f1 commit 9035b4e
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 99 deletions.
10 changes: 7 additions & 3 deletions spyder/api/config/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ def get_conf_default(self,
)
return CONF.get_default(section, option)

def get_shortcut(self, name: str, context: Optional[str] = None) -> str:
def get_shortcut(
self, name: str, context: Optional[str] = None,
plugin_name: Optional[str] = None) -> str:
"""
Get a shortcut sequence stored under the given name and context.
Expand All @@ -194,7 +196,9 @@ def get_shortcut(self, name: str, context: Optional[str] = None) -> str:
name: str
Key identifier under which the shortcut is stored.
context: Optional[str]
Name of the context (plugin) where the shortcut was defined.
Name of the shortcut context.
plugin: Optional[str]
Name of the plugin where the shortcut is defined.
Returns
-------
Expand All @@ -207,7 +211,7 @@ def get_shortcut(self, name: str, context: Optional[str] = None) -> str:
If the section does not exist in the configuration.
"""
context = self.CONF_SECTION if context is None else context
return CONF.get_shortcut(context, name)
return CONF.get_shortcut(context, name, plugin_name)

def config_shortcut(
self, action: QAction, name: str, parent: QWidget,
Expand Down
105 changes: 30 additions & 75 deletions spyder/app/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@
delete_debug_log_files, qt_message_handler, set_links_color, setup_logging,
set_opengl_implementation)
from spyder.api.plugin_registration.registry import PLUGIN_REGISTRY
from spyder.api.config.mixins import SpyderConfigurationAccessor
from spyder.config.base import (_, DEV, get_conf_path, get_debug_level,
get_home_dir, is_pynsist, running_in_mac_app,
running_under_pytest, STDERR)
from spyder.config.gui import is_dark_font_color
from spyder.config.main import OPEN_FILES_PORT
from spyder.config.manager import CONF
from spyder.config.utils import IMPORT_EXT, is_gtk_desktop
from spyder.config.user import NoDefault
from spyder.otherplugins import get_spyderplugins_mods
from spyder.py3compat import configparser as cp, PY3, to_text_string
from spyder.utils import encoding, programs
Expand Down Expand Up @@ -119,11 +119,14 @@
#==============================================================================
qInstallMessageHandler(qt_message_handler)


#==============================================================================
# Main Window
#==============================================================================
class MainWindow(QMainWindow):
class MainWindow(QMainWindow, SpyderConfigurationAccessor):
"""Spyder main window"""
CONF_SECTION = 'main'

DOCKOPTIONS = (
QMainWindow.AllowTabbedDocks | QMainWindow.AllowNestedDocks |
QMainWindow.AnimatedDocks
Expand Down Expand Up @@ -170,9 +173,6 @@ def __init__(self, splash=None, options=None):
# Save command line options for plugins to access them
self._cli_options = options

# To have an easy to access reference to CONF
self._conf = CONF

logger.info("Start of MainWindow constructor")

def signal_handler(signum, frame=None):
Expand Down Expand Up @@ -469,8 +469,8 @@ def register_plugin(self, plugin_name, external=False, omit_conf=False):
context = '_'
name = 'switch to {}'.format(plugin.CONF_SECTION)
shortcut = self.get_shortcut(
context,
name,
context,
plugin_name=plugin.CONF_SECTION
)
except (cp.NoSectionError, cp.NoOptionError):
Expand Down Expand Up @@ -522,8 +522,8 @@ def unregister_plugin(self, plugin):
context = '_'
name = 'switch to {}'.format(plugin.CONF_SECTION)
shortcut = self.get_shortcut(
context,
name,
context,
plugin_name=plugin.CONF_SECTION
)
except Exception:
Expand Down Expand Up @@ -714,7 +714,7 @@ def _update_shortcuts_in_panes_menu(self, show=True):
context = '_'
name = 'switch to {}'.format(section)
shortcut = self.get_shortcut(
context, name, plugin_name=section)
name, context, plugin_name=section)
except (cp.NoSectionError, cp.NoOptionError):
shortcut = QKeySequence()
else:
Expand All @@ -739,8 +739,8 @@ def setup(self):
self.update_python_path(path_dict)

logger.info("Applying theme configuration...")
ui_theme = self.get_conf(option='ui_theme', section='appearance')
color_scheme = self.get_conf(option='selected', section='appearance')
ui_theme = self.get_conf('ui_theme', section='appearance')
color_scheme = self.get_conf('selected', section='appearance')

if ui_theme == 'dark':
if not running_under_pytest():
Expand Down Expand Up @@ -819,9 +819,7 @@ def setup(self):
registry_external_plugins[plugin_name] = (
plugin_main_attribute_name, plugin)
try:
if self.get_conf(
option="enable",
section=plugin_main_attribute_name):
if self.get_conf("enable", section=plugin_main_attribute_name):
enabled_plugins[plugin_name] = plugin
PLUGIN_REGISTRY.set_plugin_enabled(plugin_name)
except (cp.NoOptionError, cp.NoSectionError):
Expand Down Expand Up @@ -1114,20 +1112,25 @@ def post_visible_setup(self):
Actions to be performed only after the main window's `show` method
is triggered.
"""
# Process pending events and hide splash before loading the
# previous session.
# This must be run before the main window is shown.
# Fixes spyder-ide/spyder#12104
self.layouts.on_mainwindow_visible()

# Process pending events and hide splash screen before moving forward.
QApplication.processEvents()
if self.splash is not None:
self.splash.hide()

# Call on_mainwindow_visible for all plugins.
# Call on_mainwindow_visible for all plugins, except Layout because it
# needs to be called first (see above).
for plugin_name in PLUGIN_REGISTRY:
plugin = PLUGIN_REGISTRY.get_plugin(plugin_name)
try:
plugin.on_mainwindow_visible()
QApplication.processEvents()
except AttributeError:
pass
if plugin_name != Plugins.Layout:
plugin = PLUGIN_REGISTRY.get_plugin(plugin_name)
try:
plugin.on_mainwindow_visible()
QApplication.processEvents()
except AttributeError:
pass

self.restore_scrollbar_position.emit()

Expand Down Expand Up @@ -1189,6 +1192,7 @@ def reopen_last_session(self):
reopen_last_session = True

if editor and reopen_last_session:
logger.info("Restoring opened files from the previous session")
editor.setup_open_files(close_previous_files=False)

def restore_undocked_plugins(self):
Expand Down Expand Up @@ -1314,57 +1318,6 @@ def hideEvent(self, event):
except RuntimeError:
QMainWindow.hideEvent(self, event)

# ---- Configuration
# -------------------------------------------------------------------------
def get_conf(self, option, section='main', default=NoDefault):
"""
Get an option from the Spyder configuration system.
Parameters
----------
option: str
Name of the option to get its value from.
section: str, optional
Section in the configuration system, e.g. `shortcuts`. The default
is 'main'.
default: Optional
Fallback value to return if the option is not found on the
configuration system.
"""
return self._conf.get(section, option, default)

def set_conf(self, option, value, section='main'):
"""
Set an option in the Spyder configuration system.
Parameters
----------
option: str
Name of the option to set its value.
value:
Value to set on the configuration system.
section: str, optional
Section in the configuration system, e.g. `shortcuts`. The default
is 'main'.
"""
return self._conf.set(section, option, value)

def get_shortcut(self, context, name, plugin_name=None):
"""
Get a shortcut from the Spyder configuration system.
Parameters
----------
context: str
Context where the shortcut applies. It can be either '_' for global
shortcuts or a specific context.
name: str
Name of the shortcut in the configutration system.
plugin_name: str, optional
Name of the plugin to which the shortcut is associated.
"""
return self._conf.get_shortcut(context, name, plugin_name)

# ---- Other
# -------------------------------------------------------------------------
def update_source_menu(self):
Expand Down Expand Up @@ -1542,6 +1495,8 @@ def closing(self, cancelable=False, close_immediately=False):
if self.already_closed or self.is_starting_up:
return True

self.layouts.save_visible_plugins()

self.plugin_registry = PLUGIN_REGISTRY

if cancelable and self.get_conf('prompt_on_exit'):
Expand Down Expand Up @@ -1628,11 +1583,11 @@ def open_external_console(self, fname, wdir, args, interact, debug, python,
if systerm:
# Running script in an external system terminal
try:
if self.get_conf(option='default', section='main_interpreter'):
if self.get_conf('default', section='main_interpreter'):
executable = get_python_executable()
else:
executable = self.get_conf(
option='executable',
'executable',
section='main_interpreter'
)
pypath = self.get_conf('spyder_pythonpath', default=None)
Expand Down
41 changes: 41 additions & 0 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5376,6 +5376,47 @@ def test_out_runfile_runcell(main_window, qtbot):
assert not "]: " + str(num) in control.toPlainText()


@pytest.mark.slow
def test_visible_plugins(main_window, qtbot):
"""
Test that saving and restoring visible plugins works as expected.
"""
# Wait until the window is fully up
shell = main_window.ipyconsole.get_current_shellwidget()
qtbot.waitUntil(
lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT)

# Load default layout
main_window.layouts.quick_layout_switch(DefaultLayouts.SpyderLayout)

# Make some non-default plugins visible
selected = [Plugins.Plots, Plugins.History]
for plugin_name in selected:
main_window.get_plugin(plugin_name).dockwidget.raise_()

# Save visible plugins
main_window.layouts.save_visible_plugins()

# Change visible plugins
for plugin_name in [Plugins.VariableExplorer, Plugins.IPythonConsole]:
main_window.get_plugin(plugin_name).dockwidget.raise_()

# Make sure plugins to test are not visible
for plugin_name in selected:
assert not main_window.get_plugin(plugin_name).get_widget().is_visible

# Restore saved visible plugins
main_window.layouts.restore_visible_plugins()

# Assert visible plugins are the expected ones
visible_plugins = []
for plugin_name, plugin in main_window.get_dockable_plugins():
if plugin_name != Plugins.Editor and plugin.get_widget().is_visible:
visible_plugins.append(plugin_name)

assert set(selected) == set(visible_plugins)


@pytest.mark.slow
def test_cwd_is_synced_when_switching_consoles(main_window, qtbot, tmpdir):
"""
Expand Down
6 changes: 0 additions & 6 deletions spyder/plugins/help/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,6 @@ def apply_conf(self, options_set, notify=False):
except SpyderAPIError:
pass

def on_mainwindow_visible(self):
# Raise plugin the first time Spyder starts
if self.get_conf('show_first_time', default=True):
self.dockwidget.raise_()
self.set_conf('show_first_time', False)

# --- Private API
# ------------------------------------------------------------------------
def _setup_menus(self):
Expand Down
5 changes: 0 additions & 5 deletions spyder/plugins/ipythonconsole/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,11 +395,6 @@ def on_close(self, cancelable=False):
def on_mainwindow_visible(self):
self.create_new_client(give_focus=False)

# Raise plugin the first time Spyder starts
if self.get_conf('show_first_time', default=True):
self.dockwidget.raise_()
self.set_conf('show_first_time', False)

# ---- Private methods
# -------------------------------------------------------------------------
def _load_file_in_editor(self, fname, lineno, word, processevents):
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/ipythonconsole/widgets/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def __init__(self, *args, **kwargs):
self._pdb_prompt = (None, None) # prompt, password
self._pdb_last_cmd = '' # last command sent to pdb
self._pdb_frame_loc = (None, None) # fname, lineno
self._pdb_focus_to_editor = True # Focus to editor after command
self._pdb_focus_to_editor = False # Focus to editor after command
# execution
# Command queue
self._pdb_input_queue = [] # List of (code, hidden, echo_stack_entry)
Expand Down
5 changes: 4 additions & 1 deletion spyder/plugins/ipythonconsole/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2173,7 +2173,10 @@ def pdb_has_stopped(self, fname, lineno, shellwidget):
fname, lineno, '', False)

# Give focus to console if requested
if not shellwidget._pdb_focus_to_editor:
if shellwidget._pdb_focus_to_editor:
# Next focus to editor was enabled
shellwidget._pdb_focus_to_editor = False
else:
self.activateWindow()
shellwidget._control.setFocus()

Expand Down
Loading

0 comments on commit 9035b4e

Please sign in to comment.