feat: “About this account” support to fetch account-based-in location from X#398
feat: “About this account” support to fetch account-based-in location from X#398
Conversation
…About data, allows to new get location based from X.
Reviewer's GuideImplements support for Twitter/X’s “About this account” GraphQL endpoint by introducing an AccountAbout model, wiring new client and guest-client methods to call the new GQL query, exposing convenient User/GuestUser helpers, and documenting usage with an example script and README snippet. Sequence diagram for get_user_about flow via guest clientsequenceDiagram
actor Developer
participant Script as ExampleScript
participant GuestClient
participant GqlClient
participant TwitterAPI as Twitter_GraphQL_Endpoint
participant AccountAbout
Developer->>Script: run about_account.py
Script->>GuestClient: get_user_about("sama")
GuestClient->>GqlClient: about_account("sama")
GqlClient->>TwitterAPI: gql_get(ABOUT_ACCOUNT, variables, ABOUT_ACCOUNT_FEATURES)
TwitterAPI-->>GqlClient: GraphQL response data
GqlClient-->>GuestClient: (response, guest_token)
GuestClient->>GuestClient: extract user_result_by_screen_name
GuestClient->>GuestClient: validate result or raise error
GuestClient->>AccountAbout: __init__(user_data)
AccountAbout-->>GuestClient: AccountAbout instance
GuestClient-->>Script: AccountAbout instance
Script->>Script: access account_based_in, username_changes, is_identity_verified
Script-->>Developer: display about-account info
Class diagram for AccountAbout and new about-account API surfaceclassDiagram
class AccountAbout {
+str id
+str rest_id
+str screen_name
+str name
+str account_based_in
+bool location_accurate
+str affiliate_username
+str source
+int username_changes
+int username_last_changed_at
+bool is_identity_verified
+int verified_since_msec
+__init__(data) AccountAbout
+_to_int(value) int
+__repr__() str
}
class Client {
+get_user_by_screen_name(screen_name) User
+get_user_about(screen_name) AccountAbout
}
class GuestClient {
+get_user_by_screen_name(screen_name) User
+get_user_about(screen_name) AccountAbout
}
class GqlClient {
+user_by_screen_name(screen_name)
+user_by_rest_id(user_id)
+about_account(screen_name)
}
class User {
-Client _client
+str id
+str screen_name
+get_tweets(tweet_type, count) list
+get_about() AccountAbout
}
class GuestUser {
-GuestClient _client
+str id
+str screen_name
+get_tweets(tweet_type, count) list
+get_about() AccountAbout
}
class Endpoint {
<<enumeration>>
+USER_BY_SCREEN_NAME
+USER_BY_REST_ID
+ABOUT_ACCOUNT
}
class Constants {
<<static>>
+ABOUT_ACCOUNT_FEATURES
}
Client --> GqlClient : uses
GuestClient --> GqlClient : uses
Client ..> AccountAbout : creates
GuestClient ..> AccountAbout : creates
User --> Client : holds
GuestUser --> GuestClient : holds
User ..> AccountAbout : returns from get_about
GuestUser ..> AccountAbout : returns from get_about
GqlClient ..> Endpoint : uses
GqlClient ..> Constants : uses ABOUT_ACCOUNT_FEATURES
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
WalkthroughA new feature for fetching account information is implemented. New Changes
Sequence DiagramsequenceDiagram
participant User as User Code
participant Client as Guest Client
participant GQL as GQL Client
participant API as Twitter API
User->>Client: get_user_about(screen_name)
Client->>GQL: about_account(screen_name)
GQL->>API: GET about_account_endpoint
API-->>GQL: JSON response
GQL-->>Client: response data
alt User not found
Client-->>User: raise UserNotFound
else Account unavailable
Client-->>User: raise UserUnavailable
else Success
Client->>Client: Parse AccountAbout
Client-->>User: return AccountAbout
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. 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. Comment |
There was a problem hiding this comment.
Hey there - I've reviewed your changes - here's some feedback:
- The
get_user_aboutimplementations inclient.Clientandguest.Clientduplicate the same GraphQL call and error handling; consider extracting a shared helper to keep this logic in one place and reduce the chance of divergence. - In
AccountAbout, fields likeusername_last_changed_atandverified_since_msecare exposed only as raw millisecond timestamps; consider adding convenience properties that returndatetimeobjects for consistency withUser.created_at_datetime. User.get_about/GuestUser.get_aboutdepend onself.screen_name; you might want to handle the case wherescreen_nameisNoneor stale (e.g., by raising a clearer error or falling back to a rest_id-based lookup if that becomes available).
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `get_user_about` implementations in `client.Client` and `guest.Client` duplicate the same GraphQL call and error handling; consider extracting a shared helper to keep this logic in one place and reduce the chance of divergence.
- In `AccountAbout`, fields like `username_last_changed_at` and `verified_since_msec` are exposed only as raw millisecond timestamps; consider adding convenience properties that return `datetime` objects for consistency with `User.created_at_datetime`.
- `User.get_about` / `GuestUser.get_about` depend on `self.screen_name`; you might want to handle the case where `screen_name` is `None` or stale (e.g., by raising a clearer error or falling back to a rest_id-based lookup if that becomes available).Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (36)
.DS_Storeis excluded by!**/.DS_Storetwikit/.DS_Storeis excluded by!**/.DS_Storetwikit/__pycache__/__init__.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/bookmark.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/community.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/constants.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/errors.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/geo.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/group.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/list.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/media.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/message.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/notification.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/streaming.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/trend.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/tweet.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/user.cpython-310.pycis excluded by!**/*.pyctwikit/__pycache__/utils.cpython-310.pycis excluded by!**/*.pyctwikit/_captcha/__pycache__/__init__.cpython-310.pycis excluded by!**/*.pyctwikit/_captcha/__pycache__/base.cpython-310.pycis excluded by!**/*.pyctwikit/_captcha/__pycache__/capsolver.cpython-310.pycis excluded by!**/*.pyctwikit/client/__pycache__/client.cpython-310.pycis excluded by!**/*.pyctwikit/client/__pycache__/gql.cpython-310.pycis excluded by!**/*.pyctwikit/client/__pycache__/v11.cpython-310.pycis excluded by!**/*.pyctwikit/guest/__pycache__/__init__.cpython-310.pycis excluded by!**/*.pyctwikit/guest/__pycache__/client.cpython-310.pycis excluded by!**/*.pyctwikit/guest/__pycache__/tweet.cpython-310.pycis excluded by!**/*.pyctwikit/guest/__pycache__/user.cpython-310.pycis excluded by!**/*.pyctwikit/ui_metrics/__pycache__/__init__.cpython-310.pycis excluded by!**/*.pyctwikit/ui_metrics/__pycache__/dom.cpython-310.pycis excluded by!**/*.pyctwikit/x_client_transaction/__pycache__/__init__.cpython-310.pycis excluded by!**/*.pyctwikit/x_client_transaction/__pycache__/cubic_curve.cpython-310.pycis excluded by!**/*.pyctwikit/x_client_transaction/__pycache__/interpolate.cpython-310.pycis excluded by!**/*.pyctwikit/x_client_transaction/__pycache__/rotation.cpython-310.pycis excluded by!**/*.pyctwikit/x_client_transaction/__pycache__/transaction.cpython-310.pycis excluded by!**/*.pyctwikit/x_client_transaction/__pycache__/utils.cpython-310.pycis excluded by!**/*.pyc
📒 Files selected for processing (9)
README.md(1 hunks)examples/about_account.py(1 hunks)twikit/__init__.py(1 hunks)twikit/client/client.py(2 hunks)twikit/client/gql.py(3 hunks)twikit/constants.py(1 hunks)twikit/guest/client.py(2 hunks)twikit/guest/user.py(2 hunks)twikit/user.py(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
twikit/user.py (3)
twikit/client/client.py (2)
get(209-211)get_user_about(1404-1425)twikit/guest/client.py (2)
get(156-158)get_user_about(234-255)twikit/guest/user.py (1)
get_about(123-132)
twikit/guest/client.py (3)
twikit/errors.py (4)
UserNotFound(77-80)UserUnavailable(82-85)TwitterException(4-13)Unauthorized(20-23)twikit/client/client.py (3)
user(674-678)get_user_about(1404-1425)get(209-211)twikit/user.py (1)
AccountAbout(17-80)
twikit/guest/user.py (3)
twikit/client/client.py (2)
user(674-678)get_user_about(1404-1425)twikit/user.py (2)
AccountAbout(17-80)get_about(238-247)twikit/guest/client.py (1)
get_user_about(234-255)
twikit/client/gql.py (1)
twikit/client/v11.py (1)
Endpoint(14-50)
twikit/__init__.py (1)
twikit/user.py (2)
AccountAbout(17-80)User(83-598)
examples/about_account.py (2)
twikit/client/client.py (2)
user(674-678)get_user_about(1404-1425)twikit/guest/client.py (1)
get_user_about(234-255)
🪛 markdownlint-cli2 (0.18.1)
README.md
132-132: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
🪛 Ruff (0.14.5)
twikit/guest/client.py
251-251: Avoid specifying long messages outside the exception class
(TRY003)
examples/about_account.py
7-7: Possible hardcoded password assigned to: "PASSWORD"
(S105)
14-14: Local variable client_user is assigned to but never used
Remove assignment to unused variable client_user
(F841)
twikit/client/client.py
1421-1421: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (10)
twikit/constants.py (1)
44-46: LGTM!The new
ABOUT_ACCOUNT_FEATURESconstant follows the established pattern and is correctly defined for the about account GraphQL endpoint.README.md (1)
132-136: LGTM!The documentation example clearly demonstrates the new "About this account" feature usage and follows the existing README style.
twikit/__init__.py (1)
31-31: LGTM!The public API correctly exports
AccountAboutalongsideUser, making the new data class accessible to library users.twikit/user.py (2)
17-80: LGTM!The
AccountAboutclass is well-designed with:
- Comprehensive docstring documenting all attributes
- Safe data extraction using
.get()with fallback to empty dicts- Robust
_to_inthelper that handles None and conversion errors gracefully- Proper
__repr__for debugging
238-247: LGTM!The
get_aboutmethod is correctly implemented as a convenience method that delegates to the client, following the same pattern as other User methods likeget_tweets.twikit/guest/user.py (1)
6-6: LGTM!The import and
get_aboutmethod are correctly implemented, maintaining consistency with the authenticated User class pattern.Also applies to: 123-132
twikit/client/gql.py (1)
6-6: LGTM!The GraphQL endpoint and method are correctly implemented:
- Endpoint URL follows the established pattern
- Method signature and implementation are consistent with similar methods like
user_by_screen_name- Proper use of imported
ABOUT_ACCOUNT_FEATURESAlso applies to: 43-43, 264-268
twikit/guest/client.py (2)
22-23: LGTM!The necessary error types and
AccountAboutclass are correctly imported to support the new functionality.Also applies to: 27-27
234-255: LGTM!The
get_user_aboutmethod is correctly implemented with:
- Proper error handling for missing users and unavailable accounts
- Safe nested dictionary access using
.get()with fallback values- Consistent error messages that match the authenticated client implementation
- Correct construction and return of
AccountAboutinstanceThe implementation is identical to the authenticated
Client.get_user_aboutmethod, ensuring consistency across both client types.twikit/client/client.py (1)
49-49: I'm unable to access the repository to verify the AccountAbout class due to persistent clone failures. However, I can provide guidance based on the code context provided.Verify AccountAbout class is properly defined and exported from the user module.
The import statement at line 49 follows the existing pattern and is syntactically correct. However, ensure that:
- The
AccountAboutclass is defined intwikit/user.pyand properly exported- The class includes all necessary fields for the "About this account" feature
- The
get_user_about()method at lines 1404-1426 correctly usesAccountAboutas the return typeThese verifications should be confirmed through code review or integration testing.
|
|
||
| async def main(): | ||
| client.load_cookies('cookies.json') | ||
| client_user = await client.user() |
There was a problem hiding this comment.
Remove unused variable.
The client_user variable is fetched but never used. Consider either removing this line or using client_user.screen_name instead of the hardcoded 'sama' on line 16 to make the example more dynamic.
Apply this diff to remove the unused line:
- client_user = await client.user()
-
about = await client.get_user_about('sama')Or alternatively, use the fetched user:
client_user = await client.user()
-
- about = await client.get_user_about('sama')
+ about = await client.get_user_about(client_user.screen_name)Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 Ruff (0.14.5)
14-14: Local variable client_user is assigned to but never used
Remove assignment to unused variable client_user
(F841)
🤖 Prompt for AI Agents
In examples/about_account.py around line 14, the variable client_user is
assigned but never used; either remove the unused line "client_user = await
client.user()" to eliminate dead code, or keep it and replace the hardcoded
'sama' on line 16 with client_user.screen_name so the example uses the fetched
user dynamically; ensure the await remains if you keep the call and update any
related code to reference client_user.screen_name.
| async def get_user_about(self, screen_name: str) -> AccountAbout: | ||
| """ | ||
| Fetches "About this account" information by screen name. | ||
|
|
||
| Parameter | ||
| --------- | ||
| screen_name : :class:`str` | ||
| The screen name of the Twitter user. | ||
|
|
||
| Returns | ||
| ------- | ||
| :class:`AccountAbout` | ||
| A data object containing profile provenance details. | ||
| """ | ||
| response, _ = await self.gql.about_account(screen_name) | ||
| user_result = response.get('data', {}).get('user_result_by_screen_name') | ||
| if not user_result or 'result' not in user_result: | ||
| raise UserNotFound('The user does not exist.') | ||
| user_data = user_result['result'] | ||
| if user_data.get('__typename') == 'UserUnavailable': | ||
| raise UserUnavailable(user_data.get('message')) | ||
| return AccountAbout(user_data) | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
Script executed:
#!/bin/bash
# First, find the client.py file and verify basic structure
fd -t f "client.py" | head -5Repository: d60/twikit
<shell_result>
Repository: d60/twikit
Script execution failed with unrecoverable error: [CAPABILITY:RUN_SHELL_SCRIPT] Failed to clone repository d60/twikit: Clone operation failed
</shell_result>
twikit AccountAbout class documentation
<web_search_result>
Do you mean the Twikit "AccountAbout" class in their API/SDK (backend) or a component in the Twikit Design System (frontend)? I can search and fetch the official documentation — which would you like?
</web_search_result>
twikit Python SDK AccountAbout class gql about_account
<web_search_result>
I can help — do you want (pick one):
- the twikit Python SDK docs or source for the AccountAbout class and the GraphQL query/mutation named about_account,
- a short code example showing how to call a GraphQL about_account query using the twikit SDK (or using gql/httpx), or
- help debugging an error you get when using AccountAbout/about_account?
Tell me which and I’ll fetch the exact docs/code.
</web_search_result>
twikit Python SDK AccountAbout class source code and gql about_account GraphQL query method documentation
<web_search_result>
I couldn't find an AccountAbout class or an about_account GraphQL method in the publicly available twikit docs/source I searched (twikit.readthedocs.io and related repos). Can you (please) tell me:
- which repository or PyPI package name/version you mean (link if possible), or
- paste the file or a small code excerpt you have?
With that I can fetch the exact source and the gql about_account documentation.
</web_search_result>
Based on the context provided, I can see that AccountAbout and gql.about_account are likely new additions in this PR being reviewed, which is why they're not in the public documentation yet. The code snippet itself demonstrates they exist and are being used.
Let me now assess the review comment on its merits:
Evaluating the Original Review Comment:
Given:
- The code snippet shows the method IS implemented (lines 1404-1426)
- The implementation uses
AccountAbout(user_data)- indicating the class accepts user_data - The method calls
self.gql.about_account(screen_name)- indicating the gql method exists - Proper error handling is in place
- The docstring has a typo: "Parameter" instead of "Parameters"
Conclusion:
The review comment makes valid suggestions for documentation improvements. However, the verification requests (checking if gql.about_account and AccountAbout exist) cannot be completed without direct repository access. Since the code is already shown to be implemented and integrated, these concerns are likely addressed.
The only verifiable issue is the docstring inconsistency ("Parameter" vs "Parameters"), which is a minor documentation fix.
Correct the docstring typo and consider adding examples for consistency.
The implementation is sound with proper error handling. One clear issue:
- Line 1408: Change "Parameter" to "Parameters" to match standard NumPy docstring format
Consider also adding an Examples section if similar methods in the file use this pattern.
The review's verification requests about gql.about_account and AccountAbout cannot be confirmed without repository access, but the code shown indicates these are properly integrated.
🧰 Tools
🪛 Ruff (0.14.5)
1421-1421: Avoid specifying long messages outside the exception class
(TRY003)
🤖 Prompt for AI Agents
In twikit/client/client.py around lines 1404 to 1426, the docstring header uses
"Parameter" instead of the standard "Parameters"; change "Parameter" to
"Parameters" and, for consistency with other methods in this file, consider
adding an "Examples" section or aligning the docstring format to match the
project's NumPy-style docstrings.
Adds support for Twitter's "about this account" feature. Returns account region, location accuracy, username change history, and verification status. Document new usage and provide an example script showing retrieval of the “account based in” location from X.
Summary by Sourcery
Add support for retrieving and representing Twitter/X "About this account" metadata for users, including exposure via both authenticated and guest clients and basic documentation and example usage.
New Features:
Enhancements:
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.