Skip to content

Commit

Permalink
Make QtWebEngine optional through lazy loading
Browse files Browse the repository at this point in the history
  • Loading branch information
hmaarrfk committed Jul 8, 2024
1 parent 98cc43e commit dbcf9df
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 16 deletions.
7 changes: 7 additions & 0 deletions spyder/api/plugins/new_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ class SpyderPluginV2(QObject, SpyderActionMixin, SpyderConfigurationObserver,
# disabled. Default: True
CAN_BE_DISABLED = True

# Qt Web Widgets may be a heavy dependency for many packagers
# (e.g. conda-forge)
# We thus ask plugins to declare whether or not they need
# web widgets to enhance the distribution of Spyder to users
# https://github.com/spyder-ide/spyder/pull/22196#issuecomment-2189377043
REQUIRE_WEB_WIDGETS = False

# --- API: Signals -------------------------------------------------------
# ------------------------------------------------------------------------
# Signals here are automatically connected by the Spyder main window and
Expand Down
23 changes: 16 additions & 7 deletions spyder/app/mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@
from qtpy import QtSvg # analysis:ignore

# Avoid a bug in Qt: https://bugreports.qt.io/browse/QTBUG-46720
from qtpy import QtWebEngineWidgets # analysis:ignore
try:
from qtpy.QtWebEngineWidgets import WEBENGINE
except ImportError:
WEBENGINE = False

from qtawesome.iconic_font import FontError

Expand Down Expand Up @@ -759,12 +762,6 @@ def setup(self):
registry_external_plugins = {}
for plugin in all_plugins.values():
plugin_name = plugin.NAME
# Disable panes that use web widgets (currently Help and Online
# Help) if the user asks for it.
# See spyder-ide/spyder#16518
if self._cli_options.no_web_widgets:
if "help" in plugin_name:
continue
plugin_main_attribute_name = (
self._INTERNAL_PLUGINS_MAPPING[plugin_name]
if plugin_name in self._INTERNAL_PLUGINS_MAPPING
Expand All @@ -791,6 +788,18 @@ def setup(self):
if plugin_name in enabled_plugins:
PluginClass = internal_plugins[plugin_name]
if issubclass(PluginClass, SpyderPluginV2):
# Disable plugins that use web widgets (currently Help and
# Online Help) if the user asks for it.
# See spyder-ide/spyder#16518
# The plugins that require QtWebengine must declare
# themselves as needing that dependency
# https://github.com/spyder-ide/spyder/pull/22196#issuecomment-2189377043
if PluginClass.REQUIRE_WEB_WIDGETS and (
not WEBENGINE or
self._cli_options.no_web_widgets
):
continue

PLUGIN_REGISTRY.register_plugin(self, PluginClass,
external=False)

Expand Down
1 change: 1 addition & 0 deletions spyder/plugins/help/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Help(SpyderDockablePlugin):
LOG_PATH = get_conf_path(CONF_SECTION)
FONT_SIZE_DELTA = DEFAULT_SMALL_DELTA
DISABLE_ACTIONS_WHEN_HIDDEN = False
REQUIRE_WEB_WIDGETS = True

# Signals
sig_focus_changed = Signal() # TODO: What triggers this?
Expand Down
13 changes: 10 additions & 3 deletions spyder/plugins/help/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
from qtpy import PYQT5
from qtpy.QtCore import Qt, QUrl, Signal, Slot, QPoint
from qtpy.QtGui import QColor
from qtpy.QtWebEngineWidgets import WEBENGINE, QWebEnginePage
from qtpy.QtWidgets import (QActionGroup, QComboBox, QLabel, QLineEdit,
QMessageBox, QSizePolicy, QStackedLayout,
QMessageBox, QSizePolicy, QStackedWidget,
QVBoxLayout, QWidget)

# Local imports
Expand All @@ -36,11 +35,16 @@
from spyder.utils.image_path_manager import get_image_path
from spyder.utils.palette import QStylePalette
from spyder.utils.qthelpers import start_file
from spyder.widgets.browser import FrameWebView
from spyder.widgets.comboboxes import EditableComboBox
from spyder.widgets.findreplace import FindReplace
from spyder.widgets.simplecodeeditor import SimpleCodeEditor

# In case WebEngine is not available (e.g. in Conda-forge)
try:
from qtpy.QtWebEngineWidgets import WEBENGINE
except ImportError:
WEBENGINE = False


# --- Constants
# ----------------------------------------------------------------------------
Expand Down Expand Up @@ -157,6 +161,9 @@ def __init__(self, parent):
QWidget.__init__(self, parent)
SpyderWidgetMixin.__init__(self, class_parent=parent)

from qtpy.QtWebEngineWidgets import QWebEnginePage
from spyder.widgets.browser import FrameWebView

self.webview = FrameWebView(self)
self.webview.setup()

Expand Down
15 changes: 11 additions & 4 deletions spyder/plugins/ipythonconsole/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
import qstylizer.style
from qtconsole.client import QtKernelClient
from qtpy.QtCore import Signal, Slot
from qtpy.QtGui import QColor
from qtpy.QtWebEngineWidgets import WEBENGINE
from qtpy.QtGui import QColor, QKeySequence
from qtpy.QtPrintSupport import QPrintDialog, QPrinter
from qtpy.QtWidgets import (
QApplication, QHBoxLayout, QLabel, QMessageBox, QVBoxLayout, QWidget)
from traitlets.config.loader import Config, load_pyconfig_files
Expand All @@ -46,11 +46,16 @@
from spyder.utils import encoding, programs, sourcecode
from spyder.utils.misc import get_error_match, remove_backslashes
from spyder.utils.palette import QStylePalette
from spyder.widgets.browser import FrameWebView
from spyder.widgets.findreplace import FindReplace
from spyder.widgets.tabs import Tabs
from spyder.plugins.ipythonconsole.utils.stdfile import StdFile

# In case WebEngine is not available (e.g. in Conda-forge)
try:
from qtpy.QtWebEngineWidgets import WEBENGINE
except ImportError:
WEBENGINE = False


# Logging
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -308,7 +313,7 @@ def __init__(self, name=None, plugin=None, parent=None):
self.enable_infowidget = True
if plugin:
cli_options = plugin.get_command_line_options()
if cli_options.no_web_widgets:
if cli_options.no_web_widgets or not WEBENGINE:
self.enable_infowidget = False

# Attrs for testing
Expand Down Expand Up @@ -351,6 +356,8 @@ def __init__(self, name=None, plugin=None, parent=None):

# Info widget
if self.enable_infowidget:
from spyder.widgets.browser import FrameWebView

self.infowidget = FrameWebView(self)
if WEBENGINE:
self.infowidget.page().setBackgroundColor(
Expand Down
1 change: 1 addition & 0 deletions spyder/plugins/onlinehelp/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class OnlineHelp(SpyderDockablePlugin):
CONF_FILE = False
WIDGET_CLASS = PydocBrowser
LOG_PATH = get_conf_path(NAME)
REQUIRE_WEB_WIDGETS = True

# --- Signals
# ------------------------------------------------------------------------
Expand Down
16 changes: 14 additions & 2 deletions spyder/plugins/onlinehelp/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@
# Third party imports
from qtpy.QtCore import Qt, QThread, QUrl, Signal, Slot
from qtpy.QtGui import QCursor
from qtpy.QtWebEngineWidgets import WEBENGINE
from qtpy.QtWidgets import QApplication, QLabel, QVBoxLayout

# Local imports
from spyder.api.translations import _
from spyder.api.widgets.main_widget import PluginMainWidget
from spyder.plugins.onlinehelp.pydoc_patch import _start_server, _url_handler
from spyder.widgets.browser import FrameWebView, WebViewActions
from spyder.widgets.comboboxes import UrlComboBox
from spyder.widgets.findreplace import FindReplace

# In case WebEngine is not available (e.g. in Conda-forge)
try:
from qtpy.QtWebEngineWidgets import WEBENGINE
except ImportError:
WEBENGINE = False


# --- Constants
# ----------------------------------------------------------------------------
Expand Down Expand Up @@ -139,6 +143,8 @@ class PydocBrowser(PluginMainWidget):
"""

def __init__(self, name=None, plugin=None, parent=None):
from spyder.widgets.browser import FrameWebView

super().__init__(name, plugin, parent=parent)

self._is_running = False
Expand Down Expand Up @@ -194,6 +200,8 @@ def get_focus_widget(self):
return self.url_combo

def setup(self):
from spyder.widgets.browser import WebViewActions

# Actions
home_action = self.create_action(
PydocBrowserActions.Home,
Expand Down Expand Up @@ -244,6 +252,8 @@ def setup(self):
self.sig_toggle_view_changed.connect(self.initialize)

def update_actions(self):
from spyder.widgets.browser import WebViewActions

stop_action = self.get_action(WebViewActions.Stop)
refresh_action = self.get_action(WebViewActions.Refresh)

Expand Down Expand Up @@ -272,6 +282,8 @@ def _continue_initialization(self):

def _handle_url_combo_activation(self):
"""Load URL from combo box first item."""
from spyder.widgets.browser import WebViewActions

if not self._is_running:
text = str(self.url_combo.currentText())
self.go_to(self.text_to_url(text))
Expand Down

0 comments on commit dbcf9df

Please sign in to comment.