Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions test/test_wbi_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mapping), search, merge, SPARQL and the various pure helper functions.
"""
import logging
from types import MappingProxyType

import pytest
import requests
Expand Down Expand Up @@ -144,6 +145,46 @@ def test_assert_user_and_bot_flags(self, wikibase, item_q582):
assert wikibase.last_request['assert'] == 'bot'


class TestRequestDataNotMutated:
"""The caller's request payload must be left untouched by the API helpers."""

def test_helper_does_not_mutate_caller_data(self, wikibase, item_q582):
login = FakeLogin(mediawiki_api_url=wikibase.mediawiki_api_url)
data = {'action': 'wbgetentities', 'ids': 'Q582'}

mediawiki_api_call_helper(data=data, login=login, is_bot=True)

assert data == {'action': 'wbgetentities', 'ids': 'Q582'}
# The copy sent over the wire still gets the automatic parameters
assert wikibase.last_request['token'] == login.edit_token
assert wikibase.last_request['assert'] == 'bot'
assert wikibase.last_request['maxlag'] == '5'
assert wikibase.last_request['format'] == 'json'

def test_api_call_does_not_mutate_caller_data(self, requests_mock):
url = 'https://example.org/w/api.php'
requests_mock.post(url, json={'success': 1})
data = {'action': 'query'}

mediawiki_api_call('POST', mediawiki_api_url=url, data=data)

assert data == {'action': 'query'}
assert 'format=json' in requests_mock.last_request.text

def test_api_call_accepts_read_only_mapping(self, requests_mock):
url = 'https://example.org/w/api.php'
requests_mock.post(url, json={'success': 1})

assert mediawiki_api_call('POST', mediawiki_api_url=url, data=MappingProxyType({'action': 'query'})) == {'success': 1}
assert 'format=json' in requests_mock.last_request.text

def test_helper_accepts_none_data(self, requests_mock):
url = 'https://example.org/w/api.php'
requests_mock.post(url, json={'success': 1})

assert mediawiki_api_call_helper(data=None, mediawiki_api_url=url, allow_anonymous=True) == {'success': 1}


class TestUserAgent:
def test_no_warning_when_user_agent_set(self, wikibase, item_q582, caplog):
data = {'action': 'wbgetentities', 'ids': 'Q582', 'format': 'json'}
Expand Down
2 changes: 2 additions & 0 deletions wikibaseintegrator/wbi_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def mediawiki_api_call(method: str, mediawiki_api_url: str | None = None, sessio
# TODO: Add support for 'multipart/form-data' when using POST (https://www.mediawiki.org/wiki/API:Edit#Large_edits)

if 'data' in kwargs and kwargs['data']:
kwargs['data'] = dict(kwargs['data'])
if 'format' not in kwargs['data']:
kwargs['data'].update({'format': 'json'})
elif kwargs['data']['format'] != 'json':
Expand Down Expand Up @@ -165,6 +166,7 @@ def mediawiki_api_call_helper(data: dict[str, Any], login: _Login | None = None,
"""
mediawiki_api_url = str(mediawiki_api_url or config['MEDIAWIKI_API_URL'])
user_agent = user_agent or (str(config['USER_AGENT']) if config['USER_AGENT'] is not None else None)
data = dict(data) if data is not None else None

hostname = urlparse(mediawiki_api_url).hostname
if hostname is not None and hostname.endswith(('wikidata.org', 'wikipedia.org', 'wikimedia.org')) and user_agent is None:
Expand Down
Loading