Upload a file #64

Closed
jonathan-s opened this Issue Feb 16, 2016 · 28 comments

Comments

Projects
None yet
@jonathan-s

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.

@prongs

This comment has been minimized.

Show comment
Hide comment
@prongs

prongs Mar 10, 2016

Have you found a workaround for that?

prongs commented Mar 10, 2016

Have you found a workaround for that?

@prongs

This comment has been minimized.

Show comment
Hide comment
@prongs

prongs Mar 10, 2016

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

prongs commented Mar 10, 2016

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

@MidTin

This comment has been minimized.

Show comment
Hide comment
@MidTin

MidTin Mar 30, 2016

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

MidTin commented Mar 30, 2016

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

@prongs

This comment has been minimized.

Show comment
Hide comment
@prongs

prongs Mar 30, 2016

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

prongs commented Mar 30, 2016

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

@MidTin

This comment has been minimized.

Show comment
Hide comment
@MidTin

MidTin Mar 30, 2016

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})

MidTin commented Mar 30, 2016

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})
@MidTin

This comment has been minimized.

Show comment
Hide comment
@MidTin

MidTin Mar 30, 2016

@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.

MidTin commented Mar 30, 2016

@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.

@prongs

This comment has been minimized.

Show comment
Hide comment
@prongs

prongs Mar 30, 2016

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

prongs commented Mar 30, 2016

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

@lcd1232

This comment has been minimized.

Show comment
Hide comment
@lcd1232

lcd1232 Apr 2, 2016

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)

lcd1232 commented Apr 2, 2016

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)
@prongs

This comment has been minimized.

Show comment
Hide comment
@prongs

prongs Apr 2, 2016

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

prongs commented Apr 2, 2016

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

@lcd1232

This comment has been minimized.

Show comment
Hide comment
@lcd1232

lcd1232 Apr 2, 2016

I can but I don't know how

On Sat, Apr 2, 2016, 16:56 Rajat Khandelwal notifications@github.com
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
#64 (comment)

lcd1232 commented Apr 2, 2016

I can but I don't know how

On Sat, Apr 2, 2016, 16:56 Rajat Khandelwal notifications@github.com
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
#64 (comment)

@prongs

This comment has been minimized.

Show comment
Hide comment
@prongs

prongs Apr 2, 2016

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/

prongs commented Apr 2, 2016

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/

@Yasumoto Yasumoto closed this in 13f4373 Jul 1, 2016

@rgreasons

This comment has been minimized.

Show comment
Hide comment
@rgreasons

rgreasons Jul 31, 2016

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.

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.

@liuhenry

This comment has been minimized.

Show comment
Hide comment
@liuhenry

liuhenry Sep 21, 2016

@rgreasons looks like this is fixed by 5766321 but there hasn't been a PyPI release yet

@rgreasons looks like this is fixed by 5766321 but there hasn't been a PyPI release yet

@Yasumoto

This comment has been minimized.

Show comment
Hide comment
@Yasumoto

Yasumoto Sep 22, 2016

Contributor

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

Contributor

Yasumoto commented Sep 22, 2016

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

@SadE54

This comment has been minimized.

Show comment
Hide comment
@SadE54

SadE54 Oct 27, 2016

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

SadE54 commented Oct 27, 2016

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

@dj80hd

This comment has been minimized.

Show comment
Hide comment
@dj80hd

dj80hd Nov 9, 2016

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

dj80hd commented Nov 9, 2016

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

@Wouter0100

This comment has been minimized.

Show comment
Hide comment
@Wouter0100

Wouter0100 Nov 14, 2016

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

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

@Roach Roach added the bug label Nov 22, 2016

@heejune

This comment has been minimized.

Show comment
Hide comment
@heejune

heejune Dec 19, 2016

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 commented Dec 19, 2016

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)))

@Jacob-Dixon

This comment has been minimized.

Show comment
Hide comment
@Jacob-Dixon

Jacob-Dixon Mar 1, 2017

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.

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.

@qria

This comment has been minimized.

Show comment
Hide comment
@qria

qria Apr 7, 2017

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.

qria commented Apr 7, 2017

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.

@stianlp

This comment has been minimized.

Show comment
Hide comment
@stianlp

stianlp Oct 22, 2017

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.

stianlp commented Oct 22, 2017

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.

@alexandraj777

This comment has been minimized.

Show comment
Hide comment
@alexandraj777

alexandraj777 Oct 25, 2017

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.

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.

@stianlp

This comment has been minimized.

Show comment
Hide comment
@stianlp

stianlp Oct 26, 2017

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.

stianlp commented Oct 26, 2017

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.

@jonathan-s

This comment has been minimized.

Show comment
Hide comment
@jonathan-s

jonathan-s Oct 26, 2017

@tsando

This comment has been minimized.

Show comment
Hide comment
@tsando

tsando Dec 4, 2017

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

tsando commented Dec 4, 2017

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

@nicolaskern

This comment has been minimized.

Show comment
Hide comment
@nicolaskern

nicolaskern Jan 15, 2018

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.

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.

@alexandraj777

This comment has been minimized.

Show comment
Hide comment
@alexandraj777

alexandraj777 Jan 16, 2018

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.

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.

@qajay

This comment has been minimized.

Show comment
Hide comment
@qajay

qajay Jul 5, 2018

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.

qajay commented Jul 5, 2018

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment