twitter-openapi-python 0.0.43__py3-none-any.whl → 0.0.45__py3-none-any.whl

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 (28) hide show
  1. twitter_openapi_python/__init__.py +15 -15
  2. twitter_openapi_python/api/__init__.py +13 -13
  3. twitter_openapi_python/api/default_api.py +80 -80
  4. twitter_openapi_python/api/initial_state_api.py +72 -72
  5. twitter_openapi_python/api/post_api.py +166 -166
  6. twitter_openapi_python/api/tweet_api.py +428 -353
  7. twitter_openapi_python/api/user_api.py +80 -80
  8. twitter_openapi_python/api/user_list_api.py +171 -171
  9. twitter_openapi_python/api/users_api.py +56 -56
  10. twitter_openapi_python/api/v11_get_api.py +67 -70
  11. twitter_openapi_python/api/v11_post_api.py +61 -66
  12. twitter_openapi_python/client.py +194 -194
  13. twitter_openapi_python/models/__init__.py +22 -22
  14. twitter_openapi_python/models/base.py +9 -9
  15. twitter_openapi_python/models/header.py +20 -20
  16. twitter_openapi_python/models/initial_state.py +17 -17
  17. twitter_openapi_python/models/response.py +19 -19
  18. twitter_openapi_python/models/timeline.py +40 -40
  19. twitter_openapi_python/tid.py +27 -17
  20. twitter_openapi_python/utils/__init__.py +22 -22
  21. twitter_openapi_python/utils/api.py +288 -288
  22. {twitter_openapi_python-0.0.43.dist-info → twitter_openapi_python-0.0.45.dist-info}/METADATA +118 -117
  23. twitter_openapi_python-0.0.45.dist-info/RECORD +27 -0
  24. {twitter_openapi_python-0.0.43.dist-info → twitter_openapi_python-0.0.45.dist-info}/WHEEL +1 -2
  25. {twitter_openapi_python-0.0.43.dist-info → twitter_openapi_python-0.0.45.dist-info}/licenses/LICENSE +31 -31
  26. {twitter_openapi_python-0.0.43.dist-info → twitter_openapi_python-0.0.45.dist-info}/licenses/LICENSE.AGPL +660 -660
  27. twitter_openapi_python-0.0.43.dist-info/RECORD +0 -28
  28. twitter_openapi_python-0.0.43.dist-info/top_level.txt +0 -1
@@ -1,288 +1,288 @@
1
- import json
2
- from typing import Any, Dict, List, Mapping, Optional, TypeGuard, TypeVar
3
-
4
- import twitter_openapi_python_generated as twitter
5
- import twitter_openapi_python_generated.models as models
6
- from x_client_transaction import ClientTransaction
7
-
8
- from twitter_openapi_python.models import (
9
- ApiUtilsHeader,
10
- CursorApiUtilsResponse,
11
- TweetApiUtilsData,
12
- TwitterApiUtilsRaw,
13
- TwitterApiUtilsResponse,
14
- UserApiUtilsData,
15
- )
16
-
17
- T = TypeVar("T")
18
- T1 = TypeVar("T1")
19
- T2 = TypeVar("T2")
20
- ParamType = dict[str, Any]
21
-
22
-
23
- def flat(matrix: List[List[T]]) -> List[T]:
24
- return [x for row in matrix for x in row]
25
-
26
-
27
- def non_nullable(x: Optional[T]) -> T:
28
- if x is None:
29
- raise Exception("No data")
30
- return x
31
-
32
-
33
- def non_nullable_list(x: List[Optional[T]]) -> List[T]:
34
- def filter_fn(x: Optional[T]) -> TypeGuard[T]:
35
- return x is not None
36
-
37
- return list(filter(filter_fn, x))
38
-
39
-
40
- def get_kwargs(flag: ParamType, additional: ParamType, ct: ClientTransaction) -> ParamType:
41
- assert flag is not None
42
- kwargs = {"path_query_id": flag["queryId"]}
43
- if flag.get("variables") is not None:
44
- kwargs["variables"] = json.dumps(flag["variables"] | additional)
45
- if flag.get("features") is not None:
46
- kwargs["features"] = json.dumps(flag["features"])
47
- if flag.get("fieldToggles") is not None:
48
- kwargs["field_toggles"] = json.dumps(flag["fieldToggles"])
49
- if flag.get("@path") is not None:
50
- kwargs["_headers"] = get_headers(flag, ct)
51
- return kwargs
52
-
53
-
54
- def get_headers(flag: ParamType, ct: ClientTransaction) -> Dict[str, str]:
55
- tid = ct.generate_transaction_id(flag["@method"], flag["@path"])
56
- return {"x-client-transaction-id": tid}
57
-
58
-
59
- def get_legacy_kwargs(flag: ParamType, additional: ParamType) -> ParamType:
60
- assert flag is not None
61
-
62
- def to_snake_case(x: str) -> str:
63
- return "".join(["_" + i.lower() if i.isupper() else i for i in x]).lstrip("_")
64
-
65
- res = {to_snake_case(k): v for k, v in flag.items()}
66
-
67
- return res | additional
68
-
69
-
70
- def error_check(data: Optional[T], error: Optional[List[models.ErrorResponse]]) -> T:
71
- if data is None:
72
- if error is None:
73
- raise Exception("No data")
74
- else:
75
- raise Exception(", ".join([x.message for x in error]))
76
- return data
77
-
78
-
79
- def instruction_to_entry(
80
- input: List[models.InstructionUnion],
81
- ) -> List[models.TimelineAddEntry]:
82
- def map_fn(x: models.InstructionUnion) -> List[models.TimelineAddEntry]:
83
- one_of = x.actual_instance
84
-
85
- if isinstance(one_of, models.TimelineAddEntries):
86
- return one_of.entries
87
- elif isinstance(one_of, models.TimelineReplaceEntry):
88
- return [one_of.entry]
89
- else:
90
- return []
91
-
92
- return flat(list(map(map_fn, input)))
93
-
94
-
95
- def tweet_entries_converter(
96
- input: List[models.TimelineAddEntry],
97
- ) -> List[TweetApiUtilsData]:
98
- def map_fn(x: models.TimelineAddEntry) -> Optional[List[TweetApiUtilsData]]:
99
- one_of = x.content.actual_instance
100
-
101
- if isinstance(one_of, models.TimelineTimelineItem):
102
- item = one_of.item_content.actual_instance
103
- if isinstance(item, models.TimelineTweet):
104
- return non_nullable_list(
105
- [
106
- build_tweet_api_utils(
107
- result=item.tweet_results,
108
- promoted_metadata=item.promoted_metadata,
109
- reply=[],
110
- )
111
- ]
112
- )
113
- elif isinstance(one_of, models.TimelineTimelineModule):
114
- module = one_of.items or []
115
- timelineList = non_nullable_list(list(map(map_fn_2, module)))
116
- if len(timelineList) == 0:
117
- return None
118
- if one_of.display_type == models.DisplayType.VERTICALGRID:
119
- return non_nullable_list(
120
- [
121
- build_tweet_api_utils(
122
- result=x.tweet_results,
123
- promoted_metadata=x.promoted_metadata,
124
- reply=[],
125
- )
126
- for x in timelineList
127
- ]
128
- )
129
- else:
130
- timeline = timelineList[0]
131
- return non_nullable_list(
132
- [
133
- build_tweet_api_utils(
134
- result=timeline.tweet_results,
135
- promoted_metadata=timeline.promoted_metadata,
136
- reply=timelineList[1:],
137
- )
138
- ]
139
- )
140
-
141
- def map_fn_2(x: models.ModuleItem) -> Optional[models.TimelineTweet]:
142
- item = x.item.item_content.actual_instance
143
- if isinstance(item, models.TimelineTweet):
144
- return item
145
-
146
- return flat(non_nullable_list(list(map(map_fn, input))))
147
-
148
-
149
- def user_or_null_converter(user: models.UserUnion) -> Optional[models.User]:
150
- if isinstance(user.actual_instance, models.User):
151
- return user.actual_instance
152
-
153
-
154
- def build_tweet_api_utils(
155
- result: models.ItemResult,
156
- promoted_metadata: Optional[dict[str, Any]] = None,
157
- reply: Optional[List[models.TimelineTweet]] = None,
158
- ) -> Optional[TweetApiUtilsData]:
159
- tweet = tweet_results_converter(result)
160
- if tweet is None:
161
- return None
162
- if tweet.core is None:
163
- return None
164
- if tweet.core.user_results.result is None:
165
- return None
166
- user = user_or_null_converter(tweet.core.user_results.result)
167
- if user is None:
168
- return None
169
-
170
- quoted = tweet.quoted_status_result
171
-
172
- retweeted = None if tweet.legacy is None else tweet.legacy.retweeted_status_result
173
-
174
- def reply_fn(x: models.TimelineTweet) -> Optional[TweetApiUtilsData]:
175
- return build_tweet_api_utils(x.tweet_results, x.promoted_metadata, [])
176
-
177
- return TweetApiUtilsData(
178
- raw=result,
179
- promoted_metadata=promoted_metadata,
180
- tweet=tweet,
181
- user=user,
182
- replies=non_nullable_list(list(map(reply_fn, reply or []))),
183
- retweeted=build_tweet_api_utils(retweeted, None, []) if retweeted else None,
184
- quoted=build_tweet_api_utils(quoted, None, []) if quoted else None,
185
- )
186
-
187
-
188
- def tweet_results_converter(tweetResults: models.ItemResult) -> Optional[models.Tweet]:
189
- if tweetResults.result is None:
190
- return None
191
- properties = tweetResults.result.actual_instance
192
- if isinstance(properties, models.Tweet):
193
- return properties
194
- elif isinstance(properties, models.TweetWithVisibilityResults):
195
- return properties.tweet
196
- elif isinstance(properties, models.TweetTombstone):
197
- return None
198
- raise Exception()
199
-
200
-
201
- def user_entries_converter(
202
- item: list[models.TimelineAddEntry],
203
- ) -> list[models.UserResults]:
204
- def map_fn(x: models.TimelineAddEntry) -> Optional[models.UserResults]:
205
- one_of = x.content.actual_instance
206
- if isinstance(one_of, models.TimelineTimelineItem):
207
- item = one_of.item_content.actual_instance
208
- if isinstance(item, models.TimelineUser):
209
- return item.user_results
210
-
211
- return non_nullable_list(list(map(map_fn, item)))
212
-
213
-
214
- def user_result_converter(item: list[models.UserResults]) -> List[UserApiUtilsData]:
215
- def map_fn(raw: models.UserResults) -> Optional[UserApiUtilsData]:
216
- if raw.result is None:
217
- return None
218
- user = user_or_null_converter(raw.result)
219
- if user is None:
220
- return None
221
-
222
- return UserApiUtilsData(
223
- raw=raw,
224
- user=user,
225
- )
226
-
227
- return non_nullable_list(list(map(map_fn, item)))
228
-
229
-
230
- def entries_cursor(item: List[models.TimelineAddEntry]) -> CursorApiUtilsResponse:
231
- def map_fn(x: models.TimelineAddEntry) -> Optional[models.TimelineTimelineCursor]:
232
- item = x.content.actual_instance
233
- if isinstance(item, models.TimelineTimelineCursor):
234
- return item
235
- elif isinstance(item, models.TimelineTimelineItem):
236
- content = item.item_content.actual_instance
237
- if isinstance(content, models.TimelineTimelineCursor):
238
- return content
239
-
240
- return build_cursor(non_nullable_list(list(map(map_fn, item))))
241
-
242
-
243
- def build_cursor(list: list[models.TimelineTimelineCursor]) -> CursorApiUtilsResponse:
244
- def find_fn_1(x: models.TimelineTimelineCursor) -> bool:
245
- return x.cursor_type == models.CursorType.TOP
246
-
247
- def find_fn_2(x: models.TimelineTimelineCursor) -> bool:
248
- return x.cursor_type == models.CursorType.BOTTOM
249
-
250
- return CursorApiUtilsResponse(
251
- top=next(filter(find_fn_1, list), None),
252
- bottom=next(filter(find_fn_2, list), None),
253
- )
254
-
255
-
256
- def build_header(headers: Dict[str, str]) -> ApiUtilsHeader:
257
- return ApiUtilsHeader(
258
- raw=headers,
259
- connection_hash=headers.get("x-connection-hash"),
260
- content_type_options=headers.get("x-content-type-options"),
261
- frame_options=headers.get("x-frame-options"),
262
- rate_limit_limit=int(headers.get("x-rate-limit-limit", 0)),
263
- rate_limit_remaining=int(headers.get("x-rate-limit-remaining", 0)),
264
- rate_limit_reset=int(headers.get("x-rate-limit-reset", 0)),
265
- response_time=int(headers.get("x-response-time", 0)),
266
- tfe_preserve_body=headers.get("x-tfe-preserve-body") == "true",
267
- transaction_id=headers.get("x-transaction-id"),
268
- twitter_response_tags=headers.get("x-twitter-response-tags"),
269
- xss_protection= int(headers["x-xss-protection"]) if headers.get("x-xss-protection") is not None else None,
270
- )
271
-
272
-
273
- def build_response(response: twitter.ApiResponse, data: T1) -> TwitterApiUtilsResponse[T1]:
274
- if response.headers is None:
275
- raise Exception("headers is None")
276
-
277
- if isinstance(response.headers, Dict):
278
- header = build_header(response.headers)
279
- elif isinstance(response.headers, Mapping):
280
- header = build_header(dict(response.headers))
281
- else:
282
- raise Exception("headers is not a dict")
283
-
284
- return TwitterApiUtilsResponse(
285
- raw=TwitterApiUtilsRaw(response=response),
286
- header=header,
287
- data=data,
288
- )
1
+ import json
2
+ from typing import Any, Dict, List, Mapping, Optional, TypeGuard, TypeVar
3
+
4
+ import twitter_openapi_python_generated as twitter
5
+ import twitter_openapi_python_generated.models as models
6
+ from x_client_transaction import ClientTransaction
7
+
8
+ from twitter_openapi_python.models import (
9
+ ApiUtilsHeader,
10
+ CursorApiUtilsResponse,
11
+ TweetApiUtilsData,
12
+ TwitterApiUtilsRaw,
13
+ TwitterApiUtilsResponse,
14
+ UserApiUtilsData,
15
+ )
16
+
17
+ T = TypeVar("T")
18
+ T1 = TypeVar("T1")
19
+ T2 = TypeVar("T2")
20
+ ParamType = dict[str, Any]
21
+
22
+
23
+ def flat(matrix: List[List[T]]) -> List[T]:
24
+ return [x for row in matrix for x in row]
25
+
26
+
27
+ def non_nullable(x: Optional[T]) -> T:
28
+ if x is None:
29
+ raise Exception("No data")
30
+ return x
31
+
32
+
33
+ def non_nullable_list(x: List[Optional[T]]) -> List[T]:
34
+ def filter_fn(x: Optional[T]) -> TypeGuard[T]:
35
+ return x is not None
36
+
37
+ return list(filter(filter_fn, x))
38
+
39
+
40
+ def get_kwargs(flag: ParamType, additional: ParamType, ct: ClientTransaction) -> ParamType:
41
+ assert flag is not None
42
+ kwargs = {"path_query_id": flag["queryId"]}
43
+ if flag.get("variables") is not None:
44
+ kwargs["variables"] = json.dumps(flag["variables"] | additional)
45
+ if flag.get("features") is not None:
46
+ kwargs["features"] = json.dumps(flag["features"])
47
+ if flag.get("fieldToggles") is not None:
48
+ kwargs["field_toggles"] = json.dumps(flag["fieldToggles"])
49
+ if flag.get("@path") is not None:
50
+ kwargs["_headers"] = get_headers(flag, ct)
51
+ return kwargs
52
+
53
+
54
+ def get_headers(flag: ParamType, ct: ClientTransaction) -> Dict[str, str]:
55
+ tid = ct.generate_transaction_id(flag["@method"], flag["@path"])
56
+ return {"x-client-transaction-id": tid}
57
+
58
+
59
+ def get_legacy_kwargs(flag: ParamType, additional: ParamType) -> ParamType:
60
+ assert flag is not None
61
+
62
+ def to_snake_case(x: str) -> str:
63
+ return "".join(["_" + i.lower() if i.isupper() else i for i in x]).lstrip("_")
64
+
65
+ res = {to_snake_case(k): v for k, v in flag.items()}
66
+
67
+ return res | additional
68
+
69
+
70
+ def error_check(data: Optional[T], error: Optional[List[models.ErrorResponse]]) -> T:
71
+ if data is None:
72
+ if error is None:
73
+ raise Exception("No data")
74
+ else:
75
+ raise Exception(", ".join([x.message for x in error]))
76
+ return data
77
+
78
+
79
+ def instruction_to_entry(
80
+ input: List[models.InstructionUnion],
81
+ ) -> List[models.TimelineAddEntry]:
82
+ def map_fn(x: models.InstructionUnion) -> List[models.TimelineAddEntry]:
83
+ one_of = x.actual_instance
84
+
85
+ if isinstance(one_of, models.TimelineAddEntries):
86
+ return one_of.entries
87
+ elif isinstance(one_of, models.TimelineReplaceEntry):
88
+ return [one_of.entry]
89
+ else:
90
+ return []
91
+
92
+ return flat(list(map(map_fn, input)))
93
+
94
+
95
+ def tweet_entries_converter(
96
+ input: List[models.TimelineAddEntry],
97
+ ) -> List[TweetApiUtilsData]:
98
+ def map_fn(x: models.TimelineAddEntry) -> Optional[List[TweetApiUtilsData]]:
99
+ one_of = x.content.actual_instance
100
+
101
+ if isinstance(one_of, models.TimelineTimelineItem):
102
+ item = one_of.item_content.actual_instance
103
+ if isinstance(item, models.TimelineTweet):
104
+ return non_nullable_list(
105
+ [
106
+ build_tweet_api_utils(
107
+ result=item.tweet_results,
108
+ promoted_metadata=item.promoted_metadata,
109
+ reply=[],
110
+ )
111
+ ]
112
+ )
113
+ elif isinstance(one_of, models.TimelineTimelineModule):
114
+ module = one_of.items or []
115
+ timelineList = non_nullable_list(list(map(map_fn_2, module)))
116
+ if len(timelineList) == 0:
117
+ return None
118
+ if one_of.display_type == models.DisplayType.VERTICALGRID:
119
+ return non_nullable_list(
120
+ [
121
+ build_tweet_api_utils(
122
+ result=x.tweet_results,
123
+ promoted_metadata=x.promoted_metadata,
124
+ reply=[],
125
+ )
126
+ for x in timelineList
127
+ ]
128
+ )
129
+ else:
130
+ timeline = timelineList[0]
131
+ return non_nullable_list(
132
+ [
133
+ build_tweet_api_utils(
134
+ result=timeline.tweet_results,
135
+ promoted_metadata=timeline.promoted_metadata,
136
+ reply=timelineList[1:],
137
+ )
138
+ ]
139
+ )
140
+
141
+ def map_fn_2(x: models.ModuleItem) -> Optional[models.TimelineTweet]:
142
+ item = x.item.item_content.actual_instance
143
+ if isinstance(item, models.TimelineTweet):
144
+ return item
145
+
146
+ return flat(non_nullable_list(list(map(map_fn, input))))
147
+
148
+
149
+ def user_or_null_converter(user: models.UserUnion) -> Optional[models.User]:
150
+ if isinstance(user.actual_instance, models.User):
151
+ return user.actual_instance
152
+
153
+
154
+ def build_tweet_api_utils(
155
+ result: models.ItemResult,
156
+ promoted_metadata: Optional[dict[str, Any]] = None,
157
+ reply: Optional[List[models.TimelineTweet]] = None,
158
+ ) -> Optional[TweetApiUtilsData]:
159
+ tweet = tweet_results_converter(result)
160
+ if tweet is None:
161
+ return None
162
+ if tweet.core is None:
163
+ return None
164
+ if tweet.core.user_results.result is None:
165
+ return None
166
+ user = user_or_null_converter(tweet.core.user_results.result)
167
+ if user is None:
168
+ return None
169
+
170
+ quoted = tweet.quoted_status_result
171
+
172
+ retweeted = None if tweet.legacy is None else tweet.legacy.retweeted_status_result
173
+
174
+ def reply_fn(x: models.TimelineTweet) -> Optional[TweetApiUtilsData]:
175
+ return build_tweet_api_utils(x.tweet_results, x.promoted_metadata, [])
176
+
177
+ return TweetApiUtilsData(
178
+ raw=result,
179
+ promoted_metadata=promoted_metadata,
180
+ tweet=tweet,
181
+ user=user,
182
+ replies=non_nullable_list(list(map(reply_fn, reply or []))),
183
+ retweeted=build_tweet_api_utils(retweeted, None, []) if retweeted else None,
184
+ quoted=build_tweet_api_utils(quoted, None, []) if quoted else None,
185
+ )
186
+
187
+
188
+ def tweet_results_converter(tweetResults: models.ItemResult) -> Optional[models.Tweet]:
189
+ if tweetResults.result is None:
190
+ return None
191
+ properties = tweetResults.result.actual_instance
192
+ if isinstance(properties, models.Tweet):
193
+ return properties
194
+ elif isinstance(properties, models.TweetWithVisibilityResults):
195
+ return properties.tweet
196
+ elif isinstance(properties, models.TweetTombstone):
197
+ return None
198
+ raise Exception()
199
+
200
+
201
+ def user_entries_converter(
202
+ item: list[models.TimelineAddEntry],
203
+ ) -> list[models.UserResults]:
204
+ def map_fn(x: models.TimelineAddEntry) -> Optional[models.UserResults]:
205
+ one_of = x.content.actual_instance
206
+ if isinstance(one_of, models.TimelineTimelineItem):
207
+ item = one_of.item_content.actual_instance
208
+ if isinstance(item, models.TimelineUser):
209
+ return item.user_results
210
+
211
+ return non_nullable_list(list(map(map_fn, item)))
212
+
213
+
214
+ def user_result_converter(item: list[models.UserResults]) -> List[UserApiUtilsData]:
215
+ def map_fn(raw: models.UserResults) -> Optional[UserApiUtilsData]:
216
+ if raw.result is None:
217
+ return None
218
+ user = user_or_null_converter(raw.result)
219
+ if user is None:
220
+ return None
221
+
222
+ return UserApiUtilsData(
223
+ raw=raw,
224
+ user=user,
225
+ )
226
+
227
+ return non_nullable_list(list(map(map_fn, item)))
228
+
229
+
230
+ def entries_cursor(item: List[models.TimelineAddEntry]) -> CursorApiUtilsResponse:
231
+ def map_fn(x: models.TimelineAddEntry) -> Optional[models.TimelineTimelineCursor]:
232
+ item = x.content.actual_instance
233
+ if isinstance(item, models.TimelineTimelineCursor):
234
+ return item
235
+ elif isinstance(item, models.TimelineTimelineItem):
236
+ content = item.item_content.actual_instance
237
+ if isinstance(content, models.TimelineTimelineCursor):
238
+ return content
239
+
240
+ return build_cursor(non_nullable_list(list(map(map_fn, item))))
241
+
242
+
243
+ def build_cursor(list: list[models.TimelineTimelineCursor]) -> CursorApiUtilsResponse:
244
+ def find_fn_1(x: models.TimelineTimelineCursor) -> bool:
245
+ return x.cursor_type == models.CursorType.TOP
246
+
247
+ def find_fn_2(x: models.TimelineTimelineCursor) -> bool:
248
+ return x.cursor_type == models.CursorType.BOTTOM
249
+
250
+ return CursorApiUtilsResponse(
251
+ top=next(filter(find_fn_1, list), None),
252
+ bottom=next(filter(find_fn_2, list), None),
253
+ )
254
+
255
+
256
+ def build_header(headers: Dict[str, str]) -> ApiUtilsHeader:
257
+ return ApiUtilsHeader(
258
+ raw=headers,
259
+ connection_hash=headers.get("x-connection-hash"),
260
+ content_type_options=headers.get("x-content-type-options"),
261
+ frame_options=headers.get("x-frame-options"),
262
+ rate_limit_limit=int(headers.get("x-rate-limit-limit", 0)),
263
+ rate_limit_remaining=int(headers.get("x-rate-limit-remaining", 0)),
264
+ rate_limit_reset=int(headers.get("x-rate-limit-reset", 0)),
265
+ response_time=int(headers.get("x-response-time", 0)),
266
+ tfe_preserve_body=headers.get("x-tfe-preserve-body") == "true",
267
+ transaction_id=headers.get("x-transaction-id"),
268
+ twitter_response_tags=headers.get("x-twitter-response-tags"),
269
+ xss_protection= int(headers["x-xss-protection"]) if headers.get("x-xss-protection") is not None else None,
270
+ )
271
+
272
+
273
+ def build_response(response: twitter.ApiResponse, data: T1) -> TwitterApiUtilsResponse[T1]:
274
+ if response.headers is None:
275
+ raise Exception("headers is None")
276
+
277
+ if isinstance(response.headers, Dict):
278
+ header = build_header(response.headers)
279
+ elif isinstance(response.headers, Mapping):
280
+ header = build_header(dict(response.headers))
281
+ else:
282
+ raise Exception("headers is not a dict")
283
+
284
+ return TwitterApiUtilsResponse(
285
+ raw=TwitterApiUtilsRaw(response=response),
286
+ header=header,
287
+ data=data,
288
+ )