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

Change subject: [IMPR] Move site decorators to its own _decorators.py file
......................................................................

[IMPR] Move site decorators to its own _decorators.py file

Also move decorator tests from dry_site_tests.py to new
site_decorators_tests.py

Change-Id: Ib6f00ce181d936aa116391f25913591d4dc209b8
---
M pywikibot/CONTENT.rst
M pywikibot/site/__init__.py
A pywikibot/site/_decorators.py
M tests/__init__.py
M tests/dry_site_tests.py
A tests/site_decorators_tests.py
6 files changed, 434 insertions(+), 404 deletions(-)

Approvals:
  Matěj Suchánek: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/pywikibot/CONTENT.rst b/pywikibot/CONTENT.rst
index 3f606e8..30f92ee 100644
--- a/pywikibot/CONTENT.rst
+++ b/pywikibot/CONTENT.rst
@@ -111,6 +111,8 @@
     
+============================+======================================================+
     | __init__.py                | Objects representing MediaWiki sites 
(wikis)         |
     
+----------------------------+------------------------------------------------------+
+    | _decorators.py             | Decorators used by site models.             
         |
+    
+----------------------------+------------------------------------------------------+


     
+----------------------------+------------------------------------------------------+
diff --git a/pywikibot/site/__init__.py b/pywikibot/site/__init__.py
index ad106bf..5a606e6 100644
--- a/pywikibot/site/__init__.py
+++ b/pywikibot/site/__init__.py
@@ -67,19 +67,28 @@
     UnknownExtension,
     UnknownSite,
     UserBlocked,
-    UserRightsError,
 )
+from pywikibot.site._decorators import need_extension, need_right, need_version
 from pywikibot.throttle import Throttle
 from pywikibot.tools import (
+    ComparableMixin,
     compute_file_hash,
-    itergroup, ComparableMixin, SelfCallMixin, SelfCallString,
-    deprecated, deprecate_arg, deprecated_args, remove_last_args,
-    redirect_func, issue_deprecation_warning,
-    manage_wrapping, MediaWikiVersion, first_upper, normalize_username,
-    merge_unique_dicts,
+    deprecated,
+    deprecate_arg,
+    deprecated_args,
     filter_unique,
+    first_upper,
+    is_IP,
+    issue_deprecation_warning,
+    itergroup,
+    MediaWikiVersion,
+    merge_unique_dicts,
+    normalize_username,
+    remove_last_args,
+    redirect_func,
+    SelfCallMixin,
+    SelfCallString,
 )
-from pywikibot.tools import is_IP


 _logger = 'wiki.site'
@@ -1242,126 +1251,6 @@
         return self.getUrl(address, data=data)


-@deprecated_args(right=None)
-def must_be(group=None):
-    """Decorator to require a certain user status when method is called.
-
-    @param group: The group the logged in user should belong to.
-                  This parameter can be overridden by
-                  keyword argument 'as_group'.
-    @type group: str
-    @return: method decorator
-    @raises UserRightsError: user is not part of the required user group.
-    """
-    def decorator(fn):
-        def callee(self, *args, **kwargs):
-            grp = kwargs.pop('as_group', group)
-            if self.obsolete:
-                if not self.has_group('steward'):
-                    raise UserRightsError(
-                        'Site {} has been closed. Only steward '
-                        'can perform requested action.'
-                        .format(self.sitename))
-
-            elif not self.has_group(grp):
-                raise UserRightsError('User "{}" is not part of the required '
-                                      'user group "{}"'
-                                      .format(self.user(), grp))
-
-            return fn(self, *args, **kwargs)
-
-        if not __debug__:
-            return fn
-
-        manage_wrapping(callee, fn)
-        return callee
-
-    return decorator
-
-
-def need_right(right=None):
-    """Decorator to require a certain user right when method is called.
-
-    @param right: The right the logged in user should have.
-    @type right: str
-    @return: method decorator
-    @raises UserRightsError: user has insufficient rights.
-    """
-    def decorator(fn):
-        def callee(self, *args, **kwargs):
-            if self.obsolete:
-                if not self.has_group('steward'):
-                    raise UserRightsError(
-                        'Site {} has been closed. Only steward '
-                        'can perform requested action.'
-                        .format(self.sitename))
-
-            elif right is not None and not self.has_right(right):
-                raise UserRightsError('User "{}" does not have required '
-                                      'user right "{}"'
-                                      .format(self.user(), right))
-            return fn(self, *args, **kwargs)
-
-        if not __debug__:
-            return fn
-
-        manage_wrapping(callee, fn)
-        return callee
-
-    return decorator
-
-
-def need_version(version):
-    """Decorator to require a certain MediaWiki version number.
-
-    @param version: the mw version number required
-    @type version: str
-    @return: a decorator to make sure the requirement is satisfied when
-        the decorated function is called.
-    """
-    def decorator(fn):
-        def callee(self, *args, **kwargs):
-            if MediaWikiVersion(self.version()) < MediaWikiVersion(version):
-                raise NotImplementedError(
-                    'Method or function "%s"\n'
-                    "isn't implemented in MediaWiki version < %s"
-                    % (fn.__name__, version))
-            return fn(self, *args, **kwargs)
-
-        if not __debug__:
-            return fn
-
-        manage_wrapping(callee, fn)
-
-        return callee
-    return decorator
-
-
-def need_extension(extension):
-    """Decorator to require a certain MediaWiki extension.
-
-    @param extension: the MediaWiki extension required
-    @type extension: str
-    @return: a decorator to make sure the requirement is satisfied when
-        the decorated function is called.
-    """
-    def decorator(fn):
-        def callee(self, *args, **kwargs):
-            if not self.has_extension(extension):
-                raise UnknownExtension(
-                    'Method "%s" is not implemented without the extension %s'
-                    % (fn.__name__, extension))
-            return fn(self, *args, **kwargs)
-
-        if not __debug__:
-            return fn
-
-        manage_wrapping(callee, fn)
-
-        return callee
-    return decorator
-
-
 class Siteinfo(Container):

     """
diff --git a/pywikibot/site/_decorators.py b/pywikibot/site/_decorators.py
new file mode 100644
index 0000000..8085beb
--- /dev/null
+++ b/pywikibot/site/_decorators.py
@@ -0,0 +1,127 @@
+# -*- coding: utf-8 -*-
+"""Decorators used by site models."""
+#
+# (C) Pywikibot team, 2008-2020
+#
+# Distributed under the terms of the MIT license.
+#
+from pywikibot.exceptions import UnknownExtension, UserRightsError
+from pywikibot.tools import deprecated_args, manage_wrapping, MediaWikiVersion
+
+
+@deprecated_args(right=True)
+def must_be(group=None):
+    """Decorator to require a certain user status when method is called.
+
+    @param group: The group the logged in user should belong to.
+                  This parameter can be overridden by
+                  keyword argument 'as_group'.
+    @type group: str or None
+    @return: method decorator
+    @raises UserRightsError: user is not part of the required user group.
+    """
+    def decorator(fn):
+        def callee(self, *args, **kwargs):
+            grp = kwargs.pop('as_group', group)
+            if self.obsolete:
+                if not self.has_group('steward'):
+                    raise UserRightsError(
+                        'Site {} has been closed. Only steward '
+                        'can perform requested action.'
+                        .format(self.sitename))
+
+            elif not self.has_group(grp):
+                raise UserRightsError('User "{}" is not part of the required '
+                                      'user group "{}"'
+                                      .format(self.user(), grp))
+
+            return fn(self, *args, **kwargs)
+
+        if not __debug__:
+            return fn
+
+        manage_wrapping(callee, fn)
+        return callee
+
+    return decorator
+
+
+def need_extension(extension: str):
+    """Decorator to require a certain MediaWiki extension.
+
+    @param extension: the MediaWiki extension required
+    @return: a decorator to make sure the requirement is satisfied when
+        the decorated function is called.
+    """
+    def decorator(fn):
+        def callee(self, *args, **kwargs):
+            if not self.has_extension(extension):
+                raise UnknownExtension(
+                    'Method "{}" is not implemented without the extension {}'
+                    .format(fn.__name__, extension))
+            return fn(self, *args, **kwargs)
+
+        if not __debug__:
+            return fn
+
+        manage_wrapping(callee, fn)
+        return callee
+
+    return decorator
+
+
+def need_right(right=None):
+    """Decorator to require a certain user right when method is called.
+
+    @param right: The right the logged in user should have.
+    @type right: str or None
+    @return: method decorator
+    @raises UserRightsError: user has insufficient rights.
+    """
+    def decorator(fn):
+        def callee(self, *args, **kwargs):
+            if self.obsolete:
+                if not self.has_group('steward'):
+                    raise UserRightsError(
+                        'Site {} has been closed. Only steward '
+                        'can perform requested action.'
+                        .format(self.sitename))
+
+            elif right is not None and not self.has_right(right):
+                raise UserRightsError('User "{}" does not have required '
+                                      'user right "{}"'
+                                      .format(self.user(), right))
+            return fn(self, *args, **kwargs)
+
+        if not __debug__:
+            return fn
+
+        manage_wrapping(callee, fn)
+        return callee
+
+    return decorator
+
+
+def need_version(version: str):
+    """Decorator to require a certain MediaWiki version number.
+
+    @param version: the mw version number required
+    @return: a decorator to make sure the requirement is satisfied when
+        the decorated function is called.
+    """
+    def decorator(fn):
+        def callee(self, *args, **kwargs):
+            if MediaWikiVersion(self.version()) < MediaWikiVersion(version):
+                raise NotImplementedError(
+                    'Method or function "%s"\n'
+                    "isn't implemented in MediaWiki version < %s"
+                    % (fn.__name__, version))
+            return fn(self, *args, **kwargs)
+
+        if not __debug__:
+            return fn
+
+        manage_wrapping(callee, fn)
+
+        return callee
+    return decorator
diff --git a/tests/__init__.py b/tests/__init__.py
index 9a23c64..628cfe0 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -109,6 +109,7 @@
     'plural',
     'proofreadpage',
     'site',
+    'site_decorators',
     'site_detect',
     'sparql',
     'tests',
diff --git a/tests/dry_site_tests.py b/tests/dry_site_tests.py
index 04083c7..3a9298b 100644
--- a/tests/dry_site_tests.py
+++ b/tests/dry_site_tests.py
@@ -8,17 +8,10 @@
 from __future__ import absolute_import, division, unicode_literals

 import pywikibot
-from pywikibot.tools import deprecated
-from pywikibot.site import must_be, need_right, need_version
-from pywikibot.comms.http import user_agent
-from pywikibot.exceptions import UserRightsError

-from tests.aspects import (
-    unittest,
-    DefaultDrySiteTestCase,
-    DebugOnlyTestCase,
-    DeprecationTestCase,
-)
+from pywikibot.comms.http import user_agent
+
+from tests.aspects import unittest, DefaultDrySiteTestCase, DeprecationTestCase


 class TestDrySite(DefaultDrySiteTestCase):
@@ -140,272 +133,5 @@
                          '{0}X{0}'.format(self._old_config))


-class TestMustBe(DebugOnlyTestCase):
-
-    """Test cases for the must_be decorator."""
-
-    net = False
-
-    # Implemented without setUpClass(cls) and global variables as objects
-    # were not completely disposed and recreated but retained 'memory'
-    def setUp(self):
-        """Creating fake variables to appear as a site."""
-        self.code = 'test'
-        self.family = lambda: None
-        self.family.name = 'test'
-        self.sitename = self.family.name + ':' + self.code
-        self._logged_in_as = None
-        self._userinfo = []
-        self.obsolete = False
-        super(TestMustBe, self).setUp()
-        self.version = lambda: '1.14'  # lowest supported release
-
-    def login(self, group):
-        """Fake the log in as required user group."""
-        self._logged_in_as = group
-        self._userinfo = [group]
-
-    def user(self):
-        """Fake the logged in user."""
-        return self._logged_in_as
-
-    def has_group(self, group):
-        """Fake the groups user belongs to."""
-        return group in self._userinfo
-
-    def testMockInTest(self):
-        """Test that setUp and login work."""
-        self.assertIsNone(self._logged_in_as)
-        self.login('user')
-        self.assertEqual(self._logged_in_as, 'user')
-
-    # Test that setUp is actually called between each test
-    testMockInTestReset = testMockInTest  # noqa: N815
-
-    @must_be('steward')
-    def call_this_steward_req_function(self, *args, **kwargs):
-        """Require a sysop to function."""
-        return args, kwargs
-
-    @must_be('sysop')
-    def call_this_sysop_req_function(self, *args, **kwargs):
-        """Require a sysop to function."""
-        return args, kwargs
-
-    @must_be('user')
-    def call_this_user_req_function(self, *args, **kwargs):
-        """Require a user to function."""
-        return args, kwargs
-
-    def testMustBeSteward(self):
-        """Test a function which requires a sysop."""
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('steward')
-        retval = self.call_this_steward_req_function(*args, **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-
-    def testMustBeSysop(self):
-        """Test a function which requires a sysop."""
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('sysop')
-        retval = self.call_this_sysop_req_function(*args, **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-        self.assertRaises(UserRightsError, self.call_this_steward_req_function,
-                          args, kwargs)
-
-    def testMustBeUser(self):
-        """Test a function which requires a user."""
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('user')
-        retval = self.call_this_user_req_function(*args, **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-        self.assertRaises(UserRightsError, self.call_this_sysop_req_function,
-                          args, kwargs)
-
-    def testOverrideUserType(self):
-        """Test overriding the required group."""
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('sysop')
-        retval = self.call_this_user_req_function(
-            *args, as_group='sysop', **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-
-    def testObsoleteSite(self):
-        """Test when the site is obsolete and shouldn't be edited."""
-        self.obsolete = True
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('steward')
-        retval = self.call_this_user_req_function(*args, **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-        self.login('user')
-        self.assertRaises(UserRightsError, self.call_this_user_req_function,
-                          args, kwargs)
-
-
-class TestNeedRight(DebugOnlyTestCase):
-
-    """Test cases for the must_be decorator."""
-
-    net = False
-
-    # Implemented without setUpClass(cls) and global variables as objects
-    # were not completely disposed and recreated but retained 'memory'
-    def setUp(self):
-        """Creating fake variables to appear as a site."""
-        self.code = 'test'
-        self.family = lambda: None
-        self.family.name = 'test'
-        self.sitename = self.family.name + ':' + self.code
-        self._logged_in_as = None
-        self._userinfo = []
-        self.obsolete = False
-        super(TestNeedRight, self).setUp()
-        self.version = lambda: '1.14'  # lowest supported release
-
-    def login(self, group, right):
-        """Fake the log in as required user group."""
-        self._logged_in_as = group
-        self._userinfo = [right]
-
-    def user(self):
-        """Fake the logged in user."""
-        return self._logged_in_as
-
-    def has_right(self, right):
-        """Fake the groups user belongs to."""
-        return right in self._userinfo
-
-    @need_right('edit')
-    def call_this_edit_req_function(self, *args, **kwargs):
-        """Require a sysop to function."""
-        return args, kwargs
-
-    @need_right('move')
-    def call_this_move_req_function(self, *args, **kwargs):
-        """Require a sysop to function."""
-        return args, kwargs
-
-    def testNeedRightEdit(self):
-        """Test a function which requires a sysop."""
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('user', 'edit')
-        retval = self.call_this_edit_req_function(*args, **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-
-    def testNeedRightMove(self):
-        """Test a function which requires a sysop."""
-        args = (1, 2, 'a', 'b')
-        kwargs = {'i': 'j', 'k': 'l'}
-        self.login('user', 'move')
-        retval = self.call_this_move_req_function(*args, **kwargs)
-        self.assertEqual(retval[0], args)
-        self.assertEqual(retval[1], kwargs)
-        self.assertRaises(UserRightsError, self.call_this_edit_req_function,
-                          args, kwargs)
-
-
-class TestNeedVersion(DeprecationTestCase):
-
-    """Test cases for the need_version decorator."""
-
-    net = False
-
-    # Implemented without setUpClass(cls) and global variables as objects
-    # were not completely disposed and recreated but retained 'memory'
-    def setUp(self):
-        """Set up test method."""
-        super(TestNeedVersion, self).setUp()
-        self.version = lambda: '1.23'
-
-    @need_version('1.24')
-    def too_new(self):
-        """Method which is to new."""
-        return True
-
-    @need_version('1.23')
-    def old_enough(self):
-        """Method which is as new as the server."""
-        return True
-
-    @need_version('1.22')
-    def older(self):
-        """Method which is old enough."""
-        return True
-
-    @need_version('1.24')
-    @deprecated
-    def deprecated_unavailable_method(self):
-        """Method which is to new and then deprecated."""
-        return True
-
-    @deprecated
-    @need_version('1.24')
-    def deprecated_unavailable_method2(self):
-        """Method which is deprecated first and then to new."""
-        return True
-
-    @need_version('1.22')
-    @deprecated
-    def deprecated_available_method(self):
-        """Method which is old enough and then deprecated."""
-        return True
-
-    @deprecated
-    @need_version('1.22')
-    def deprecated_available_method2(self):
-        """Method which is deprecated first and then old enough."""
-        return True
-
-    def test_need_version(self):
-        """Test need_version when the version is new, exact or old enough."""
-        self.assertRaises(NotImplementedError, self.too_new)
-        self.assertTrue(self.old_enough())
-        self.assertTrue(self.older())
-
-    def test_need_version_fail_with_deprecated(self):
-        """Test order of combined version check and deprecation warning."""
-        # FIXME: The deprecation message should be:
-        #   __name__ + '.TestNeedVersion.deprecated_unavailable_method
-
-        # The outermost decorator is the version check, so no
-        # deprecation message.
-        self.assertRaisesRegex(
-            NotImplementedError,
-            'deprecated_unavailable_method',
-            self.deprecated_unavailable_method)
-        self.assertNoDeprecation()
-
-        # The deprecator is first, but the version check still
-        # raises exception.
-        self.assertRaisesRegex(
-            NotImplementedError,
-            'deprecated_unavailable_method2',
-            self.deprecated_unavailable_method2)
-        self.assertOneDeprecationParts(
-            __name__ + '.TestNeedVersion.deprecated_unavailable_method2')
-
-    def test_need_version_success_with_deprecated(self):
-        """Test order of combined version check and deprecation warning."""
-        self.deprecated_available_method()
-        self.assertOneDeprecationParts(
-            __name__ + '.TestNeedVersion.deprecated_available_method')
-
-        self.deprecated_available_method2()
-        self.assertOneDeprecationParts(
-            __name__ + '.TestNeedVersion.deprecated_available_method2')
-
-
 if __name__ == '__main__':  # pragma: no cover
     unittest.main()
diff --git a/tests/site_decorators_tests.py b/tests/site_decorators_tests.py
new file mode 100644
index 0000000..5578164
--- /dev/null
+++ b/tests/site_decorators_tests.py
@@ -0,0 +1,285 @@
+# -*- coding: utf-8 -*-
+"""Tests against a fake Site object."""
+#
+# (C) Pywikibot team, 2012-2020
+#
+# Distributed under the terms of the MIT license.
+#
+from __future__ import absolute_import, division, unicode_literals
+
+from pywikibot.tools import deprecated
+from pywikibot.site._decorators import must_be, need_right, need_version
+from pywikibot.exceptions import UserRightsError
+
+from tests.aspects import unittest, DebugOnlyTestCase, DeprecationTestCase
+
+
+class TestMustBe(DebugOnlyTestCase):
+
+    """Test cases for the must_be decorator."""
+
+    net = False
+
+    # Implemented without setUpClass(cls) and global variables as objects
+    # were not completely disposed and recreated but retained 'memory'
+    def setUp(self):
+        """Creating fake variables to appear as a site."""
+        self.code = 'test'
+        self.family = lambda: None
+        self.family.name = 'test'
+        self.sitename = self.family.name + ':' + self.code
+        self._logged_in_as = None
+        self._userinfo = []
+        self.obsolete = False
+        super(TestMustBe, self).setUp()
+        self.version = lambda: '1.14'  # lowest supported release
+
+    def login(self, group):
+        """Fake the log in as required user group."""
+        self._logged_in_as = group
+        self._userinfo = [group]
+
+    def user(self):
+        """Fake the logged in user."""
+        return self._logged_in_as
+
+    def has_group(self, group):
+        """Fake the groups user belongs to."""
+        return group in self._userinfo
+
+    def test_mock_in_test(self):
+        """Test that setUp and login work."""
+        self.assertIsNone(self._logged_in_as)
+        self.login('user')
+        self.assertEqual(self._logged_in_as, 'user')
+
+    # Test that setUp is actually called between each test
+    test_mock_in_test_reset = test_mock_in_test
+
+    @must_be('steward')
+    def call_this_steward_req_function(self, *args, **kwargs):
+        """Require a sysop to function."""
+        return args, kwargs
+
+    @must_be('sysop')
+    def call_this_sysop_req_function(self, *args, **kwargs):
+        """Require a sysop to function."""
+        return args, kwargs
+
+    @must_be('user')
+    def call_this_user_req_function(self, *args, **kwargs):
+        """Require a user to function."""
+        return args, kwargs
+
+    def test_must_be_steward(self):
+        """Test a function which requires a sysop."""
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('steward')
+        retval = self.call_this_steward_req_function(*args, **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+
+    def test_must_be_sysop(self):
+        """Test a function which requires a sysop."""
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('sysop')
+        retval = self.call_this_sysop_req_function(*args, **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+        self.assertRaises(UserRightsError, self.call_this_steward_req_function,
+                          args, kwargs)
+
+    def test_must_be_user(self):
+        """Test a function which requires a user."""
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('user')
+        retval = self.call_this_user_req_function(*args, **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+        self.assertRaises(UserRightsError, self.call_this_sysop_req_function,
+                          args, kwargs)
+
+    def test_override_usertype(self):
+        """Test overriding the required group."""
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('sysop')
+        retval = self.call_this_user_req_function(
+            *args, as_group='sysop', **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+
+    def test_obsolete_site(self):
+        """Test when the site is obsolete and shouldn't be edited."""
+        self.obsolete = True
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('steward')
+        retval = self.call_this_user_req_function(*args, **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+        self.login('user')
+        self.assertRaises(UserRightsError, self.call_this_user_req_function,
+                          args, kwargs)
+
+
+class TestNeedRight(DebugOnlyTestCase):
+
+    """Test cases for the must_be decorator."""
+
+    net = False
+
+    # Implemented without setUpClass(cls) and global variables as objects
+    # were not completely disposed and recreated but retained 'memory'
+    def setUp(self):
+        """Creating fake variables to appear as a site."""
+        self.code = 'test'
+        self.family = lambda: None
+        self.family.name = 'test'
+        self.sitename = self.family.name + ':' + self.code
+        self._logged_in_as = None
+        self._userinfo = []
+        self.obsolete = False
+        super(TestNeedRight, self).setUp()
+        self.version = lambda: '1.14'  # lowest supported release
+
+    def login(self, group, right):
+        """Fake the log in as required user group."""
+        self._logged_in_as = group
+        self._userinfo = [right]
+
+    def user(self):
+        """Fake the logged in user."""
+        return self._logged_in_as
+
+    def has_right(self, right):
+        """Fake the groups user belongs to."""
+        return right in self._userinfo
+
+    @need_right('edit')
+    def call_this_edit_req_function(self, *args, **kwargs):
+        """Require a sysop to function."""
+        return args, kwargs
+
+    @need_right('move')
+    def call_this_move_req_function(self, *args, **kwargs):
+        """Require a sysop to function."""
+        return args, kwargs
+
+    def test_need_right_edit(self):
+        """Test a function which requires a sysop."""
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('user', 'edit')
+        retval = self.call_this_edit_req_function(*args, **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+
+    def test_need_right_move(self):
+        """Test a function which requires a sysop."""
+        args = (1, 2, 'a', 'b')
+        kwargs = {'i': 'j', 'k': 'l'}
+        self.login('user', 'move')
+        retval = self.call_this_move_req_function(*args, **kwargs)
+        self.assertEqual(retval[0], args)
+        self.assertEqual(retval[1], kwargs)
+        self.assertRaises(UserRightsError, self.call_this_edit_req_function,
+                          args, kwargs)
+
+
+class TestNeedVersion(DeprecationTestCase):
+
+    """Test cases for the need_version decorator."""
+
+    net = False
+
+    # Implemented without setUpClass(cls) and global variables as objects
+    # were not completely disposed and recreated but retained 'memory'
+    def setUp(self):
+        """Set up test method."""
+        super(TestNeedVersion, self).setUp()
+        self.version = lambda: '1.23'
+
+    @need_version('1.24')
+    def too_new(self):
+        """Method which is to new."""
+        return True
+
+    @need_version('1.23')
+    def old_enough(self):
+        """Method which is as new as the server."""
+        return True
+
+    @need_version('1.22')
+    def older(self):
+        """Method which is old enough."""
+        return True
+
+    @need_version('1.24')
+    @deprecated
+    def deprecated_unavailable_method(self):
+        """Method which is to new and then deprecated."""
+        return True
+
+    @deprecated
+    @need_version('1.24')
+    def deprecated_unavailable_method2(self):
+        """Method which is deprecated first and then to new."""
+        return True
+
+    @need_version('1.22')
+    @deprecated
+    def deprecated_available_method(self):
+        """Method which is old enough and then deprecated."""
+        return True
+
+    @deprecated
+    @need_version('1.22')
+    def deprecated_available_method2(self):
+        """Method which is deprecated first and then old enough."""
+        return True
+
+    def test_need_version(self):
+        """Test need_version when the version is new, exact or old enough."""
+        self.assertRaises(NotImplementedError, self.too_new)
+        self.assertTrue(self.old_enough())
+        self.assertTrue(self.older())
+
+    def test_need_version_fail_with_deprecated(self):
+        """Test order of combined version check and deprecation warning."""
+        # FIXME: The deprecation message should be:
+        #   __name__ + '.TestNeedVersion.deprecated_unavailable_method
+
+        # The outermost decorator is the version check, so no
+        # deprecation message.
+        self.assertRaisesRegex(
+            NotImplementedError,
+            'deprecated_unavailable_method',
+            self.deprecated_unavailable_method)
+        self.assertNoDeprecation()
+
+        # The deprecator is first, but the version check still
+        # raises exception.
+        self.assertRaisesRegex(
+            NotImplementedError,
+            'deprecated_unavailable_method2',
+            self.deprecated_unavailable_method2)
+        self.assertOneDeprecationParts(
+            __name__ + '.TestNeedVersion.deprecated_unavailable_method2')
+
+    def test_need_version_success_with_deprecated(self):
+        """Test order of combined version check and deprecation warning."""
+        self.deprecated_available_method()
+        self.assertOneDeprecationParts(
+            __name__ + '.TestNeedVersion.deprecated_available_method')
+
+        self.deprecated_available_method2()
+        self.assertOneDeprecationParts(
+            __name__ + '.TestNeedVersion.deprecated_available_method2')
+
+
+if __name__ == '__main__':  # pragma: no cover
+    unittest.main()

--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/616100
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: Ib6f00ce181d936aa116391f25913591d4dc209b8
Gerrit-Change-Number: 616100
Gerrit-PatchSet: 6
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Dvorapa <[email protected]>
Gerrit-Reviewer: Matěj Suchánek <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/pywikibot-commits

Reply via email to