From 5640c422e0ed01ea682fc2c0926eabbb895d7323 Mon Sep 17 00:00:00 2001 From: Jeremy Low Date: Mon, 13 Feb 2017 19:37:06 -0500 Subject: [PATCH] fix to upload video/gifs to correct endpoint if filesize < self.chunk_size previously, if a gif or a video (mp4/quicktime) was less than self.chunk_size, it would be uploaded via UploadMediaSimple, but this was a bug because that endpoint cannot handle videos or gifs. closes #433 --- tests/test_api_30.py | 19 +++++++++++++++++++ twitter/api.py | 18 ++++++++---------- twitter/twitter_utils.py | 6 +++--- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/tests/test_api_30.py b/tests/test_api_30.py index b966c70d..67d7b337 100644 --- a/tests/test_api_30.py +++ b/tests/test_api_30.py @@ -2,9 +2,15 @@ from __future__ import unicode_literals, print_function import json +import os import re import sys +from tempfile import NamedTemporaryFile import unittest +try: + from unittest.mock import patch +except ImportError: + from mock import patch import warnings import twitter @@ -1713,3 +1719,16 @@ def test_UpdateBackgroundImage_deprecation(self): with warnings.catch_warnings(record=True) as w: resp = self.api.UpdateBackgroundImage(image='testdata/168NQ.jpg') self.assertTrue(issubclass(w[0].category, DeprecationWarning)) + + @responses.activate + @patch('twitter.api.Api.UploadMediaChunked') + def test_UploadSmallVideoUsesChunkedData(self, mocker): + responses.add(POST, DEFAULT_URL, body='{}') + video = NamedTemporaryFile(suffix='.mp4') + video.write(b'10' * 1024) + video.seek(0, 0) + + resp = self.api.PostUpdate('test', media=video) + assert os.path.getsize(video.name) <= 1024 * 1024 + assert isinstance(resp, twitter.Status) + assert twitter.api.Api.UploadMediaChunked.called diff --git a/twitter/api.py b/twitter/api.py index 94ec3545..d41a6487 100644 --- a/twitter/api.py +++ b/twitter/api.py @@ -1026,6 +1026,7 @@ def PostUpdate(self, parameters['attachment_url'] = attachment_url if media: + chunked_types = ['video/mp4', 'video/quicktime', 'image/gif'] media_ids = [] if isinstance(media, int): media_ids.append(media) @@ -1041,9 +1042,8 @@ def PostUpdate(self, _, _, file_size, media_type = parse_media_file(media_file) if media_type == 'image/gif' or media_type == 'video/mp4': raise TwitterError( - 'You cannot post more than 1 GIF or 1 video in a ' - 'single status.') - if file_size > self.chunk_size: + 'You cannot post more than 1 GIF or 1 video in a single status.') + if file_size > self.chunk_size or media_type in chunked_types: media_id = self.UploadMediaChunked( media=media_file, additional_owners=media_additional_owners, @@ -1055,13 +1055,11 @@ def PostUpdate(self, media_category=media_category) media_ids.append(media_id) else: - _, _, file_size, _ = parse_media_file(media) - if file_size > self.chunk_size: - media_ids.append( - self.UploadMediaChunked(media, media_additional_owners)) + _, _, file_size, media_type = parse_media_file(media) + if file_size > self.chunk_size or media_type in chunked_types: + media_ids.append(self.UploadMediaChunked(media, media_additional_owners)) else: - media_ids.append( - self.UploadMediaSimple(media, media_additional_owners)) + media_ids.append(self.UploadMediaSimple(media, media_additional_owners)) parameters['media_ids'] = ','.join([str(mid) for mid in media_ids]) if latitude is not None and longitude is not None: @@ -1263,7 +1261,7 @@ def _UploadMediaChunkedAppend(self, try: media_fp.close() - except: + except Exception as e: pass return True diff --git a/twitter/twitter_utils.py b/twitter/twitter_utils.py index 0b2af5bb..66ce8b24 100644 --- a/twitter/twitter_utils.py +++ b/twitter/twitter_utils.py @@ -223,8 +223,8 @@ def parse_media_file(passed_media): # Otherwise, if a file object was passed in the first place, # create the standard reference to media_file (i.e., rename it to fp). else: - if passed_media.mode != 'rb': - raise TwitterError({'message': 'File mode must be "rb".'}) + if passed_media.mode not in ['rb', 'rb+', 'w+b']: + raise TwitterError('File mode must be "rb" or "rb+"') filename = os.path.basename(passed_media.name) data_file = passed_media @@ -233,7 +233,7 @@ def parse_media_file(passed_media): try: data_file.seek(0) - except: + except Exception as e: pass media_type = mimetypes.guess_type(os.path.basename(filename))[0]