Merge remote-tracking branch 'florian/master' into quickmark-completion

This commit is contained in:
Claude 2014-10-17 20:46:00 +02:00
commit 9613cc0eab
17 changed files with 236 additions and 150 deletions

View File

@ -151,7 +151,8 @@ class Application(QApplication):
log.init.debug("Initializing websettings...")
websettings.init()
log.init.debug("Initializing quickmarks...")
quickmarks.init()
quickmark_manager = quickmarks.QuickmarkManager()
objreg.register('quickmark-manager', quickmark_manager)
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing cookies...")
@ -313,7 +314,7 @@ class Application(QApplication):
quickstart_done = False
if not quickstart_done:
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='current')
window='last-focused')
tabbed_browser.tabopen(
QUrl('http://www.qutebrowser.org/quickstart.html'))
try:
@ -341,6 +342,7 @@ class Application(QApplication):
config_obj = objreg.get('config')
self.lastWindowClosed.connect(self.shutdown)
config_obj.style_changed.connect(style.get_stylesheet.cache_clear)
self.focusChanged.connect(self.on_focus_changed)
def _get_widgets(self):
"""Get a string list of all widgets."""
@ -541,7 +543,7 @@ class Application(QApplication):
out = traceback.format_exc()
qutescheme.pyeval_output = out
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='current')
window='last-focused')
tabbed_browser.openurl(QUrl('qute:pyeval'), newtab=True)
@cmdutils.register(instance='app')
@ -636,12 +638,8 @@ class Application(QApplication):
self.removeEventFilter(self._event_filter)
except AttributeError:
pass
# Close all tabs
for win_id in objreg.window_registry:
log.destroy.debug("Closing tabs in window {}...".format(win_id))
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window=win_id)
tabbed_browser.shutdown()
# Close all windows
QApplication.closeAllWindows()
# Shut down IPC
try:
objreg.get('ipc-server').shutdown()
@ -663,14 +661,19 @@ class Application(QApplication):
pass
else:
to_save.append(("keyconfig", key_config.save))
to_save += [("window geometry", self._save_geometry),
("quickmarks", quickmarks.save)]
to_save += [("window geometry", self._save_geometry)]
try:
command_history = objreg.get('command-history')
except KeyError:
pass
else:
to_save.append(("command history", command_history.save))
try:
quickmark_manager = objreg.get('quickmark-manager')
except KeyError:
pass
else:
to_save.append(("command history", quickmark_manager.save))
try:
state_config = objreg.get('state-config')
except KeyError:
@ -700,6 +703,20 @@ class Application(QApplication):
# segfaults.
QTimer.singleShot(0, functools.partial(self.exit, status))
def on_focus_changed(self, _old, new):
"""Register currently focused main window in the object registry."""
if new is None:
window = None
else:
window = new.window()
if window is None or not isinstance(window, mainwindow.MainWindow):
try:
objreg.delete('last-focused-main-window')
except KeyError:
pass
else:
objreg.register('last-focused-main-window', window, update=True)
def exit(self, status):
"""Extend QApplication::exit to log the event."""
log.destroy.debug("Now calling QApplication::exit.")

View File

@ -36,7 +36,7 @@ import pygments.formatters
from qutebrowser.commands import userscripts, cmdexc, cmdutils
from qutebrowser.config import config
from qutebrowser.browser import quickmarks, webelem
from qutebrowser.browser import webelem
from qutebrowser.utils import (message, editor, usertypes, log, qtutils,
urlutils, objreg, utils)
@ -815,7 +815,8 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
def quickmark_save(self):
"""Save the current page as a quickmark."""
quickmarks.prompt_save(self._win_id, self._current_url())
quickmark_manager = objreg.get('quickmark-manager')
quickmark_manager.prompt_save(self._win_id, self._current_url())
@cmdutils.register(instance='command-dispatcher', scope='window',
completion=[usertypes.Completion.quickmark])
@ -828,7 +829,7 @@ class CommandDispatcher:
bg: Load the quickmark in a new background tab.
window: Load the quickmark in a new window.
"""
url = quickmarks.get(name)
url = objreg.get('quickmark-manager').get(name)
self._open(url, tab, bg, window)
@cmdutils.register(instance='command-dispatcher', name='inspector',

View File

@ -62,6 +62,7 @@ class DownloadItem(QObject):
_reply: The QNetworkReply associated with this download.
_last_done: The count of bytes which where downloaded when calculating
the speed the last time.
_error: The current error message, or None
Signals:
data_changed: The downloads metadata changed.
@ -88,6 +89,7 @@ class DownloadItem(QObject):
self._reply = reply
self._bytes_total = None
self._speed = 0
self._error = None
self.basename = '???'
samples = int(self.SPEED_AVG_WINDOW *
(1000 / self.SPEED_REFRESH_INTERVAL))
@ -127,9 +129,13 @@ class DownloadItem(QObject):
down = utils.format_size(self._bytes_done, suffix='B')
perc = self._percentage()
remaining = self._remaining_time()
if self._error is None:
errmsg = ""
else:
errmsg = " - {}".format(self._error)
if all(e is None for e in (perc, remaining, self._bytes_total)):
return ('{name} [{speed:>10}|{down}]'.format(
name=self.basename, speed=speed, down=down))
return ('{name} [{speed:>10}|{down}]{errmsg}'.format(
name=self.basename, speed=speed, down=down, errmsg=errmsg))
if perc is None:
perc = '??'
else:
@ -140,9 +146,9 @@ class DownloadItem(QObject):
remaining = utils.format_seconds(remaining)
total = utils.format_size(self._bytes_total, suffix='B')
return ('{name} [{speed:>10}|{remaining:>5}|{perc:>2}%|'
'{down}/{total}]'.format(name=self.basename, speed=speed,
remaining=remaining, perc=perc,
down=down, total=total))
'{down}/{total}]{errmsg}'.format(
name=self.basename, speed=speed, remaining=remaining,
perc=perc, down=down, total=total, errmsg=errmsg))
def _die(self, msg):
"""Abort the download and emit an error."""
@ -150,17 +156,19 @@ class DownloadItem(QObject):
self._reply.finished.disconnect()
self._reply.error.disconnect()
self._reply.readyRead.disconnect()
self._error = msg
self._bytes_done = self._bytes_total
self.timer.stop()
self.error.emit(msg)
self._reply.abort()
self._reply.deleteLater()
self._reply = None
if self._fileobj is not None:
try:
self._fileobj.close()
except OSError as e:
self.error.emit(e.strerror)
self.finished.emit()
self.data_changed.emit()
def _percentage(self):
"""The current download percentage, or None if unknown."""
@ -187,7 +195,10 @@ class DownloadItem(QObject):
start = config.get('colors', 'downloads.bg.start')
stop = config.get('colors', 'downloads.bg.stop')
system = config.get('colors', 'downloads.bg.system')
if self._percentage() is None:
error = config.get('colors', 'downloads.bg.error')
if self._error is not None:
return error
elif self._percentage() is None:
return start
else:
return utils.interpolate_color(start, stop, self._percentage(),
@ -198,8 +209,9 @@ class DownloadItem(QObject):
log.downloads.debug("cancelled")
self.cancelled.emit()
self._is_cancelled = True
self._reply.abort()
self._reply.deleteLater()
if self._reply is not None:
self._reply.abort()
self._reply.deleteLater()
if self._fileobj is not None:
self._fileobj.close()
if self._filename is not None and os.path.exists(self._filename):
@ -352,7 +364,7 @@ class DownloadManager(QAbstractListModel):
page: The QWebPage to get the download from.
"""
if not url.isValid():
urlutils.invalid_url_error('current', url, "start download")
urlutils.invalid_url_error('last-focused', url, "start download")
return
req = QNetworkRequest(url)
reply = page.networkAccessManager().get(req)
@ -389,7 +401,8 @@ class DownloadManager(QAbstractListModel):
functools.partial(self.on_finished, download))
download.data_changed.connect(
functools.partial(self.on_data_changed, download))
download.error.connect(self.on_error)
download.error.connect(
functools.partial(self.on_error, download))
download.basename = suggested_filename
idx = len(self.downloads) + 1
self.beginInsertRows(QModelIndex(), idx, idx)
@ -407,7 +420,7 @@ class DownloadManager(QAbstractListModel):
self.questions.append(q)
download.cancelled.connect(q.abort)
message_bridge = objreg.get('message-bridge', scope='window',
window='current')
window='last-focused')
message_bridge.ask(q, blocking=False)
@pyqtSlot(DownloadItem)
@ -428,10 +441,10 @@ class DownloadManager(QAbstractListModel):
qtutils.ensure_valid(model_idx)
self.dataChanged.emit(model_idx, model_idx)
@pyqtSlot(str)
def on_error(self, msg):
@pyqtSlot(DownloadItem, str)
def on_error(self, download, msg):
"""Display error message on download errors."""
message.error('current', "Download error: {}".format(msg))
message.error('last-focused', "Download error: {}".format(msg))
def last_index(self):
"""Get the last index in the model.
@ -465,6 +478,11 @@ class DownloadManager(QAbstractListModel):
data = item.bg_color()
elif role == ModelRole.item:
data = item
elif role == Qt.ToolTipRole:
if item._error is None:
data = QVariant()
else:
return item._error
else:
data = QVariant()
return data

View File

@ -82,10 +82,8 @@ class HintContext:
"""Get the arguments, with {hint-url} replaced by the given URL."""
args = []
for arg in self.args:
if arg == '{hint-url}':
args.append(urlstr)
else:
args.append(arg)
arg = arg.replace('{hint-url}', urlstr)
args.append(arg)
return args
@ -274,9 +272,14 @@ class HintManager(QObject):
else:
display = 'none'
rect = elem.geometry()
left = rect.x()
top = rect.y()
if not config.get('ui', 'zoom-text-only'):
zoom = elem.webFrame().zoomFactor()
left /= zoom
top /= zoom
return self.HINT_CSS.format(
left=rect.x(), top=rect.y(), config=objreg.get('config'),
display=display)
left=left, top=top, config=objreg.get('config'), display=display)
def _draw_label(self, elem, string):
"""Draw a hint label over an element.

View File

@ -27,91 +27,99 @@ to a file on shutdown, so it makes sense to keep them as strings here.
import functools
import collections
from PyQt5.QtCore import QStandardPaths, QUrl
from PyQt5.QtCore import pyqtSignal, QStandardPaths, QUrl, QObject
from qutebrowser.utils import message, usertypes, urlutils, standarddir
from qutebrowser.commands import cmdexc, cmdutils
from qutebrowser.config import lineparser
marks = collections.OrderedDict()
linecp = None
class QuickmarkManager(QObject):
"""Manager for quickmarks.
def init():
"""Read quickmarks from the config file."""
global linecp
confdir = standarddir.get(QStandardPaths.ConfigLocation)
linecp = lineparser.LineConfigParser(confdir, 'quickmarks')
for line in linecp:
try:
key, url = line.rsplit(maxsplit=1)
except ValueError:
message.error(0, "Invalid quickmark '{}'".format(line))
Attributes:
marks: An OrderedDict of all quickmarks.
_linecp: The LineConfigParser used for the quickmarks.
"""
changed = pyqtSignal()
def __init__(self, parent=None):
"""Initialize and read quickmarks."""
super().__init__(parent)
self.marks = collections.OrderedDict()
confdir = standarddir.get(QStandardPaths.ConfigLocation)
self._linecp = lineparser.LineConfigParser(confdir, 'quickmarks')
for line in self._linecp:
try:
key, url = line.rsplit(maxsplit=1)
except ValueError:
message.error(0, "Invalid quickmark '{}'".format(line))
else:
self.marks[key] = url
def save(self):
"""Save the quickmarks to disk."""
self._linecp.data = [' '.join(tpl) for tpl in self.marks.items()]
self._linecp.save()
def prompt_save(self, win_id, url):
"""Prompt for a new quickmark name to be added and add it.
Args:
win_id: The current window ID.
url: The quickmark url as a QUrl.
"""
if not url.isValid():
urlutils.invalid_url_error(win_id, url, "save quickmark")
return
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
message.ask_async(
win_id, "Add quickmark:", usertypes.PromptMode.text,
functools.partial(self.quickmark_add, win_id, urlstr))
@cmdutils.register(instance='quickmark-manager')
def quickmark_add(self, win_id: {'special': 'win_id'}, url, name):
"""Add a new quickmark.
Args:
win_id: The window ID to display the errors in.
url: The url to add as quickmark.
name: The name for the new quickmark.
"""
# We don't raise cmdexc.CommandError here as this can be called async
# via prompt_save.
if not name:
message.error(win_id, "Can't set mark with empty name!")
return
if not url:
message.error(win_id, "Can't set mark with empty URL!")
return
def set_mark():
"""Really set the quickmark."""
self.marks[name] = url
self.changed.emit()
if name in self.marks:
message.confirm_async(
win_id, "Override existing quickmark?", set_mark, default=True)
else:
marks[key] = url
set_mark()
def save():
"""Save the quickmarks to disk."""
linecp.data = [' '.join(tpl) for tpl in marks.items()]
linecp.save()
def prompt_save(win_id, url):
"""Prompt for a new quickmark name to be added and add it.
Args:
win_id: The current window ID.
url: The quickmark url as a QUrl.
"""
if not url.isValid():
urlutils.invalid_url_error(win_id, url, "save quickmark")
return
urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded)
message.ask_async(win_id, "Add quickmark:", usertypes.PromptMode.text,
functools.partial(quickmark_add, win_id, urlstr))
@cmdutils.register()
def quickmark_add(win_id: {'special': 'win_id'}, url, name):
"""Add a new quickmark.
Args:
win_id: The window ID to display the errors in.
url: The url to add as quickmark.
name: The name for the new quickmark.
"""
# We don't raise cmdexc.CommandError here as this can be called async via
# prompt_save.
if not name:
message.error(win_id, "Can't set mark with empty name!")
return
if not url:
message.error(win_id, "Can't set mark with empty URL!")
return
def set_mark():
"""Really set the quickmark."""
marks[name] = url
if name in marks:
message.confirm_async(win_id, "Override existing quickmark?", set_mark,
default=True)
else:
set_mark()
def get(name):
"""Get the URL of the quickmark named name as a QUrl."""
if name not in marks:
raise cmdexc.CommandError(
"Quickmark '{}' does not exist!".format(name))
urlstr = marks[name]
try:
url = urlutils.fuzzy_url(urlstr)
except urlutils.FuzzyUrlError:
raise cmdexc.CommandError(
"Invalid URL for quickmark {}: {} ({})".format(name, urlstr,
url.errorString()))
return url
def get(self, name):
"""Get the URL of the quickmark named name as a QUrl."""
if name not in self.marks:
raise cmdexc.CommandError(
"Quickmark '{}' does not exist!".format(name))
urlstr = self.marks[name]
try:
url = urlutils.fuzzy_url(urlstr)
except urlutils.FuzzyUrlError:
raise cmdexc.CommandError(
"Invalid URL for quickmark {}: {} ({})".format(
name, urlstr, url.errorString()))
return url

View File

@ -59,7 +59,7 @@ class HelpAction(argparse.Action):
def __call__(self, parser, _namespace, _values, _option_string=None):
tabbed_browser = objreg.get('tabbed-browser', scope='window',
window='current')
window='last-focused')
tabbed_browser.tabopen(
QUrl('qute://help/commands.html#{}'.format(parser.name)))
parser.exit()

View File

@ -714,6 +714,10 @@ DATA = collections.OrderedDict([
('downloads.bg.system',
SettingValue(typ.ColorSystem(), 'rgb'),
"Color gradient interpolation system for downloads."),
('downloads.bg.error',
SettingValue(typ.QtColor(), 'red'),
"Background color for downloads with errors."),
)),
('fonts', sect.KeyValue(

View File

@ -35,7 +35,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
Attributes:
_pattern: The pattern to filter with.
_srcmodel: The current source model.
srcmodel: The current source model.
Kept as attribute because calling `sourceModel` takes quite
a long time for some reason.
"""
@ -43,7 +43,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
def __init__(self, source, parent=None):
super().__init__(parent)
super().setSourceModel(source)
self._srcmodel = source
self.srcmodel = source
self._pattern = ''
def set_pattern(self, val):
@ -61,7 +61,7 @@ class CompletionFilterModel(QSortFilterProxyModel):
self.invalidateFilter()
sortcol = 0
try:
self._srcmodel.sort(sortcol)
self.srcmodel.sort(sortcol)
except NotImplementedError:
self.sort(sortcol)
self.invalidate()
@ -111,14 +111,14 @@ class CompletionFilterModel(QSortFilterProxyModel):
qtutils.ensure_valid(index)
index = self.mapToSource(index)
qtutils.ensure_valid(index)
self._srcmodel.mark_item(index, text)
self.srcmodel.mark_item(index, text)
def setSourceModel(self, model):
"""Override QSortFilterProxyModel's setSourceModel to clear pattern."""
log.completion.debug("Setting source model: {}".format(model))
self.set_pattern('')
super().setSourceModel(model)
self._srcmodel = model
self.srcmodel = model
def filterAcceptsRow(self, row, parent):
"""Custom filter implementation.
@ -135,9 +135,9 @@ class CompletionFilterModel(QSortFilterProxyModel):
"""
if parent == QModelIndex():
return True
idx = self._srcmodel.index(row, 0, parent)
idx = self.srcmodel.index(row, 0, parent)
qtutils.ensure_valid(idx)
data = self._srcmodel.data(idx)
data = self.srcmodel.data(idx)
# TODO more sophisticated filtering
if not self._pattern:
return True
@ -159,14 +159,14 @@ class CompletionFilterModel(QSortFilterProxyModel):
qtutils.ensure_valid(lindex)
qtutils.ensure_valid(rindex)
left_sort = self._srcmodel.data(lindex, role=completion.Role.sort)
right_sort = self._srcmodel.data(rindex, role=completion.Role.sort)
left_sort = self.srcmodel.data(lindex, role=completion.Role.sort)
right_sort = self.srcmodel.data(rindex, role=completion.Role.sort)
if left_sort is not None and right_sort is not None:
return left_sort < right_sort
left = self._srcmodel.data(lindex)
right = self._srcmodel.data(rindex)
left = self.srcmodel.data(lindex)
right = self.srcmodel.data(rindex)
leftstart = left.startswith(self._pattern)
rightstart = right.startswith(self._pattern)

View File

@ -181,7 +181,6 @@ class Completer(QObject):
else:
self._ignore_change = True
self.change_completed_part.emit(data, False)
self._ignore_change = False
@pyqtSlot(str, list, int)
def on_update_completion(self, prefix, parts, cursor_part):
@ -204,6 +203,7 @@ class Completer(QObject):
cursor_part: The part the cursor is currently over.
"""
if self._ignore_change:
self._ignore_change = False
log.completion.debug("Ignoring completion update")
return
@ -235,7 +235,7 @@ class Completer(QObject):
log.completion.debug(
"New completion for {}: {}, with pattern '{}'".format(
parts, model._srcmodel.__class__.__name__, pattern))
parts, model.srcmodel.__class__.__name__, pattern))
if self._model().count() == 0:
completion.hide()

View File

@ -136,6 +136,15 @@ def _get_window_registry(window):
win = app.activeWindow()
if win is None or not hasattr(win, 'win_id'):
raise RegistryUnavailableError('window')
elif window == 'last-focused':
try:
win = get('last-focused-main-window')
except KeyError:
try:
win = get('last-main-window')
except KeyError:
raise RegistryUnavailableError('window')
assert hasattr(win, 'registry')
else:
try:
win = window_registry[window]

View File

@ -22,7 +22,7 @@
import functools
import sip
from PyQt5.QtCore import pyqtSlot, QSize, Qt
from PyQt5.QtCore import pyqtSlot, QSize, Qt, QTimer
from PyQt5.QtWidgets import QListView, QSizePolicy, QMenu
from qutebrowser.browser import downloads
@ -44,9 +44,16 @@ def update_geometry(obj):
Original bug: https://github.com/The-Compiler/qutebrowser/issues/167
Workaround bug: https://github.com/The-Compiler/qutebrowser/issues/171
"""
if sip.isdeleted(obj):
return
obj.updateGeometry()
def _update_geometry():
"""Actually update the geometry if the object still exists."""
if sip.isdeleted(obj):
return
obj.updateGeometry()
# If we don't use a singleShot QTimer, the geometry isn't updated correctly
# and won't include the new item.
QTimer.singleShot(0, _update_geometry)
class DownloadView(QListView):

View File

@ -87,7 +87,6 @@ class MainWindow(QWidget):
self._downloadview.show()
self._tabbed_browser = tabbedbrowser.TabbedBrowser(win_id)
self._tabbed_browser.title_changed.connect(self.setWindowTitle)
objreg.register('tabbed-browser', self._tabbed_browser, scope='window',
window=win_id)
self._vbox.addWidget(self._tabbed_browser)
@ -333,3 +332,4 @@ class MainWindow(QWidget):
e.accept()
objreg.get('app').geometry = bytes(self.saveGeometry())
log.destroy.debug("Closing window {}".format(self.win_id))
self._tabbed_browser.shutdown()

View File

@ -20,8 +20,8 @@
"""Misc. widgets used at different places."""
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtGui import QValidator
from PyQt5.QtWidgets import QLineEdit, QApplication
from PyQt5.QtGui import QValidator, QClipboard
from qutebrowser.models import cmdhistory
from qutebrowser.utils import utils
@ -64,6 +64,9 @@ class CommandLineEdit(QLineEdit):
self.cursorPositionChanged.connect(self.__on_cursor_position_changed)
self._promptlen = 0
def __repr__(self):
return utils.get_repr(self, text=self.text())
@pyqtSlot(str)
def on_text_edited(self, _text):
"""Slot for textEdited. Stop history browsing."""
@ -94,8 +97,16 @@ class CommandLineEdit(QLineEdit):
if mark:
self.setSelection(self._promptlen, oldpos - self._promptlen)
def __repr__(self):
return utils.get_repr(self, text=self.text())
def keyPressEvent(self, e):
"""Override keyPressEvent to paste primary selection on Shift + Ins."""
if e.key() == Qt.Key_Insert and e.modifiers() == Qt.ShiftModifier:
clipboard = QApplication.clipboard()
if clipboard.supportsSelection():
e.accept()
text = clipboard.text(QClipboard.Selection)
self.insert(text)
return
super().keyPressEvent(e)
class _CommandValidator(QValidator):

View File

@ -79,8 +79,6 @@ class TabbedBrowser(tabwidget.TabWidget):
start_download: Emitted when any tab wants to start downloading
something.
current_tab_changed: The current tab changed to the emitted WebView.
title_changed: Emitted when the application title should be changed.
arg: The new title as string.
"""
cur_progress = pyqtSignal(int)
@ -96,7 +94,6 @@ class TabbedBrowser(tabwidget.TabWidget):
resized = pyqtSignal('QRect')
got_cmd = pyqtSignal(str)
current_tab_changed = pyqtSignal(webview.WebView)
title_changed = pyqtSignal(str)
def __init__(self, win_id, parent=None):
super().__init__(win_id, parent)
@ -138,9 +135,10 @@ class TabbedBrowser(tabwidget.TabWidget):
def _change_app_title(self, text):
"""Change the window title based on the tab text."""
if not text:
self.title_changed.emit('qutebrowser')
title = 'qutebrowser'
else:
self.title_changed.emit('{} - qutebrowser'.format(text))
title = '{} - qutebrowser'.format(text)
self.window().setWindowTitle(title)
def _connect_tab_signals(self, tab):
"""Set up the needed signals for tab."""

View File

@ -127,6 +127,13 @@ class WebView(QWebView):
url = utils.elide(self.url().toDisplayString(), 50)
return utils.get_repr(self, tab_id=self.tab_id, url=url)
def __del__(self):
# Explicitely releasing the page here seems to prevent some segfaults
# when quitting.
# Copied from:
# https://code.google.com/p/webscraping/source/browse/webkit.py#325
self.setPage(None)
def _set_load_status(self, val):
"""Setter for load_status."""
if not isinstance(val, LoadStatus):
@ -257,15 +264,11 @@ class WebView(QWebView):
"""Shut down the webview."""
# We disable javascript because that prevents some segfaults when
# quitting it seems.
log.destroy.debug("Shutting down {!r}.".format(self))
settings = self.settings()
settings.setAttribute(QWebSettings.JavascriptEnabled, False)
self.stop()
self.page().networkAccessManager().shutdown()
# Explicitely releasing the page here seems to prevent some segfaults
# when quitting.
# Copied from:
# https://code.google.com/p/webscraping/source/browse/webkit.py#325
self.setPage(None)
def openurl(self, url):
"""Open a URL in the browser.

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2014 Claude (longneck) <longneck@scratchbook.ch>
@ -49,8 +50,8 @@ def get_args():
def import_chromium(bookmarks_file):
"""Import bookmarks from a HTML file generated by Chromium."""
import bs4
soup = bs4.BeautifulSoup(open(bookmarks_file, encoding='utf-8'))
with open(bookmarks_file, encoding='utf-8') as f:
soup = bs4.BeautifulSoup(f)
html_tags = soup.findAll('a')

View File

@ -52,10 +52,16 @@ class OpenEncodingChecker(checkers.BaseChecker):
keyword='mode')
except utils.NoSuchArgumentError:
mode_arg = None
_encoding = None
try:
_encoding = utils.get_argument_from_call(node, position=2,
keyword='encoding')
_encoding = utils.get_argument_from_call(node, position=2)
except utils.NoSuchArgumentError:
try:
_encoding = utils.get_argument_from_call(node,
keyword='encoding')
except utils.NoSuchArgumentError:
pass
if _encoding is None:
if mode_arg is not None:
mode = utils.safe_infer(mode_arg)
if (mode_arg is not None and isinstance(mode, astroid.Const) and