Add Client.like and Client.unlike
authorHarmon <Harmon758@gmail.com>
Tue, 27 Apr 2021 13:40:19 +0000 (08:40 -0500)
committerHarmon <Harmon758@gmail.com>
Tue, 27 Apr 2021 13:40:19 +0000 (08:40 -0500)
cassettes/test_like_and_unlike.yaml [new file with mode: 0644]
docs/client.rst
tests/test_client.py
tweepy/client.py

diff --git a/cassettes/test_like_and_unlike.yaml b/cassettes/test_like_and_unlike.yaml
new file mode 100644 (file)
index 0000000..b23e7b8
--- /dev/null
@@ -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
index 1dd2d5f556e88d6290ec0322a3c619239044edf5..1d8df5d98c6b43dac60cc24b7bab820cacb50c21 100644 (file)
@@ -18,6 +18,13 @@ Hide replies
 
 .. automethod:: Client.unhide_reply
 
+Likes
+-----
+
+.. automethod:: Client.unlike
+
+.. automethod:: Client.like
+
 Search Tweets
 -------------
 
index 205a00b66aaf3f87a5144629ed36f0d7c9946f9a..e4c26e90583efd9dbb7daa0df9796ea3fb52c9a2 100644 (file)
@@ -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")
index f4537613c4383be346824a879b48d6b2b69c8588..a1c62a1157bc21fae51e6312bdad3cd016e0f345 100644 (file)
@@ -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):