jenkins-bot has submitted this change. (
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1358207?usp=email )
Change subject: [bugfix] Use uciprange for IP ranges in usercontribs
......................................................................
[bugfix] Use uciprange for IP ranges in usercontribs
Site.usercontribs() and User.contributions() sent an IP range in CIDR
notation as ucuser, which the API rejects with a baduser error. Send it
as uciprange instead. The API also accepts a range with host bits set,
so add a strict parameter to tools.is_ip_network() to detect it.
Bug: T362377
Change-Id: I1f27935ea0cf361e28d2f53fb1780ecd26ee6e32
---
M pywikibot/site/_generators.py
M pywikibot/tools/__init__.py
M tests/tools_tests.py
M tests/user_tests.py
4 files changed, 76 insertions(+), 4 deletions(-)
Approvals:
jenkins-bot: Verified
Xqt: Looks good to me, approved
diff --git a/pywikibot/site/_generators.py b/pywikibot/site/_generators.py
index 2dea689..43b0f49 100644
--- a/pywikibot/site/_generators.py
+++ b/pywikibot/site/_generators.py
@@ -33,6 +33,7 @@
deprecated_args,
deprecated_signature,
is_ip_address,
+ is_ip_network,
)
from pywikibot.tools.itertools import filter_unique, union_generators
@@ -1728,7 +1729,11 @@
All parameters are keyword-only now. The *new*, *patrolled*,
and *autopatrolled* parameters were added.
- :param user: Iterate contributions by this user (name or IP).
+ .. version-changed:: 11.10
+ An IP range in CIDR notation is accepted as *user*.
+
+ :param user: Iterate contributions by this user (name, IP or IP
+ range in CIDR notation).
:param userprefix: Iterate contributions by all users whose
names or IPs start with this substring.
:param start: Iterate contributions starting at this Timestamp.
@@ -1784,7 +1789,11 @@
formatversion=formatversion
)
if user:
- ucgen.request['ucuser'] = user
+ # the API expects an IP range in uciprange, not in ucuser
+ if '/' in user and is_ip_network(user, strict=False):
+ ucgen.request['uciprange'] = user
+ else:
+ ucgen.request['ucuser'] = user
if userprefix:
ucgen.request['ucuserprefix'] = userprefix
if reverse:
diff --git a/pywikibot/tools/__init__.py b/pywikibot/tools/__init__.py
index d49481a..dcf271c 100644
--- a/pywikibot/tools/__init__.py
+++ b/pywikibot/tools/__init__.py
@@ -117,16 +117,21 @@
return False
-def is_ip_network(value: str) -> bool:
+def is_ip_network(value: str, *, strict: bool = True) -> bool:
"""Check if a value is a valid range of IPv4 or IPv6 addresses.
.. version-added:: 9.0
+ .. version-changed:: 11.10
+ The *strict* parameter was added.
.. seealso:: :func:`is_ip_address`
:param value: Value to check
+ :param strict: If ``True`` (default), the host bits of the address
+ must be zero; if ``False``, they are ignored, so
+ ``'1.2.3.4/24'`` is accepted
"""
with suppress(ValueError):
- ipaddress.ip_network(value)
+ ipaddress.ip_network(value, strict=strict)
return True
return False
diff --git a/tests/tools_tests.py b/tests/tools_tests.py
index 4d2db4e..32f719c 100755
--- a/tests/tools_tests.py
+++ b/tests/tools_tests.py
@@ -1077,6 +1077,29 @@
self.assertFalse(is_ip_network(ip_range))
+class TestIsIpNetworkNotStrict(TestCase):
+
+ """Unit test class for is_ip_network with the strict parameter."""
+
+ net = False
+
+ def test_host_bits(self) -> None:
+ """Check that host bits are only accepted with strict=False."""
+ for ip_range in ('1.2.3.4/24', '5.119.174.237/16', '192.168.0.0/8',
+ '2001:0db8::/16'):
+ with self.subTest(ip_network=ip_range):
+ self.assertFalse(is_ip_network(ip_range))
+ self.assertFalse(is_ip_network(ip_range, strict=True))
+ self.assertTrue(is_ip_network(ip_range, strict=False))
+
+ def test_invalid_ranges(self) -> None:
+ """Check that invalid values are rejected with strict=False."""
+ for ip_range in (None, '', '/32', 'a.b.c.d', '1.2.3.256/24',
+ '2001:db8::aaaa::1/128'):
+ with self.subTest(ip_network=ip_range):
+ self.assertFalse(is_ip_network(ip_range, strict=False))
+
+
class TestHasModule(TestCase):
"""Unit test class for has_module."""
diff --git a/tests/user_tests.py b/tests/user_tests.py
index 11f52a7..0d496bd 100755
--- a/tests/user_tests.py
+++ b/tests/user_tests.py
@@ -355,6 +355,41 @@
self.assertEqual(event.user(), user.username)
+class TestUsercontribsUserParameter(TestCase):
+
+ """Test how usercontribs() passes the user to the API."""
+
+ family = 'wikipedia'
+ code = 'test'
+ dry = True
+
+ def get_request(self, user: str) -> dict:
+ """Return the request parameters set by usercontribs()."""
+ with patch.object(self.site, '_generator') as generator, \
+ patch('pywikibot.data.api.OptionSet'):
+ generator.return_value.request = {}
+ self.site.usercontribs(user=user)
+ return generator.return_value.request
+
+ def test_ip_range(self) -> None:
+ """Test that an IP range is passed as uciprange."""
+ for user in ('5.119.0.0/16', '5.119.174.237/16', '1.2.3.4/32',
+ '2001:db8::/32'):
+ with self.subTest(user=user):
+ request = self.get_request(user)
+ self.assertEqual(request['uciprange'], user)
+ self.assertNotIn('ucuser', request)
+
+ def test_user_and_ip(self) -> None:
+ """Test that a name or a single IP is passed as ucuser."""
+ for user in ('Example', 'Example/Subpage', '5.119.174.237',
+ '2001:db8::1'):
+ with self.subTest(user=user):
+ request = self.get_request(user)
+ self.assertEqual(request['ucuser'], user)
+ self.assertNotIn('uciprange', request)
+
+
class TestUserRefreshParameter(DeprecationTestCase):
"""Test the rename of the *force* parameter to *refresh*."""
--
To view, visit
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1358207?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I1f27935ea0cf361e28d2f53fb1780ecd26ee6e32
Gerrit-Change-Number: 1358207
Gerrit-PatchSet: 2
Gerrit-Owner: AkashKumar7902 <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-CC: Mahveotm <[email protected]>
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]