From 5beaa24e4c39b9c6777c87dd7e0eeed9a9ee8355 Mon Sep 17 00:00:00 2001 From: Harmon Date: Tue, 27 Apr 2021 08:40:19 -0500 Subject: [PATCH] Add Client.like and Client.unlike --- cassettes/test_like_and_unlike.yaml | 127 ++++++++++++++++++++++++++++ docs/client.rst | 7 ++ tests/test_client.py | 6 ++ tweepy/client.py | 50 +++++++++++ 4 files changed, 190 insertions(+) create mode 100644 cassettes/test_like_and_unlike.yaml diff --git a/cassettes/test_like_and_unlike.yaml b/cassettes/test_like_and_unlike.yaml new file mode 100644 index 0000000..b23e7b8 --- /dev/null +++ b/cassettes/test_like_and_unlike.yaml @@ -0,0 +1,127 @@ +interactions: +- request: + body: '{"tweet_id": "1293593516040269825"}' + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '35' + Content-Type: + - application/json + User-Agent: + - Python/3.9.4 Requests/2.25.1 Tweepy/3.10.0 + method: POST + uri: https://api.twitter.com/2/users/1072250532645998596/likes + response: + body: + string: !!binary | + H4sIAAAAAAAAAKpWSkksSVSyqlbKycxOTVGyKikqTa2tBQAAAP//AwBNdUtrFwAAAA== + headers: + cache-control: + - no-cache, no-store, max-age=0 + content-disposition: + - attachment; filename=json.json + content-encoding: + - gzip + content-length: + - '49' + content-type: + - application/json; charset=utf-8 + date: + - Tue, 27 Apr 2021 13:36:57 GMT + server: + - tsa_b + set-cookie: + - personalization_id="v1_mJwlDgL3AaV2hMqz2in0QA=="; Max-Age=63072000; Expires=Thu, + 27 Apr 2023 13:36:57 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None + - guest_id=v1%3A161953061767846372; Max-Age=63072000; Expires=Thu, 27 Apr 2023 + 13:36:57 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None + strict-transport-security: + - max-age=631138519 + x-access-level: + - read-write-directmessages + x-connection-hash: + - f07ca4fdb8880cbdab6f39edfeec115f + x-content-type-options: + - nosniff + x-frame-options: + - SAMEORIGIN + x-rate-limit-limit: + - '50' + x-rate-limit-remaining: + - '48' + x-rate-limit-reset: + - '1619531089' + x-response-time: + - '104' + x-tsa-request-body-time: + - '4' + x-xss-protection: + - '0' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + Cookie: + - guest_id=v1%3A161953061767846372; personalization_id="v1_mJwlDgL3AaV2hMqz2in0QA==" + User-Agent: + - Python/3.9.4 Requests/2.25.1 Tweepy/3.10.0 + method: DELETE + uri: https://api.twitter.com/2/users/1072250532645998596/likes/1293593516040269825 + response: + body: + string: !!binary | + H4sIAAAAAAAAAKpWSkksSVSyqlbKycxOTVGySkvMKU6trQUAAAD//wMA/mYEixgAAAA= + headers: + cache-control: + - no-cache, no-store, max-age=0 + content-disposition: + - attachment; filename=json.json + content-encoding: + - gzip + content-length: + - '50' + content-type: + - application/json; charset=utf-8 + date: + - Tue, 27 Apr 2021 13:36:57 GMT + server: + - tsa_b + strict-transport-security: + - max-age=631138519 + x-access-level: + - read-write-directmessages + x-connection-hash: + - f07ca4fdb8880cbdab6f39edfeec115f + x-content-type-options: + - nosniff + x-frame-options: + - SAMEORIGIN + x-rate-limit-limit: + - '50' + x-rate-limit-remaining: + - '48' + x-rate-limit-reset: + - '1619531097' + x-response-time: + - '42' + x-xss-protection: + - '0' + status: + code: 200 + message: OK +version: 1 diff --git a/docs/client.rst b/docs/client.rst index 1dd2d5f..1d8df5d 100644 --- a/docs/client.rst +++ b/docs/client.rst @@ -18,6 +18,13 @@ Hide replies .. automethod:: Client.unhide_reply +Likes +----- + +.. automethod:: Client.unlike + +.. automethod:: Client.like + Search Tweets ------------- diff --git a/tests/test_client.py b/tests/test_client.py index 205a00b..e4c26e9 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -20,6 +20,12 @@ class TweepyTestCase(unittest.TestCase): self.assertTrue(self.client.hide_reply(reply_id)) self.assertFalse(self.client.unhide_reply(reply_id)) + @tape.use_cassette("test_like_and_unlike.yaml", serializer="yaml") + def test_like_and_unlike(self): + tweet_id = 1293593516040269825 # @TwitterDev Tweet announcing API v2 + self.assertTrue(self.client.like(tweet_id)) + self.assertFalse(self.client.unlike(tweet_id)) + # TODO: test_search_all_tweets with access to Academic Research product track @tape.use_cassette("test_search_recent_tweets.yaml", serializer="yaml") diff --git a/tweepy/client.py b/tweepy/client.py index f453761..a1c62a1 100644 --- a/tweepy/client.py +++ b/tweepy/client.py @@ -216,6 +216,56 @@ class Client: user_auth=True )[0]["hidden"] + # Likes + + def unlike(self, tweet_id): + """Unlike a Tweet. + + The request succeeds with no action when the user sends a request to a + user they're not liking the Tweet or have already unliked the Tweet. + + Parameters + ---------- + tweet_id : Union[int, str] + The ID of the Tweet that you would like to unlike. + + Returns + ------- + bool + Indicates if the Tweet was successfully unliked. + + References + ---------- + https://developer.twitter.com/en/docs/twitter-api/tweets/likes/api-reference/delete-users-user_id-likes + """ + id = self.access_token.partition('-')[0] + route = f"/2/users/{id}/likes/{tweet_id}" + + return self._make_request("DELETE", route, user_auth=True)[0]["liked"] + + def like(self, tweet_id): + """Like a Tweet. + + Parameters + ---------- + tweet_id : Union[int, str] + The ID of the Tweet that you would like to Like. + + Returns + ------- + bool + Indicates if the Tweet was successfully Liked. + + References + ---------- + https://developer.twitter.com/en/docs/twitter-api/tweets/likes/api-reference/post-users-user_id-likes + """ + id = self.access_token.partition('-')[0] + return self._make_request( + "POST", f"/2/users/{id}/likes", json={"tweet_id": str(tweet_id)}, + user_auth=True + )[0]["liked"] + # Search Tweets def search_all_tweets(self, query, **params): -- 2.25.1