python-twitter icon indicating copy to clipboard operation
python-twitter copied to clipboard

PostUpdate() doesn't handle StringIO media like PostMedia() did

Open jdimpson opened this issue 8 years ago • 2 comments

Both the deprecated PostMedia() and the preferred PostUpdate() methods of the API say they can post media taken from "file like objects (something with a read() method)".

In my case, I am posting a StringIO buffer full of a JPEG image. This works in with PostMedia() but fails in PostUpdate() with the following:

     status = self.api.PostUpdate(mess, media=image)
   File "/usr/local/lib/python2.7/dist-packages/twitter/api.py", line 1058, in PostUpdate
     _, _, file_size, _ = parse_media_file(media)
   File "/usr/local/lib/python2.7/dist-packages/twitter/twitter_utils.py", line 226, in parse_media_file
     if passed_media.mode != 'rb':
 AttributeError: StringIO instance has no attribute 'mode'

Python-twitter version 3.2.1, pythin 2.7

My brief analysis: PostMedia() checks if the media argument is has a read attribute. If so, it read()s the media into data[media] and moves on.

PostUpdate() passes the media argument to parse_media_file() which checks if the media has a mode attribute. Apparantly it does not.

I'm not sure if this a ramification to Twitter's deprecation of the endpoint that PostMedia is based on. I see parse_media_file() doing other mimetype-like stuff. I'm also not sure that StringIO is the best way to do what I want to do (post an image from a buffer)

I'm willing to help troubleshoot further. Thank you!

Jeremy

jdimpson avatar Jan 25 '17 23:01 jdimpson

Yeah, there's a lot going on in that function, which could probably be broken out a bit.

So with the old method (PostMedia()), the API just assumed that you were posting a photo (cause, at the time, that's all you could post to twitter) and so read()ing in a stream of data made sense. Now the API can handle GIFs and videos and each of those have different file-size limitations and attachment limitations, so we try to figure out what you want to upload before uploading the data.

The problem with using a StringIO buffer to post a photo or video is that there's no way (that I know of) of determining if the buffer contains a photo or video or GIF. (Off the top of my head, there may be a way you could probably do it by reading the first bytes of the buffer and then guessing the file type from that, but I don't know without further research.) So this doesn't have anything to do with Twitter's deprecation of that endpoint, just with our manner of figuring out what a user wants to upload.

As for a solution, you can write the buffer out to a NamedTemporaryFile with the extension you want and then pass that to PostUpdate since it'll have a read and mode attribute. This is effectively what we do when we get a URL (check out the http_to_file() method in twitter_utils.py).

Let me know if that solves the problem for you.

jeremylow avatar Jan 27 '17 10:01 jeremylow

Is this issue solved ? Because I am still having problems using BytesIO buffer with the same exception on python 3.7

shubidubapp avatar Sep 17 '19 17:09 shubidubapp