summaryrefslogtreecommitdiff
path: root/qutebrowser/utils
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2021-03-11 14:51:47 +0100
committerFlorian Bruhin <me@the-compiler.org>2021-03-11 16:45:40 +0100
commit4709d46936b379605aca110c7dd336d1cff45db6 (patch)
tree3641c2f36be03c3cf6a549e591cfd3be432f9d36 /qutebrowser/utils
parentdc5a63f70bbdaf342511344e70f45562ecbf5a9e (diff)
downloadqutebrowser-4709d46936b379605aca110c7dd336d1cff45db6.tar.gz
qutebrowser-4709d46936b379605aca110c7dd336d1cff45db6.zip
Add custom VersionNumber class
Qt's API is kind of painful, and we need some custom functionality anyways. Wrap QVersionNumber with our own class instead of piling up workarounds.
Diffstat (limited to 'qutebrowser/utils')
-rw-r--r--qutebrowser/utils/qtutils.py12
-rw-r--r--qutebrowser/utils/utils.py86
-rw-r--r--qutebrowser/utils/version.py16
3 files changed, 76 insertions, 38 deletions
diff --git a/qutebrowser/utils/qtutils.py b/qutebrowser/utils/qtutils.py
index f7c5a3ce0..01234a42b 100644
--- a/qutebrowser/utils/qtutils.py
+++ b/qutebrowser/utils/qtutils.py
@@ -98,15 +98,15 @@ def version_check(version: str,
if compiled and exact:
raise ValueError("Can't use compiled=True with exact=True!")
- parsed = utils.parse_version(version)
+ parsed = utils.VersionNumber.parse(version)
op = operator.eq if exact else operator.ge
- result = op(utils.parse_version(qVersion()), parsed)
+ result = op(utils.VersionNumber.parse(qVersion()), parsed)
if compiled and result:
# qVersion() ==/>= parsed, now check if QT_VERSION_STR ==/>= parsed.
- result = op(utils.parse_version(QT_VERSION_STR), parsed)
+ result = op(utils.VersionNumber.parse(QT_VERSION_STR), parsed)
if compiled and result:
# Finally, check PYQT_VERSION_STR as well.
- result = op(utils.parse_version(PYQT_VERSION_STR), parsed)
+ result = op(utils.VersionNumber.parse(PYQT_VERSION_STR), parsed)
return result
@@ -116,8 +116,8 @@ MAX_WORLD_ID = 256
def is_new_qtwebkit() -> bool:
"""Check if the given version is a new QtWebKit."""
assert qWebKitVersion is not None
- return (utils.parse_version(qWebKitVersion()) >
- utils.parse_version('538.1'))
+ return (utils.VersionNumber.parse(qWebKitVersion()) >
+ utils.VersionNumber.parse('538.1'))
def is_single_process() -> bool:
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
index 698a608ef..af9d5fad7 100644
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -92,26 +92,74 @@ class Comparable(Protocol):
...
-if TYPE_CHECKING:
- class VersionNumber(Comparable, QVersionNumber):
+class VersionNumber:
- """WORKAROUND for incorrect PyQt stubs."""
-else:
- class VersionNumber(QVersionNumber):
+ """A representation of a version number."""
- """We can't inherit from Protocol and QVersionNumber at runtime."""
+ def __init__(self, *args: int) -> None:
+ self._ver = QVersionNumber(*args)
+ if self._ver.isNull():
+ raise ValueError("Can't construct a null version")
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- normalized = self.normalized()
- if normalized != self:
- raise ValueError(
- f"Refusing to construct non-normalized version from {args} "
- f"(normalized: {tuple(normalized.segments())}).")
+ normalized = self._ver.normalized()
+ if normalized != self._ver:
+ raise ValueError(
+ f"Refusing to construct non-normalized version from {args} "
+ f"(normalized: {tuple(normalized.segments())}).")
- def __repr__(self):
- args = ", ".join(str(s) for s in self.segments())
- return f'VersionNumber({args})'
+ self.major = self._ver.majorVersion()
+ self.minor = self._ver.minorVersion()
+ self.patch = self._ver.microVersion()
+ self.segments = self._ver.segments()
+
+ assert len(self.segments) <= 3, self.segments
+
+ def __str__(self) -> str:
+ return ".".join(str(s) for s in self.segments)
+
+ def __repr__(self) -> str:
+ args = ", ".join(str(s) for s in self.segments)
+ return f'VersionNumber({args})'
+
+ def strip_patch(self) -> 'VersionNumber':
+ """Get a new VersionNumber with the patch version removed."""
+ return VersionNumber(*self.segments[:2])
+
+ @classmethod
+ def parse(cls, s: str) -> 'VersionNumber':
+ """Parse a version number from a string."""
+ ver, _suffix = QVersionNumber.fromString(s)
+ # FIXME: Should we support a suffix?
+
+ if ver.isNull():
+ raise ValueError(f"Failed to parse {s}")
+
+ return cls(*ver.normalized().segments())
+
+ def __hash__(self) -> int:
+ return hash(self._ver)
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, VersionNumber):
+ return NotImplemented
+ return self._ver == other._ver
+
+ def __ne__(self, other: object) -> bool:
+ if not isinstance(other, VersionNumber):
+ return NotImplemented
+ return self._ver != other._ver
+
+ def __ge__(self, other: 'VersionNumber') -> bool:
+ return self._ver >= other._ver # type: ignore[operator]
+
+ def __gt__(self, other: 'VersionNumber') -> bool:
+ return self._ver > other._ver # type: ignore[operator]
+
+ def __le__(self, other: 'VersionNumber') -> bool:
+ return self._ver <= other._ver # type: ignore[operator]
+
+ def __lt__(self, other: 'VersionNumber') -> bool:
+ return self._ver < other._ver # type: ignore[operator]
class Unreachable(Exception):
@@ -294,12 +342,6 @@ def read_file_binary(filename: str) -> bytes:
return path.read_bytes()
-def parse_version(version: str) -> VersionNumber:
- """Parse a version string."""
- ver, _suffix = QVersionNumber.fromString(version)
- return VersionNumber(ver.normalized())
-
-
def format_seconds(total_seconds: int) -> str:
"""Format a count of seconds to get a [H:]M:SS string."""
prefix = '-' if total_seconds < 0 else ''
diff --git a/qutebrowser/utils/version.py b/qutebrowser/utils/version.py
index a10f50ffc..4a4455c99 100644
--- a/qutebrowser/utils/version.py
+++ b/qutebrowser/utils/version.py
@@ -160,7 +160,7 @@ def distribution() -> Optional[DistributionInfo]:
dist_version: Optional[utils.VersionNumber] = None
for version_key in ['VERSION', 'VERSION_ID']:
if version_key in info:
- dist_version = utils.parse_version(info[version_key])
+ dist_version = utils.VersionNumber.parse(info[version_key])
break
dist_id = info.get('ID', None)
@@ -568,7 +568,7 @@ class WebEngineVersions:
}
def __str__(self) -> str:
- s = f'QtWebEngine {self.webengine.toString()}'
+ s = f'QtWebEngine {self.webengine}'
if self.chromium is not None:
s += f', Chromium {self.chromium}'
if self.source != 'UA':
@@ -585,7 +585,7 @@ class WebEngineVersions:
"""
assert ua.qt_version is not None, ua
return cls(
- webengine=utils.parse_version(ua.qt_version),
+ webengine=utils.VersionNumber.parse(ua.qt_version),
chromium=ua.upstream_browser_version,
source='UA',
)
@@ -602,7 +602,7 @@ class WebEngineVersions:
(though hackish) way to get a more accurate result.
"""
return cls(
- webengine=utils.parse_version(versions.webengine),
+ webengine=utils.VersionNumber.parse(versions.webengine),
chromium=versions.chromium,
source='ELF',
)
@@ -624,11 +624,7 @@ class WebEngineVersions:
minor_version = v5_15_3
else:
# e.g. 5.14.2 -> 5.14
- segments = pyqt_webengine_version.segments()[:2]
- if segments[-1] == 0:
- del segments[-1] # pragma: no cover
-
- minor_version = utils.VersionNumber(*segments)
+ minor_version = pyqt_webengine_version.strip_patch()
return cls._CHROMIUM_VERSIONS.get(minor_version)
@@ -651,7 +647,7 @@ class WebEngineVersions:
Note that we only can get the PyQtWebEngine version with PyQt 5.13 or newer.
With Qt 5.12, we instead rely on qVersion().
"""
- parsed = utils.parse_version(pyqt_webengine_version)
+ parsed = utils.VersionNumber.parse(pyqt_webengine_version)
return cls(
webengine=parsed,
chromium=cls._infer_chromium_version(parsed),