XZise has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/217275

Change subject: [FEAT] upload: Support continue/finish uploads
......................................................................

[FEAT] upload: Support continue/finish uploads

When the upload was interrupted or didn't finished because of a warning it's
possible to reuse the already uploaded data and just publish it (if it was
finished) or upload the rest (when chunked mode is used).

Bug: T101657
Change-Id: I7f676b21856fbc8a65be7ced42a98dd1ca34d921
---
M pywikibot/data/api.py
M pywikibot/site.py
M scripts/upload.py
3 files changed, 56 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core 
refs/changes/75/217275/1

diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py
index 236f58a..bec26a6 100644
--- a/pywikibot/data/api.py
+++ b/pywikibot/data/api.py
@@ -113,9 +113,20 @@
 
     """Upload failed with a warning message (passed as the argument)."""
 
-    def __init__(self, code, message):
-        """Constructor."""
+    def __init__(self, code, message, filekey=None, offset=0):
+        """
+        Create a new UploadWarning instance.
+
+        @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
+        @param offset: The starting offset for a chunked upload. Is False when
+            there is no offset.
+        @type offset: int or bool
+        """
         super(UploadWarning, self).__init__(code, message)
+        self.filekey = filekey
+        self.offset = offset
 
     @property
     def message(self):
diff --git a/pywikibot/site.py b/pywikibot/site.py
index 2c4f288..ed49fff 100644
--- a/pywikibot/site.py
+++ b/pywikibot/site.py
@@ -4959,7 +4959,7 @@
     @deprecate_arg('imagepage', 'filepage')
     def upload(self, filepage, source_filename=None, source_url=None,
                comment=None, text=None, watch=False, ignore_warnings=False,
-               chunk_size=0):
+               chunk_size=0, file_key=None, offset=0):
         """Upload a file to the wiki.
 
         Either source_filename or source_url, but not both, must be provided.
@@ -4981,6 +4981,13 @@
             will only upload in chunks, if the version number is 1.20 or higher
             and the chunk size is positive but lower than the file size.
         @type chunk_size: int
+        @param file_key: Reuses an already uploaded file using the filekey. If
+            None (default) it will upload the file.
+        @type file_key: str or None
+        @param offset: When file_key is not None this can be an integer to
+            continue a previously canceled chunked upload. If False it treats
+            that as a finished upload. By default starts at 0.
+        @type offset: int or bool
         """
         upload_warnings = {
             # map API warning codes to user error messages
@@ -5017,7 +5024,14 @@
         token = self.tokens['edit']
         result = None
         file_page_title = filepage.title(withNamespace=False)
-        if source_filename:
+        if file_key and offset is False:
+            pywikibot.log('Reused already upload file using '
+                          'filekey "{0}"'.format(file_key))
+            req = api.Request(site=self, action='upload', token=token,
+                              filename=file_page_title,
+                              comment=comment, text=text,
+                              filekey=file_key)
+        elif source_filename:
             # TODO: Dummy value to allow also Unicode names, see bug 73661
             mime_filename = 'FAKE-NAME'
             # upload local file
@@ -5032,8 +5046,9 @@
                               MediaWikiVersion(self.version()) >= 
MediaWikiVersion('1.20'))
             with open(source_filename, 'rb') as f:
                 if chunked_upload:
-                    offset = 0
-                    file_key = None
+                    if offset > 0:
+                        pywikibot.log('Continuing upload from byte '
+                                      '{0}'.format(offset))
                     while True:
                         f.seek(offset)
                         chunk = f.read(chunk_size)
@@ -5063,13 +5078,19 @@
                         if 'offset' in data:
                             new_offset = int(data['offset'])
                             if offset + len(chunk) != new_offset:
+                                pywikibot.log('Old offset: {0}; Returned '
+                                              'offset: {1}; Chunk size: '
+                                              '{2}'.format(offset, new_offset,
+                                                           len(chunk)))
                                 pywikibot.warning('Unexpected offset.')
                             offset = new_offset
                         else:
                             pywikibot.warning('Offset was not supplied.')
                             offset += len(chunk)
                         if data['result'] != 'Continue':  # finished
+                            pywikibot.log('Finished uploading last chunk.')
                             additional_parameters['filekey'] = file_key
+                            offset = False
                             break
                 else:  # not chunked upload
                     file_contents = f.read()
@@ -5082,6 +5103,7 @@
                                      {'filename': mime_filename})
                         }
                     }
+                    offset = False
             req = api.Request(site=self, action="upload", token=token,
                               filename=file_page_title,
                               comment=comment, text=text, throttle=throttle,
@@ -5095,6 +5117,7 @@
             req = api.Request(site=self, action="upload", token=token,
                               filename=file_page_title,
                               url=source_url, comment=comment, text=text)
+            offset = False
         if not result:
             req['watch'] = watch
             req['ignorewarnings'] = ignore_warnings
@@ -5113,8 +5136,10 @@
             # TODO: Handle multiple warnings at the same time
             warning = list(result["warnings"].keys())[0]
             message = result["warnings"][warning]
+            # TODO: Determine when filekey was introduced
             raise pywikibot.UploadWarning(warning, upload_warnings[warning]
-                                          % {'msg': message})
+                                          % {'msg': message}, 
result['filekey'],
+                                          result['offset'] if 'offset' in 
result else 0)
         elif "result" not in result:
             pywikibot.output(u"Upload: unrecognized response: %s" % result)
         if result["result"] == "Success":
diff --git a/scripts/upload.py b/scripts/upload.py
index 95c3a77..7c9ab7b 100755
--- a/scripts/upload.py
+++ b/scripts/upload.py
@@ -333,7 +333,7 @@
         """Upload image."""
         self.upload_file(self.url, debug)
 
-    def upload_file(self, file_url, debug=False):
+    def upload_file(self, file_url, debug=False, upload_warning=None):
         """Upload the image at file_url to the target wiki.
 
         Return the filename that was used to upload the image.
@@ -351,13 +351,21 @@
 
         pywikibot.output(u'Uploading file to %s via API...' % site)
 
+        if upload_warning:
+            filekey = upload_warning.filekey
+            offset = upload_warning.offset
+        else:
+            filekey = None
+            offset = 0
+
         try:
             apiIgnoreWarnings = False
             if self.ignoreWarning is True:
                 apiIgnoreWarnings = True
             if self.uploadByUrl:
                 site.upload(imagepage, source_url=file_url,
-                            ignore_warnings=apiIgnoreWarnings)
+                            ignore_warnings=apiIgnoreWarnings,
+                            filekey=filekey, offset=offset)
             else:
                 if "://" in file_url:
                     temp = self.read_file_content(file_url)
@@ -365,7 +373,8 @@
                     temp = file_url
                 site.upload(imagepage, source_filename=temp,
                             ignore_warnings=apiIgnoreWarnings,
-                            chunk_size=self.chunk_size)
+                            chunk_size=self.chunk_size,
+                            file_key=filekey, offset=offset)
 
         except pywikibot.data.api.UploadWarning as warn:
             pywikibot.output(
@@ -380,7 +389,7 @@
             if answer:
                 self.ignoreWarning = True
                 self.keepFilename = True
-                return self.upload_file(file_url, debug)
+                return self.upload_file(file_url, debug, warn)
             else:
                 pywikibot.output(u"Upload aborted.")
                 return

-- 
To view, visit https://gerrit.wikimedia.org/r/217275
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I7f676b21856fbc8a65be7ced42a98dd1ca34d921
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

Reply via email to