From 8efbee2156372076a805885bcba2653db81fa81d Mon Sep 17 00:00:00 2001 From: hjpotter92 Date: Tue, 26 Sep 2017 14:59:02 +0530 Subject: [PATCH 1/3] Add globally available method to allow for uploading binary object This commit references maxtepkeev/python-redmine#186 Signed-off-by: hjpotter92 --- redminelib/__init__.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/redminelib/__init__.py b/redminelib/__init__.py index c7b693f..779ac9d 100644 --- a/redminelib/__init__.py +++ b/redminelib/__init__.py @@ -90,6 +90,23 @@ def upload(self, filepath): return response['upload']['token'] + def upload_object(self, fileobj): + """ + Uploads binary file object to Redmine and returns an assigned token. + + :param string fileobj: (required). File object that will be uploaded. + """ + if self.ver is not None and LooseVersion(str(self.ver)) < LooseVersion('1.4.0'): + raise exceptions.VersionMismatchError('File uploading') + + if not isinstance(fileobj, file): + raise exceptions.NoFileError + + url = '{0}/uploads.json'.format(self.url) + headers = {'Content-Type': 'application/octet-stream'} + response = self.engine.request('post', url, data=fileobj, headers=headers) + return response['upload']['token'] + def download(self, url, savepath=None, filename=None, params=None): """ Downloads file from Redmine and saves it to savepath or returns a response directly From a3df8497a9bfb79621735edbcb075b35840eea02 Mon Sep 17 00:00:00 2001 From: hjpotter92 Date: Wed, 27 Sep 2017 09:30:43 +0530 Subject: [PATCH 2/3] Merge `upload` and `upload_object` into a single method * The method first checks if the parameter is of type `file`, otherwise proceeds as before. * Define `url` and `headers` before any processing is done. Signed-off-by: hjpotter92 --- redminelib/__init__.py | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/redminelib/__init__.py b/redminelib/__init__.py index 779ac9d..24d46e6 100644 --- a/redminelib/__init__.py +++ b/redminelib/__init__.py @@ -71,40 +71,25 @@ def session(self, **options): yield self self.engine = engine - def upload(self, filepath): + def upload(self, filepath_obj): """ Uploads file from filepath to Redmine and returns an assigned token. - :param string filepath: (required). Path to the file that will be uploaded. + :param string filepath_obj: (required). Path to the file or filestream that will be uploaded. """ if self.ver is not None and LooseVersion(str(self.ver)) < LooseVersion('1.4.0'): raise exceptions.VersionMismatchError('File uploading') - if not os.path.isfile(filepath) or os.path.getsize(filepath) == 0: - raise exceptions.NoFileError - - with open(filepath, 'rb') as stream: - url = '{0}/uploads.json'.format(self.url) - headers = {'Content-Type': 'application/octet-stream'} - response = self.engine.request('post', url, data=stream, headers=headers) - - return response['upload']['token'] - - def upload_object(self, fileobj): - """ - Uploads binary file object to Redmine and returns an assigned token. - - :param string fileobj: (required). File object that will be uploaded. - """ - if self.ver is not None and LooseVersion(str(self.ver)) < LooseVersion('1.4.0'): - raise exceptions.VersionMismatchError('File uploading') - - if not isinstance(fileobj, file): - raise exceptions.NoFileError - url = '{0}/uploads.json'.format(self.url) headers = {'Content-Type': 'application/octet-stream'} - response = self.engine.request('post', url, data=fileobj, headers=headers) + if isinstance(filepath_obj, file): + response = self.engine.request('post', url, data=filepath_obj, headers=headers) + else: + if not os.path.isfile(filepath_obj) or os.path.getsize(filepath_obj) == 0: + raise exceptions.NoFileError + with open(filepath_obj, 'rb') as stream: + response = self.engine.request('post', url, data=stream, headers=headers) + return response['upload']['token'] def download(self, url, savepath=None, filename=None, params=None): From 1a5b9f1dc3099a0463beeae05a3927070fde41df Mon Sep 17 00:00:00 2001 From: hjpotter92 Date: Wed, 27 Sep 2017 09:52:21 +0530 Subject: [PATCH 3/3] Support for filetypes in Python 3 version Also allow for `StringIO` type variables Signed-off-by: hjpotter92 --- redminelib/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/redminelib/__init__.py b/redminelib/__init__.py index 24d46e6..1a66669 100644 --- a/redminelib/__init__.py +++ b/redminelib/__init__.py @@ -82,7 +82,13 @@ def upload(self, filepath_obj): url = '{0}/uploads.json'.format(self.url) headers = {'Content-Type': 'application/octet-stream'} - if isinstance(filepath_obj, file): + try: + from StringIO import StringIO + filetype = (file, StringIO) + except (NameError, ImportError): + from io import IOBase + filetype = IOBase + if isinstance(filepath_obj, filetype): response = self.engine.request('post', url, data=filepath_obj, headers=headers) else: if not os.path.isfile(filepath_obj) or os.path.getsize(filepath_obj) == 0: