diff --git a/mwclient/client.py b/mwclient/client.py index 777b5cb888a7188f8c36097e41867b0d187c6850..e98afee219c5e120fc59490c852d3bf912392ccb 100644 --- a/mwclient/client.py +++ b/mwclient/client.py @@ -143,27 +143,32 @@ class Site(object): while True: info = self.raw_api(action, **kwargs) if not info: info = {} + res = self.handle_api_result(info) + if res: + return info - try: - userinfo = compatibility.userinfo(info, self.require(1, 12, raise_error = None)) - except KeyError: - userinfo = () - if 'blockedby' in userinfo: - self.blocked = (userinfo['blockedby'], userinfo.get('blockreason', u'')) - else: - self.blocked = False - self.hasmsg = 'message' in userinfo - self.logged_in = 'anon' not in userinfo - if 'error' in info: - if info['error']['code'] in (u'internal_api_error_DBConnectionError', ): - self.wait(token) - continue - if '*' in info['error']: - raise errors.APIError(info['error']['code'], - info['error']['info'], info['error']['*']) + + def handle_api_result(self, info, kwargs = None): + try: + userinfo = compatibility.userinfo(info, self.require(1, 12, raise_error = None)) + except KeyError: + userinfo = () + if 'blockedby' in userinfo: + self.blocked = (userinfo['blockedby'], userinfo.get('blockreason', u'')) + else: + self.blocked = False + self.hasmsg = 'message' in userinfo + self.logged_in = 'anon' not in userinfo + if 'error' in info: + if info['error']['code'] in (u'internal_api_error_DBConnectionError', ): + self.wait(token) + return False + if '*' in info['error']: raise errors.APIError(info['error']['code'], + info['error']['info'], info['error']['*']) + raise errors.APIError(info['error']['code'], info['error']['info'], kwargs) - return info + return True @staticmethod def _to_str(data): @@ -181,7 +186,9 @@ class Site(object): def raw_call(self, script, data): url = self.path + script + self.ext - headers = {'Content-Type': 'application/x-www-form-urlencoded'} + headers = {} + if not issubclass(data.__class__, upload.Upload): + headers['Content-Type'] = 'application/x-www-form-urlencoded' if self.compress and gzip: headers['Accept-Encoding'] = 'gzip' @@ -314,12 +321,16 @@ class Site(object): self.site_init() - def upload(self, file, filename, description, license = '', ignore = False, file_size = None): + def upload(self, file, filename, description, ignore = False, file_size = None): + if self.version[:2] < (1, 17): + # To 1.16 once deployed on Wikimedia + return compatibility.old_upload(self, file = file, filename = filename, + description = description, ignore = ignore, + file_size = file_size) + image = self.Images[filename] if not image.can('upload'): raise errors.InsufficientPermission(filename) - if image.exists and not ignore: - raise errors.FileExists(filename) if type(file) is str: file_size = len(file) @@ -331,22 +342,26 @@ class Site(object): predata = {} # Do this thing later so that an incomplete upload won't work - # predata['wpDestFile'] = filename - predata['wpUploadDescription'] = description - predata['wpLicense'] = license - if ignore: predata['wpIgnoreWarning'] = 'true' - predata['wpUpload'] = 'Upload file' - predata['wpSourceType'] = 'file' - predata['wpDestFile'] = filename - postdata = upload.UploadFile('wpUploadFile', filename, file_size, file, predata) + predata['comment'] = description + if ignore: + predata['ignorewarnings'] = 'true' + predata['token'] = image.get_token('edit') + predata['action'] = 'upload' + predata['format'] = 'json' + predata['filename'] = filename + + postdata = upload.UploadFile('file', filename, file_size, file, predata) wait_token = self.wait_token() while True: try: - self.connection.post(self.host, - self.path + 'index.php?title=Special:Upload&maxlag=' + self.max_lag, - data = postdata).read() + data = self.raw_call('api', postdata).read() + info = simplejson.loads(data) + if not info: + info = {} + if self.handle_api_result(info): + return info except errors.HTTPStatusError, e: if e[0] == 503 and e[1].getheader('X-Database-Lag'): self.wait(wait_token, int(e[1].getheader('Retry-After'))) @@ -356,8 +371,6 @@ class Site(object): self.wait(wait_token) except errors.HTTPError: self.wait(wait_token) - else: - return file.seek(0, 0) def parse(self, text, title = None): diff --git a/mwclient/compatibility.py b/mwclient/compatibility.py index 69ee4fce68b117e4a176627176f9bd926913be59..0ac4d6001a09ec7567f35c10c02d3e9c6e3bdc8f 100644 --- a/mwclient/compatibility.py +++ b/mwclient/compatibility.py @@ -1,3 +1,5 @@ +import upload, errors + def title(prefix, new_format): if new_format: return prefix + 'title' @@ -36,4 +38,53 @@ def protectright(version): if version[:2] >= (1, 13): return 'editprotected' else: - return 'protect' \ No newline at end of file + return 'protect' + +def old_upload(self, file, filename, description, license = '', ignore = False, file_size = None): + image = self.Images[filename] + if not image.can('upload'): + raise errors.InsufficientPermission(filename) + if image.exists and not ignore: + raise errors.FileExists(filename) + + if type(file) is str: + file_size = len(file) + file = StringIO(file) + if file_size is None: + file.seek(0, 2) + file_size = file.tell() + file.seek(0, 0) + + predata = {} + # Do this thing later so that an incomplete upload won't work + # predata['wpDestFile'] = filename + predata['wpUploadDescription'] = description + predata['wpLicense'] = license + if ignore: predata['wpIgnoreWarning'] = 'true' + predata['wpUpload'] = 'Upload file' + predata['wpSourceType'] = 'file' + predata['wpDestFile'] = filename + predata['wpEditToken'] = image.get_token('edit') + + postdata = upload.UploadFile('wpUploadFile', filename, file_size, file, predata) + + wait_token = self.wait_token() + while True: + try: + self.connection.post(self.host, + self.path + 'index.php?title=Special:Upload&maxlag=' + + self.max_lag, data = postdata).read() + except errors.HTTPStatusError, e: + if e[0] == 503 and e[1].getheader('X-Database-Lag'): + self.wait(wait_token, int(e[1].getheader('Retry-After'))) + elif e[0] < 500 or e[0] > 599: + raise + else: + self.wait(wait_token) + except errors.HTTPError: + self.wait(wait_token) + else: + return + file.seek(0, 0) + + \ No newline at end of file