diff --git a/mypy.ini b/mypy.ini index b0ed54888..f830f3fca 100644 --- a/mypy.ini +++ b/mypy.ini @@ -141,8 +141,8 @@ check_untyped_defs = True [mypy-qutebrowser.mainwindow.*] check_untyped_defs = True -# [mypy-qutebrowser.misc.*] -# check_untyped_defs = True +[mypy-qutebrowser.misc.*] +check_untyped_defs = True [mypy-qutebrowser.app] check_untyped_defs = True diff --git a/qutebrowser/misc/cmdhistory.py b/qutebrowser/misc/cmdhistory.py index ef51b60e1..ce9570a80 100644 --- a/qutebrowser/misc/cmdhistory.py +++ b/qutebrowser/misc/cmdhistory.py @@ -19,6 +19,8 @@ """Command history for the status bar.""" +import typing + from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject from qutebrowser.utils import usertypes, log, standarddir, objreg @@ -58,7 +60,7 @@ class History(QObject): super().__init__(parent) self._tmphist = None if history is None: - self.history = [] + self.history = [] # type: typing.Sequence[str] else: self.history = history diff --git a/qutebrowser/misc/consolewidget.py b/qutebrowser/misc/consolewidget.py index 82d6caf98..fab8d5a3e 100644 --- a/qutebrowser/misc/consolewidget.py +++ b/qutebrowser/misc/consolewidget.py @@ -173,7 +173,7 @@ class ConsoleWidget(QWidget): 'objreg': objreg, } self._more = False - self._buffer = [] + self._buffer = [] # type: typing.MutableSequence[str] self._lineedit = ConsoleLineEdit(namespace, self) self._lineedit.execute.connect(self.push) self._output = ConsoleTextEdit() diff --git a/qutebrowser/misc/crashdialog.py b/qutebrowser/misc/crashdialog.py index de89a2436..9cb88f91b 100644 --- a/qutebrowser/misc/crashdialog.py +++ b/qutebrowser/misc/crashdialog.py @@ -28,6 +28,7 @@ import fnmatch import traceback import datetime import enum +import typing import pkg_resources from PyQt5.QtCore import pyqtSlot, Qt, QSize @@ -117,7 +118,7 @@ class _CrashDialog(QDialog): super().__init__(parent) # We don't set WA_DeleteOnClose here as on an exception, we'll get # closed anyways, and it only could have unintended side-effects. - self._crash_info = [] + self._crash_info = [] # type: typing.Sequence[typing.Tuple[str, str]] self._btn_box = None self._btn_report = None self._btn_cancel = None @@ -135,18 +136,23 @@ class _CrashDialog(QDialog): info = QLabel("What were you doing when this crash/bug happened?") self._vbox.addWidget(info) - self._info = QTextEdit(tabChangesFocus=True, acceptRichText=False) + self._info = QTextEdit() + self._info.setTabChangesFocus(True) + self._info.setAcceptRichText(False) self._info.setPlaceholderText("- Opened http://www.example.com/\n" "- Switched tabs\n" "- etc...") self._vbox.addWidget(self._info, 5) self._vbox.addSpacing(15) - self._debug_log = QTextEdit(tabChangesFocus=True, acceptRichText=False, - lineWrapMode=QTextEdit.NoWrap) + self._debug_log = QTextEdit() + self._debug_log.setTabChangesFocus(True) + self._debug_log.setAcceptRichText(False) + self._debug_log.setLineWrapMode(QTextEdit.NoWrap) self._debug_log.hide() info = QLabel("You can edit the log below to remove sensitive " - "information.", wordWrap=True) + "information.") + info.setWordWrap(True) info.hide() self._fold = miscwidgets.DetailFold("Show log", self) self._fold.toggled.connect(self._debug_log.setVisible) @@ -174,10 +180,12 @@ class _CrashDialog(QDialog): """Initialize the widget asking for contact info.""" contact = QLabel("I'd like to be able to follow up with you, to keep " "you posted on the status of this crash and get more " - "information if I need it - how can I contact you?", - wordWrap=True) + "information if I need it - how can I contact you?") + contact.setWordWrap(True) self._vbox.addWidget(contact) - self._contact = QTextEdit(tabChangesFocus=True, acceptRichText=False) + self._contact = QTextEdit() + self._contact.setTabChangesFocus(True) + self._contact.setAcceptRichText(False) try: try: info = configfiles.state['general']['contact-info'] @@ -195,8 +203,10 @@ class _CrashDialog(QDialog): Should be extended by subclasses to set the actual text. """ - self._lbl = QLabel(wordWrap=True, openExternalLinks=True, - textInteractionFlags=Qt.LinksAccessibleByMouse) + self._lbl = QLabel() + self._lbl.setWordWrap(True) + self._lbl.setOpenExternalLinks(True) + self._lbl.setTextInteractionFlags(Qt.LinksAccessibleByMouse) self._vbox.addWidget(self._lbl) def _init_checkboxes(self): @@ -207,19 +217,21 @@ class _CrashDialog(QDialog): self._btn_box = QDialogButtonBox() self._vbox.addWidget(self._btn_box) - self._btn_report = QPushButton("Report", default=True) + self._btn_report = QPushButton("Report") + self._btn_report.setDefault(True) self._btn_report.clicked.connect(self.on_report_clicked) self._btn_box.addButton(self._btn_report, QDialogButtonBox.AcceptRole) - self._btn_cancel = QPushButton("Don't report", autoDefault=False) + self._btn_cancel = QPushButton("Don't report") + self._btn_cancel.setAutoDefault(False) self._btn_cancel.clicked.connect(self.finish) self._btn_box.addButton(self._btn_cancel, QDialogButtonBox.RejectRole) def _init_info_text(self): """Add an info text encouraging the user to report crashes.""" info_label = QLabel("
Note that without your help, I can't fix " - "the bug you encountered.", - wordWrap=True) + "the bug you encountered.") + info_label.setWordWrap(True) self._vbox.addWidget(info_label) def _gather_crash_info(self): @@ -338,7 +350,7 @@ class _CrashDialog(QDialog): text: The paste text to show. """ error_dlg = ReportErrorDialog(text, self._paste_text, self) - error_dlg.finished.connect(self.finish) + error_dlg.finished.connect(self.finish) # type: ignore error_dlg.show() @pyqtSlot(str) @@ -415,8 +427,8 @@ class ExceptionCrashDialog(_CrashDialog): self._chk_restore = QCheckBox("Restore open pages") self._chk_restore.setChecked(True) self._vbox.addWidget(self._chk_restore) - self._chk_log = QCheckBox("Include a debug log in the report", - checked=True) + self._chk_log = QCheckBox("Include a debug log in the report") + self._chk_log.setChecked(True) try: if config.val.content.private_browsing: self._chk_log.setChecked(False) @@ -427,7 +439,8 @@ class ExceptionCrashDialog(_CrashDialog): info_label = QLabel("This makes it a lot easier to diagnose the " "crash, but it might contain sensitive " "information such as which pages you visited " - "or keyboard input.", wordWrap=True) + "or keyboard input.") + info_label.setWordWrap(True) self._vbox.addWidget(info_label) def _get_error_type(self): @@ -450,8 +463,10 @@ class ExceptionCrashDialog(_CrashDialog): ("Objects", self._qobjects), ] try: - self._crash_info.append( - ("Debug log", log.ram_handler.dump_log())) + text = "Log output was disabled." + if log.ram_handler is not None: + text = log.ram_handler.dump_log() + self._crash_info.append(("Debug log", text)) except Exception: self._crash_info.append(("Debug log", traceback.format_exc())) @@ -508,8 +523,8 @@ class FatalCrashDialog(_CrashDialog): """Add checkboxes to the dialog.""" super()._init_checkboxes() self._chk_history = QCheckBox("Include a history of the last " - "accessed pages in the report.", - checked=True) + "accessed pages in the report.") + self._chk_history.setChecked(True) try: if config.val.content.private_browsing: self._chk_history.setChecked(False) @@ -607,8 +622,10 @@ class ReportErrorDialog(QDialog): "crash@qutebrowser.org - Thanks!".format( html.escape(exc_text))) vbox.addWidget(label) - txt = QTextEdit(readOnly=True, tabChangesFocus=True, - acceptRichText=False) + txt = QTextEdit() + txt.setReadOnly(True) + txt.setTabChangesFocus(True) + txt.setAcceptRichText(False) txt.setText(text) txt.selectAll() vbox.addWidget(txt) diff --git a/qutebrowser/misc/crashsignal.py b/qutebrowser/misc/crashsignal.py index 53e203866..d511d12ee 100644 --- a/qutebrowser/misc/crashsignal.py +++ b/qutebrowser/misc/crashsignal.py @@ -27,6 +27,7 @@ import pdb # noqa: T002 import signal import functools import faulthandler +import typing try: # WORKAROUND for segfaults when using pdb in pytest for some reason... import readline # pylint: disable=unused-import @@ -36,6 +37,7 @@ except ImportError: import attr from PyQt5.QtCore import (pyqtSlot, qInstallMessageHandler, QObject, QSocketNotifier, QTimer, QUrl) +from PyQt5.QtCore import pyqtSignal # pylint: disable=unused-import from qutebrowser.api import cmdutils from qutebrowser.misc import earlyinit, crashdialog, ipc, objects @@ -236,10 +238,11 @@ class CrashHandler(QObject): self._quitter.quit_status['crash'] = False info = self._get_exception_info() - try: - ipc.server.ignored = True - except Exception: - log.destroy.exception("Error while ignoring ipc") + if ipc.server is not None: + try: + ipc.server.ignored = True + except Exception: + log.destroy.exception("Error while ignoring ipc") try: self._app.lastWindowClosed.disconnect( @@ -295,7 +298,8 @@ class SignalHandler(QObject): self._quitter = quitter self._notifier = None self._timer = usertypes.Timer(self, 'python_hacks') - self._orig_handlers = {} + self._orig_handlers = { + } # type: typing.Mapping[pyqtSignal, typing.Callable[..., None]] self._activated = False self._orig_wakeup_fd = None @@ -322,7 +326,8 @@ class SignalHandler(QObject): fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) self._notifier = QSocketNotifier(read_fd, QSocketNotifier.Read, self) - self._notifier.activated.connect(self.handle_signal_wakeup) + self._notifier.activated.connect( # type: ignore + self.handle_signal_wakeup) self._orig_wakeup_fd = signal.set_wakeup_fd(write_fd) # pylint: enable=import-error,no-member,useless-suppression else: diff --git a/qutebrowser/misc/earlyinit.py b/qutebrowser/misc/earlyinit.py index 54c94706c..94d1e8951 100644 --- a/qutebrowser/misc/earlyinit.py +++ b/qutebrowser/misc/earlyinit.py @@ -141,7 +141,7 @@ def pyinstaller_qt_workaround(): hasattr(sys, '_MEIPASS') and sys.platform == 'win32'): # pylint: disable=no-member,protected-access - os.environ['PATH'] += os.pathsep + sys._MEIPASS + os.environ['PATH'] += os.pathsep + sys._MEIPASS # type: ignore def check_pyqt(): @@ -265,7 +265,7 @@ def configure_pyqt(): from qutebrowser.qt import sip try: # Added in sip 4.19.4 - sip.enableoverflowchecking(True) + sip.enableoverflowchecking(True) # type: ignore except AttributeError: pass diff --git a/qutebrowser/misc/httpclient.py b/qutebrowser/misc/httpclient.py index 3478884da..d84348f94 100644 --- a/qutebrowser/misc/httpclient.py +++ b/qutebrowser/misc/httpclient.py @@ -19,6 +19,7 @@ """An HTTP client based on QNetworkAccessManager.""" +import typing import functools import urllib.request import urllib.parse @@ -66,7 +67,7 @@ class HTTPClient(QObject): def __init__(self, parent=None): super().__init__(parent) self._nam = QNetworkAccessManager(self) - self._timers = {} + self._timers = {} # type: typing.Mapping[QNetworkReply, QTimer] def post(self, url, data=None): """Create a new POST request. diff --git a/qutebrowser/misc/keyhintwidget.py b/qutebrowser/misc/keyhintwidget.py index 4b2c5d685..9cc00c6a8 100644 --- a/qutebrowser/misc/keyhintwidget.py +++ b/qutebrowser/misc/keyhintwidget.py @@ -89,7 +89,10 @@ class KeyHintView(QLabel): Args: prefix: The current partial keystring. """ - countstr, prefix = re.fullmatch(r'(\d*)(.*)', prefix).groups() + match = re.fullmatch(r'(\d*)(.*)', prefix) + assert match is not None, prefix + + countstr, prefix = match.groups() if not prefix: self._show_timer.stop() self.hide() diff --git a/qutebrowser/misc/lineparser.py b/qutebrowser/misc/lineparser.py index b40532eb2..2656a4f29 100644 --- a/qutebrowser/misc/lineparser.py +++ b/qutebrowser/misc/lineparser.py @@ -22,6 +22,7 @@ import os import os.path import contextlib +import typing from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject @@ -149,7 +150,7 @@ class LineParser(BaseLineParser): """ super().__init__(configdir, fname, binary=binary, parent=parent) if not os.path.isfile(self._configfile): - self.data = [] + self.data = [] # type: typing.Sequence[str] else: log.init.debug("Reading {}".format(self._configfile)) self._read() diff --git a/qutebrowser/misc/miscwidgets.py b/qutebrowser/misc/miscwidgets.py index 2bf2b282d..6047c0dd8 100644 --- a/qutebrowser/misc/miscwidgets.py +++ b/qutebrowser/misc/miscwidgets.py @@ -54,7 +54,7 @@ class MinimalLineEditMixin: e.accept() self.insert(text) return - super().keyPressEvent(e) + super().keyPressEvent(e) # type: ignore def __repr__(self): return utils.get_repr(self) diff --git a/qutebrowser/misc/msgbox.py b/qutebrowser/misc/msgbox.py index 5b31d64c6..387b44e2a 100644 --- a/qutebrowser/misc/msgbox.py +++ b/qutebrowser/misc/msgbox.py @@ -60,7 +60,7 @@ def msgbox(parent, title, text, *, icon, buttons=QMessageBox.Ok, box.setIcon(icon) box.setStandardButtons(buttons) if on_finished is not None: - box.finished.connect(on_finished) + box.finished.connect(on_finished) # type: ignore if plain_text: box.setTextFormat(Qt.PlainText) elif plain_text is not None: diff --git a/qutebrowser/misc/readline.py b/qutebrowser/misc/readline.py index 9c42d5b02..527d7c671 100644 --- a/qutebrowser/misc/readline.py +++ b/qutebrowser/misc/readline.py @@ -19,6 +19,8 @@ """Bridge to provide readline-like shortcuts for QLineEdits.""" +import typing + from PyQt5.QtWidgets import QApplication, QLineEdit from qutebrowser.api import cmdutils @@ -34,13 +36,13 @@ class ReadlineBridge: _deleted: Mapping from widgets to their last deleted text. """ - def __init__(self): - self._deleted = {} + def __init__(self) -> None: + self._deleted = {} # type: typing.MutableMapping[QLineEdit, str] - def __repr__(self): + def __repr__(self) -> str: return utils.get_repr(self) - def _widget(self): + def _widget(self) -> typing.Optional[QLineEdit]: """Get the currently active QLineEdit.""" w = QApplication.instance().focusWidget() if isinstance(w, QLineEdit): @@ -50,7 +52,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_backward_char(self): + def rl_backward_char(self) -> None: """Move back a character. This acts like readline's backward-char. @@ -62,7 +64,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_forward_char(self): + def rl_forward_char(self) -> None: """Move forward a character. This acts like readline's forward-char. @@ -74,7 +76,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_backward_word(self): + def rl_backward_word(self) -> None: """Move back to the start of the current or previous word. This acts like readline's backward-word. @@ -86,7 +88,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_forward_word(self): + def rl_forward_word(self) -> None: """Move forward to the end of the next word. This acts like readline's forward-word. @@ -98,7 +100,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_beginning_of_line(self): + def rl_beginning_of_line(self) -> None: """Move to the start of the line. This acts like readline's beginning-of-line. @@ -110,7 +112,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_end_of_line(self): + def rl_end_of_line(self) -> None: """Move to the end of the line. This acts like readline's end-of-line. @@ -122,7 +124,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_unix_line_discard(self): + def rl_unix_line_discard(self) -> None: """Remove chars backward from the cursor to the beginning of the line. This acts like readline's unix-line-discard. @@ -136,7 +138,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_kill_line(self): + def rl_kill_line(self) -> None: """Remove chars from the cursor to the end of the line. This acts like readline's kill-line. @@ -148,7 +150,7 @@ class ReadlineBridge: self._deleted[widget] = widget.selectedText() widget.del_() - def _rubout(self, delim): + def _rubout(self, delim: typing.Iterable[str]) -> None: """Delete backwards using the characters in delim as boundaries.""" widget = self._widget() if widget is None: @@ -175,7 +177,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_unix_word_rubout(self): + def rl_unix_word_rubout(self) -> None: """Remove chars from the cursor to the beginning of the word. This acts like readline's unix-word-rubout. Whitespace is used as a @@ -185,7 +187,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_unix_filename_rubout(self): + def rl_unix_filename_rubout(self) -> None: """Remove chars from the cursor to the previous path separator. This acts like readline's unix-filename-rubout. @@ -194,7 +196,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_backward_kill_word(self): + def rl_backward_kill_word(self) -> None: """Remove chars from the cursor to the beginning of the word. This acts like readline's backward-kill-word. Any non-alphanumeric @@ -209,7 +211,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_kill_word(self): + def rl_kill_word(self) -> None: """Remove chars from the cursor to the end of the current word. This acts like readline's kill-word. @@ -223,7 +225,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_yank(self): + def rl_yank(self) -> None: """Paste the most recently deleted text. This acts like readline's yank. @@ -235,7 +237,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_delete_char(self): + def rl_delete_char(self) -> None: """Delete the character after the cursor. This acts like readline's delete-char. @@ -247,7 +249,7 @@ class ReadlineBridge: @cmdutils.register(instance='readline-bridge', modes=[typ.KeyMode.command, typ.KeyMode.prompt]) - def rl_backward_delete_char(self): + def rl_backward_delete_char(self) -> None: """Delete the character before the cursor. This acts like readline's backward-delete-char. diff --git a/qutebrowser/misc/savemanager.py b/qutebrowser/misc/savemanager.py index f2a551c7d..6fe449f5c 100644 --- a/qutebrowser/misc/savemanager.py +++ b/qutebrowser/misc/savemanager.py @@ -21,6 +21,7 @@ import os.path import collections +import typing from PyQt5.QtCore import pyqtSlot, QObject, QTimer @@ -110,7 +111,8 @@ class SaveManager(QObject): def __init__(self, parent=None): super().__init__(parent) - self.saveables = collections.OrderedDict() + self.saveables = collections.OrderedDict( + ) # type: typing.MutableMapping[str, Saveable] self._save_timer = usertypes.Timer(self, name='save-timer') self._save_timer.timeout.connect(self.autosave) self._set_autosave_interval() diff --git a/qutebrowser/misc/sessions.py b/qutebrowser/misc/sessions.py index 62fce370f..37a831956 100644 --- a/qutebrowser/misc/sessions.py +++ b/qutebrowser/misc/sessions.py @@ -38,6 +38,9 @@ from qutebrowser.mainwindow import mainwindow from qutebrowser.qt import sip +_JsonType = typing.MutableMapping[str, typing.Any] + + class Sentinel: """Sentinel value for default argument.""" @@ -169,7 +172,7 @@ class SessionManager(QObject): """ data = { 'url': bytes(item.url().toEncoded()).decode('ascii'), - } + } # type: _JsonType if item.title(): data['title'] = item.title() @@ -215,7 +218,7 @@ class SessionManager(QObject): tab: The WebView to save. active: Whether the tab is currently active. """ - data = {'history': []} + data = {'history': []} # type: _JsonType if active: data['active'] = True for idx, item in enumerate(tab.history): @@ -232,9 +235,9 @@ class SessionManager(QObject): def _save_all(self, *, only_window=None, with_private=False): """Get a dict with data for all windows/tabs.""" - data = {'windows': []} + data = {'windows': []} # type: _JsonType if only_window is not None: - winlist = [only_window] + winlist = [only_window] # type: typing.Iterable[int] else: winlist = objreg.window_registry @@ -251,7 +254,7 @@ class SessionManager(QObject): if tabbed_browser.is_private and not with_private: continue - win_data = {} + win_data = {} # type: _JsonType active_window = QApplication.instance().activeWindow() if getattr(active_window, 'win_id', None) == win_id: win_data['active'] = True @@ -309,10 +312,10 @@ class SessionManager(QObject): else: data = self._save_all(only_window=only_window, with_private=with_private) - log.sessions.vdebug("Saving data: {}".format(data)) + log.sessions.vdebug("Saving data: {}".format(data)) # type: ignore try: with qtutils.savefile_open(path) as f: - utils.yaml_dump(data, f) + utils.yaml_dump(data, f) # type: ignore except (OSError, UnicodeEncodeError, yaml.YAMLError) as e: raise SessionError(e) @@ -345,7 +348,7 @@ class SessionManager(QObject): def _load_tab(self, new_tab, data): """Load yaml data into a newly opened tab.""" entries = [] - lazy_load = [] + lazy_load = [] # type: typing.MutableSequence[_JsonType] # use len(data['history']) # -> dropwhile empty if not session.lazy_session lazy_index = len(data['history']) diff --git a/qutebrowser/misc/split.py b/qutebrowser/misc/split.py index cf3fe4829..cb6620b3c 100644 --- a/qutebrowser/misc/split.py +++ b/qutebrowser/misc/split.py @@ -139,7 +139,7 @@ def split(s, keep=False): out = [] spaces = "" - log.shlexer.vdebug("{!r} -> {!r}".format(s, tokens)) + log.shlexer.vdebug("{!r} -> {!r}".format(s, tokens)) # type: ignore for t in tokens: if t.isspace(): diff --git a/qutebrowser/misc/sql.py b/qutebrowser/misc/sql.py index da509fa8c..4a38a0c9c 100644 --- a/qutebrowser/misc/sql.py +++ b/qutebrowser/misc/sql.py @@ -188,7 +188,7 @@ class Query: raise BugError("Cannot iterate inactive query") rec = self.query.record() fields = [rec.fieldName(i) for i in range(rec.count())] - rowtype = collections.namedtuple('ResultRow', fields) + rowtype = collections.namedtuple('ResultRow', fields) # type: ignore while self.query.next(): rec = self.query.record()