mediawiki-utilities / python-mwapi

Simple Python Wrapper around MediaWiki API
http://pythonhosted.org/mwapi
MIT License
31 stars 11 forks source link

Support new error format #34

Open lucaswerkmeister opened 5 years ago

lucaswerkmeister commented 5 years ago

Since MediaWiki 1.29, the API can return errors in a new format (documentation): if the global errorformat parameter is set to anything other than bc (the default, for backwards compatibility), then instead of a single error object, the response can contain an errors list of error objects. Since mwapi currently only checks if the response contains an error, if the user specifies a different error format then mwapi will not recognize the error(s) and instead return the result as a regular response.

I’m not sure what mwapi should do in this case, though. Throw an APIError for the first error and ignore the rest? Define a new exception class for a list of APIErrors (which should probably derive from APIError so it can still be caught like one)?

lucaswerkmeister commented 3 years ago

I’m not sure what mwapi should do in this case, though. Throw an APIError for the first error and ignore the rest? Define a new exception class for a list of APIErrors (which should probably derive from APIError so it can still be caught like one)?

PEP 654 proposes exception groups (LWN.net article), which might be an interesting answer to this question.

lucaswerkmeister commented 1 year ago

Exception groups and except* are released in Python 3.11 now (see the PEP for details). I’m not sure they’re a good fit for mwapi, though: the main motivation for exception groups seems to be situations where the original exceptions come from different sources, and they repeatedly mention that a handler of an exception group would typically not handle the specific exceptions in great detail: the “handling KeyError here is meaningless” example from the “Applying an except* Clause on One Exception at a Time” section of the PEP Neither of these matches the mwapi situation.

lucaswerkmeister commented 3 months ago

Code to test the behavior with multiple errors:

import mwapi

session = mwapi.Session(host='https://test.wikipedia.org',
                        user_agent='mwapi-errors-test (https://github.com/mediawiki-utilities/python-mwapi/issues/34; mail@lucaswerkmeister.de)')
token = session.get(action='query',
                    meta='tokens',
                    type='csrf')['query']['tokens']['csrftoken']
params = {
    'action': 'edit',
    'title': 'Sandbox',
    'appendtext': 'the abuse filter will block this\nthe abuse filter will also block this',
    'token': token,
}
for errorformat in ['bc', 'plaintext']:
    try:
        response = session.post(errorformat=errorformat, **params)
        print(f'{errorformat=} did not throw, {response=}')
    except mwapi.errors.APIError as exception:
        print(f'{errorformat=} did throw, {exception=}')

Current output:

errorformat='bc' did throw, exception=APIError('abusefilter-disallowed: This action has been automatically identified as harmful, and therefore disallowed. If you believe your action was constructive, please inform an administrator of what you were trying to do. A brief description of the abuse rule which your action matched is: No saying "The abuse filter will block this" -- See https://test.wikipedia.org/w/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/postorius/lists/mediawiki-api-announce.lists.wikimedia.org/> for notice of API deprecations and breaking changes.')
errorformat='plaintext' did not throw, response={'errors': [{'code': 'abusefilter-disallowed', 'data': {'abusefilter': {'id': '1', 'description': 'No saying "The abuse filter will block this"', 'actions': ['disallow']}}, 'module': 'edit', '*': 'This action has been automatically identified as harmful, and therefore disallowed. If you believe your action was constructive, please inform an administrator of what you were trying to do. A brief description of the abuse rule which your action matched is: No saying "The abuse filter will block this"'}, {'code': 'abusefilter-disallowed', 'data': {'abusefilter': {'id': '266', 'description': 'No saying "The abuse filter will also block this"', 'actions': ['disallow']}}, 'module': 'edit', '*': 'This action has been automatically identified as harmful, and therefore disallowed. If you believe your action was constructive, please inform an administrator of what you were trying to do. A brief description of the abuse rule which your action matched is: No saying "The abuse filter will also block this"'}], 'servedby': 'mw1359', '*': 'See https://test.wikipedia.org/w/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/postorius/lists/mediawiki-api-announce.lists.wikimedia.org/> for notice of API deprecations and breaking changes.'}

(Notice that errorformat=bc only reports one of the two AbuseFilter errors.)