XZise has uploaded a new change for review.
https://gerrit.wikimedia.org/r/232841
Change subject: [FEAT] upload: Support multiple warnings
......................................................................
[FEAT] upload: Support multiple warnings
When the upload fails it might return multiple warnings. Until now it just used
one randomly depending on how Python ordered them. With this patch it's
reporting all warnings at once.
With this feature the upload bot also allows to select to abort on every
warning which isn't explicitly ignored. At the moment it only works that it
aborts on certain warnings and ignores the rest.
Change-Id: Id6b7831f71eb188204e6b16cd5354644222b79f4
---
M pywikibot/data/api.py
M pywikibot/site.py
M scripts/upload.py
3 files changed, 110 insertions(+), 19 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core
refs/changes/41/232841/1
diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py
index d838f0c..055b99b 100644
--- a/pywikibot/data/api.py
+++ b/pywikibot/data/api.py
@@ -29,7 +29,9 @@
import pywikibot
from pywikibot import config, login
-from pywikibot.tools import MediaWikiVersion, deprecated, itergroup, ip, PY2
+from pywikibot.tools import (
+ MediaWikiVersion, deprecated, deprecated_args, itergroup, ip, PY2,
+)
from pywikibot.exceptions import (
Server504Error, Server414Error, FatalServerError, NoUsername, Error
)
@@ -93,29 +95,57 @@
def __init__(self, code, info, **kwargs):
"""Save error dict returned by MW API."""
- self.code = code
- self.info = info
+ self._code = code
+ self._info = info
self.other = kwargs
self.unicode = unicode(self.__str__())
def __repr__(self):
"""Return internal representation."""
- return '{name}("{code}", "{info}", {other})'.format(
+ return '{name}("{_code}", "{_info}", {other})'.format(
name=self.__class__.__name__, **self.__dict__)
def __str__(self):
"""Return a string representation."""
- return "%(code)s: %(info)s" % self.__dict__
+ return "%(_code)s: %(_info)s" % self.__dict__
+
+ @property
+ def code(self):
+ """Return the error code."""
+ return self._code
+
+ @property
+ def info(self):
+ """Return the error message."""
+ return self._info
class UploadWarning(APIError):
- """Upload failed with a warning message (passed as the argument)."""
+ """
+ Upload failed with one warning or multiple warnings.
- def __init__(self, code, message, file_key=None, offset=0):
+ Each warning is stored in the messages attribute with a code/message
+ mapping. The L{code}, L{info} and L{message} attributes should be avoided
as
+ it hides when multiple warnings are present.
+ """
+
+ @deprecated_args(code='codes', message='messages')
+ def __init__(self, codes, messages, file_key=None, offset=0):
"""
Create a new UploadWarning instance.
+ @param codes: The code or codes of the warning. Either it's a dict of
+ multiple warnings (with a key/data mapping) or the code of one
+ warning (deprecated). The messages parameter must have the same
type
+ as this parameter.
+ @type codes: dict or str
+ @param messages: The messages with all the codes if codes is a dict and
+ the message of the code if it's a string. If it's a dict it is a
+ key/message mapping with one %-notation placeholder and otherwise
+ it's just the message already subtituted with the data
(deprecated).
+ The codes parameter must have the same type as this parameter.
+ @type messages: dict or str
@param filekey: The filekey of the uploaded file to reuse it later. If
no key is known or it is an incomplete file it may be None.
@type filekey: str or None
@@ -123,13 +153,46 @@
there is no offset.
@type offset: int or bool
"""
+ if isinstance(codes, dict) and isinstance(messages, dict):
+ # TODO: What to do with the other warnings?
+ self.messages = dict((c, messages[c] % {'msg': d})
+ for c, d in codes.items()
+ if c in messages)
+ # Randomly choose one code/message
+ code = next(iter(self.messages))
+ message = self.messages[code]
+ else:
+ self.messages = {codes: messages}
+ code = codes
+ message = messages
super(UploadWarning, self).__init__(code, message)
self.file_key = file_key
self.offset = offset
@property
+ @deprecated('messages')
+ def code(self):
+ """DEPRECTED: Return a warning code; random if multiple present."""
+ if len(self.messages) > 1:
+ pywikibot.warning(
+ 'The warning contains multiple codes ({0}) but returns only '
+ '{1}'.format(', '.join(self.messages), self._code))
+ return super(UploadWarning, self).code
+
+ @property
+ @deprecated('messages')
+ def info(self):
+ """DEPRECTED: Return a warning info; random if multiple present."""
+ if len(self.messages) > 1:
+ pywikibot.warning(
+ 'The warning contains multiple infos ({0}) but returns only '
+ '{1}'.format(', '.join(self.messages.values()), self._info))
+ return super(UploadWarning, self).info
+
+ @property
+ @deprecated('messages')
def message(self):
- """Return warning message."""
+ """DEPRECTED: Return a warning info (random if multiple present)."""
return self.info
diff --git a/pywikibot/site.py b/pywikibot/site.py
index c09f399..03d5d75 100644
--- a/pywikibot/site.py
+++ b/pywikibot/site.py
@@ -5358,9 +5358,6 @@
pywikibot.debug(result, _logger)
if "warnings" in result and not ignore_warnings:
- # TODO: Handle multiple warnings at the same time
- warning = list(result["warnings"].keys())[0]
- message = result["warnings"][warning]
if 'filekey' in result:
_file_key = result['filekey']
elif 'sessionkey' in result:
@@ -5370,8 +5367,7 @@
else:
_file_key = None
pywikibot.warning('No filekey defined.')
- raise pywikibot.UploadWarning(warning, upload_warnings[warning]
- % {'msg': message},
+ raise pywikibot.UploadWarning(result['warnings'], upload_warnings,
file_key=_file_key,
offset=result['offset']
if 'offset' in result else
False)
diff --git a/scripts/upload.py b/scripts/upload.py
index abf0ff7..6156886 100755
--- a/scripts/upload.py
+++ b/scripts/upload.py
@@ -23,6 +23,13 @@
'Mi': Mebibytes (1024x1024 B)
The suffixes are case insensitive.
+It is possible to combine -abortonwarn and -ignorewarn so that if the specific
+warning is given it won't apply the general one but more specific one. So if it
+should ignore specific warnings and abort on the rest it's possible by defining
+no warning for -abortonwarn and the specific warnings for -ignorewarn. The
order
+does not matter. If both are unspecific or a warning is specified by both,
it'll
+prefer aborting.
+
If any other arguments are given, the first is either URL, filename or
directory
to upload, and the rest is a proposed description to go with the upload. If
none
of these are given, the user is asked for the directory, file or URL to upload.
@@ -197,6 +204,23 @@
t.close()
return tempname
+ def _handle_warning(self, warning):
+ """
+ Return whether the warning cause an abort or be ignored.
+
+ @param warning: The warning name
+ @type warning: str
+ @return: False if this warning should cause an abort, True if it should
+ be ignored or None if this warning has no default handler.
+ @rtype: bool or None
+ """
+ if self.aborts is not True:
+ if warning in self.aborts:
+ return False
+ if self.ignoreWarning is True or warning in self.ignoreWarning:
+ return True
+ return None if self.aborts is not True else False
+
def process_filename(self, file_url=None):
"""Return base filename portion of file_url."""
if not file_url:
@@ -370,13 +394,21 @@
_file_key=_file_key, _offset=_offset)
except pywikibot.data.api.UploadWarning as warn:
+ messages = '\n'.join('{0}: {1}'.format(code, message)
+ for code, message in warn.messages.items())
+ if len(warn.messages) > 1:
+ messages = '\n' + messages
pywikibot.output(
- u'We got a warning message: {0} - {1}'.format(warn.code,
warn.message))
- if self.abort_on_warn(warn.code):
- answer = False
- elif self.ignore_on_warn(warn.code):
- answer = True
- else:
+ 'We got the following warning(s): ' + messages)
+ answer = True
+ for code in warn.messages:
+ this_answer = self._handle_warning(code)
+ if this_answer is False:
+ answer = False
+ break
+ elif this_answer is None:
+ answer = None
+ if answer is None:
answer = pywikibot.input_yn(u"Do you want to ignore?",
default=False,
automatic_quit=False)
if answer:
--
To view, visit https://gerrit.wikimedia.org/r/232841
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id6b7831f71eb188204e6b16cd5354644222b79f4
Gerrit-PatchSet: 1
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: XZise <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits