def test_importlib(self, qt, qt5, expected, patch_elf_fail, importlib_patcher): """Test the importlib version logic with different Qt packages. With PyQtWebEngine 5.15.4, PyQtWebEngine-Qt was renamed to PyQtWebEngine-Qt5. """ importlib_patcher(qt=qt, qt5=qt5) versions = version.qtwebengine_versions(avoid_init=True) assert versions.source == 'importlib' assert versions.webengine == expected
def handle_download(self, qt_item): """Start a download coming from a QWebEngineProfile.""" qt_filename = os.path.basename(qt_item.path()) # FIXME use 5.14 API mime_type = qt_item.mimeType() url = qt_item.url() # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-90355 if version.qtwebengine_versions().webengine >= utils.VersionNumber( 5, 15, 3): needs_workaround = False elif url.scheme().lower() == 'data': if '/' in url.path().split(',')[-1]: # e.g. a slash in base64 wrong_filename = url.path().split('/')[-1] else: wrong_filename = mime_type.split('/')[1] needs_workaround = qt_filename == wrong_filename else: needs_workaround = False if needs_workaround: suggested_filename = urlutils.filename_from_url( url, fallback='qutebrowser-download') else: suggested_filename = _strip_suffix(qt_filename) use_pdfjs = pdfjs.should_use_pdfjs(mime_type, url) download = DownloadItem(qt_item, manager=self) self._init_item(download, auto_remove=use_pdfjs, suggested_filename=suggested_filename) if self._mhtml_target is not None: download.set_target(self._mhtml_target) self._mhtml_target = None return if use_pdfjs: download.set_target(downloads.PDFJSDownloadTarget()) return filename = downloads.immediate_download_path() if filename is not None: # User doesn't want to be asked, so just use the download_dir target = downloads.FileDownloadTarget(filename) download.set_target(target) return # Ask the user for a filename - needs to be blocking! question = downloads.get_filename_question( suggested_filename=suggested_filename, url=qt_item.url(), parent=self) self._init_filename_question(question, download) message.global_bridge.ask(question, blocking=True)
def _qtwe_version_str(self) -> str: """Get the QtWebEngine version string. Note that it's too early to use objects.backend here... """ try: import PyQt5.QtWebEngineWidgets # pylint: disable=unused-import except ImportError: return 'no' return str(version.qtwebengine_versions(avoid_init=True).webengine)
def _qtwebengine_args( namespace: argparse.Namespace, special_flags: Sequence[str], ) -> Iterator[str]: """Get the QtWebEngine arguments to use based on the config.""" versions = version.qtwebengine_versions(avoid_init=True) qt_514_ver = utils.VersionNumber(5, 14) qt_515_ver = utils.VersionNumber(5, 15) if qt_514_ver <= versions.webengine < qt_515_ver: # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-82105 yield '--disable-shared-workers' # WORKAROUND equivalent to # https://codereview.qt-project.org/c/qt/qtwebengine/+/256786 # also see: # https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/265753 if versions.webengine >= utils.VersionNumber(5, 12, 3): if 'stack' in namespace.debug_flags: # Only actually available in Qt 5.12.5, but let's save another # check, as passing the option won't hurt. yield '--enable-in-process-stack-traces' else: if 'stack' not in namespace.debug_flags: yield '--disable-in-process-stack-traces' if 'chromium' in namespace.debug_flags: yield '--enable-logging' yield '--v=1' if 'wait-renderer-process' in namespace.debug_flags: yield '--renderer-startup-dialog' from qutebrowser.browser.webengine import darkmode darkmode_settings = darkmode.settings( versions=versions, special_flags=special_flags, ) for switch_name, values in darkmode_settings.items(): # If we need to use other switches (say, --enable-features), we might need to # refactor this so values still get combined with existing ones. assert switch_name in ['dark-mode-settings', 'blink-settings'], switch_name yield f'--{switch_name}=' + ','.join(f'{k}={v}' for k, v in values) enabled_features, disabled_features = _qtwebengine_features( versions, special_flags) if enabled_features: yield _ENABLE_FEATURES + ','.join(enabled_features) if disabled_features: yield _DISABLE_FEATURES + ','.join(disabled_features) yield from _qtwebengine_settings_args(versions)
def test_simulated(self, request, patches, sources): """Test various simulated error conditions. This dynamically gets a list of fixtures (above) to do the patching. It then checks whether the version it got is from one of the expected sources. Depending on the environment this test is run in, some sources might fail "naturally", i.e. without any patching related to them. """ for patch in patches: request.getfixturevalue(f'patch_{patch}') versions = version.qtwebengine_versions(avoid_init=True) assert versions.source in sources
def _init_default_profile(): """Init the default QWebEngineProfile.""" global default_profile default_profile = QWebEngineProfile.defaultProfile() assert parsed_user_agent is None # avoid earlier profile initialization non_ua_version = version.qtwebengine_versions(avoid_init=True) init_user_agent() ua_version = version.qtwebengine_versions() if ua_version.webengine != non_ua_version.webengine: log.init.warning( "QtWebEngine version mismatch - unexpected behavior might occur, " "please open a bug about this.\n" f" Early version: {non_ua_version}\n" f" Real version: {ua_version}") default_profile.setCachePath( os.path.join(standarddir.cache(), 'webengine')) default_profile.setPersistentStoragePath( os.path.join(standarddir.data(), 'webengine')) _init_profile(default_profile)
def _on_renderer_process_terminated(self, tab, status, code): """Show an error when a renderer process terminated.""" if status == browsertab.TerminationStatus.normal: return messages = { browsertab.TerminationStatus.abnormal: "Renderer process exited", browsertab.TerminationStatus.crashed: "Renderer process crashed", browsertab.TerminationStatus.killed: "Renderer process was killed", browsertab.TerminationStatus.unknown: "Renderer process did not start", } msg = messages[status] + f" (status {code})" # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-91715 versions = version.qtwebengine_versions() is_qtbug_91715 = (status == browsertab.TerminationStatus.unknown and code == 1002 and versions.webengine == utils.VersionNumber( 5, 15, 3)) def show_error_page(html): tab.set_html(html) log.webview.error(msg) if is_qtbug_91715: log.webview.error(msg) log.webview.error('') log.webview.error( 'NOTE: If you see this and "Network service crashed, restarting ' 'service.", please see:') log.webview.error( 'https://github.com/qutebrowser/qutebrowser/issues/6235') log.webview.error( 'You can set the "qt.workarounds.locale" setting in qutebrowser to ' 'work around the issue.') log.webview.error( 'A proper fix is likely available in QtWebEngine soon (which is why ' 'the workaround is disabled by default).') log.webview.error('') else: url_string = tab.url(requested=True).toDisplayString() error_page = jinja.render( 'error.html', title="Error loading {}".format(url_string), url=url_string, error=msg) QTimer.singleShot(100, lambda: show_error_page(error_page))
def test_new_chromium(): """Fail if we encounter an unknown Chromium version. Dark mode in Chromium (or rather, the underlying Blink) is being changed with almost every Chromium release. Make this test fail deliberately with newer Chromium versions, so that we can test whether dark mode still works manually, and adjust if not. """ if version.webenginesettings is None: pytest.skip("QtWebKit not available") assert version.qtwebengine_versions().chromium in [ '61.0.3163.140', # Qt 5.10 '65.0.3325.230', # Qt 5.11 '69.0.3497.128', # Qt 5.12 '73.0.3683.105', # Qt 5.13 '77.0.3865.129', # Qt 5.14 '80.0.3987.163', # Qt 5.15.0 '83.0.4103.122', # Qt 5.15.2 ]
def test_avoided(self, monkeypatch): versions = version.qtwebengine_versions(avoid_init=True) assert versions.source in ['ELF', 'importlib', 'PyQt', 'Qt']
def test_unpatched(self, qapp, cache_tmpdir, data_tmpdir, config_stub): assert version.qtwebengine_versions().chromium is not None
def test_fake_ua(self, monkeypatch, caplog): ver = '77.0.3865.98' webenginesettings._init_user_agent_str(_QTWE_USER_AGENT.format(ver)) assert version.qtwebengine_versions().chromium == ver
def _notifications_supported() -> bool: """Check whether the current QtWebEngine version has notification support.""" versions = version.qtwebengine_versions(avoid_init=True) return versions.webengine >= utils.VersionNumber(5, 14)
def test_elf_fail_old_qt_simulated(self, monkeypatch): monkeypatch.setattr(elf, 'parse_webenginecore', lambda: None) monkeypatch.setattr(version, 'PYQT_WEBENGINE_VERSION_STR', None) versions = version.qtwebengine_versions(avoid_init=True) assert versions.source == 'Qt'
def test_elf_fail_simulated(self, monkeypatch): monkeypatch.setattr(elf, 'parse_webenginecore', lambda: None) versions = version.qtwebengine_versions(avoid_init=True) assert versions.source in ['PyQt', 'Qt']