jenkins-bot submitted this change.

View Change

Approvals: Matěj Suchánek: Looks good to me, approved jenkins-bot: Verified
[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(-)

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 change 616100. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ib6f00ce181d936aa116391f25913591d4dc209b8
Gerrit-Change-Number: 616100
Gerrit-PatchSet: 6
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: Dvorapa <dvorapa@seznam.cz>
Gerrit-Reviewer: Matěj Suchánek <matejsuchanek97@gmail.com>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged