tweetapi 2.2.1__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tweetapi-2.2.1 → tweetapi-2.3.0}/PKG-INFO +8 -2
- {tweetapi-2.2.1 → tweetapi-2.3.0}/README.md +7 -1
- {tweetapi-2.2.1 → tweetapi-2.3.0}/pyproject.toml +1 -1
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/__init__.py +1 -1
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/client.py +15 -7
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/profile.py +15 -1
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/types.py +8 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/.gitignore +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/errors.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/pagination.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/py.typed +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/__init__.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/auth.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/community.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/explore.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/interaction.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/list_.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/post.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/space.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/tweet.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/unencrypted_dm.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/user.py +0 -0
- {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/xchat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tweetapi
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Python SDK for TweetAPI's Twitter/X data and account API
|
|
5
5
|
Project-URL: Homepage, https://tweetapi.com?utm_source=pypi&utm_medium=readme&utm_campaign=python-sdk
|
|
6
6
|
Project-URL: Documentation, https://tweetapi.com/docs?utm_source=pypi&utm_medium=readme&utm_campaign=python-sdk
|
|
@@ -65,7 +65,7 @@ next_page = client.user.get_followers(
|
|
|
65
65
|
## SDK behavior
|
|
66
66
|
|
|
67
67
|
- Public methods have type annotations, and response models use `TypedDict`.
|
|
68
|
-
- The client retries rate limits, server errors, timeouts, and connection failures.
|
|
68
|
+
- The client retries rate limits, server errors, timeouts, and connection failures by default; username changes disable automatic retries because the mutation is non-idempotent.
|
|
69
69
|
- `paginate()` yields items from cursor-based responses; `paginate_pages()` yields full response pages.
|
|
70
70
|
- HTTP errors map to exception classes such as `RateLimitError` and `NotFoundError`.
|
|
71
71
|
- Timeouts can use one value or separate connect and read values.
|
|
@@ -124,6 +124,7 @@ next_page = client.user.get_followers(
|
|
|
124
124
|
| `client.profile.banner(auth_token=..., media=..., proxy=...)` | Update profile banner |
|
|
125
125
|
| `client.profile.remove_banner(auth_token=..., proxy=...)` | Remove the profile banner |
|
|
126
126
|
| `client.profile.set_privacy(auth_token=..., is_private=..., proxy=...)` | Make the account public or private |
|
|
127
|
+
| `client.profile.update_username(auth_token=..., password=..., username=..., proxy=...)` | Update the account username |
|
|
127
128
|
|
|
128
129
|
### Interaction
|
|
129
130
|
|
|
@@ -253,6 +254,11 @@ client.profile.banner(
|
|
|
253
254
|
)
|
|
254
255
|
client.profile.remove_banner(auth_token="AUTH_TOKEN")
|
|
255
256
|
client.profile.set_privacy(auth_token="AUTH_TOKEN", is_private=True)
|
|
257
|
+
client.profile.update_username(
|
|
258
|
+
auth_token="AUTH_TOKEN",
|
|
259
|
+
password="ACCOUNT_PASSWORD",
|
|
260
|
+
username="NEW_USERNAME",
|
|
261
|
+
)
|
|
256
262
|
```
|
|
257
263
|
|
|
258
264
|
Use `client.list` for list mutations. The older helpers under `client.interaction` remain available:
|
|
@@ -35,7 +35,7 @@ next_page = client.user.get_followers(
|
|
|
35
35
|
## SDK behavior
|
|
36
36
|
|
|
37
37
|
- Public methods have type annotations, and response models use `TypedDict`.
|
|
38
|
-
- The client retries rate limits, server errors, timeouts, and connection failures.
|
|
38
|
+
- The client retries rate limits, server errors, timeouts, and connection failures by default; username changes disable automatic retries because the mutation is non-idempotent.
|
|
39
39
|
- `paginate()` yields items from cursor-based responses; `paginate_pages()` yields full response pages.
|
|
40
40
|
- HTTP errors map to exception classes such as `RateLimitError` and `NotFoundError`.
|
|
41
41
|
- Timeouts can use one value or separate connect and read values.
|
|
@@ -94,6 +94,7 @@ next_page = client.user.get_followers(
|
|
|
94
94
|
| `client.profile.banner(auth_token=..., media=..., proxy=...)` | Update profile banner |
|
|
95
95
|
| `client.profile.remove_banner(auth_token=..., proxy=...)` | Remove the profile banner |
|
|
96
96
|
| `client.profile.set_privacy(auth_token=..., is_private=..., proxy=...)` | Make the account public or private |
|
|
97
|
+
| `client.profile.update_username(auth_token=..., password=..., username=..., proxy=...)` | Update the account username |
|
|
97
98
|
|
|
98
99
|
### Interaction
|
|
99
100
|
|
|
@@ -223,6 +224,11 @@ client.profile.banner(
|
|
|
223
224
|
)
|
|
224
225
|
client.profile.remove_banner(auth_token="AUTH_TOKEN")
|
|
225
226
|
client.profile.set_privacy(auth_token="AUTH_TOKEN", is_private=True)
|
|
227
|
+
client.profile.update_username(
|
|
228
|
+
auth_token="AUTH_TOKEN",
|
|
229
|
+
password="ACCOUNT_PASSWORD",
|
|
230
|
+
username="NEW_USERNAME",
|
|
231
|
+
)
|
|
226
232
|
```
|
|
227
233
|
|
|
228
234
|
Use `client.list` for list mutations. The older helpers under `client.interaction` remain available:
|
|
@@ -108,12 +108,18 @@ class TweetAPI:
|
|
|
108
108
|
}
|
|
109
109
|
return self._request("GET", path, params=clean_params)
|
|
110
110
|
|
|
111
|
-
def _post(
|
|
111
|
+
def _post(
|
|
112
|
+
self,
|
|
113
|
+
path: str,
|
|
114
|
+
body: Optional[dict[str, Any]] = None,
|
|
115
|
+
*,
|
|
116
|
+
retry: bool = True,
|
|
117
|
+
) -> Any:
|
|
112
118
|
"""Send a POST request to the API."""
|
|
113
119
|
clean_body = None
|
|
114
120
|
if body:
|
|
115
121
|
clean_body = {k: v for k, v in body.items() if v is not None}
|
|
116
|
-
return self._request("POST", path, json=clean_body)
|
|
122
|
+
return self._request("POST", path, json=clean_body, retry=retry)
|
|
117
123
|
|
|
118
124
|
@property
|
|
119
125
|
def rate_limit_info(self) -> Optional[dict[str, Any]]:
|
|
@@ -146,11 +152,13 @@ class TweetAPI:
|
|
|
146
152
|
path: str,
|
|
147
153
|
params: Optional[dict[str, Any]] = None,
|
|
148
154
|
json: Optional[dict[str, Any]] = None,
|
|
155
|
+
retry: bool = True,
|
|
149
156
|
) -> Any:
|
|
150
157
|
url = f"{self._base_url}{path}"
|
|
151
158
|
last_error: Optional[TweetAPIError] = None
|
|
159
|
+
max_retries = self._max_retries if retry else 0
|
|
152
160
|
|
|
153
|
-
for attempt in range(
|
|
161
|
+
for attempt in range(max_retries + 1):
|
|
154
162
|
try:
|
|
155
163
|
response = self._session.request(
|
|
156
164
|
method,
|
|
@@ -163,19 +171,19 @@ class TweetAPI:
|
|
|
163
171
|
last_error = ConnectionError_(
|
|
164
172
|
f"Request timed out ({self._timeout_desc})", e
|
|
165
173
|
)
|
|
166
|
-
if attempt <
|
|
174
|
+
if attempt < max_retries:
|
|
167
175
|
time.sleep(self._calculate_retry_delay(last_error, attempt))
|
|
168
176
|
continue
|
|
169
177
|
raise last_error from e
|
|
170
178
|
except requests.exceptions.ConnectionError as e:
|
|
171
179
|
last_error = ConnectionError_(f"Network error: {e}", e)
|
|
172
|
-
if attempt <
|
|
180
|
+
if attempt < max_retries:
|
|
173
181
|
time.sleep(self._calculate_retry_delay(last_error, attempt))
|
|
174
182
|
continue
|
|
175
183
|
raise last_error from e
|
|
176
184
|
except requests.exceptions.RequestException as e:
|
|
177
185
|
last_error = ConnectionError_(f"Request failed: {e}", e)
|
|
178
|
-
if attempt <
|
|
186
|
+
if attempt < max_retries:
|
|
179
187
|
time.sleep(self._calculate_retry_delay(last_error, attempt))
|
|
180
188
|
continue
|
|
181
189
|
raise last_error from e
|
|
@@ -190,7 +198,7 @@ class TweetAPI:
|
|
|
190
198
|
"retry_after": err.retry_after,
|
|
191
199
|
"timestamp": time.time(),
|
|
192
200
|
}
|
|
193
|
-
if attempt <
|
|
201
|
+
if attempt < max_retries and self._is_retryable(err):
|
|
194
202
|
time.sleep(self._calculate_retry_delay(err, attempt))
|
|
195
203
|
continue
|
|
196
204
|
raise
|
|
@@ -4,7 +4,12 @@ from typing import Optional, TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from ..client import TweetAPI
|
|
7
|
-
from ..types import
|
|
7
|
+
from ..types import (
|
|
8
|
+
ProfileMediaInput,
|
|
9
|
+
ProfilePrivacyResponse,
|
|
10
|
+
ProfileUsernameResponse,
|
|
11
|
+
UserResponse,
|
|
12
|
+
)
|
|
8
13
|
|
|
9
14
|
|
|
10
15
|
class ProfileResource:
|
|
@@ -41,3 +46,12 @@ class ProfileResource:
|
|
|
41
46
|
return self._client._post("/tw-v2/profile/privacy", {
|
|
42
47
|
"authToken": auth_token, "isPrivate": is_private, "proxy": proxy,
|
|
43
48
|
})
|
|
49
|
+
|
|
50
|
+
def update_username(self, *, auth_token: str, password: str, username: str, proxy: Optional[str] = None) -> ProfileUsernameResponse:
|
|
51
|
+
"""Update the authenticated account's username."""
|
|
52
|
+
return self._client._post("/tw-v2/profile/username", {
|
|
53
|
+
"authToken": auth_token,
|
|
54
|
+
"password": password,
|
|
55
|
+
"username": username,
|
|
56
|
+
"proxy": proxy,
|
|
57
|
+
}, retry=False)
|
|
@@ -568,6 +568,14 @@ class ProfilePrivacyResponse(TypedDict):
|
|
|
568
568
|
data: ProfilePrivacy
|
|
569
569
|
|
|
570
570
|
|
|
571
|
+
class ProfileUsername(TypedDict):
|
|
572
|
+
username: str
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
class ProfileUsernameResponse(TypedDict):
|
|
576
|
+
data: ProfileUsername
|
|
577
|
+
|
|
578
|
+
|
|
571
579
|
class UsersResponse(TypedDict):
|
|
572
580
|
data: list[User]
|
|
573
581
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|