PostUpdate() doesn't handle StringIO media like PostMedia() did
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
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.
Is this issue solved ? Because I am still having problems using BytesIO buffer with the same exception on python 3.7