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.
Files changed (23) hide show
  1. {tweetapi-2.2.1 → tweetapi-2.3.0}/PKG-INFO +8 -2
  2. {tweetapi-2.2.1 → tweetapi-2.3.0}/README.md +7 -1
  3. {tweetapi-2.2.1 → tweetapi-2.3.0}/pyproject.toml +1 -1
  4. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/__init__.py +1 -1
  5. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/client.py +15 -7
  6. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/profile.py +15 -1
  7. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/types.py +8 -0
  8. {tweetapi-2.2.1 → tweetapi-2.3.0}/.gitignore +0 -0
  9. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/errors.py +0 -0
  10. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/pagination.py +0 -0
  11. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/py.typed +0 -0
  12. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/__init__.py +0 -0
  13. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/auth.py +0 -0
  14. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/community.py +0 -0
  15. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/explore.py +0 -0
  16. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/interaction.py +0 -0
  17. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/list_.py +0 -0
  18. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/post.py +0 -0
  19. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/space.py +0 -0
  20. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/tweet.py +0 -0
  21. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/unencrypted_dm.py +0 -0
  22. {tweetapi-2.2.1 → tweetapi-2.3.0}/tweetapi/resources/user.py +0 -0
  23. {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.2.1
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:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "tweetapi"
7
- version = "2.2.1"
7
+ version = "2.3.0"
8
8
  description = "Python SDK for TweetAPI's Twitter/X data and account API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -37,4 +37,4 @@ __all__ = [
37
37
  "paginate_pages",
38
38
  ]
39
39
 
40
- __version__ = "2.2.1"
40
+ __version__ = "2.3.0"
@@ -108,12 +108,18 @@ class TweetAPI:
108
108
  }
109
109
  return self._request("GET", path, params=clean_params)
110
110
 
111
- def _post(self, path: str, body: Optional[dict[str, Any]] = None) -> Any:
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(self._max_retries + 1):
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 < self._max_retries:
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 < self._max_retries:
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 < self._max_retries:
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 < self._max_retries and self._is_retryable(err):
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 ProfileMediaInput, ProfilePrivacyResponse, UserResponse
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