News download: Allow using show_browser() in recipes when using --test

This commit is contained in:
Kovid Goyal 2015-04-18 09:00:11 +05:30
parent a3a7b20f07
commit f9ce74d58a
3 changed files with 20 additions and 14 deletions

View File

@ -1149,16 +1149,16 @@ def open_local_file(path):
_ea_lock = Lock() _ea_lock = Lock()
def ensure_app(): def ensure_app(headless=True):
global _store_app global _store_app
with _ea_lock: with _ea_lock:
if _store_app is None and QApplication.instance() is None: if _store_app is None and QApplication.instance() is None:
args = sys.argv[:1] args = sys.argv[:1]
headless = islinux or isbsd if headless and (islinux or isbsd):
if headless:
args += ['-platformpluginpath', sys.extensions_location, '-platform', 'headless'] args += ['-platformpluginpath', sys.extensions_location, '-platform', 'headless']
_store_app = QApplication(args) _store_app = QApplication(args)
_store_app.headless = headless if headless and (islinux or isbsd):
_store_app.headless = True
import traceback import traceback
# This is needed because as of PyQt 5.4 if sys.execpthook == # This is needed because as of PyQt 5.4 if sys.execpthook ==
# sys.__excepthook__ PyQt will abort the application on an # sys.__excepthook__ PyQt will abort the application on an
@ -1175,14 +1175,17 @@ def ensure_app():
pass pass
sys.excepthook = eh sys.excepthook = eh
def must_use_qt(): def app_is_headless():
return getattr(_store_app, 'headless', False)
def must_use_qt(headless=True):
''' This function should be called if you want to use Qt for some non-GUI ''' This function should be called if you want to use Qt for some non-GUI
task like rendering HTML/SVG or using a headless browser. It will raise a task like rendering HTML/SVG or using a headless browser. It will raise a
RuntimeError if using Qt is not possible, which will happen if the current RuntimeError if using Qt is not possible, which will happen if the current
thread is not the main GUI thread. On linux, it uses a special QPA headless thread is not the main GUI thread. On linux, it uses a special QPA headless
plugin, so that the X server does not need to be running. ''' plugin, so that the X server does not need to be running. '''
global gui_thread global gui_thread
ensure_app() ensure_app(headless=headless)
if gui_thread is None: if gui_thread is None:
gui_thread = QThread.currentThread() gui_thread = QThread.currentThread()
if gui_thread is not QThread.currentThread(): if gui_thread is not QThread.currentThread():

View File

@ -487,7 +487,7 @@ class BasicNewsRecipe(Recipe):
if getattr(self, 'browser', None) is not None: if getattr(self, 'browser', None) is not None:
return self.clone_browser(self.browser) return self.clone_browser(self.browser)
from calibre.web.jsbrowser.browser import Browser from calibre.web.jsbrowser.browser import Browser
br = Browser() br = Browser(headless=not self.test)
with br: with br:
self.javascript_login(br, self.username, self.password) self.javascript_login(br, self.username, self.password)
kwargs['user_agent'] = br.user_agent kwargs['user_agent'] = br.user_agent

View File

@ -14,15 +14,15 @@ from threading import current_thread
from PyQt5.QtWebKit import QWebSettings, QWebElement from PyQt5.QtWebKit import QWebSettings, QWebElement
from PyQt5.QtWebKitWidgets import QWebPage, QWebView from PyQt5.QtWebKitWidgets import QWebPage, QWebView
from PyQt5.Qt import ( from PyQt5.Qt import (
QObject, QNetworkAccessManager, QNetworkDiskCache, QCoreApplication, QObject, QNetworkAccessManager, QNetworkDiskCache, QNetworkProxy,
QNetworkProxy, QNetworkProxyFactory, QEventLoop, QUrl, pyqtSignal, QNetworkProxyFactory, QEventLoop, QUrl, pyqtSignal, QDialog, QVBoxLayout,
QDialog, QVBoxLayout, QSize, QNetworkCookieJar, Qt, pyqtSlot, QPixmap) QSize, QNetworkCookieJar, Qt, pyqtSlot, QPixmap)
from calibre import USER_AGENT, prints, get_proxies, get_proxy_info, prepare_string_for_xml from calibre import USER_AGENT, prints, get_proxies, get_proxy_info, prepare_string_for_xml
from calibre.constants import ispy3, cache_dir from calibre.constants import ispy3, cache_dir
from calibre.ptempfile import PersistentTemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.logging import ThreadSafeLog from calibre.utils.logging import ThreadSafeLog
from calibre.gui2 import must_use_qt from calibre.gui2 import must_use_qt, app_is_headless
from calibre.web.jsbrowser.forms import FormsMixin, default_timeout from calibre.web.jsbrowser.forms import FormsMixin, default_timeout
class Timeout(Exception): class Timeout(Exception):
@ -364,9 +364,12 @@ class Browser(QObject, FormsMixin):
verbosity=0, verbosity=0,
# The default timeout (in seconds) # The default timeout (in seconds)
default_timeout=30 default_timeout=30,
# If True, do not connect to the X server on linux
headless=True
): ):
must_use_qt() must_use_qt(headless=headless)
QObject.__init__(self) QObject.__init__(self)
FormsMixin.__init__(self) FormsMixin.__init__(self)
@ -682,7 +685,7 @@ class Browser(QObject, FormsMixin):
''' '''
Show the currently loaded web page in a window. Useful for debugging. Show the currently loaded web page in a window. Useful for debugging.
''' '''
if getattr(QCoreApplication.instance(), 'headless', False): if app_is_headless():
raise RuntimeError('Cannot show browser when running in a headless Qt application') raise RuntimeError('Cannot show browser when running in a headless Qt application')
view = BrowserView(self.page) view = BrowserView(self.page)
view.exec_() view.exec_()