jenkins-bot has submitted this change and it was merged.
Change subject: [FIX] MediaWikiVersion: Support non-wmf versions ......................................................................
[FIX] MediaWikiVersion: Support non-wmf versions
Previously it didn't require to match the complete version number. If now a version '1.25alpha' was used in MediaWikiVersion it just ignored the 'alpha' part. This now requires that the complete version number is matched and does allow several different version number suffixes:
* 'wmf<number>' * 'alpha' * 'beta<number>' * 'rc<number>'/'-rc.<number>'/'-rc<number>'/'rc.<number>'
It follows in that order, so an alpha version is considered newer (and is thus using newer API) than a wmf version, but older than any beta version. All suffixes are considered older than a version number without a suffix. If the suffix doesn't follow in this scheme the version number is invalid.
Because alpha releases might not represent the newest wmf version the family can now define a 'force_version' number which must return a valid version number for MediaWikiVersion. If it's not empty that version number will be used at all times.
This in theory breaks the API as MediaWikiVersion has no 'wmf_version' attribute, but that shouldn't be used anyway outside of that class. It has been replaced by '_dev_version' which maps those above to a 'subversion' (e.g. wmf42 = (0, 42)). The stable releases (without a suffix) use (4,) for simplification of the comparision.
As family's version method shouldn't be used directly anymore it's marked as deprecated.
Change-Id: Id8b37d16765bae5007456dc9923dc5c81daca4e5 --- M generate_family_file.py M pywikibot/families/anarchopedia_family.py M pywikibot/families/wikia_family.py M pywikibot/families/wowwiki_family.py M pywikibot/family.py M pywikibot/site.py M pywikibot/tools.py M tests/mediawikiversion_tests.py 8 files changed, 129 insertions(+), 36 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/generate_family_file.py b/generate_family_file.py index 2dd21e4..380fd0c 100644 --- a/generate_family_file.py +++ b/generate_family_file.py @@ -185,6 +185,7 @@ """
from pywikibot import family +from pywikibot.tools import deprecated
class Family(family.Family): def __init__(self): @@ -210,6 +211,7 @@ f.write(" }[code]\n") f.write("\n")
+ f.write(" @deprecated('APISite.version()')\n") f.write(" def version(self, code):\n") f.write(" return {\n") for w in self.wikis.values(): diff --git a/pywikibot/families/anarchopedia_family.py b/pywikibot/families/anarchopedia_family.py index 42f4a96..789ae2c 100644 --- a/pywikibot/families/anarchopedia_family.py +++ b/pywikibot/families/anarchopedia_family.py @@ -4,6 +4,7 @@ __version__ = '$Id$'
from pywikibot import family +from pywikibot.tools import deprecated
# The Anarchopedia family @@ -67,6 +68,7 @@ 'nob': None, }
+ @deprecated('APISite.version()') def version(self, code): """Return the version for this family.""" return "1.14alpha" diff --git a/pywikibot/families/wikia_family.py b/pywikibot/families/wikia_family.py index 9ab8cdd..7dc627a 100644 --- a/pywikibot/families/wikia_family.py +++ b/pywikibot/families/wikia_family.py @@ -4,6 +4,7 @@ __version__ = '$Id$'
from pywikibot import family +from pywikibot.tools import deprecated
# The Wikia Search family @@ -25,6 +26,7 @@ """Return the hostname for every site in this family.""" return u'www.wikia.com'
+ @deprecated('APISite.version()') def version(self, code): """Return the version for this family.""" return "1.19.20" diff --git a/pywikibot/families/wowwiki_family.py b/pywikibot/families/wowwiki_family.py index fbf820e..96b70c0 100644 --- a/pywikibot/families/wowwiki_family.py +++ b/pywikibot/families/wowwiki_family.py @@ -4,6 +4,7 @@ __version__ = '$Id$'
from pywikibot import family +from pywikibot.tools import deprecated
class Family(family.Family): @@ -61,6 +62,7 @@ """Return the script path for this family.""" return ''
+ @deprecated('APISite.version()') def version(self, code): """Return the version for this family.""" return '1.19.20' diff --git a/pywikibot/family.py b/pywikibot/family.py index bf04dbb..4c62cd4 100644 --- a/pywikibot/family.py +++ b/pywikibot/family.py @@ -1097,6 +1097,7 @@ return '%s%s' % (code, self.name)
# Which version of MediaWiki is used? + @deprecated('APISite.version()') def version(self, code): """ Return MediaWiki version number as a string.
@@ -1105,7 +1106,27 @@ # Here we return the latest mw release for downloading return '1.24.1'
- @deprecated("version()") + def force_version(self, code): + """ + Return a manual version number. + + The site is usually using the version number from the servers' + siteinfo, but if there is a problem with that it's possible to return + a non-empty string here representing another version number. + + For example, L{pywikibot.tools.MediaWikiVersion} treats version + numbers ending with 'alpha', 'beta' or 'rc' as newer than any version + ending with 'wmf<number>'. But if that causes breakage it's possible + to override it here to a version number which doesn't cause breakage. + + @return: A version number which can be parsed using + L{pywikibot.tools.MediaWikiVersion}. If empty/None it uses the + version returned via siteinfo. + @rtype: str + """ + return None + + @deprecated("APISite.version()") def versionnumber(self, code): """ DEPRECATED, use version() instead.
diff --git a/pywikibot/site.py b/pywikibot/site.py index 973edaf..79df01a 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -2225,13 +2225,15 @@ This overwrites the corresponding family method for APISite class. Use L{pywikibot.tools.MediaWikiVersion} to compare MediaWiki versions. """ - try: - version = self.siteinfo.get('generator', expiry=1).split(' ')[1] - except pywikibot.data.api.APIError: - # May occur if you are not logged in (no API read permissions). - pywikibot.exception( - 'You have no API read permissions. Seems you are not logged in') - version = self.family.version(self.code) + version = self.force_version() + if not version: + try: + version = self.siteinfo.get('generator', expiry=1).split(' ')[1] + except pywikibot.data.api.APIError: + # May occur if you are not logged in (no API read permissions). + pywikibot.exception('You have no API read permissions. Seems ' + 'you are not logged in') + version = self.family.version(self.code) return version
@property diff --git a/pywikibot/tools.py b/pywikibot/tools.py index 6844a1b..0eb772e 100644 --- a/pywikibot/tools.py +++ b/pywikibot/tools.py @@ -105,26 +105,51 @@
class MediaWikiVersion(Version):
- """Version object to allow comparing 'wmf' versions with normal ones.""" + """ + Version object to allow comparing 'wmf' versions with normal ones.
- MEDIAWIKI_VERSION = re.compile(r'(\d+(?:.\d+)*)(?:wmf(\d+))?') + The version mainly consist of digits separated by periods. After that is a + suffix which may only be 'wmf<number>', 'alpha', 'beta<number>' or + '-rc.<number>' (the - and . are optional). They are considered from old to + new in that order with a version number without suffix is considered the + newest. This secondary difference is stored in an internal _dev_version + attribute. + + Two versions are equal if their normal version and dev version are equal. A + version is greater if the normal version or dev version is greater. For + example: + 1.24 < 1.24.1 < 1.25wmf1 < 1.25alpha < 1.25beta1 < 1.25beta2 + < 1.25-rc-1 < 1.25-rc.2 < 1.25 + + Any other suffixes are considered invalid. + """ + + MEDIAWIKI_VERSION = re.compile(r'^(\d+(?:.\d+)+)(wmf(\d+)|alpha|beta(\d+)|-?rc.?(\d+))?$')
def parse(self, vstring): version_match = MediaWikiVersion.MEDIAWIKI_VERSION.match(vstring) if not version_match: - raise ValueError('Invalid version number') + raise ValueError('Invalid version number "{0}"'.format(vstring)) components = [int(n) for n in version_match.group(1).split('.')] - self.wmf_version = None - if version_match.group(2): # wmf version - self.wmf_version = int(version_match.group(2)) + # 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): + self._dev_version = (2, int(version_match.group(4))) + elif version_match.group(5): + self._dev_version = (3, int(version_match.group(5))) + elif version_match.group(2) == 'alpha': + self._dev_version = (1, ) + else: + self._dev_version = (4, ) + self.suffix = version_match.group(2) or '' self.version = tuple(components)
def __str__(self): - """Return version number with optional "wmf" suffix.""" - vstring = '.'.join(str(v) for v in self.version) - if self.wmf_version: - vstring += 'wmf{0}'.format(self.wmf_version) - return vstring + """Return version number with optional suffix.""" + return '.'.join(str(v) for v in self.version) + self.suffix
def _cmp(self, other): if isinstance(other, basestring): @@ -134,18 +159,11 @@ return 1 if self.version < other.version: return -1 - if self.wmf_version and other.wmf_version: - if self.wmf_version > other.wmf_version: - return 1 - if self.wmf_version < other.wmf_version: - return -1 - return 0 - elif other.wmf_version: + if self._dev_version > other._dev_version: return 1 - elif self.wmf_version: + if self._dev_version < other._dev_version: return -1 - else: - return 0 + return 0
if sys.version_info[0] == 2: __cmp__ = _cmp diff --git a/tests/mediawikiversion_tests.py b/tests/mediawikiversion_tests.py index 8bcb254..17bd115 100644 --- a/tests/mediawikiversion_tests.py +++ b/tests/mediawikiversion_tests.py @@ -19,18 +19,62 @@
net = False
+ def _make(self, version): + """Create a MediaWikiVersion instance and check that the str stays.""" + v = V(version) + self.assertEqual(str(v), version) + return v + def test_normal_versions(self): - self.assertGreater(V('1.23'), V('1.22.0')) - self.assertTrue(V('1.23') == V('1.23')) - self.assertEqual(V('1.23'), V('1.23')) + """Test comparison between release versions.""" + self.assertGreater(self._make('1.23'), self._make('1.22.0')) + self.assertTrue(self._make('1.23') == self._make('1.23')) + self.assertEqual(self._make('1.23'), self._make('1.23'))
def test_wmf_versions(self): - self.assertGreater(V('1.23wmf10'), V('1.23wmf9')) - self.assertEqual(V('1.23wmf10'), V('1.23wmf10')) + """Test comparison between wmf versions.""" + self.assertGreater(self._make('1.23wmf10'), self._make('1.23wmf9')) + self.assertEqual(self._make('1.23wmf10'), self._make('1.23wmf10'))
def test_combined_versions(self): - self.assertGreater(V('1.23wmf10'), V('1.22.3')) - self.assertGreater(V('1.23'), V('1.23wmf10')) + """Test comparison between wmf versions and release versions.""" + self.assertGreater(self._make('1.23wmf10'), self._make('1.22.3')) + self.assertGreater(self._make('1.23'), self._make('1.23wmf10')) + + def test_non_wmf_scheme(self): + """Test version numbers not following the wmf-scheme.""" + self.assertGreater(self._make('1.23alpha'), self._make('1.22.3')) + self.assertGreater(self._make('1.23alpha'), self._make('1.23wmf1')) + self.assertGreater(self._make('1.23beta1'), self._make('1.23alpha')) + self.assertGreater(self._make('1.23beta2'), self._make('1.23beta1')) + self.assertGreater(self._make('1.23-rc.1'), self._make('1.23beta2')) + self.assertGreater(self._make('1.23-rc.2'), self._make('1.23-rc.1')) + self.assertGreater(self._make('1.23'), self._make('1.23-rc.2')) + self.assertEqual(self._make('1.23rc1'), self._make('1.23-rc.1')) + + def _version_check(self, version, digits, dev_version, suffix): + v = self._make(version) + self.assertEqual(v.version, digits) + self.assertEqual(v._dev_version, dev_version) + self.assertEqual(v.suffix, suffix) + + def test_interpretation(self): + """Test if the data is correctly interpreted.""" + self._version_check('1.23', (1, 23), (4, ), '') + self._version_check('1.23wmf1', (1, 23), (0, 1), 'wmf1') + self._version_check('1.23alpha', (1, 23), (1, ), 'alpha') + self._version_check('1.23beta1', (1, 23), (2, 1), 'beta1') + self._version_check('1.23rc1', (1, 23), (3, 1), 'rc1') + self._version_check('1.23-rc1', (1, 23), (3, 1), '-rc1') + self._version_check('1.23-rc.1', (1, 23), (3, 1), '-rc.1') + + def test_invalid_versions(self): + """Verify that insufficient version fail creating.""" + self.assertRaises(ValueError, V, 'invalid') + self.assertRaises(ValueError, V, '1number') + self.assertRaises(ValueError, V, '1.missing') + self.assertRaises(ValueError, V, '1.23wmf-1') + self.assertRaises(ValueError, V, '1.23text')
if __name__ == '__main__':
pywikibot-commits@lists.wikimedia.org