Skip to content
Permalink
Browse files

Start using attrs

Closes #1073
  • Loading branch information...
The-Compiler committed Sep 19, 2017
1 parent 7226750 commit 3a5241b642da666e4517a32e0eb945254d86a6da
Showing with 453 additions and 252 deletions.
  1. +2 −0 .pylintrc
  2. +1 −0 README.asciidoc
  3. +1 −0 doc/changelog.asciidoc
  4. +1 −0 misc/requirements/requirements-qutebrowser.txt-raw
  5. +1 −0 misc/requirements/requirements-tests-git.txt
  6. +8 −7 qutebrowser/browser/browsertab.py
  7. +16 −13 qutebrowser/browser/hints.py
  8. +6 −2 qutebrowser/browser/qtnetworkdownloads.py
  9. +10 −5 qutebrowser/browser/webkit/mhtml.py
  10. +11 −1 qutebrowser/browser/webkit/network/networkmanager.py
  11. +8 −2 qutebrowser/browser/webkit/rfc6266.py
  12. +16 −27 qutebrowser/commands/command.py
  13. +11 −2 qutebrowser/commands/runners.py
  14. +10 −5 qutebrowser/completion/completer.py
  15. +17 −4 qutebrowser/config/configdata.py
  16. +7 −8 qutebrowser/config/configexc.py
  17. +10 −3 qutebrowser/config/configtypes.py
  18. +10 −13 qutebrowser/keyinput/modeman.py
  19. +11 −4 qutebrowser/mainwindow/prompt.py
  20. +7 −7 qutebrowser/mainwindow/statusbar/bar.py
  21. +16 −9 qutebrowser/mainwindow/tabbedbrowser.py
  22. +13 −4 qutebrowser/mainwindow/tabwidget.py
  23. +10 −4 qutebrowser/misc/crashsignal.py
  24. +3 −0 qutebrowser/misc/earlyinit.py
  25. +5 −8 qutebrowser/utils/utils.py
  26. +17 −8 qutebrowser/utils/version.py
  27. +1 −0 requirements.txt
  28. +13 −3 scripts/dev/check_coverage.py
  29. +14 −2 scripts/dev/get_coredumpctl_traces.py
  30. +6 −0 scripts/dev/run_vulture.py
  31. +1 −1 setup.py
  32. +4 −6 tests/end2end/fixtures/testprocess.py
  33. +4 −10 tests/end2end/fixtures/webserver.py
  34. +17 −3 tests/end2end/test_dirbrowser.py
  35. +6 −3 tests/end2end/test_hints_html.py
  36. +13 −4 tests/helpers/fixtures.py
  37. +10 −4 tests/helpers/messagemock.py
  38. +13 −13 tests/helpers/stubs.py
  39. +6 −2 tests/unit/browser/test_signalfilter.py
  40. +13 −3 tests/unit/browser/webkit/network/test_filescheme.py
  41. +6 −3 tests/unit/browser/webkit/test_tabhistory.py
  42. +9 −3 tests/unit/browser/webkit/test_webkitelem.py
  43. +16 −11 tests/unit/config/test_configtypes.py
  44. +10 −5 tests/unit/misc/test_ipc.py
  45. +16 −11 tests/unit/misc/test_split.py
  46. +20 −11 tests/unit/utils/test_standarddir.py
  47. +6 −3 tests/unit/utils/test_urlutils.py
  48. +6 −2 tests/unit/utils/test_utils.py
  49. +15 −13 tests/unit/utils/test_version.py
@@ -43,6 +43,7 @@ function-rgx=[a-z_][a-z0-9_]{2,50}$
const-rgx=[A-Za-z_][A-Za-z0-9_]{0,30}$
method-rgx=[a-z_][A-Za-z0-9_]{1,50}$
attr-rgx=[a-z_][a-z0-9_]{0,30}$
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$
argument-rgx=[a-z_][a-z0-9_]{0,30}$
variable-rgx=[a-z_][a-z0-9_]{0,30}$
docstring-min-length=3
@@ -64,6 +65,7 @@ valid-metaclass-classmethod-first-arg=cls

[TYPECHECK]
ignored-modules=PyQt5,PyQt5.QtWebKit
ignored-classes=_CountingAttr

[IMPORTS]
# WORKAROUND
@@ -116,6 +116,7 @@ The following software and libraries are required to run qutebrowser:
* http://jinja.pocoo.org/[jinja2]
* http://pygments.org/[pygments]
* http://pyyaml.org/wiki/PyYAML[PyYAML]
* http://www.attrs.org/[attrs]
The following libraries are optional:

@@ -27,6 +27,7 @@ Breaking changes
- (TODO) New dependency on ruamel.yaml; dropped PyYAML dependency.
- (TODO) The QtWebEngine backend is now used by default if available.
- New dependency on the QtSql module and Qt sqlite support.
- New dependency on the `attrs` Python module.
- New config system which ignores the old config file.
- The depedency on PyOpenGL (when using QtWebEngine) got removed. Note
that PyQt5.QtOpenGL is still a dependency.
@@ -4,3 +4,4 @@ pyPEG2
PyYAML
colorama
cssutils
attrs
@@ -40,6 +40,7 @@ git+https://github.com/pallets/jinja.git
git+https://github.com/pallets/markupsafe.git
hg+http://bitbucket.org/birkenfeld/pygments-main
hg+https://bitbucket.org/fdik/pypeg
git+https://github.com/python-attrs/attrs.git

# Fails to build:
# gcc: error: ext/_yaml.c: No such file or directory
@@ -21,6 +21,7 @@

import itertools

import attr
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QApplication
@@ -82,6 +83,7 @@ class UnsupportedOperationError(WebTabError):
])


@attr.s
class TabData:

"""A simple namespace with a fixed set of attributes.
@@ -97,13 +99,12 @@ class TabData:
fullscreen: Whether the tab has a video shown fullscreen currently.
"""

def __init__(self):
self.keep_icon = False
self.viewing_source = False
self.inspector = None
self.override_target = None
self.pinned = False
self.fullscreen = False
keep_icon = attr.ib(False)
viewing_source = attr.ib(False)
inspector = attr.ib(None)
override_target = attr.ib(None)
pinned = attr.ib(False)
fullscreen = attr.ib(False)


class AbstractAction:
@@ -26,6 +26,7 @@
import html
from string import ascii_lowercase

import attr
from PyQt5.QtCore import pyqtSlot, QObject, Qt, QUrl
from PyQt5.QtWidgets import QLabel

@@ -131,6 +132,7 @@ def cleanup(self):
self.deleteLater()


@attr.s
class HintContext:

"""Context namespace used for hinting.
@@ -158,19 +160,18 @@ class HintContext:
group: The group of web elements to hint.
"""

def __init__(self):
self.all_labels = []
self.labels = {}
self.target = None
self.baseurl = None
self.to_follow = None
self.rapid = False
self.add_history = False
self.filterstr = None
self.args = []
self.tab = None
self.group = None
self.hint_mode = None
all_labels = attr.ib(attr.Factory(list))
labels = attr.ib(attr.Factory(dict))
target = attr.ib(None)
baseurl = attr.ib(None)
to_follow = attr.ib(None)
rapid = attr.ib(False)
add_history = attr.ib(False)
filterstr = attr.ib(None)
args = attr.ib(attr.Factory(list))
tab = attr.ib(None)
group = attr.ib(None)
hint_mode = attr.ib(None)

def get_args(self, urlstr):
"""Get the arguments, with {hint-url} replaced by the given URL."""
@@ -389,6 +390,7 @@ def _get_text(self):

def _cleanup(self):
"""Clean up after hinting."""
# pylint: disable=not-an-iterable
for label in self._context.all_labels:
label.cleanup()

@@ -795,6 +797,7 @@ def filter_hints(self, filterstr):
log.hints.debug("Filtering hints on {!r}".format(filterstr))

visible = []
# pylint: disable=not-an-iterable
for label in self._context.all_labels:
try:
if self._filter_matches(filterstr, str(label.elem)):
@@ -22,8 +22,8 @@
import io
import shutil
import functools
import collections

import attr
from PyQt5.QtCore import pyqtSlot, pyqtSignal, QTimer
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply

@@ -34,7 +34,11 @@
from qutebrowser.browser.webkit.network import networkmanager


_RetryInfo = collections.namedtuple('_RetryInfo', ['request', 'manager'])
@attr.s
class _RetryInfo:

request = attr.ib()
manager = attr.ib()


class DownloadItem(downloads.AbstractDownloadItem):
@@ -25,7 +25,6 @@
import os
import re
import sys
import collections
import uuid
import email.policy
import email.generator
@@ -34,15 +33,21 @@
import email.message
import quopri

import attr
from PyQt5.QtCore import QUrl

from qutebrowser.browser import downloads
from qutebrowser.browser.webkit import webkitelem
from qutebrowser.utils import log, objreg, message, usertypes, utils, urlutils

_File = collections.namedtuple('_File',
['content', 'content_type', 'content_location',
'transfer_encoding'])

@attr.s
class _File:

content = attr.ib()
content_type = attr.ib()
content_location = attr.ib()
transfer_encoding = attr.ib()


_CSS_URL_PATTERNS = [re.compile(x) for x in [
@@ -174,7 +179,7 @@ class MHTMLWriter:
root_content: The root content as bytes.
content_location: The url of the page as str.
content_type: The MIME-type of the root content as str.
_files: Mapping of location->_File namedtuple.
_files: Mapping of location->_File object.
"""

def __init__(self, root_content, content_location, content_type):
@@ -24,6 +24,7 @@
import netrc
import html

import attr
from PyQt5.QtCore import (pyqtSlot, pyqtSignal, QCoreApplication, QUrl,
QByteArray)
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply, QSslSocket
@@ -37,10 +38,19 @@


HOSTBLOCK_ERROR_STRING = '%HOSTBLOCK%'
ProxyId = collections.namedtuple('ProxyId', 'type, hostname, port')
_proxy_auth_cache = {}


@attr.s
class ProxyId:

"""Information identifying a proxy server."""

type = attr.ib()
hostname = attr.ib()
port = attr.ib()


def _is_secure_cipher(cipher):
"""Check if a given SSL cipher (hopefully) isn't broken yet."""
tokens = [e.upper() for e in cipher.name().split('-')]
@@ -19,11 +19,11 @@

"""pyPEG parsing for the RFC 6266 (Content-Disposition) header."""

import collections
import urllib.parse
import string
import re

import attr
import pypeg2 as peg

from qutebrowser.utils import utils
@@ -210,7 +210,13 @@ class ContentDispositionValue:
peg.optional(';'))


LangTagged = collections.namedtuple('LangTagged', ['string', 'langtag'])
@attr.s
class LangTagged:

"""A string with an associated language."""

string = attr.ib()
langtag = attr.ib()


class Error(Exception):
@@ -24,43 +24,32 @@
import traceback
import typing

import attr

from qutebrowser.commands import cmdexc, argparser
from qutebrowser.utils import (log, utils, message, docutils, objreg,
usertypes)
from qutebrowser.utils import log, message, docutils, objreg, usertypes
from qutebrowser.utils import debug as debug_utils
from qutebrowser.misc import objects


@attr.s
class ArgInfo:

"""Information about an argument."""

def __init__(self, win_id=False, count=False, hide=False, metavar=None,
flag=None, completion=None, choices=None):
if win_id and count:
win_id = attr.ib(False)
count = attr.ib(False)
hide = attr.ib(False)
metavar = attr.ib(None)
flag = attr.ib(None)
completion = attr.ib(None)
choices = attr.ib(None)

@win_id.validator
@count.validator
def _validate_exclusive(self, _attr, _value):
if self.win_id and self.count:
raise TypeError("Argument marked as both count/win_id!")
self.win_id = win_id
self.count = count
self.flag = flag
self.hide = hide
self.metavar = metavar
self.completion = completion
self.choices = choices

def __eq__(self, other):
return (self.win_id == other.win_id and
self.count == other.count and
self.flag == other.flag and
self.hide == other.hide and
self.metavar == other.metavar and
self.completion == other.completion and
self.choices == other.choices)

def __repr__(self):
return utils.get_repr(self, win_id=self.win_id, count=self.count,
flag=self.flag, hide=self.hide,
metavar=self.metavar, completion=self.completion,
choices=self.choices, constructor=True)


class Command:
@@ -19,10 +19,10 @@

"""Module containing command managers (SearchRunner and CommandRunner)."""

import collections
import traceback
import re

import attr
from PyQt5.QtCore import pyqtSlot, QUrl, QObject

from qutebrowser.config import config
@@ -31,10 +31,19 @@
from qutebrowser.misc import split


ParseResult = collections.namedtuple('ParseResult', ['cmd', 'args', 'cmdline'])
last_command = {}


@attr.s
class ParseResult:

"""The result of parsing a commandline."""

cmd = attr.ib()
args = attr.ib()
cmdline = attr.ib()


def _current_url(tabbed_browser):
"""Convenience method to get the current url."""
try:
@@ -19,8 +19,7 @@

"""Completer attached to a CompletionView."""

import collections

import attr
from PyQt5.QtCore import pyqtSlot, QObject, QTimer

from qutebrowser.config import config
@@ -29,9 +28,13 @@
from qutebrowser.completion.models import miscmodels


# Context passed into all completion functions
CompletionInfo = collections.namedtuple('CompletionInfo',
['config', 'keyconf'])
@attr.s
class CompletionInfo:

"""Context passed into all completion functions."""

config = attr.ib()
keyconf = attr.ib()


class Completer(QObject):
@@ -130,7 +133,9 @@ def _partition(self):
return [], '', []
parser = runners.CommandParser()
result = parser.parse(text, fallback=True, keep=True)
# pylint: disable=not-an-iterable
parts = [x for x in result.cmdline if x]
# pylint: enable=not-an-iterable
pos = self._cmd.cursorPosition() - len(self._cmd.prefix())
pos = min(pos, len(text)) # Qt treats 2-byte UTF-16 chars as 2 chars
log.completion.debug('partitioning {} around position {}'.format(parts,
Oops, something went wrong.

0 comments on commit 3a5241b

Please sign in to comment.
You can’t perform that action at this time.