Python-slack-sdk: Upload a file

Created on 16 Feb 2016  Â·  31Comments  Â·  Source: slackapi/python-slack-sdk

It says here: https://api.slack.com/methods/files.upload that files need to be uploaded via multipart/form-data, which it looks like the current client doesn't support.

If we moved to requests #54, it would make it easier to use their files argument for that.

Most helpful comment

FWIW I'm using slackclient 1.0.9 and I just successfully used the following code to upload a file via a bot user:

from slackclient import SlackClient
sc = SlackClient(SLACK_TOKEN)
sc.api_call(
  'files.upload', 
  channels='#slacktesting', 
  as_user=True, 
  filename='pic.jpg', 
  file=open('puppy.jpg', 'rb'),
)

@stianlp Is 'notifications' a channel? If so, you might need to use '#notifications' to get your code to work.

All 31 comments

Have you found a workaround for that?

I see that's merged. So can you paste sample code for upload?

@jonathan-s It works when using the argument 'content' instead of 'file'.

I tried to upload an image like this. It uploaded alright, but it uploaded as a text file. How do I upload an image?

You should override the method 'do' of slackclient._slackrequest.SlackRequest, make it looks like this:

@staticmethod
- def do(token, request="?", post_data=None, domain="slack.com"):
+ def do(token, request="?", post_data=None, domain="slack.com", **kwargs):
       if post_data is None:
            post_data = {}

       return requests.post(
           'https://{0}/api/{1}'.format(domain, request),
           data=dict(post_data, token=token),
+          **kwargs
       )

and you can upload an image like this:

with open('my_image.png', 'rb') as f:
    client.api_call('files.upload', channels=[...], filename='pic.png', files={'file': f})

@prongs oh, sorry. Only overrides the method 'do' of slackclient._slackrequest.SlackRequest is not enough,the method 'api_call' of slackclient._client.SlackClient should be overrided too.

Can't someone put a pull request for this? I'd spent 3-4 hours on this last and couldn't get it right.

Easy way. Change file _slackrequest.py to this

import requests


class SlackRequest(object):

    @staticmethod
    def do(token, request="?", post_data=None, domain="slack.com"):
        if post_data is None:
            post_data = {}

        if "files" in post_data:
            temp = {element:post_data[element] for element in post_data if not "files" in element}
            return requests.post(
            'https://{0}/api/{1}'.format(domain, request),
            data=dict(temp, token=token), files=post_data["files"]
            )
        else:
            return requests.post(
                'https://{0}/api/{1}'.format(domain, request),
                data=dict(post_data, token=token),
            )
files = {'file': open('test.png', 'rb')}
client.api_call('files.upload', channels=[...], filename='pic.png', files=files)

Thanks, it worked. Do you wanna post it as a pull request? If not, can I post it?

I can but I don't know how

On Sat, Apr 2, 2016, 16:56 Rajat Khandelwal [email protected]
wrote:

Thanks, it worked. Do you wanna post it as a pull request? If not, can I
post it?

—
You are receiving this because you commented.
Reply to this email directly or view it on GitHub
https://github.com/slackhq/python-slackclient/issues/64#issuecomment-204720466

Just fork the repo, make changes and push those in your fork. Then click on New pull request on https://github.com/slackhq/python-slackclient. If stuck, internet is your friend. I found one tutorial: https://yangsu.github.io/pull-request-tutorial/

Has anyone tried doing this since this issue was closed? I'm getting some errors when trying to send a file. Looks like in the time between this was closed and python 2 & 3 has been included via six. The new out-of-the-box logic now tries to serialize the JSON file.

@rgreasons looks like this is fixed by https://github.com/slackhq/python-slackclient/commit/5766321e7bd7e0f27e033b7bc57aa92c829e87c9 but there hasn't been a PyPI release yet

A new version was pushed to pypi thanks to @jammons !

I still got the error with the 1.0.2 :-/
TypeError: <_io.BufferedReader name='test.txt'> is not JSON serializable

@SadE54 Yup. I confirmed still an issue with 1.0.2 as well

@SadE54 I can confirm this as well in the latest pypi release.

For those who're still experiencing this,

Instead of following,

files = {'file': open('test.png', 'rb')}
client.api_call('files.upload', channels=[...], filename='pic.png', files=files)

Try this:

client.api_call('files.upload', channels=[...], filename='pic.png', files=open('test.png', 'rb'))

  1. channels param requires a single string, not a list
  2. files param should be a file object, not a dict

For example, I successfully uploaded a plain text file through:

self.sc.api_call("files.upload", filename='result.txt', channels='#somechannel', file= io.BytesIO(str.encode(content)))

Heejune is just about right. In version 1.0.2 it expects 'file', NOT ''files'. So typing:
client.api_call('files.upload', channels=[...], filename='pic.png', files=open('test.png', 'rb'))
will currently give you a JSON serializable error. But:
client.api_call('files.upload', channels=[...], filename='pic.png', file=open('test.png', 'rb'))
works just fine.

Those of you still getting JSON serializable error, check if you aren't calling 'file.upload' instead of 'files.upload'.

Pretty stupid, I know, but it took me a good one hour to realize this error.

I cannot figure out how to upload a file. I am getting 200 and ok: True, but no success uploading the file to the channel.

self.slack_client.api_call('files.upload',
channel='notifications',
filename='heeeelooo.jpg',
file=open('heeeelooo.jpg', 'rb'))

Using kwarg file and not files.

Sending text messages works fine.

Anyone with similar issues?

EDIT: If I try to open any of the urls I get: The requested file could not be found.

FWIW I'm using slackclient 1.0.9 and I just successfully used the following code to upload a file via a bot user:

from slackclient import SlackClient
sc = SlackClient(SLACK_TOKEN)
sc.api_call(
  'files.upload', 
  channels='#slacktesting', 
  as_user=True, 
  filename='pic.jpg', 
  file=open('puppy.jpg', 'rb'),
)

@stianlp Is 'notifications' a channel? If so, you might need to use '#notifications' to get your code to work.

I tried with # and without, couldn't find out how to make it work, so I gave up.

Used requests instead, and it's working perfectly:

r = requests.post('https://slack.com/api/files.upload',
                          data={'token': self.bot_token, 'channels': [self.channel],
                                'title': 'Analysis Graph'},
                          files={'file': open(file_path, 'rb')})

Is anyone else have trouble, you can always just send a request like the code above.

Yeah, that method in the api wrapper is broken.

Jonathan Sundqvist
Twitter http://www.twitter.com/ecologythinking | Linkedin
http://se.linkedin.com/in/jonathansundqvist

2017-10-26 9:16 GMT+02:00 Stian Lind Petlund notifications@github.com:

I tried with # and without, couldn't find out how to make it work, so I
gave up.

Used requests instead, and it's working perfectly:

r = requests.post('https://slack.com/api/files.upload', data={'token':
self.bot_token, 'channels': [self.channel], 'title': 'Analysis Graph'},
files={'file': open(file_path, 'rb')})

Is anyone else have trouble, you can always just send a request like the
code above.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/slackapi/python-slackclient/issues/64#issuecomment-339574315,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACBsEr9KIhQ3mwFngg0q1brXEdoF_Ho0ks5swDHfgaJpZM4HbggM
.

also for me the only way it worked was by adding as_user=True to the api call as suggested by @alexandraj777. If you don't do this, then the call doesn't throw an error but the file is uploaded as private, so not visible in the channel to others

The solution given by @alexandraj777 works like a charm.
However, having as_user or not makes the image always uploaded by an user, and not the slackbot.

Huh, from @tsando's and @nicolaskern's responses I'm starting to think the as_user option might have a different outcome depending on the account/integration the SLACK_TOKEN is linked to. SLACK_TOKEN in my code snippet is for a bot user.

Perhaps others were not making the silly mistake I was, but I saw the same issue (uploaded files were always private) and fixed it. It turns out I had copied my code from a chat.message call. So, I was using "channel" instead of "channels" so I wasn't actually posting the file to a channel. Once I realized my error and used "channels" it worked perfectly and the file was public. I'll swallow my pride and admit my dumb mistake in the hopes that it might help someone else.

Some clarifications that helped me:

  1. I am using slackclient 1.2.1
  2. I am POSTing a file as a bot
  3. I am using an in-memory buffer with io.BytesIO that is generated from a PIL.Image drawn beforehand
# replace with your channel code or name
channel="C111111"

# Example of an image created beforehand using Python PIL.Image
content = io.BytesIO()
image.save(content, "PNG")

slack_client.api_call("files.upload",
  channels=channel,
  file=content.getvalue(),
  filename="mypicture.png",
  as_user=True)

Thank you @alexandraj777 it save my day

Thanks @alexandraj777.

To make that script work with bot just change as_user to as_bot

from slackclient import SlackClient
SLACK_TOKEN = "your bot token"
sc = SlackClient(SLACK_TOKEN)
sc.api_call(
  'files.upload', 
  channels='#slackchannel', 
  as_bot=True, 
  filename='mypicture.jpg', 
  file=open('mypicture.jpg', 'rb'),
)
Was this page helpful?
0 / 5 - 0 ratings