Skip to content

Commit 8f19b90

Browse files
authored
Merge pull request #165 from MerleLiuKun/feat-search-users
Feat search users
2 parents 326ae7c + e9bc313 commit 8f19b90

File tree

6 files changed

+83
-1
lines changed

6 files changed

+83
-1
lines changed

docs/docs/usage/users/search.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
The Users Search endpoint provides a simple, relevance-based search interface to public user accounts on X. Try querying by topical interest, full name, company name, location, or other criteria.
2+
3+
You can get more information for this at [docs](https://developer.twitter.com/en/docs/twitter-api/users/search/introduction)
4+
5+
## Search Users
6+
7+
Get users that match a search query.
8+
9+
```python
10+
my_api.search_users(query="developers")
11+
# Response(data=[User(id='866707894389141505', name='Refinitiv Developers', username='Developers'), User(id='2244994945', name='Developers', username='XDevelopers')])
12+
```

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ nav:
5353
- Follows: usage/users/follows.md
5454
- Blocks: usage/users/blocks.md
5555
- Mutes: usage/users/mutes.md
56+
- Search: usage/users/search.md
5657
- Spaces:
5758
- Spaces Lookup: usage/spaces/spaces-lookup.md
5859
- Search Spaces: usage/spaces/search.md

pytwitter/api.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,47 @@ def get_me(
17861786
return_json=return_json,
17871787
)
17881788

1789+
def search_users(
1790+
self,
1791+
query: str,
1792+
*,
1793+
max_results: Optional[int] = None,
1794+
next_token: Optional[str] = None,
1795+
user_fields: Optional[Union[str, List, Tuple]] = None,
1796+
expansions: Optional[Union[str, List, Tuple]] = None,
1797+
tweet_fields: Optional[Union[str, List, Tuple]] = None,
1798+
return_json: bool = False,
1799+
) -> Union[dict, md.Response]:
1800+
"""
1801+
returns Users that match a search query.
1802+
:param query: One query for matching Users.
1803+
:param max_results: The maximum number of search results to be returned by a request. A number between 1 and 1000. By default, a request response will return 100 results.
1804+
:param next_token: Token for the pagination.
1805+
:param user_fields: Fields for the user object.
1806+
:param expansions: Fields for the expansions.
1807+
:param tweet_fields: Fields for the tweet object, Expansion required.
1808+
:param return_json: Type for returned data. If you set True JSON data will be returned.
1809+
:return: Response instance or json.
1810+
"""
1811+
1812+
args = {
1813+
"query": query,
1814+
"max_results": max_results,
1815+
"next_token": next_token,
1816+
"user.fields": enf_comma_separated(name="user_fields", value=user_fields),
1817+
"expansions": enf_comma_separated(name="expansions", value=expansions),
1818+
"tweet.fields": enf_comma_separated(
1819+
name="tweet_fields", value=tweet_fields
1820+
),
1821+
}
1822+
return self._get(
1823+
url="https://api.twitter.com/2/users/search",
1824+
params=args,
1825+
cls=md.User,
1826+
multi=True,
1827+
return_json=return_json,
1828+
)
1829+
17891830
def get_following(
17901831
self,
17911832
user_id: str,

pytwitter/rate_limit.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ def get_limit(self, auth_type, method="GET"):
179179
LIMIT_APP_GET=300,
180180
LIMIT_USER_GET=900,
181181
)
182+
USERS_SEARCH = Endpoint(
183+
resource="/users/search",
184+
regex=re.compile(r"/users/search"),
185+
LIMIT_USER_GET=900,
186+
)
182187
USER_FOLLOWING = Endpoint(
183188
resource="/users/:id/following",
184189
regex=re.compile(r"/users/\d+/following"),
@@ -371,6 +376,12 @@ def get_limit(self, auth_type, method="GET"):
371376
LIMIT_APP_GET=50,
372377
)
373378

379+
TRENDS = Endpoint(
380+
resource="/trends/by/woeid/:woeid",
381+
regex=re.compile(r"/trends/by/woeid/\d+"),
382+
LIMIT_APP_GET=75,
383+
)
384+
374385
MEDIA_UPLOAD = Endpoint(
375386
resource="/media/upload.json",
376387
regex=re.compile(r"/media/upload.json"),
@@ -399,6 +410,7 @@ def get_limit(self, auth_type, method="GET"):
399410
USERS_BY_ID,
400411
USER_BY_USERNAME,
401412
USERS_BY_USERNAME,
413+
USERS_SEARCH,
402414
USER_FOLLOWING,
403415
USER_REMOVE_FOLLOWING,
404416
USER_FOLLOWER,
@@ -433,6 +445,7 @@ def get_limit(self, auth_type, method="GET"):
433445
DM_MESSAGE_TO_CONVERSATION,
434446
DM_CONVERSATIONS,
435447
USAGE_TWEETS,
448+
TRENDS,
436449
MEDIA_UPLOAD,
437450
]
438451

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"data":[{"location":"127.0.0.1","name":"Developers","description":"The voice of the X Dev team and your official source for updates, news, and events, related to the X API.","username":"XDevelopers","id":"2244994945"},{"location":"Seattle, WA","name":"Suhem Parack","description":"Partner Engineering @XDevelopers","username":"suhemparack","id":"857699969263964161"},{"location":"New York, NY","name":"Chris Park","description":"𝕏 | @X @API @XDevelopers","username":"chrisparkX","id":"2533341854"},{"location":"Islington, London","name":"Haim Vaturi","description":"@XDevelopers","username":"haimvat","id":"853388192"},{"location":"Canada","name":"ROBLOX Devs","description":"Follow this account for a lot of cool ROBLOXdev from all kinds of different ROBLOX developers! Not an official @ROBLOX twitter account","username":"RBXdevelopers","id":"829457852125306890"},{"location":"東京都港区","name":"Twitter Dev Japan","description":"This account is no longer active. Follow @XDevelopers for updates.","username":"TwitterDevJP","id":"70915829"},{"name":"Rains®™☔️🧠 0xdevelopers.eth.eth","description":"","username":"0xdevelopersTm","id":"1619352801104039936"},{"name":"Project X Developers","description":"","username":"ProXDevelopers","id":"708786906058756096"},{"location":"Los Angeles, CA","name":"XDevelopersUS","description":"","username":"XDevelopersUS","id":"1315227013028904960"},{"location":"Rio de Janeiro & São Paulo","name":"XDevelopers","description":"Contato e Suporte Via Telefone (RJ): 21 980534086 e Via Email: [email protected]","username":"XDevBrasil","id":"3296066705"},{"location":"India","name":"ajX developers","description":"app developernweb designernentrepreneurnmachine learningnAI PIONEERnage just 16","username":"ajXdevelopers","id":"1234855897370910720"},{"name":"The X Developers","description":"","username":"TheXDevelopers","id":"1453775246"},{"name":"RBLXdevelopers","description":"","username":"XdevelopersRbl","id":"1513675812486193158"},{"location":"London, England","name":"XDevelopersUK","description":"","username":"XDevelopersUK","id":"1375178694520627204"},{"name":"xDevelopers","description":"","username":"xdevelopers_st","id":"1363113804842881024"},{"name":"xdevelopers","description":"","username":"itdenps","id":"2885219741"},{"name":"X","description":"","username":"xdevelopers_es","id":"1684769811539087362"},{"name":"XDevelopers","description":"","username":"XDeveloper_","id":"732232220803485696"},{"name":"xDevelopers","description":"","username":"developers_x","id":"831241935675326464"},{"location":"United States","name":"0xspark","description":"","username":"0xdevelopers","id":"1580611661169238016"},{"name":"XeXDevelopers","description":"","username":"XeXDevelopers","id":"2175184873"},{"name":"Izu","description":"","username":"XDevelopersJP","id":"1684141917129539585"},{"name":"SXDevelopers","description":"","username":"SonyXDevelopers","id":"1521381726"}],"meta":{"next_token":"5qym3iwm0f05lqu1ezcdkohsl2i4lyq"}}

tests/apis/test_users.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_get_me(api_with_user, helpers):
104104

105105
responses.add(
106106
responses.GET,
107-
url=f"https://api.twitter.com/2/users/me",
107+
url="https://api.twitter.com/2/users/me",
108108
json=me_data,
109109
)
110110

@@ -116,6 +116,20 @@ def test_get_me(api_with_user, helpers):
116116
assert me_resp.data.id == "2244994945"
117117

118118

119+
@responses.activate
120+
def test_search_users(api_with_user, helpers):
121+
responses.add(
122+
responses.GET,
123+
url="https://api.twitter.com/2/users/search",
124+
json=helpers.load_json_data("testdata/apis/user/search_users_resp.json"),
125+
)
126+
search_resp = api_with_user.search_users(
127+
query="developers",
128+
user_fields="id,name,username,description,location",
129+
)
130+
assert search_resp.data[0].name == "Developers"
131+
132+
119133
@responses.activate
120134
def test_block_and_unblock_user(api_with_user):
121135
user_id, target_user_id = "123456", "78910"

0 commit comments

Comments
 (0)