Skip to content

Conversation

Madhav-MKNC
Copy link

@Madhav-MKNC Madhav-MKNC commented Jul 1, 2025

Added get_user_mentions functionality (X API v2).

Example usage:

mentions = await client.get_user_mentions('5mknc5', search_count=30)
for mention in mentions:
        print(mention)

Output:

<Tweet id="...">
<Tweet id="...">
...
...

Summary by Sourcery

Introduce get_user_mentions method to fetch and filter tweets mentioning a specified user handle and return them as sorted Tweet objects.

New Features:

  • Add get_user_mentions method to retrieve tweets mentioning a given user via the search API and filter results by handle.
  • Sort retrieved mentions by tweet ID before returning them.

Summary by CodeRabbit

  • New Features
    • Added the ability to retrieve recent tweets mentioning a specific Twitter user handle. Users can specify how many mentions to fetch, with results sorted by tweet ID.

Copy link

sourcery-ai bot commented Jul 1, 2025

Reviewer's Guide

Introduces a new get_user_mentions method in the client to fetch tweets mentioning a given handle by leveraging the existing search_tweet function, filtering the results for the target handle, sorting them by ID, and returning a list of Tweet objects.

Sequence diagram for get_user_mentions method

sequenceDiagram
    actor User
    participant Client as Client
    participant TwitterAPI as Twitter API
    participant Tweet as Tweet Objects

    User->>Client: get_user_mentions(handle, search_count)
    Client->>Client: search_tweet(f"@{handle}", "Latest", count=search_count)
    Client->>TwitterAPI: Send search request
    TwitterAPI-->>Client: Return tweets
    loop For each tweet in result
        Client->>Tweet: Check if tweet mentions handle
        alt Tweet contains @handle
            Client->>Client: Add tweet to mentions
        end
    end
    Client->>Client: Sort mentions by tweet id
    Client-->>User: Return list of mentions
Loading

Class diagram for Client with new get_user_mentions method

classDiagram
    class Client {
        +async get_user_mentions(handle: str, search_count: int = 20) List[Tweet]
        +async search_tweet(...)
        ...
    }
    class Tweet {
        +id: int
        +full_text: str
        +text: str
        ...
    }
    Client --> Tweet : returns List[Tweet]
Loading

File-Level Changes

Change Details Files
Added get_user_mentions method to fetch and return user mentions
  • Define asynchronous get_user_mentions with handle and search_count parameters and detailed docstring
  • Invoke search_tweet with an @handle query and the specified count
  • Filter returned tweets to only those containing the handle in their text
  • Sort the filtered tweets by their numeric ID for chronological order
  • Return the sorted list of Tweet objects
twikit/client/client.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

coderabbitai bot commented Jul 1, 2025

Walkthrough

A new asynchronous method get_user_mentions was added to the Client class. It retrieves tweets mentioning a specified Twitter handle by searching with a formatted query, filters results for actual mentions, sorts them by tweet ID in ascending order, and returns a list of Tweet objects.

Changes

File Change Summary
twikit/client/client.py Added async method get_user_mentions to fetch, filter, sort, and return tweets mentioning a handle.

Poem

🐇
A mention here, a mention there,
Now Client finds them everywhere!
With tweets retrieved and sorted neat,
Each mention makes the task complete.
So hop along, search with delight—
Your mentions gathered, morning to night!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff3f08b and 68c6b45.

📒 Files selected for processing (1)
  • twikit/client/client.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • twikit/client/client.py
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Madhav-MKNC - I've reviewed your changes - here's some feedback:

  • The function signature claims to return List[Tweet] but you’re actually returning List[Tuple[str, Tweet]]—either update the type hint or unpack the tuples to return only the Tweet objects.
  • Sorting by int-casted tweet_id strings works but could be more straightforward and reliable by sorting on the tweet.id or tweet.created_at attribute directly.
  • The substring-based mention check (f"@{handle.lower()}" in text) may yield false positives in URLs or longer words—consider using a regex with word boundaries to match standalone mentions.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The function signature claims to return List[Tweet] but you’re actually returning List[Tuple[str, Tweet]]—either update the type hint or unpack the tuples to return only the Tweet objects.
- Sorting by int-casted tweet_id strings works but could be more straightforward and reliable by sorting on the tweet.id or tweet.created_at attribute directly.
- The substring-based mention check (f"@{handle.lower()}" in text) may yield false positives in URLs or longer words—consider using a regex with word boundaries to match standalone mentions.

## Individual Comments

### Comment 1
<location> `twikit/client/client.py:788` </location>
<code_context>
             previous_cursor
         )

+    async def get_user_mentions(
+        self,
+        handle: str,
</code_context>

<issue_to_address>
The method returns a list of (tweet_id, tweet) tuples, not Tweet objects as the docstring and type hint suggest.

Please update the docstring and type hint to match the actual return type, or modify the method to return a List[Tweet] as documented.
</issue_to_address>

### Comment 2
<location> `twikit/client/client.py:821` </location>
<code_context>
+        """
+        result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
+        mentions = []
+        for tweet in result:
+            tweet_id = str(tweet.id)
+            if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
+                mentions.append((tweet_id, tweet))
+        mentions.sort(key=lambda x: int(x[0]))
</code_context>

<issue_to_address>
The mention detection logic may produce false positives for substrings and does not account for word boundaries.

Using a substring search can incorrectly match partial usernames (e.g., '@elon' in '@elona'). Use a regular expression with word boundaries or stricter logic to ensure only exact mentions are detected.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
        result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
        mentions = []
        for tweet in result:
            tweet_id = str(tweet.id)
            if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
                mentions.append((tweet_id, tweet))
        mentions.sort(key=lambda x: int(x[0]))
=======
        import re

        result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
        mentions = []
        mention_pattern = re.compile(rf"@{re.escape(handle)}\b", re.IGNORECASE)
        for tweet in result:
            tweet_id = str(tweet.id)
            text = (tweet.full_text or tweet.text or "").strip()
            if mention_pattern.search(text):
                mentions.append((tweet_id, tweet))
        mentions.sort(key=lambda x: int(x[0]))
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

previous_cursor
)

async def get_user_mentions(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: The method returns a list of (tweet_id, tweet) tuples, not Tweet objects as the docstring and type hint suggest.

Please update the docstring and type hint to match the actual return type, or modify the method to return a List[Tweet] as documented.

Comment on lines 819 to 825
result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
mentions = []
for tweet in result:
tweet_id = str(tweet.id)
if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
mentions.append((tweet_id, tweet))
mentions.sort(key=lambda x: int(x[0]))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): The mention detection logic may produce false positives for substrings and does not account for word boundaries.

Using a substring search can incorrectly match partial usernames (e.g., '@elon' in '@elona'). Use a regular expression with word boundaries or stricter logic to ensure only exact mentions are detected.

Suggested change
result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
mentions = []
for tweet in result:
tweet_id = str(tweet.id)
if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
mentions.append((tweet_id, tweet))
mentions.sort(key=lambda x: int(x[0]))
import re
result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
mentions = []
mention_pattern = re.compile(rf"@{re.escape(handle)}\b", re.IGNORECASE)
for tweet in result:
tweet_id = str(tweet.id)
text = (tweet.full_text or tweet.text or "").strip()
if mention_pattern.search(text):
mentions.append((tweet_id, tweet))
mentions.sort(key=lambda x: int(x[0]))

Comment on lines 820 to 824
mentions = []
for tweet in result:
tweet_id = str(tweet.id)
if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
mentions.append((tweet_id, tweet))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): We've found these issues:

Suggested change
mentions = []
for tweet in result:
tweet_id = str(tweet.id)
if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
mentions.append((tweet_id, tweet))
mentions = [
(str(tweet.id), tweet)
for tweet in result
if f"@{handle.lower()}"
in (tweet.full_text or tweet.text or "").strip().lower()
]

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
twikit/client/client.py (1)

10-10: Add missing List import for type annotations.

The get_user_mentions method uses List[Tweet] in its return type annotation, but List is not imported from the typing module.

-from typing import Any, AsyncGenerator, Literal
+from typing import Any, AsyncGenerator, List, Literal
🧹 Nitpick comments (1)
twikit/client/client.py (1)

819-826: Consider improving search accuracy and efficiency.

The current implementation searches for "@handle" and then manually filters results, which may include false positives and could be inefficient.

Consider these improvements:

  1. The search might return tweets containing "@handle" in contexts other than actual mentions
  2. Manual filtering after fetching could be wasteful if most results don't match
  3. The return format (tuples) seems unnecessary - users likely just want the Tweet objects

Alternative implementation that returns List[Tweet] directly:

-        result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
-        mentions = []
-        for tweet in result:
-            tweet_id = str(tweet.id)
-            if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
-                mentions.append((tweet_id, tweet))
-        mentions.sort(key=lambda x: int(x[0]))
-        return mentions
+        result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
+        mentions = []
+        for tweet in result:
+            if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
+                mentions.append(tweet)
+        mentions.sort(key=lambda x: int(x.id))
+        return mentions
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12f744c and 5d423c4.

📒 Files selected for processing (1)
  • twikit/client/client.py (1 hunks)

Comment on lines +810 to +816
>>> mentions = await client.get_user_mentions('5mknc5', search_count=30)
>>> for mention in mentions:
... print(mention)
<Tweet id="...">
<Tweet id="...">
...
...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Update documentation examples to match actual return format.

The examples show the result as <Tweet id="..."> but the method actually returns tuples of (tweet_id, tweet).

-        >>> mentions = await client.get_user_mentions('5mknc5', search_count=30)
-        >>> for mention in mentions:
-        ...     print(mention)
-        <Tweet id="...">
-        <Tweet id="...">
+        >>> mentions = await client.get_user_mentions('5mknc5', search_count=30)
+        >>> for tweet_id, tweet in mentions:
+        ...     print(f"Tweet ID: {tweet_id}, Tweet: {tweet}")
+        Tweet ID: 123456789, Tweet: <Tweet id="123456789">
+        Tweet ID: 123456790, Tweet: <Tweet id="123456790">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
>>> mentions = await client.get_user_mentions('5mknc5', search_count=30)
>>> for mention in mentions:
... print(mention)
<Tweet id="...">
<Tweet id="...">
...
...
>>> mentions = await client.get_user_mentions('5mknc5', search_count=30)
>>> for tweet_id, tweet in mentions:
... print(f"Tweet ID: {tweet_id}, Tweet: {tweet}")
Tweet ID: 123456789, Tweet: <Tweet id="123456789">
Tweet ID: 123456790, Tweet: <Tweet id="123456790">
🤖 Prompt for AI Agents
In twikit/client/client.py around lines 810 to 816, the documentation example
incorrectly shows the method returning <Tweet id="..."> objects, but it actually
returns tuples of (tweet_id, tweet). Update the example to reflect this by
showing the iteration over mentions unpacking or accessing the tuple elements,
demonstrating the correct return format.

self,
handle: str,
search_count: int = 20
) -> List[Tweet]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix return type annotation to match actual implementation.

The method declares it returns List[Tweet] but actually returns List[Tuple[str, Tweet]] (tuples of tweet ID and tweet object).

-) -> List[Tweet]:
+) -> List[Tuple[str, Tweet]]:

You'll also need to import Tuple:

-from typing import Any, AsyncGenerator, List, Literal
+from typing import Any, AsyncGenerator, List, Literal, Tuple
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
) -> List[Tweet]:
# at the top of twikit/client/client.py
-from typing import Any, AsyncGenerator, List, Literal
+from typing import Any, AsyncGenerator, List, Literal, Tuple
# … later in the file, around line 792 …
- ) -> List[Tweet]:
+ ) -> List[Tuple[str, Tweet]]:
🤖 Prompt for AI Agents
In twikit/client/client.py at line 792, the return type annotation is
incorrectly specified as List[Tweet] while the method actually returns
List[Tuple[str, Tweet]]. Update the return type annotation to List[Tuple[str,
Tweet]] to accurately reflect the returned data structure. Additionally, add an
import statement for Tuple from the typing module at the top of the file if it
is not already imported.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
twikit/client/client.py (1)

10-10: Add missing import for List type annotation.

The method uses List[Tweet] as return type annotation but List is not imported from typing.

Add the import:

-from typing import Any, AsyncGenerator, Literal
+from typing import Any, AsyncGenerator, List, Literal
♻️ Duplicate comments (1)
twikit/client/client.py (1)

823-823: Improve mention detection to avoid false positives.

The current substring search can incorrectly match partial usernames (e.g., '@elon' would match '@ElonMusk'). Consider using word boundaries for more accurate detection.

Use regex with word boundaries for precise matching:

+import re
+
 async def get_user_mentions(
     self,
     handle: str,
     search_count: int = 20
 ) -> List[Tweet]:
     # ... existing docstring ...
     result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
+    mention_pattern = re.compile(rf"\b@{re.escape(handle)}\b", re.IGNORECASE)
     mentions = []
     for tweet in result:
-        if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
+        text = (tweet.full_text or tweet.text or "").strip()
+        if mention_pattern.search(text):
             mentions.append(tweet)
🧹 Nitpick comments (1)
twikit/client/client.py (1)

819-826: Consider using list comprehension for cleaner code.

The filtering and sorting logic can be made more concise and readable.

-    result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
-    mentions = []
-    for tweet in result:
-        if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower():
-            mentions.append(tweet)
-    mentions.sort(key=lambda x: int(x.id))
-    return mentions
+    result = await self.search_tweet(f"@{handle}", "Latest", count=search_count)
+    mentions = [
+        tweet for tweet in result
+        if f"@{handle.lower()}" in (tweet.full_text or tweet.text or "").strip().lower()
+    ]
+    return sorted(mentions, key=lambda x: int(x.id))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d423c4 and ff3f08b.

📒 Files selected for processing (1)
  • twikit/client/client.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
twikit/client/client.py (2)
twikit/tweet.py (4)
  • Tweet (19-560)
  • id (112-113)
  • full_text (225-229)
  • text (120-121)
twikit/community.py (1)
  • search_tweet (244-269)
🪛 Ruff (0.11.9)
twikit/client/client.py

822-822: Local variable tweet_id is assigned to but never used

Remove assignment to unused variable tweet_id

(F841)

🪛 Flake8 (7.2.0)
twikit/client/client.py

[error] 822-822: local variable 'tweet_id' is assigned to but never used

(F841)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant