jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/681239 )
Change subject: [cleanup] Revise MediaWikiVersion ......................................................................
[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(-)
Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
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, ), '')
pywikibot-commits@lists.wikimedia.org