jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/835198 )

Change subject: [cleanup] Drop support for MediaWiki < 1.27
......................................................................

[cleanup] Drop support for MediaWiki < 1.27

Drop support for MediaWiki < 1.27 in several modules.

Bug: T306637
Change-Id: I6a0e8d360b1eeda089a38c2680eed21f4ee18438
---
M README.rst
M docs/index.rst
M pywikibot/data/api/_requests.py
M pywikibot/logentries.py
M pywikibot/page/_page.py
M pywikibot/site/_apisite.py
M pywikibot/site/_generators.py
M pywikibot/site_detect.py
M tests/dry_api_tests.py
M tests/logentries_tests.py
M tests/page_tests.py
M tests/site_detect_tests.py
12 files changed, 77 insertions(+), 196 deletions(-)

Approvals:
  JJMC89: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/README.rst b/README.rst
index bcd87a7..81734a5 100644
--- a/README.rst
+++ b/README.rst
@@ -41,7 +41,7 @@

 The Pywikibot framework is a Python library that interfaces with the
 `MediaWiki API <https://www.mediawiki.org/wiki/API:Main_page>`_
-version 1.23 or higher.
+version 1.27 or higher.

 Also included are various general function scripts that can be adapted for
 different tasks.
diff --git a/docs/index.rst b/docs/index.rst
index b460247..4384161 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -11,7 +11,8 @@
 The project started in 2003 and is currently on core version |version|.
 It features full API usage and is up-to-date with new MediaWiki features and
 a Pythonic package layout. But it also works with older installations of
-MediaWiki 1.23 or higher.
+MediaWiki 1.27 or higher. For older MediaWiki versions you have to use older
+Pywikibot releases; refer :manpage:`Compatibility`.

 Pywikibot supports Microsoft Windows, macOS and Linux when used with a
 compatible version of Python. It should also work on any other operating
diff --git a/pywikibot/data/api/_requests.py b/pywikibot/data/api/_requests.py
index 70d1207..f8dce8c 100644
--- a/pywikibot/data/api/_requests.py
+++ b/pywikibot/data/api/_requests.py
@@ -440,7 +440,8 @@
             if ('tokens' not in meta and 'continue' not in self._params
                     and self.site.mw_version >= '1.25wmf5'):
                 self._params.setdefault('rawcontinue', [''])
-        elif self.action == 'help' and self.site.mw_version > '1.24':
+
+        elif self.action == 'help':
             self['wrap'] = ''

         if config.maxlag:
diff --git a/pywikibot/logentries.py b/pywikibot/logentries.py
index 2eb9ff2..9208ec0 100644
--- a/pywikibot/logentries.py
+++ b/pywikibot/logentries.py
@@ -6,7 +6,6 @@
 #
 import datetime
 from collections import UserDict
-from contextlib import suppress
 from typing import Any, Optional, Type, Union

 import pywikibot
@@ -97,8 +96,6 @@
     @property
     def _params(self) -> Dict[str, Any]:
         """Additional data for some log entry types."""
-        with suppress(KeyError):
-            return self[self._expected_type]  # old behaviour
         return self.get('params', {})

     @cached
@@ -185,11 +182,7 @@
         if self.action() == 'unblock':
             return []

-        flags = self._params.get('flags', [])
-        # pre mw 1.25 returned a delimited string.
-        if isinstance(flags, str):
-            flags = flags.split(',') if flags else []
-        return flags
+        return self._params.get('flags', [])

     @cached
     def duration(self) -> Optional[datetime.timedelta]:
@@ -224,11 +217,7 @@
            LogEntry has no additional data e.g. due to hidden data and
            insufficient rights.
         """
-        params = self._params
-        if 'old' in params:  # old mw style (mw < 1.25)
-            return params['old'].split(',') if params['old'] else []
-
-        return params.get('oldgroups', [])
+        return self._params.get('oldgroups', [])

     @property
     def newgroups(self) -> List[str]:
@@ -239,11 +228,7 @@
            LogEntry has no additional data e.g. due to hidden data and
            insufficient rights.
         """
-        params = self._params
-        if 'new' in params:  # old mw style (mw < 1.25)
-            return params['new'].split(',') if params['new'] else []
-
-        return params.get('newgroups', [])
+        return self._params.get('newgroups', [])


 class UploadEntry(LogEntry):
@@ -267,18 +252,12 @@
     @property
     def target_ns(self) -> 'pywikibot.site._namespace.Namespace':
         """Return namespace object of target page."""
-        # key has been changed in mw 1.25 to 'target_ns'
-        return self.site.namespaces[self._params['target_ns']
-                                    if 'target_ns' in self._params
-                                    else self._params['new_ns']]
+        return self.site.namespaces[self._params['target_ns']]

     @property
     def target_title(self) -> str:
         """Return the target title."""
-        # key has been changed in mw 1.25 to 'target_title'
-        return (self._params['target_title']
-                if 'target_title' in self._params
-                else self._params['new_title'])
+        return self._params['target_title']

     @property
     @cached
@@ -301,18 +280,12 @@
     @property
     def current_id(self) -> int:
         """Return the current id."""
-        # key has been changed in mw 1.25; try the new mw style first
-        # sometimes it returns strs sometimes ints
-        return int(self._params['curid']
-                   if 'curid' in self._params else self._params['cur'])
+        return int(self._params['curid'])

     @property
     def previous_id(self) -> int:
         """Return the previous id."""
-        # key has been changed in mw 1.25; try the new mw style first
-        # sometimes it returns strs sometimes ints
-        return int(self._params['previd']
-                   if 'previd' in self._params else self._params['prev'])
+        return int(self._params['previd'])

     @property
     def auto(self) -> bool:
diff --git a/pywikibot/page/_page.py b/pywikibot/page/_page.py
index 94239b8..07de029 100644
--- a/pywikibot/page/_page.py
+++ b/pywikibot/page/_page.py
@@ -31,7 +31,7 @@

 import pywikibot
 from pywikibot import Timestamp, config, date, i18n, textlib
-from pywikibot.backports import Generator, Iterable, Iterator, List
+from pywikibot.backports import Generator, Iterable, Iterator, List, Set
 from pywikibot.cosmetic_changes import CANCEL, CosmeticChangesToolkit
 from pywikibot.exceptions import (
     Error,
@@ -1026,31 +1026,10 @@
         """Return a dictionary reflecting page protections."""
         return self.site.page_restrictions(self)

-    def applicable_protections(self) -> set:
-        """
-        Return the protection types allowed for that page.
-
-        If the page doesn't exist it only returns "create". Otherwise it
-        returns all protection types provided by the site, except "create".
-        It also removes "upload" if that page is not in the File namespace.
-
-        It is possible, that it returns an empty set, but only if original
-        protection types were removed.
-
-        :return: set of str
-        """
-        # New API since commit 32083235eb332c419df2063cf966b3400be7ee8a
-        if self.site.mw_version >= '1.25wmf14':
-            self.site.loadpageinfo(self)
-            return self._applicable_protections
-
-        p_types = set(self.site.protection_types())
-        if not self.exists():
-            return {'create'} if 'create' in p_types else set()
-        p_types.remove('create')  # no existing page allows that
-        if not self.is_filepage():  # only file pages allow upload
-            p_types.remove('upload')
-        return p_types
+    def applicable_protections(self) -> Set[str]:
+        """Return the protection types allowed for that page."""
+        self.site.loadpageinfo(self)
+        return self._applicable_protections

     def has_permission(self, action: str = 'edit') -> bool:
         """Determine whether the page can be modified.
diff --git a/pywikibot/site/_apisite.py b/pywikibot/site/_apisite.py
index 2050db3..b2af8da 100644
--- a/pywikibot/site/_apisite.py
+++ b/pywikibot/site/_apisite.py
@@ -439,10 +439,8 @@
         """
         if self.is_oauth_token_available():
             pywikibot.warning('Using OAuth suppresses logout function')
-        req_params = {'action': 'logout'}
-        # csrf token introduced in MW 1.24
-        with suppress(Error):
-            req_params['token'] = self.tokens['csrf']
+
+        req_params = {'action': 'logout', 'token': self.tokens['csrf']}
         uirequest = self.simple_request(**req_params)
         uirequest.submit()
         self._loginstatus = _LoginStatus.NOT_LOGGED_IN
@@ -931,19 +929,18 @@
         """
         if not isinstance(text, str):
             raise ValueError('text must be a string')
+
         if not text:
             return ''
-        req = self.simple_request(action='expandtemplates', text=text)
+
+        req = self.simple_request(action='expandtemplates',
+                                  text=text, prop='wikitext')
         if title is not None:
             req['title'] = title
         if includecomments is True:
             req['includecomments'] = ''
-        if self.mw_version > '1.24wmf7':
-            key = 'wikitext'
-            req['prop'] = key
-        else:
-            key = '*'
-        return req.submit()['expandtemplates'][key]
+
+        return req.submit()['expandtemplates']['wikitext']

     def getcurrenttimestamp(self) -> str:
         """
@@ -1087,10 +1084,10 @@
             pywikibot.error(msg)
             raise

-        if MediaWikiVersion(version) < '1.23':
+        if MediaWikiVersion(version) < '1.27':
             raise RuntimeError(
                 'Pywikibot "{}" does not support MediaWiki "{}".\n'
-                'Use Pywikibot prior to "6.0" branch instead.'
+                'Use Pywikibot prior to "8.0" branch instead.'
                 .format(pywikibot.__version__, version))
         return version

@@ -1496,12 +1493,8 @@
         return page._redirtarget

     def validate_tokens(self, types: List[str]) -> List[str]:
-        """Validate if requested tokens are acceptable.
-
-        Valid tokens depend on mw version.
-        """
-        query = 'tokens' if self.mw_version < '1.24wmf19' else 'query+tokens'
-        data = self._paraminfo.parameter(query, 'type')
+        """Validate if requested tokens are acceptable."""
+        data = self._paraminfo.parameter('query+tokens', 'type')
         assert data is not None
         return [token for token in types if token in data['type']]

@@ -1512,7 +1505,6 @@
     ) -> Dict[str, str]:
         """Preload one or multiple tokens.

-        For MediaWiki version 1.23, only one token can be retrieved at once.
         For MediaWiki versions since 1.24wmfXXX a new token
         system was introduced which reduced the amount of tokens available.
         Most of them were merged into the 'csrf' token. If the token type in
@@ -1543,21 +1535,13 @@
                 r'Action \'\w+\' is not allowed for the current user', text)

         user_tokens = {}
-        if self.mw_version < '1.24wmf19':
-            if all is not False:
-                pdata = self._paraminfo.parameter('tokens', 'type')
-                assert pdata is not None
-                types.extend(pdata['type'])
-            req = self.simple_request(action='tokens',
-                                      type=self.validate_tokens(types))
-        else:
-            if all is not False:
-                pdata = self._paraminfo.parameter('query+tokens', 'type')
-                assert pdata is not None
-                types.extend(pdata['type'])
+        if all is not False:
+            pdata = self._paraminfo.parameter('query+tokens', 'type')
+            assert pdata is not None
+            types.extend(pdata['type'])

-            req = self.simple_request(action='query', meta='tokens',
-                                      type=self.validate_tokens(types))
+        req = self.simple_request(action='query', meta='tokens',
+                                  type=self.validate_tokens(types))

         req._warning_handler = warn_handler
         data = req.submit()
@@ -2665,7 +2649,6 @@
         When the version is at least 1.27wmf9, uses general siteinfo.
         If not called directly, it is cached by the first attempted
         upload action.
-
         """
         if self.mw_version >= '1.27wmf9':
             return not self._siteinfo.get('general')['uploadsenabled']
@@ -2677,10 +2660,10 @@
         # missingparam: One of the parameters
         #    filekey, file, url, statuskey is required
         # TODO: is there another way?
+        req = self._request(throttle=False,
+                            parameters={'action': 'upload',
+                                        'token': self.tokens['edit']})
         try:
-            req = self._request(throttle=False,
-                                parameters={'action': 'upload',
-                                            'token': self.tokens['edit']})
             req.submit()
         except APIError as error:
             if error.code == 'uploaddisabled':
@@ -2694,6 +2677,7 @@
                 # Unexpected error
                 raise
             return self._uploaddisabled
+
         raise RuntimeError(
             'Unexpected success of upload action without parameters.')

diff --git a/pywikibot/site/_generators.py b/pywikibot/site/_generators.py
index 49630e3..b3d6621 100644
--- a/pywikibot/site/_generators.py
+++ b/pywikibot/site/_generators.py
@@ -10,7 +10,6 @@
 from contextlib import suppress
 from itertools import zip_longest
 from typing import Any, Optional, Union
-from warnings import warn

 import pywikibot
 from pywikibot.backports import Dict, Generator, Iterable, List  # skipcq
@@ -23,7 +22,7 @@
     NoPageError,
     UserRightsError,
 )
-from pywikibot.site._decorators import need_right, need_version
+from pywikibot.site._decorators import need_right
 from pywikibot.site._namespace import NamespaceArgType
 from pywikibot.tools import is_ip_address, issue_deprecation_warning
 from pywikibot.tools.itertools import filter_unique, itergroup
@@ -293,7 +292,6 @@
                                namespaces=namespaces, total=total,
                                g_content=content, **eiargs)

-    @need_version('1.24')
     def page_redirects(
         self,
         page: 'pywikibot.Page',
@@ -1574,28 +1572,11 @@
         :keyword prop: Which properties to get. Defaults are ids, user,
             comment, flags and timestamp
         """
-        def handle_props(props):
-            """Translate deletedrev props to deletedrevisions props."""
-            if isinstance(props, str):
-                props = props.split('|')
-            if self.mw_version >= '1.25':
-                return props
-
-            old_props = []
-            for item in props:
-                if item == 'ids':
-                    old_props += ['revid', 'parentid']
-                elif item == 'flags':
-                    old_props.append('minor')
-                elif item != 'timestamp':
-                    old_props.append(item)
-                    if item == 'content' and self.mw_version < '1.24':
-                        old_props.append('token')
-            return old_props
-
         # set default properties
         prop = kwargs.pop('prop',
                           ['ids', 'user', 'comment', 'flags', 'timestamp'])
+        if isinstance(prop, str):
+            prop = prop.split('|')
         if content:
             prop.append('content')

@@ -1608,46 +1589,26 @@
         if not bool(titles) ^ (revids is not None):
             raise Error('deletedrevs: either "titles" or "revids" parameter '
                         'must be given.')
-        if revids and self.mw_version < '1.25':
-            raise NotImplementedError(
-                'deletedrevs: "revid" is not implemented with MediaWiki {}'
-                .format(self.mw_version))

-        if self.mw_version >= '1.25':
-            pre = 'drv'
-            type_arg = 'deletedrevisions'
-            generator = api.PropertyGenerator
-        else:
-            pre = 'dr'
-            type_arg = 'deletedrevs'
-            generator = api.ListGenerator
+        gen = self._generator(api.PropertyGenerator,
+                              type_arg='deletedrevisions',
+                              titles=titles, revids=revids, total=total)

-        gen = self._generator(generator, type_arg=type_arg,
-                              titles=titles, revids=revids,
-                              total=total)
-
-        gen.request[pre + 'start'] = start
-        gen.request[pre + 'end'] = end
-        gen.request[pre + 'prop'] = handle_props(prop)
+        gen.request['drvstart'] = start
+        gen.request['drvend'] = end
+        gen.request['drvprop'] = prop
+        if reverse:
+            gen.request['drvdir'] = 'newer'
 
         # handle other parameters like user
         for k, v in kwargs.items():
-            gen.request[pre + k] = v
+            gen.request['drv' + k] = v

-        if reverse:
-            gen.request[pre + 'dir'] = 'newer'
+        for data in gen:
+            with suppress(KeyError):
+                data['revisions'] = data.pop('deletedrevisions')
+                yield data

-        if self.mw_version < '1.25':
-            yield from gen
-
-        else:
-            # The dict result is different for both generators
-            for data in gen:
-                with suppress(KeyError):
-                    data['revisions'] = data.pop('deletedrevisions')
-                    yield data
-
-    @need_version('1.25')
     def alldeletedrevisions(
         self,
         *,
@@ -1748,15 +1709,7 @@
         redirects = mapping[redirects]
         params = {}
         if redirects is not None:
-            if self.mw_version < '1.26':
-                if redirects == 'all':
-                    warn("parameter redirects=None to retrieve 'all' random"
-                         'page types is not supported by mw version {}. '
-                         'Using default.'.format(self.mw_version),
-                         UserWarning)
-                params['grnredirect'] = redirects == 'redirects'
-            else:
-                params['grnfilterredir'] = redirects
+            params['grnfilterredir'] = redirects
         return self._generator(api.PageGenerator, type_arg='random',
                                namespaces=namespaces, total=total,
                                g_content=content, **params)
diff --git a/pywikibot/site_detect.py b/pywikibot/site_detect.py
index 5031518..b4b2f6b 100644
--- a/pywikibot/site_detect.py
+++ b/pywikibot/site_detect.py
@@ -29,7 +29,7 @@
 SERVER_DB_ERROR_MSG = \
     '<h1>Sorry! This site is experiencing technical difficulties.</h1>'

-MIN_VERSION = MediaWikiVersion('1.23')
+MIN_VERSION = MediaWikiVersion('1.27')


 class MWSite:
@@ -43,7 +43,7 @@
         :raises pywikibot.exceptions.ServerError: a server error occurred
             while loading the site
         :raises Timeout: a timeout occurred while loading the site
-        :raises RuntimeError: Version not found or version less than 1.23
+        :raises RuntimeError: Version not found or version less than 1.27
         """
         if fromurl.endswith('$1'):
             fromurl = fromurl[:-2]
diff --git a/tests/dry_api_tests.py b/tests/dry_api_tests.py
index c170f3e..b42847c 100755
--- a/tests/dry_api_tests.py
+++ b/tests/dry_api_tests.py
@@ -160,7 +160,7 @@
                 self._siteinfo = DummySiteinfo({'case': 'first-letter'})

             def version(self):
-                return '1.23'  # lowest supported release
+                return '1.27'  # lowest supported release

             def protocol(self):
                 return 'http'
diff --git a/tests/logentries_tests.py b/tests/logentries_tests.py
index 4798036..bbbf189 100755
--- a/tests/logentries_tests.py
+++ b/tests/logentries_tests.py
@@ -29,9 +29,9 @@

     It uses the German Wikipedia for a current representation of the
     log entries and the test Wikipedia for the future representation.
-    It also tests on a wiki with MW < 1.25 to check that it can still
-    read the older format. It currently uses portalwiki which as of this
-    commit uses 1.23.16.
+    It also tests on a wiki with MW <= 1.27 to check that the module
+    works with older wikis. It currently uses infogalacticwiki which as
+    of this commit uses 1.27.1.
     """

     sites = {
@@ -51,8 +51,8 @@
             'target': None,
         },
         'old': {
-            'family': AutoFamily('portalwiki',
-                                 'https://theportalwiki.com/wiki/Main_Page'),
+            'family': AutoFamily('infogalactic',
+                                 'https://infogalactic.com/info/Main_Page'),
             'code': 'en',
             'target': None,
         }
@@ -64,7 +64,7 @@
             # This is an assertion as the tests don't make sense with newer
             # MW versions and otherwise it might not be visible that the test
             # isn't run on an older wiki.
-            self.assertLess(self.site.mw_version, '1.25')
+            self.assertEqual(self.site.mw_version, '1.27.1')

         with skipping(StopIteration,
                       msg=f'No entry found for {logtype!r}'):
@@ -80,11 +80,8 @@
         if logtype not in LogEntryFactory._logtypes:
             self.assertIsInstance(logentry, OtherLogEntry)

-        if self.site_key == 'old':
-            self.assertNotIn('params', logentry.data)
-        else:
-            self.assertNotIn(logentry.type(), logentry.data)
-
+        # check that we only have the new implementation
+        self.assertNotIn(logentry.type(), logentry.data)
         self.assertIsInstance(logentry.action(), str)

         try:
diff --git a/tests/page_tests.py b/tests/page_tests.py
index 32dfafb..47a0d07 100755
--- a/tests/page_tests.py
+++ b/tests/page_tests.py
@@ -1082,7 +1082,6 @@
         p2 = pywikibot.Page(site, 'User:Unicodesnowman/ProtectTest')
         p3 = pywikibot.Page(site, 'File:Wiki.png')

-        # from the API, since 1.25wmf14
         pp1 = p1.applicable_protections()
         pp2 = p2.applicable_protections()
         pp3 = p3.applicable_protections()
@@ -1093,12 +1092,6 @@
         self.assertNotIn('upload', pp2)
         self.assertIn('upload', pp3)

-        # inferred
-        site.version = lambda: '1.24'
-        self.assertEqual(pp1, p1.applicable_protections())
-        self.assertEqual(pp2, p2.applicable_protections())
-        self.assertEqual(pp3, p3.applicable_protections())
-

 class TestPageProtect(TestCase):

diff --git a/tests/site_detect_tests.py b/tests/site_detect_tests.py
index 2ac6ffc..fdbafb0 100755
--- a/tests/site_detect_tests.py
+++ b/tests/site_detect_tests.py
@@ -79,10 +79,6 @@
         """
         self.assertSite('http://www.wikichristian.org/index.php?title=$1')

-    def test_wikifur(self):
-        """Test detection of MediaWiki sites for en.wikifur.com."""
-        self.assertSite('https://en.wikifur.com/wiki/$1')
-

 class NonStandardVersionSiteTestCase(SiteDetectionTestCase):

@@ -96,14 +92,10 @@
         """Test detection of MediaWiki sites for www.arabeyes.org."""
         self.assertSite('https://www.arabeyes.org/$1')

-    def test_tfwiki(self):
-        """Test detection of MediaWiki sites for tfwiki.net."""
-        self.assertNoSite('http://tfwiki.net/wiki/$1')  # 1.19.5-1+deb7u1

+class UnsupportedSiteTestCase(SiteDetectionTestCase):

-class Pre119SiteTestCase(SiteDetectionTestCase):
-
-    """Test pre 1.19 sites which should be detected as unsupported."""
+    """Test pre 1.27 sites which should be detected as unsupported."""

     def test_hrwiki(self):
         """Test detection of MediaWiki sites for www.hrwiki.org."""
@@ -113,6 +105,14 @@
         """Test detection of MediaWiki sites for www.wikifon.org."""
         self.assertNoSite('http://www.wikifon.org/$1')  # v1.11.0

+    def test_tfwiki(self):
+        """Test detection of MediaWiki sites for tfwiki.net."""
+        self.assertNoSite('http://tfwiki.net/wiki/$1')  # 1.19.5-1+deb7u1
+
+    def test_wikifur(self):
+        """Test detection of MediaWiki sites for en.wikifur.com."""
+        self.assertNoSite('https://en.wikifur.com/wiki/$1')  # 1.23.16
+

 class PreAPISiteTestCase(SiteDetectionTestCase):


--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/835198
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I6a0e8d360b1eeda089a38c2680eed21f4ee18438
Gerrit-Change-Number: 835198
Gerrit-PatchSet: 9
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: JJMC89 <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to