stigg-api-client-v2 0.693.0__py3-none-any.whl → 5.9.0__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 (75) hide show
  1. stigg/_edge_utils.py +58 -0
  2. stigg/client.py +97 -21
  3. stigg/generated/__init__.py +734 -42
  4. stigg/generated/apply_subscription.py +4 -12
  5. stigg/generated/archive_customer.py +2 -3
  6. stigg/generated/async_base_client.py +187 -29
  7. stigg/generated/async_client.py +3659 -620
  8. stigg/generated/base_client.py +144 -23
  9. stigg/generated/base_model.py +16 -47
  10. stigg/generated/cancel_subscription.py +2 -3
  11. stigg/generated/cancel_subscription_updates.py +1 -4
  12. stigg/generated/client.py +3661 -616
  13. stigg/generated/create_payment_session.py +20 -0
  14. stigg/generated/create_subscription.py +2 -3
  15. stigg/generated/delegate_subscription_to_customer.py +22 -0
  16. stigg/generated/detach_customer_payment_method.py +20 -0
  17. stigg/generated/enums.py +426 -7
  18. stigg/generated/estimate_subscription.py +2 -3
  19. stigg/generated/estimate_subscription_update.py +2 -3
  20. stigg/generated/exceptions.py +9 -5
  21. stigg/generated/fragments.py +1864 -701
  22. stigg/generated/get_active_subscriptions.py +2 -3
  23. stigg/generated/get_active_subscriptions_list.py +22 -0
  24. stigg/generated/get_checkout_state.py +2 -3
  25. stigg/generated/get_coupons.py +4 -5
  26. stigg/generated/get_credit_balance.py +20 -0
  27. stigg/generated/get_credit_grants.py +36 -0
  28. stigg/generated/get_credit_ledger.py +25 -0
  29. stigg/generated/get_credit_usage.py +18 -0
  30. stigg/generated/get_customer_by_id.py +2 -3
  31. stigg/generated/get_customer_portal_by_ref_id.py +2 -3
  32. stigg/generated/get_customer_statistics.py +2 -3
  33. stigg/generated/get_entitlement.py +2 -3
  34. stigg/generated/get_entitlements.py +2 -3
  35. stigg/generated/get_entitlements_state.py +31 -0
  36. stigg/generated/get_mock_paywall.py +3 -5
  37. stigg/generated/get_paywall.py +2 -3
  38. stigg/generated/get_products.py +4 -5
  39. stigg/generated/get_sdk_configuration.py +3 -3
  40. stigg/generated/get_subscription.py +18 -0
  41. stigg/generated/get_subscriptions.py +35 -0
  42. stigg/generated/get_usage_history.py +2 -3
  43. stigg/generated/get_usage_history_v_2.py +18 -0
  44. stigg/generated/grant_credits.py +20 -0
  45. stigg/generated/grant_promotional_entitlements.py +2 -3
  46. stigg/generated/grant_promotional_entitlements_group.py +24 -0
  47. stigg/generated/import_customer.py +2 -3
  48. stigg/generated/import_customer_bulk.py +1 -4
  49. stigg/generated/import_subscriptions_bulk.py +1 -4
  50. stigg/generated/input_types.py +3871 -1878
  51. stigg/generated/migrate_subscription_to_latest.py +2 -3
  52. stigg/generated/preview_next_invoice.py +20 -0
  53. stigg/generated/preview_subscription.py +2 -3
  54. stigg/generated/provision_customer.py +4 -22
  55. stigg/generated/provision_subscription.py +4 -15
  56. stigg/generated/report_entitlement_check_requested.py +1 -4
  57. stigg/generated/report_event.py +1 -4
  58. stigg/generated/report_usage.py +6 -13
  59. stigg/generated/report_usage_bulk.py +22 -0
  60. stigg/generated/revoke_promotional_entitlement.py +5 -4
  61. stigg/generated/revoke_promotional_entitlements_group.py +24 -0
  62. stigg/generated/transfer_subscription.py +2 -3
  63. stigg/generated/transfer_subscription_to_resource.py +22 -0
  64. stigg/generated/unarchive_customer.py +2 -3
  65. stigg/generated/unlink_promotional_entitlements_group.py +24 -0
  66. stigg/generated/update_customer.py +2 -3
  67. stigg/generated/update_subscription.py +2 -3
  68. stigg/generated/void_credit_grant.py +18 -0
  69. {stigg_api_client_v2-0.693.0.dist-info → stigg_api_client_v2-5.9.0.dist-info}/METADATA +3 -4
  70. stigg_api_client_v2-5.9.0.dist-info/RECORD +73 -0
  71. stigg/edge_utils.py +0 -28
  72. stigg/generated/scalars.py +0 -6
  73. stigg_api_client_v2-0.693.0.dist-info/RECORD +0 -54
  74. {stigg_api_client_v2-0.693.0.dist-info → stigg_api_client_v2-5.9.0.dist-info}/LICENSE +0 -0
  75. {stigg_api_client_v2-0.693.0.dist-info → stigg_api_client_v2-5.9.0.dist-info}/WHEEL +0 -0
@@ -1,12 +1,10 @@
1
- # Generated by ariadne-codegen on 2023-12-07 19:22
1
+ # Generated by ariadne-codegen
2
2
  # Source: operations.graphql
3
3
 
4
- from typing import Optional
5
-
6
4
  from pydantic import Field
7
5
 
8
6
  from .base_model import BaseModel
9
- from .fragments import SubscriptionFragment
7
+ from .fragments import ApplySubscriptionFragment
10
8
 
11
9
 
12
10
  class ApplySubscription(BaseModel):
@@ -15,14 +13,8 @@ class ApplySubscription(BaseModel):
15
13
  )
16
14
 
17
15
 
18
- class ApplySubscriptionApplySubscription(BaseModel):
19
- subscription: Optional["ApplySubscriptionApplySubscriptionSubscription"]
20
-
21
-
22
- class ApplySubscriptionApplySubscriptionSubscription(SubscriptionFragment):
16
+ class ApplySubscriptionApplySubscription(ApplySubscriptionFragment):
23
17
  pass
24
18
 
25
19
 
26
- ApplySubscription.update_forward_refs()
27
- ApplySubscriptionApplySubscription.update_forward_refs()
28
- ApplySubscriptionApplySubscriptionSubscription.update_forward_refs()
20
+ ApplySubscription.model_rebuild()
@@ -1,4 +1,4 @@
1
- # Generated by ariadne-codegen on 2023-12-07 19:22
1
+ # Generated by ariadne-codegen
2
2
  # Source: operations.graphql
3
3
 
4
4
  from pydantic import Field
@@ -14,5 +14,4 @@ class ArchiveCustomerArchiveCustomer(BaseModel):
14
14
  customer_id: str = Field(alias="customerId")
15
15
 
16
16
 
17
- ArchiveCustomer.update_forward_refs()
18
- ArchiveCustomerArchiveCustomer.update_forward_refs()
17
+ ArchiveCustomer.model_rebuild()
@@ -1,26 +1,32 @@
1
- # Generated by ariadne-codegen on 2023-12-07 19:22
1
+ # Generated by ariadne-codegen
2
2
 
3
3
  import enum
4
4
  import json
5
- from typing import Any, AsyncIterator, Dict, Optional, TypeVar, cast
5
+ from typing import IO, Any, AsyncIterator, Dict, List, Optional, Tuple, TypeVar, cast
6
6
  from uuid import uuid4
7
7
 
8
8
  import httpx
9
9
  from pydantic import BaseModel
10
- from pydantic.json import pydantic_encoder
10
+ from pydantic_core import to_jsonable_python
11
11
 
12
- from .base_model import UNSET
12
+ from .base_model import UNSET, Upload
13
13
  from .exceptions import (
14
14
  GraphQLClientGraphQLMultiError,
15
15
  GraphQLClientHttpError,
16
16
  GraphQLClientInvalidMessageFormat,
17
- GraphQlClientInvalidResponseError,
17
+ GraphQLClientInvalidResponseError,
18
18
  )
19
19
 
20
20
  try:
21
- from websockets.client import WebSocketClientProtocol
22
- from websockets.client import connect as ws_connect
23
- from websockets.typing import Data, Origin, Subprotocol
21
+ from websockets.client import ( # type: ignore[import-not-found,unused-ignore]
22
+ WebSocketClientProtocol,
23
+ connect as ws_connect,
24
+ )
25
+ from websockets.typing import ( # type: ignore[import-not-found,unused-ignore]
26
+ Data,
27
+ Origin,
28
+ Subprotocol,
29
+ )
24
30
  except ImportError:
25
31
  from contextlib import asynccontextmanager
26
32
 
@@ -29,10 +35,12 @@ except ImportError:
29
35
  raise NotImplementedError("Subscriptions require 'websockets' package.")
30
36
  yield # pylint: disable=unreachable
31
37
 
32
- WebSocketClientProtocol = Any # type: ignore
33
- Data = Any # type: ignore
34
- Origin = Any # type: ignore
35
- Subprotocol = Any # type: ignore
38
+ WebSocketClientProtocol = Any # type: ignore[misc,assignment,unused-ignore]
39
+ Data = Any # type: ignore[misc,assignment,unused-ignore]
40
+ Origin = Any # type: ignore[misc,assignment,unused-ignore]
41
+
42
+ def Subprotocol(*args, **kwargs): # type: ignore # pylint: disable=invalid-name
43
+ raise NotImplementedError("Subscriptions require 'websockets' package.")
36
44
 
37
45
 
38
46
  Self = TypeVar("Self", bound="AsyncBaseClient")
@@ -67,6 +75,7 @@ class AsyncBaseClient:
67
75
  self.http_client = (
68
76
  http_client if http_client else httpx.AsyncClient(headers=headers)
69
77
  )
78
+
70
79
  self.ws_url = ws_url
71
80
  self.ws_headers = ws_headers or {}
72
81
  self.ws_origin = Origin(ws_origin) if ws_origin else None
@@ -84,13 +93,30 @@ class AsyncBaseClient:
84
93
  await self.http_client.aclose()
85
94
 
86
95
  async def execute(
87
- self, query: str, variables: Optional[Dict[str, Any]] = None
96
+ self,
97
+ query: str,
98
+ operation_name: Optional[str] = None,
99
+ variables: Optional[Dict[str, Any]] = None,
100
+ **kwargs: Any,
88
101
  ) -> httpx.Response:
89
- payload: Dict[str, Any] = {"query": query}
90
- if variables:
91
- payload["variables"] = self._convert_dict_to_json_serializable(variables)
92
- content = json.dumps(payload, default=pydantic_encoder)
93
- return await self.http_client.post(url=self.url, content=content)
102
+ processed_variables, files, files_map = self._process_variables(variables)
103
+
104
+ if files and files_map:
105
+ return await self._execute_multipart(
106
+ query=query,
107
+ operation_name=operation_name,
108
+ variables=processed_variables,
109
+ files=files,
110
+ files_map=files_map,
111
+ **kwargs,
112
+ )
113
+
114
+ return await self._execute_json(
115
+ query=query,
116
+ operation_name=operation_name,
117
+ variables=processed_variables,
118
+ **kwargs,
119
+ )
94
120
 
95
121
  def get_data(self, response: httpx.Response) -> Dict[str, Any]:
96
122
  if not response.is_success:
@@ -101,12 +127,14 @@ class AsyncBaseClient:
101
127
  try:
102
128
  response_json = response.json()
103
129
  except ValueError as exc:
104
- raise GraphQlClientInvalidResponseError(response=response) from exc
130
+ raise GraphQLClientInvalidResponseError(response=response) from exc
105
131
 
106
- if (not isinstance(response_json, dict)) or ("data" not in response_json):
107
- raise GraphQlClientInvalidResponseError(response=response)
132
+ if (not isinstance(response_json, dict)) or (
133
+ "data" not in response_json and "errors" not in response_json
134
+ ):
135
+ raise GraphQLClientInvalidResponseError(response=response)
108
136
 
109
- data = response_json["data"]
137
+ data = response_json.get("data")
110
138
  errors = response_json.get("errors")
111
139
 
112
140
  if errors:
@@ -114,23 +142,40 @@ class AsyncBaseClient:
114
142
  errors_dicts=errors, data=data
115
143
  )
116
144
 
117
- return cast(dict[str, Any], data)
145
+ return cast(Dict[str, Any], data)
118
146
 
119
147
  async def execute_ws(
120
- self, query: str, variables: Optional[Dict[str, Any]] = None
148
+ self,
149
+ query: str,
150
+ operation_name: Optional[str] = None,
151
+ variables: Optional[Dict[str, Any]] = None,
152
+ **kwargs: Any,
121
153
  ) -> AsyncIterator[Dict[str, Any]]:
154
+ headers = self.ws_headers.copy()
155
+ headers.update(kwargs.get("extra_headers", {}))
156
+
157
+ merged_kwargs: Dict[str, Any] = {"origin": self.ws_origin}
158
+ merged_kwargs.update(kwargs)
159
+ merged_kwargs["extra_headers"] = headers
160
+
122
161
  operation_id = str(uuid4())
123
162
  async with ws_connect(
124
163
  self.ws_url,
125
164
  subprotocols=[Subprotocol(GRAPHQL_TRANSPORT_WS)],
126
- origin=self.ws_origin,
127
- extra_headers=self.ws_headers,
165
+ **merged_kwargs,
128
166
  ) as websocket:
129
167
  await self._send_connection_init(websocket)
168
+ # wait for connection_ack from server
169
+ await self._handle_ws_message(
170
+ await websocket.recv(),
171
+ websocket,
172
+ expected_type=GraphQLTransportWSMessageType.CONNECTION_ACK,
173
+ )
130
174
  await self._send_subscribe(
131
175
  websocket,
132
176
  operation_id=operation_id,
133
177
  query=query,
178
+ operation_name=operation_name,
134
179
  variables=variables,
135
180
  )
136
181
 
@@ -139,6 +184,17 @@ class AsyncBaseClient:
139
184
  if data:
140
185
  yield data
141
186
 
187
+ def _process_variables(
188
+ self, variables: Optional[Dict[str, Any]]
189
+ ) -> Tuple[
190
+ Dict[str, Any], Dict[str, Tuple[str, IO[bytes], str]], Dict[str, List[str]]
191
+ ]:
192
+ if not variables:
193
+ return {}, {}, {}
194
+
195
+ serializable_variables = self._convert_dict_to_json_serializable(variables)
196
+ return self._get_files_from_variables(serializable_variables)
197
+
142
198
  def _convert_dict_to_json_serializable(
143
199
  self, dict_: Dict[str, Any]
144
200
  ) -> Dict[str, Any]:
@@ -150,11 +206,104 @@ class AsyncBaseClient:
150
206
 
151
207
  def _convert_value(self, value: Any) -> Any:
152
208
  if isinstance(value, BaseModel):
153
- return value.dict(by_alias=True, exclude_unset=True)
209
+ return value.model_dump(by_alias=True, exclude_unset=True)
154
210
  if isinstance(value, list):
155
211
  return [self._convert_value(item) for item in value]
156
212
  return value
157
213
 
214
+ def _get_files_from_variables(
215
+ self, variables: Dict[str, Any]
216
+ ) -> Tuple[
217
+ Dict[str, Any], Dict[str, Tuple[str, IO[bytes], str]], Dict[str, List[str]]
218
+ ]:
219
+ files_map: Dict[str, List[str]] = {}
220
+ files_list: List[Upload] = []
221
+
222
+ def separate_files(path: str, obj: Any) -> Any:
223
+ if isinstance(obj, list):
224
+ nulled_list = []
225
+ for index, value in enumerate(obj):
226
+ value = separate_files(f"{path}.{index}", value)
227
+ nulled_list.append(value)
228
+ return nulled_list
229
+
230
+ if isinstance(obj, dict):
231
+ nulled_dict = {}
232
+ for key, value in obj.items():
233
+ value = separate_files(f"{path}.{key}", value)
234
+ nulled_dict[key] = value
235
+ return nulled_dict
236
+
237
+ if isinstance(obj, Upload):
238
+ if obj in files_list:
239
+ file_index = files_list.index(obj)
240
+ files_map[str(file_index)].append(path)
241
+ else:
242
+ file_index = len(files_list)
243
+ files_list.append(obj)
244
+ files_map[str(file_index)] = [path]
245
+ return None
246
+
247
+ return obj
248
+
249
+ nulled_variables = separate_files("variables", variables)
250
+ files: Dict[str, Tuple[str, IO[bytes], str]] = {
251
+ str(i): (file_.filename, cast(IO[bytes], file_.content), file_.content_type)
252
+ for i, file_ in enumerate(files_list)
253
+ }
254
+ return nulled_variables, files, files_map
255
+
256
+ async def _execute_multipart(
257
+ self,
258
+ query: str,
259
+ operation_name: Optional[str],
260
+ variables: Dict[str, Any],
261
+ files: Dict[str, Tuple[str, IO[bytes], str]],
262
+ files_map: Dict[str, List[str]],
263
+ **kwargs: Any,
264
+ ) -> httpx.Response:
265
+ data = {
266
+ "operations": json.dumps(
267
+ {
268
+ "query": query,
269
+ "operationName": operation_name,
270
+ "variables": variables,
271
+ },
272
+ default=to_jsonable_python,
273
+ ),
274
+ "map": json.dumps(files_map, default=to_jsonable_python),
275
+ }
276
+
277
+ return await self.http_client.post(
278
+ url=self.url, data=data, files=files, **kwargs
279
+ )
280
+
281
+ async def _execute_json(
282
+ self,
283
+ query: str,
284
+ operation_name: Optional[str],
285
+ variables: Dict[str, Any],
286
+ **kwargs: Any,
287
+ ) -> httpx.Response:
288
+ headers: Dict[str, str] = {"Content-Type": "application/json"}
289
+ headers.update(kwargs.get("headers", {}))
290
+
291
+ merged_kwargs: Dict[str, Any] = kwargs.copy()
292
+ merged_kwargs["headers"] = headers
293
+
294
+ return await self.http_client.post(
295
+ url=self.url,
296
+ content=json.dumps(
297
+ {
298
+ "query": query,
299
+ "operationName": operation_name,
300
+ "variables": variables,
301
+ },
302
+ default=to_jsonable_python,
303
+ ),
304
+ **merged_kwargs,
305
+ )
306
+
158
307
  async def _send_connection_init(self, websocket: WebSocketClientProtocol) -> None:
159
308
  payload: Dict[str, Any] = {
160
309
  "type": GraphQLTransportWSMessageType.CONNECTION_INIT.value
@@ -168,12 +317,13 @@ class AsyncBaseClient:
168
317
  websocket: WebSocketClientProtocol,
169
318
  operation_id: str,
170
319
  query: str,
320
+ operation_name: Optional[str] = None,
171
321
  variables: Optional[Dict[str, Any]] = None,
172
322
  ) -> None:
173
323
  payload: Dict[str, Any] = {
174
324
  "id": operation_id,
175
325
  "type": GraphQLTransportWSMessageType.SUBSCRIBE.value,
176
- "payload": {"query": query},
326
+ "payload": {"query": query, "operationName": operation_name},
177
327
  }
178
328
  if variables:
179
329
  payload["payload"]["variables"] = self._convert_dict_to_json_serializable(
@@ -182,7 +332,10 @@ class AsyncBaseClient:
182
332
  await websocket.send(json.dumps(payload))
183
333
 
184
334
  async def _handle_ws_message(
185
- self, message: Data, websocket: WebSocketClientProtocol
335
+ self,
336
+ message: Data,
337
+ websocket: WebSocketClientProtocol,
338
+ expected_type: Optional[GraphQLTransportWSMessageType] = None,
186
339
  ) -> Optional[Dict[str, Any]]:
187
340
  try:
188
341
  message_dict = json.loads(message)
@@ -195,6 +348,11 @@ class AsyncBaseClient:
195
348
  if not type_ or type_ not in {t.value for t in GraphQLTransportWSMessageType}:
196
349
  raise GraphQLClientInvalidMessageFormat(message=message)
197
350
 
351
+ if expected_type and expected_type != type_:
352
+ raise GraphQLClientInvalidMessageFormat(
353
+ f"Invalid message received. Expected: {expected_type.value}"
354
+ )
355
+
198
356
  if type_ == GraphQLTransportWSMessageType.NEXT:
199
357
  if "data" not in payload:
200
358
  raise GraphQLClientInvalidMessageFormat(message=message)