jenkins-bot has submitted this change and it was merged.
Change subject: Add encode_url to pywikibot.data.api
......................................................................
Add encode_url to pywikibot.data.api
Use it instead of stock urlencode from urllib so that token parameters are
moved to the end (and 'wpEditToken' to the very and) to comply with
https://www.mediawiki.org/wiki/API:Edit#Parameters
Bug: T85321
Change-Id: Idb24ef35e290b26479fdff328833fab4eb63b5c4
---
M pywikibot/data/api.py
M pywikibot/site.py
M tests/api_tests.py
3 files changed, 69 insertions(+), 3 deletions(-)
Approvals:
John Vandenberg: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py
index 86cf089..efbab77 100644
--- a/pywikibot/data/api.py
+++ b/pywikibot/data/api.py
@@ -1764,7 +1764,7 @@
URL encodes the parameters provided by _encoded_items()
"""
- return urlencode(self._encoded_items())
+ return encode_url(self._encoded_items())
def __str__(self):
"""Return a string representation."""
@@ -3028,6 +3028,31 @@
http.cookie_jar.save()
+def encode_url(query):
+ """
+ Encode parameters to pass with a url.
+
+ Reorder parameters so that token parameters go last and call wraps
+ L{urlencode}. Return an HTTP URL query fragment which complies with
+
https://www.mediawiki.org/wiki/API:Edit#Parameters
+ (See the 'token' bullet.)
+
+ @param query: keys and values to be uncoded for passing with a url
+ @type query: mapping object or a sequence of two-element tuples
+ @return: encoded parameters with token parameters at the end
+ @rtype: str
+ """
+ if hasattr(query, 'items'):
+ query = query.items()
+ if PY2:
+ query = [(pair[0], pair[1].encode('utf-8')) for pair in query]
+ # parameters ending on 'token' should go last
+ # wpEditToken should go very last
+ query.sort(key=lambda x: x[0].lower().endswith('token') +
+ (x[0] == 'wpEditToken'))
+ return urlencode(query)
+
+
def update_page(page, pagedict, props=[]):
"""Update attributes of Page object page, based on query data in
pagedict.
diff --git a/pywikibot/site.py b/pywikibot/site.py
index e4aebcd..0c486d7 100644
--- a/pywikibot/site.py
+++ b/pywikibot/site.py
@@ -1212,10 +1212,10 @@
"""Return Family object for this Site."""
return self.family
- @deprecated("urllib.urlencode()")
+ @deprecated("pywikibot.data.api.encode_url")
def urlEncode(self, query):
"""DEPRECATED."""
- return urlencode(query)
+ return api.encode_url(query)
@deprecated('pywikibot.data.api.Request or pywikibot.comms.http.request')
@deprecated_args(compress=None, no_hostname=None, cookies_only=None,
diff --git a/tests/api_tests.py b/tests/api_tests.py
index 481504c..0b06b80 100644
--- a/tests/api_tests.py
+++ b/tests/api_tests.py
@@ -973,6 +973,47 @@
page.save(summary='Bad token test')
+class TestUrlEncoding(TestCase):
+
+ """Test url_encode."""
+
+ family = 'wikipedia'
+ code = 'test'
+
+ def test_url_encoding_from_list(self):
+ """Test moving 'token' parameters from a list to the
end."""
+ query = [('action', 'edit'), ('token', 'a'),
('supertoken', 'b'),
+ ('text', 'text')]
+ expect = 'action=edit&text=text&token=a&supertoken=b'
+ result = api.encode_url(query)
+ self.assertEqual(result, expect)
+ self.assertIsInstance(result, str)
+
+ def test_url_encoding_from_dict(self):
+ """Test moving 'token' parameters from a dict to the
end."""
+ # do not add other keys because dictionary is not deterministic
+ query = {'supertoken': 'b', 'text': 'text'}
+ expect = 'text=text&supertoken=b'
+ result = api.encode_url(query)
+ self.assertEqual(result, expect)
+ self.assertIsInstance(result, str)
+
+ def test_url_encoding_from_unicode(self):
+ """Test encoding unicode values."""
+ query = {'token': 'токен'}
+ expect = 'token=%D1%82%D0%BE%D0%BA%D0%B5%D0%BD'
+ result = api.encode_url(query)
+ self.assertEqual(result, expect)
+ self.assertIsInstance(result, str)
+
+ def test_moving_special_tokens(self):
+ """Test moving wpEditToken to the very end."""
+ query = {'wpEditToken': 'c', 'token': 'b',
'text': 'a'}
+ expect = 'text=a&token=b&wpEditToken=c'
+ result = api.encode_url(query)
+ self.assertEqual(result, expect)
+ self.assertIsInstance(result, str)
+
if __name__ == '__main__':
try:
unittest.main()
--
To view, visit
https://gerrit.wikimedia.org/r/258433
To unsubscribe, visit
https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Idb24ef35e290b26479fdff328833fab4eb63b5c4
Gerrit-PatchSet: 7
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Murfel <murnatty(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Murfel <murnatty(a)gmail.com>
Gerrit-Reviewer: jenkins-bot <>