jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[cleanup] Revise MediaWikiVersion

Just a couple minor adjustments...

* The 'parse()' method is an artifact of subclassing distutils.Version.
Nothing but the constructor referenced it.

* Comparison with types other than str or MediaWikiVersion failed with a
AttributeError. It should raise a TypeError instead...

>>> MediaWikiVersion('1.33') > ['wrong type']
AttributeError: 'list' object has no attribute 'version'

Bug: T281200
Change-Id: I9757b7f197872cccc2e580740e79a21ba234ba92
---
M pywikibot/tools/__init__.py
M tests/mediawikiversion_tests.py
2 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/pywikibot/tools/__init__.py b/pywikibot/tools/__init__.py
index 5edad9f..cfa3859 100644
--- a/pywikibot/tools/__init__.py
+++ b/pywikibot/tools/__init__.py
@@ -22,11 +22,11 @@
from collections.abc import Container, Iterable, Iterator, Mapping, Sized
from contextlib import suppress
from datetime import datetime
-from functools import wraps
+from functools import total_ordering, wraps
from importlib import import_module
from inspect import getfullargspec
from itertools import chain, zip_longest
-from typing import Optional
+from typing import Any, Optional
from warnings import catch_warnings, showwarning, warn

import pkg_resources
@@ -507,6 +507,7 @@
return first_upper(username)


+@total_ordering
class MediaWikiVersion:

"""
@@ -532,32 +533,26 @@
MEDIAWIKI_VERSION = re.compile(
r'(\d+(?:\.\d+)+)(-?wmf\.?(\d+)|alpha|beta(\d+)|-?rc\.?(\d+)|.*)?$')

- def __init__(self, version_str):
+ def __init__(self, version_str: str) -> None:
"""
Initializer.

@param version_str: version to parse
- @type version: str
"""
- self.parse(version_str)
+ self._parse(version_str)

- @classmethod
- def from_generator(cls, generator):
- """Create instance using the generator string."""
- if not generator.startswith('MediaWiki '):
- raise ValueError('Generator string ({!r}) must start with '
- '"MediaWiki "'.format(generator))
- return cls(generator[len('MediaWiki '):])
+ def _parse(self, version_str: str) -> None:
+ version_match = MediaWikiVersion.MEDIAWIKI_VERSION.match(version_str)

- def parse(self, vstring):
- """Parse version string."""
- version_match = MediaWikiVersion.MEDIAWIKI_VERSION.match(vstring)
if not version_match:
- raise ValueError('Invalid version number "{}"'.format(vstring))
+ raise ValueError('Invalid version number "{}"'.format(version_str))
+
components = [int(n) for n in version_match.group(1).split('.')]
+
# The _dev_version numbering scheme might change. E.g. if a stage
# between 'alpha' and 'beta' is added, 'beta', 'rc' and stable releases
# are reassigned (beta=3, rc=4, stable=5).
+
if version_match.group(3): # wmf version
self._dev_version = (0, int(version_match.group(3)))
elif version_match.group(4):
@@ -577,41 +572,45 @@
'"{}"'.format(version_match.group(2)),
_logger)
self._dev_version = (4, )
+
self.suffix = version_match.group(2) or ''
self.version = tuple(components)

- def __str__(self):
+ @staticmethod
+ def from_generator(generator: str) -> 'MediaWikiVersion':
+ """Create instance from a site's generator attribute."""
+ prefix = 'MediaWiki '
+
+ if not generator.startswith(prefix):
+ raise ValueError('Generator string ({!r}) must start with '
+ '"{}"'.format(generator, prefix))
+
+ return MediaWikiVersion(generator[len(prefix):])
+
+ def __str__(self) -> str:
"""Return version number with optional suffix."""
return '.'.join(str(v) for v in self.version) + self.suffix

- def _cmp(self, other):
+ def __eq__(self, other: Any) -> bool:
if isinstance(other, str):
other = MediaWikiVersion(other)
+ elif not isinstance(other, MediaWikiVersion):
+ return False

- if self.version > other.version:
- return 1
- if self.version < other.version:
- return -1
- if self._dev_version > other._dev_version:
- return 1
- if self._dev_version < other._dev_version:
- return -1
- return 0
+ return self.version == other.version and \
+ self._dev_version == other._dev_version

- def __eq__(self, other):
- return self._cmp(other) == 0
+ def __lt__(self, other: Any) -> bool:
+ if isinstance(other, str):
+ other = MediaWikiVersion(other)
+ elif not isinstance(other, MediaWikiVersion):
+ raise TypeError("Comparison between 'MediaWikiVersion' and '{}' "
+ 'unsupported'.format(type(other).__name__))

- def __lt__(self, other):
- return self._cmp(other) < 0
-
- def __le__(self, other):
- return self._cmp(other) <= 0
-
- def __gt__(self, other):
- return self._cmp(other) > 0
-
- def __ge__(self, other):
- return self._cmp(other) >= 0
+ if self.version != other.version:
+ return self.version < other.version
+ else:
+ return self._dev_version < other._dev_version


class RLock:
diff --git a/tests/mediawikiversion_tests.py b/tests/mediawikiversion_tests.py
index 3096057..3e13cc7 100644
--- a/tests/mediawikiversion_tests.py
+++ b/tests/mediawikiversion_tests.py
@@ -57,6 +57,15 @@
self.assertEqual(v._dev_version, dev_version)
self.assertEqual(v.suffix, suffix)

+ def test_invalid_type_comparison(self):
+ """Compare with a type other than a version or string."""
+ self.assertNotEqual(self._make('1.32.0'), ['wrong type'])
+
+ exc = "Comparison between 'MediaWikiVersion' and 'list' unsupported"
+
+ with self.assertRaisesRegex(TypeError, exc):
+ assert self._make('1.32.0') > ['wrong type']
+
def test_interpretation(self):
"""Test if the data is correctly interpreted."""
self._version_check('1.33', (1, 33), (4, ), '')

To view, visit change 681239. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I9757b7f197872cccc2e580740e79a21ba234ba92
Gerrit-Change-Number: 681239
Gerrit-PatchSet: 16
Gerrit-Owner: Damian <atagar1@gmail.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged