Skip to content

Commit

Permalink
Merge pull request #15000 from steff456/migrate-projects
Browse files Browse the repository at this point in the history
PR: Migrate projects to the new API
  • Loading branch information
ccordoba12 committed Jun 26, 2021
2 parents 277312b + 84871b8 commit b973951
Show file tree
Hide file tree
Showing 21 changed files with 614 additions and 518 deletions.
2 changes: 1 addition & 1 deletion spyder/api/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

"""Spyder API Version."""

VERSION_INFO = (0, 2, 0)
VERSION_INFO = (0, 3, 0)
__version__ = '.'.join(map(str, VERSION_INFO))
5 changes: 5 additions & 0 deletions spyder/api/config/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,11 @@ def config_shortcut(
shortcut_context = self.CONF_SECTION if context is None else context
return CONF.config_shortcut(action, shortcut_context, name, parent)

@property
def old_conf_version(self):
"""Get old Spyder configuration version."""
return CONF.old_spyder_version


class SpyderConfigurationObserver(SpyderConfigurationAccessor):
"""
Expand Down
1 change: 0 additions & 1 deletion spyder/api/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,6 @@ def get_conf(self, option, default=NoDefault, section=None):
'A spyder plugin must define a `CONF_SECTION` class '
'attribute!'
)

return self._conf.get(section, option, default)

@Slot(str, object)
Expand Down
3 changes: 1 addition & 2 deletions spyder/api/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -872,8 +872,7 @@ def setup(self):
Create widget actions, add to menu and other setup requirements.
"""
raise NotImplementedError(
'A PluginMainWidget subclass must define a `setup` '
'method!')
f'{type(self)} must define a `setup` method!')

def update_actions(self):
"""
Expand Down
39 changes: 8 additions & 31 deletions spyder/app/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -617,8 +617,6 @@ def signal_handler(signum, frame=None):
self.run_menu_actions = []
self.debug_menu = None
self.debug_menu_actions = []
self.projects_menu = None
self.projects_menu_actions = []

# TODO: Move to corresponding Plugins
self.main_toolbar = None
Expand Down Expand Up @@ -858,8 +856,7 @@ def setup(self):
# Non-migrated plugins
if plugin_name in [
Plugins.Editor,
Plugins.IPythonConsole,
Plugins.Projects]:
Plugins.IPythonConsole]:
if plugin_name == Plugins.IPythonConsole:
plugin_instance = plugin_class(self)
plugin_instance.sig_exception_occurred.connect(
Expand All @@ -868,12 +865,8 @@ def setup(self):
plugin_instance = plugin_class(self)
plugin_instance.register_plugin()
self.add_plugin(plugin_instance)
if plugin_name == Plugins.Projects:
self.project_path = plugin_instance.get_pythonpath(
at_start=True)
else:
self.preferences.register_plugin_preferences(
plugin_instance)
self.preferences.register_plugin_preferences(
plugin_instance)
# Migrated or new plugins
elif plugin_name in [
Plugins.MainMenu,
Expand All @@ -899,6 +892,7 @@ def setup(self):
Plugins.Find,
Plugins.Pylint,
Plugins.WorkingDirectory,
Plugins.Projects,
Plugins.Layout]:
plugin_instance = plugin_class(self, configuration=CONF)
self.register_plugin(plugin_instance)
Expand Down Expand Up @@ -985,8 +979,6 @@ def setup(self):
self.source_menu.aboutToShow.connect(self.update_source_menu)
self.run_menu = mainmenu.get_application_menu("run_menu")
self.debug_menu = mainmenu.get_application_menu("debug_menu")
self.projects_menu = mainmenu.get_application_menu("projects_menu")
self.projects_menu.aboutToShow.connect(self.valid_project)

# Switcher shortcuts
self.file_switcher_action = create_action(
Expand Down Expand Up @@ -1136,7 +1128,6 @@ def create_edit_action(text, tr_text, icon):
add_actions(self.source_menu, self.source_menu_actions)
add_actions(self.run_menu, self.run_menu_actions)
add_actions(self.debug_menu, self.debug_menu_actions)
add_actions(self.projects_menu, self.projects_menu_actions)

# Emitting the signal notifying plugins that main window menu and
# toolbar actions are all defined:
Expand Down Expand Up @@ -1279,6 +1270,8 @@ def post_visible_setup(self):
if self.splash is not None:
self.splash.hide()

# TODO: Remove this reference to projects once we can send the command
# line options to the plugins.
if self.open_project:
if not running_in_mac_app():
self.projects.open_project(
Expand Down Expand Up @@ -1396,6 +1389,8 @@ def set_window_title(self):
if self.window_title is not None:
title += u' -- ' + to_text_string(self.window_title)

# TODO: Remove self.projects reference once there's an API for setting
# window title.
if self.projects is not None:
path = self.projects.get_active_project_path()
if path:
Expand All @@ -1418,24 +1413,6 @@ def register_shortcut(self, qaction_or_qshortcut, context, name,
)

# --- Other
def valid_project(self):
"""Handle an invalid active project."""
try:
path = self.projects.get_active_project_path()
except AttributeError:
return

if bool(path):
if not self.projects.is_valid_project(path):
if path:
QMessageBox.critical(
self,
_('Error'),
_("<b>{}</b> is no longer a valid Spyder project! "
"Since it is the current active project, it will "
"be closed automatically.").format(path))
self.projects.close_project()

def update_source_menu(self):
"""Update source menu options that vary dynamically."""
# This is necessary to avoid an error at startup.
Expand Down
4 changes: 2 additions & 2 deletions spyder/app/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ def find_internal_plugins():
try:
mod = importlib.import_module(module)
internal_plugins[name] = getattr(mod, class_name, None)
except (ModuleNotFoundError, ImportError):
pass
except (ModuleNotFoundError, ImportError) as e:
raise e
else:
import spyder.plugins as plugin_mod

Expand Down
21 changes: 13 additions & 8 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,7 @@ def test_run_cython_code(main_window, qtbot):
def test_open_notebooks_from_project_explorer(main_window, qtbot, tmpdir):
"""Test that notebooks are open from the Project explorer."""
projects = main_window.projects
projects.toggle_view_action.setChecked(True)
editorstack = main_window.editor.get_current_editorstack()

# Create a temp project directory
Expand All @@ -1153,17 +1154,19 @@ def test_open_notebooks_from_project_explorer(main_window, qtbot, tmpdir):
projects._create_project(project_dir)

# Select notebook in the project explorer
idx = projects.explorer.treewidget.get_index('notebook.ipynb')
projects.explorer.treewidget.setCurrentIndex(idx)
idx = projects.get_widget().treewidget.get_index(
osp.join(project_dir, 'notebook.ipynb'))
projects.get_widget().treewidget.setCurrentIndex(idx)

# Prese Enter there
qtbot.keyClick(projects.explorer.treewidget, Qt.Key_Enter)
qtbot.keyClick(projects.get_widget().treewidget, Qt.Key_Enter)

# Assert that notebook was open
assert 'notebook.ipynb' in editorstack.get_current_filename()

# Convert notebook to a Python file
projects.explorer.treewidget.convert_notebook(osp.join(project_dir, 'notebook.ipynb'))
projects.get_widget().treewidget.convert_notebook(
osp.join(project_dir, 'notebook.ipynb'))

# Assert notebook was open
assert 'untitled' in editorstack.get_current_filename()
Expand All @@ -1186,6 +1189,7 @@ def test_open_notebooks_from_project_explorer(main_window, qtbot, tmpdir):
def test_runfile_from_project_explorer(main_window, qtbot, tmpdir):
"""Test that file are run from the Project explorer."""
projects = main_window.projects
projects.toggle_view_action.setChecked(True)
editorstack = main_window.editor.get_current_editorstack()

# Create a temp project directory
Expand All @@ -1200,17 +1204,18 @@ def test_runfile_from_project_explorer(main_window, qtbot, tmpdir):
projects._create_project(project_dir)

# Select file in the project explorer
idx = projects.explorer.treewidget.get_index('script.py')
projects.explorer.treewidget.setCurrentIndex(idx)
idx = projects.get_widget().treewidget.get_index(
osp.join(project_dir, 'script.py'))
projects.get_widget().treewidget.setCurrentIndex(idx)

# Press Enter there
qtbot.keyClick(projects.explorer.treewidget, Qt.Key_Enter)
qtbot.keyClick(projects.get_widget().treewidget, Qt.Key_Enter)

# Assert that the file was open
assert 'script.py' in editorstack.get_current_filename()

# Run Python file
projects.explorer.treewidget.run([osp.join(project_dir, 'script.py')])
projects.get_widget().treewidget.run([osp.join(project_dir, 'script.py')])

# Wait until the new console is fully up
shell = main_window.ipyconsole.get_current_shellwidget()
Expand Down
1 change: 1 addition & 0 deletions spyder/config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@
'max_recent_projects': 10,
'visible_if_project_open': True,
'date_column': False,
'single_click_to_open': False,
}),
('explorer',
{
Expand Down
8 changes: 6 additions & 2 deletions spyder/config/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ def __init__(self, parent=None, active_project_callback=None):
remove_obsolete=False,
)

# This is useful to know in order to execute certain operations when
# bumping CONF_VERSION
self.old_spyder_version = (
self._user_config._configs_map['spyder']._old_version)

# Store plugin configurations when CONF_FILE = True
self._plugin_configs = {}

Expand Down Expand Up @@ -137,8 +142,7 @@ def register_plugin(self, plugin_class):

# Recreate external plugin configs to deal with part two
# (the shortcut conflicts) of spyder-ide/spyder#11132
spyder_config = self._user_config._configs_map['spyder']
if check_version(spyder_config._old_version, '54.0.0', '<'):
if check_version(self.old_spyder_version, '54.0.0', '<'):
# Remove all previous .ini files
try:
plugin_config.cleanup()
Expand Down
6 changes: 3 additions & 3 deletions spyder/plugins/explorer/widgets/tests/test_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
QInputDialog, QMessageBox, QTextEdit)

# Local imports
from spyder.plugins.explorer.widgets.main_widget import (
FileExplorerTest, ProjectExplorerTest)
from spyder.plugins.projects.widgets.explorer import (
from spyder.plugins.explorer.widgets.main_widget import FileExplorerTest
from spyder.plugins.projects.widgets.main_widget import ProjectExplorerTest
from spyder.plugins.projects.widgets.main_widget import (
ProjectExplorerTest as ProjectExplorerTest2)


Expand Down
20 changes: 18 additions & 2 deletions spyder/plugins/layout/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,30 @@
ApplicationToolbars, MainToolbarSections)
from spyder.py3compat import qbytearray_to_str # FIXME:


# Localization
_ = get_translation("spyder")

# Constants

# Number of default layouts available
DEFAULT_LAYOUTS = get_class_values(DefaultLayouts)
# Version passed to saveState/restoreState
WINDOW_STATE_VERSION = 1

# ----------------------------------------------------------------------------
# ---- Window state version passed to saveState/restoreState.
# ----------------------------------------------------------------------------
# This defines the layout version used by different Spyder releases. In case
# there's a need to reset the layout when moving from one release to another,
# please increase the number below in integer steps, e.g. from 1 to 2, and
# leave a mention below explaining what prompted the change.
#
# The current versions are:
#
# * Spyder 4: Version 0 (it was the default).
# * Spyder 5.0.0 to 5.0.5: Version 1 (a bump was required due to the new API).
# * Spyder 5.1.0: Version 2 (a bump was required due to the migration of
# Projects to the new API).
WINDOW_STATE_VERSION = 2


class Layout(SpyderPluginV2):
Expand Down
6 changes: 1 addition & 5 deletions spyder/plugins/mainmenu/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ def register(self):
create_app_menu(ApplicationMenus.Run, _("&Run"), dynamic=False)
create_app_menu(ApplicationMenus.Debug, _("&Debug"), dynamic=False)
create_app_menu(ApplicationMenus.Consoles, _("C&onsoles"))
create_app_menu(
ApplicationMenus.Projects, _("&Projects"), dynamic=False)
create_app_menu(ApplicationMenus.Projects, _("&Projects"))
create_app_menu(ApplicationMenus.Tools, _("&Tools"))
create_app_menu(ApplicationMenus.View, _("&View"))
create_app_menu(ApplicationMenus.Help, _("&Help"))
Expand Down Expand Up @@ -159,8 +158,6 @@ def create_application_menu(self, menu_id, title, dynamic=True):

menu = ApplicationMenu(self.main, title, dynamic=dynamic)
menu.menu_id = menu_id
if menu_id == ApplicationMenus.Projects:
menu.setObjectName('checkbox-padding')

self._APPLICATION_MENUS[menu_id] = menu
self.main.menuBar().addMenu(menu)
Expand Down Expand Up @@ -223,7 +220,6 @@ def add_item_to_application_menu(self, item, menu=None, menu_id=None,
ApplicationMenus.Source: self._main.source_menu_actions,
ApplicationMenus.Run: self._main.run_menu_actions,
ApplicationMenus.Debug: self._main.debug_menu_actions,
ApplicationMenus.Projects: self._main.projects_menu_actions,
}

menu_id = menu_id if menu_id else menu.menu_id
Expand Down
1 change: 0 additions & 1 deletion spyder/plugins/projects/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def __init__(self, root_path, parent_plugin=None):
self.root_path = root_path
self.open_project_files = []
self.open_non_project_files = []

path = os.path.join(root_path, get_project_config_folder(), 'config')
self.config = ProjectMultiConfig(
PROJECT_NAME_MAP,
Expand Down
8 changes: 0 additions & 8 deletions spyder/plugins/projects/confpage.py

This file was deleted.

Loading

0 comments on commit b973951

Please sign in to comment.