How can I use the edit_post function in PyTumblr?

865 views Asked by At

I am trying to edit some posts in my tumblr blog using PyTumblr and the edit_post function, but I can't figure out exactly what parameters are needed. I try to put the tags parameter but it's not accepted.

I have tried this:

client = pytumblr.TumblrRestClient(CONSUMER_KEY, CONSUMER_SECRET,
                                   OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
client.edit_post('nameofblog', {'id': 39228373})

And it gives me the following error:

TypeError: edit_post() takes exactly 2 arguments (3 given)

Any ideas?

This is the function:

    def edit_post(self, blogname, **kwargs):
            """
    Edits a post with a given id

    :param blogname: a string, the url of the blog you want to edit
    :param tags: a list of tags that you want applied to the post
    :param tweet: a string, the customized tweet that you want
    :param date: a string, the GMT date and time of the post
    :param format: a string, sets the format type of the post. html or markdown
    :param slug: a string, a short text summary to the end of the post url

    :returns: a dict created from the JSON response
    """
      url = "/v2/blog/%s/post/edit" % blogname
      return self.send_api_request('post', url, kwargs)
3

There are 3 answers

2
mikedidthis On

Passing an ID is not well documented, so I asked:

client.edit_post("nameofblog", id=39228373, other="details", tags=["are", "cool"])

Ref: http://github.com/tumblr/pytumblr/issues/29

4
Martijn Pieters On

The PyTumblr library offers a thin layer over the Tumblr REST API, and all arguments apart from the blog name should be passed in as keyword arguments.

The TumblrRestClient.edit_post() method, then, acts as a proxy for the /post/edit endpoint, and it takes all the same parameters.

As such, you'd call it like:

client = pytumblr.TumblrRestClient(CONSUMER_KEY, CONSUMER_SECRET,
                               OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
client.edit_post('nameofblog', id=39228373)

That is not to say that if you have a dictionary object with post details, you cannot make use of that.

If you wanted to set the title of a given post id, you could use:

post = {'id': 39228373, 'title': 'New title!'}
client.edit_post('nameofblog', **post)

Here the post dictionary is being applied to the .edit_post() method call as separate keyword arguments using the ** syntax. Python then takes each key-value pair in the input dictionary and applies that pair as a keyword argument.

You should be able to set any of the parameters applicable to your post type, listed under the posting documentation.

The problem then, is that the .edit_post() method leaves the valid_params argument to self. send_api_request() to the default empty list, leading to a guaranteed validation exception for anything you pass in. This must be a bug, and I commented on Mike's issue to point this out to the developer.

1
IordanouGiannis On

The mentioned function edit_post, relies on the following function:

def send_api_request(self, method, url, params={}, valid_parameters=[], needs_api_key=False):
        """
Sends the url with parameters to the requested url, validating them
to make sure that they are what we expect to have passed to us

:param method: a string, the request method you want to make
:param params: a dict, the parameters used for the API request
:param valid_parameters: a list, the list of valid parameters
:param needs_api_key: a boolean, whether or not your request needs an api key injected

:returns: a dict parsed from the JSON response
"""
        if needs_api_key:
            params.update({'api_key': self.request.consumer.key})
            valid_parameters.append('api_key')

        files = []
        if 'data' in params:
            if isinstance(params['data'], list):
                files = [('data['+str(idx)+']', data, open(data, 'rb').read()) for idx, data in enumerate(params['data'])]
            else:
                files = [('data', params['data'], open(params['data'], 'rb').read())]
            del params['data']

        validate_params(valid_parameters, params)
        if method == "get":
            return self.request.get(url, params)
        else:
            return self.request.post(url, params, files)

So, the problem is that the edit_post function in the following line :

return self.send_api_request('post', url, kwargs)

does not provide the choice for valid options, as does this function in the last line:

def reblog(self, blogname, **kwargs):
        """
Creates a reblog on the given blogname

:param blogname: a string, the url of the blog you want to reblog to
:param id: an int, the post id that you are reblogging
:param reblog_key: a string, the reblog key of the post

:returns: a dict created from the JSON response
"""
        url = "/v2/blog/%s/post/reblog" % blogname

        valid_options = ['id', 'reblog_key', 'comment', 'type', 'state', 'tags', 'tweet', 'date', 'format', 'slug']
        if 'tags' in kwargs:
            # Take a list of tags and make them acceptable for upload
            kwargs['tags'] = ",".join(kwargs['tags'])
        return self.send_api_request('post', url, kwargs, valid_options)

To fix it, I modified the return line to :

send_api_request('post', url, {'id':post_id, 'tags':tags}, ['id', 'tags']

I added just the tags I wanted. It should work with others too.