eetlijst-python 0.0.1__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 (81) hide show
  1. eetlijst/__init__.py +3 -0
  2. eetlijst/eetlijst.py +37 -0
  3. eetlijst/exceptions.py +2 -0
  4. eetlijst/generated/__init__.py +1153 -0
  5. eetlijst/generated/all_attendances.py +13 -0
  6. eetlijst/generated/all_events.py +13 -0
  7. eetlijst/generated/all_expenses.py +13 -0
  8. eetlijst/generated/all_groups.py +27 -0
  9. eetlijst/generated/all_settlements.py +13 -0
  10. eetlijst/generated/all_users_in_group.py +20 -0
  11. eetlijst/generated/app_status.py +16 -0
  12. eetlijst/generated/async_base_client.py +393 -0
  13. eetlijst/generated/automatic_events.py +18 -0
  14. eetlijst/generated/base_model.py +28 -0
  15. eetlijst/generated/client.py +1748 -0
  16. eetlijst/generated/create_expense.py +15 -0
  17. eetlijst/generated/create_group.py +15 -0
  18. eetlijst/generated/create_list_item.py +15 -0
  19. eetlijst/generated/create_many_list_items.py +20 -0
  20. eetlijst/generated/create_settlement.py +15 -0
  21. eetlijst/generated/enums.py +555 -0
  22. eetlijst/generated/exceptions.py +83 -0
  23. eetlijst/generated/fragments.py +237 -0
  24. eetlijst/generated/get_attendance.py +17 -0
  25. eetlijst/generated/get_event.py +15 -0
  26. eetlijst/generated/get_group.py +20 -0
  27. eetlijst/generated/get_user.py +13 -0
  28. eetlijst/generated/get_user_in_group.py +20 -0
  29. eetlijst/generated/group_total_expense.py +45 -0
  30. eetlijst/generated/input_types.py +4702 -0
  31. eetlijst/generated/join_group.py +17 -0
  32. eetlijst/generated/list_items.py +13 -0
  33. eetlijst/generated/remove_account.py +16 -0
  34. eetlijst/generated/settle_unsettled_expenses.py +21 -0
  35. eetlijst/generated/settlement_expenses.py +13 -0
  36. eetlijst/generated/update_attendance.py +17 -0
  37. eetlijst/generated/update_event.py +15 -0
  38. eetlijst/generated/update_expense.py +20 -0
  39. eetlijst/generated/update_expense_distribution.py +23 -0
  40. eetlijst/generated/update_group.py +15 -0
  41. eetlijst/generated/update_list_item.py +15 -0
  42. eetlijst/generated/update_many_attendance.py +22 -0
  43. eetlijst/generated/update_user.py +15 -0
  44. eetlijst/generated/update_user_in_group.py +17 -0
  45. eetlijst/generated/update_users_in_group.py +25 -0
  46. eetlijst/services/__init__.py +9 -0
  47. eetlijst/services/app/__init__.py +1 -0
  48. eetlijst/services/app/app.py +20 -0
  49. eetlijst/services/app/transformers.py +10 -0
  50. eetlijst/services/event_attendance/__init__.py +1 -0
  51. eetlijst/services/event_attendance/event_attendance.py +94 -0
  52. eetlijst/services/event_attendance/transformers.py +58 -0
  53. eetlijst/services/events/__init__.py +1 -0
  54. eetlijst/services/events/events.py +148 -0
  55. eetlijst/services/events/transformers.py +67 -0
  56. eetlijst/services/expenses/__init__.py +1 -0
  57. eetlijst/services/expenses/expenses.py +98 -0
  58. eetlijst/services/expenses/transformers.py +73 -0
  59. eetlijst/services/expenses/utils.py +31 -0
  60. eetlijst/services/group_list/__init__.py +1 -0
  61. eetlijst/services/group_list/group_list.py +95 -0
  62. eetlijst/services/group_list/transformers.py +38 -0
  63. eetlijst/services/group_users/__init__.py +1 -0
  64. eetlijst/services/group_users/group_users.py +130 -0
  65. eetlijst/services/group_users/transformers.py +84 -0
  66. eetlijst/services/groups/__init__.py +1 -0
  67. eetlijst/services/groups/groups.py +84 -0
  68. eetlijst/services/groups/transformers.py +140 -0
  69. eetlijst/services/settlements/__init__.py +1 -0
  70. eetlijst/services/settlements/settlements.py +225 -0
  71. eetlijst/services/settlements/transformers.py +95 -0
  72. eetlijst/services/settlements/utils.py +84 -0
  73. eetlijst/services/users/__init__.py +1 -0
  74. eetlijst/services/users/transformers.py +103 -0
  75. eetlijst/services/users/users.py +44 -0
  76. eetlijst/utils/__init__.py +0 -0
  77. eetlijst/utils/datetime.py +25 -0
  78. eetlijst_python-0.0.1.dist-info/METADATA +80 -0
  79. eetlijst_python-0.0.1.dist-info/RECORD +81 -0
  80. eetlijst_python-0.0.1.dist-info/WHEEL +5 -0
  81. eetlijst_python-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,13 @@
1
+ from .base_model import BaseModel
2
+ from .fragments import AttendanceFields
3
+
4
+
5
+ class AllAttendances(BaseModel):
6
+ eetschema_event_attendees: list["AllAttendancesEetschemaEventAttendees"]
7
+
8
+
9
+ class AllAttendancesEetschemaEventAttendees(AttendanceFields):
10
+ pass
11
+
12
+
13
+ AllAttendances.model_rebuild()
@@ -0,0 +1,13 @@
1
+ from .base_model import BaseModel
2
+ from .fragments import EventFields
3
+
4
+
5
+ class AllEvents(BaseModel):
6
+ eetschema_event: list["AllEventsEetschemaEvent"]
7
+
8
+
9
+ class AllEventsEetschemaEvent(EventFields):
10
+ pass
11
+
12
+
13
+ AllEvents.model_rebuild()
@@ -0,0 +1,13 @@
1
+ from .base_model import BaseModel
2
+ from .fragments import ExpenseFields
3
+
4
+
5
+ class AllExpenses(BaseModel):
6
+ eetschema_expense: list["AllExpensesEetschemaExpense"]
7
+
8
+
9
+ class AllExpensesEetschemaExpense(ExpenseFields):
10
+ pass
11
+
12
+
13
+ AllExpenses.model_rebuild()
@@ -0,0 +1,27 @@
1
+ from typing import Optional
2
+
3
+ from .base_model import BaseModel
4
+ from .fragments import GroupFields, UserInGroupFields
5
+
6
+
7
+ class AllGroups(BaseModel):
8
+ eetschema_users_in_group: list["AllGroupsEetschemaUsersInGroup"]
9
+
10
+
11
+ class AllGroupsEetschemaUsersInGroup(BaseModel):
12
+ group: "AllGroupsEetschemaUsersInGroupGroup"
13
+
14
+
15
+ class AllGroupsEetschemaUsersInGroupGroup(GroupFields):
16
+ users_in_groups: Optional[
17
+ list["AllGroupsEetschemaUsersInGroupGroupUsersInGroups"]
18
+ ] = None
19
+
20
+
21
+ class AllGroupsEetschemaUsersInGroupGroupUsersInGroups(UserInGroupFields):
22
+ pass
23
+
24
+
25
+ AllGroups.model_rebuild()
26
+ AllGroupsEetschemaUsersInGroup.model_rebuild()
27
+ AllGroupsEetschemaUsersInGroupGroup.model_rebuild()
@@ -0,0 +1,13 @@
1
+ from .base_model import BaseModel
2
+ from .fragments import SettlementFields
3
+
4
+
5
+ class AllSettlements(BaseModel):
6
+ eetschema_settlements: list["AllSettlementsEetschemaSettlements"]
7
+
8
+
9
+ class AllSettlementsEetschemaSettlements(SettlementFields):
10
+ pass
11
+
12
+
13
+ AllSettlements.model_rebuild()
@@ -0,0 +1,20 @@
1
+ from typing import Optional
2
+
3
+ from .base_model import BaseModel
4
+ from .fragments import UserInGroupFields
5
+
6
+
7
+ class AllUsersInGroup(BaseModel):
8
+ eetschema_group_by_pk: Optional["AllUsersInGroupEetschemaGroupByPk"]
9
+
10
+
11
+ class AllUsersInGroupEetschemaGroupByPk(BaseModel):
12
+ users_in_groups: list["AllUsersInGroupEetschemaGroupByPkUsersInGroups"]
13
+
14
+
15
+ class AllUsersInGroupEetschemaGroupByPkUsersInGroups(UserInGroupFields):
16
+ pass
17
+
18
+
19
+ AllUsersInGroup.model_rebuild()
20
+ AllUsersInGroupEetschemaGroupByPk.model_rebuild()
@@ -0,0 +1,16 @@
1
+ from datetime import datetime
2
+
3
+ from .base_model import BaseModel
4
+
5
+
6
+ class AppStatus(BaseModel):
7
+ eetschema_app_status: list["AppStatusEetschemaAppStatus"]
8
+
9
+
10
+ class AppStatusEetschemaAppStatus(BaseModel):
11
+ id: str
12
+ beta_online: bool
13
+ updated_at: datetime
14
+
15
+
16
+ AppStatus.model_rebuild()
@@ -0,0 +1,393 @@
1
+ import asyncio
2
+ import enum
3
+ import json
4
+ from collections.abc import AsyncIterator
5
+ from typing import IO, Any, Optional, TypeVar, cast
6
+ from uuid import uuid4
7
+
8
+ import httpx
9
+ from pydantic import BaseModel
10
+ from pydantic_core import to_jsonable_python
11
+
12
+ from .base_model import UNSET, Upload
13
+ from .exceptions import (
14
+ GraphQLClientError,
15
+ GraphQLClientGraphQLMultiError,
16
+ GraphQLClientHttpError,
17
+ GraphQLClientInvalidMessageFormat,
18
+ GraphQLClientInvalidResponseError,
19
+ )
20
+
21
+ try:
22
+ from websockets import ( # type: ignore[import-not-found,unused-ignore]
23
+ ClientConnection,
24
+ )
25
+ from websockets import ( # type: ignore[import-not-found,unused-ignore]
26
+ connect as ws_connect,
27
+ )
28
+ from websockets.typing import ( # type: ignore[import-not-found,unused-ignore]
29
+ Data,
30
+ Origin,
31
+ Subprotocol,
32
+ )
33
+ except ImportError:
34
+ from contextlib import asynccontextmanager
35
+
36
+ @asynccontextmanager # type: ignore
37
+ async def ws_connect(*args, **kwargs):
38
+ raise NotImplementedError("Subscriptions require 'websockets' package.")
39
+ yield
40
+
41
+ ClientConnection = Any # type: ignore[misc,assignment,unused-ignore]
42
+ Data = Any # type: ignore[misc,assignment,unused-ignore]
43
+ Origin = Any # type: ignore[misc,assignment,unused-ignore]
44
+
45
+ def Subprotocol(*args, **kwargs): # type: ignore # noqa: N802, N803
46
+ raise NotImplementedError("Subscriptions require 'websockets' package.")
47
+
48
+
49
+ Self = TypeVar("Self", bound="AsyncBaseClient")
50
+
51
+ GRAPHQL_TRANSPORT_WS = "graphql-transport-ws"
52
+
53
+
54
+ class GraphQLTransportWSMessageType(str, enum.Enum):
55
+ CONNECTION_INIT = "connection_init"
56
+ CONNECTION_ACK = "connection_ack"
57
+ PING = "ping"
58
+ PONG = "pong"
59
+ SUBSCRIBE = "subscribe"
60
+ NEXT = "next"
61
+ ERROR = "error"
62
+ COMPLETE = "complete"
63
+
64
+
65
+ class AsyncBaseClient:
66
+ def __init__(
67
+ self,
68
+ url: str = "",
69
+ headers: Optional[dict[str, str]] = None,
70
+ http_client: Optional[httpx.AsyncClient] = None,
71
+ ws_url: str = "",
72
+ ws_headers: Optional[dict[str, Any]] = None,
73
+ ws_origin: Optional[str] = None,
74
+ ws_connection_init_payload: Optional[dict[str, Any]] = None,
75
+ ) -> None:
76
+ self.url = url
77
+ self.headers = headers
78
+ self.http_client = (
79
+ http_client if http_client else httpx.AsyncClient(headers=headers)
80
+ )
81
+
82
+ self.ws_url = ws_url
83
+ self.ws_headers = ws_headers or {}
84
+ self.ws_origin = Origin(ws_origin) if ws_origin else None
85
+ self.ws_connection_init_payload = ws_connection_init_payload
86
+
87
+ async def __aenter__(self: Self) -> Self:
88
+ return self
89
+
90
+ async def __aexit__(
91
+ self,
92
+ exc_type: object,
93
+ exc_val: object,
94
+ exc_tb: object,
95
+ ) -> None:
96
+ await self.http_client.aclose()
97
+
98
+ async def execute(
99
+ self,
100
+ query: str,
101
+ operation_name: Optional[str] = None,
102
+ variables: Optional[dict[str, Any]] = None,
103
+ **kwargs: Any,
104
+ ) -> httpx.Response:
105
+ processed_variables, files, files_map = self._process_variables(variables)
106
+
107
+ if files and files_map:
108
+ return await self._execute_multipart(
109
+ query=query,
110
+ operation_name=operation_name,
111
+ variables=processed_variables,
112
+ files=files,
113
+ files_map=files_map,
114
+ **kwargs,
115
+ )
116
+
117
+ return await self._execute_json(
118
+ query=query,
119
+ operation_name=operation_name,
120
+ variables=processed_variables,
121
+ **kwargs,
122
+ )
123
+
124
+ def get_data(self, response: httpx.Response) -> dict[str, Any]:
125
+ if not response.is_success:
126
+ raise GraphQLClientHttpError(
127
+ status_code=response.status_code, response=response
128
+ )
129
+
130
+ try:
131
+ response_json = response.json()
132
+ except ValueError as exc:
133
+ raise GraphQLClientInvalidResponseError(response=response) from exc
134
+
135
+ if (not isinstance(response_json, dict)) or (
136
+ "data" not in response_json and "errors" not in response_json
137
+ ):
138
+ raise GraphQLClientInvalidResponseError(response=response)
139
+
140
+ data = response_json.get("data")
141
+ errors = response_json.get("errors")
142
+
143
+ if errors:
144
+ raise GraphQLClientGraphQLMultiError.from_errors_dicts(
145
+ errors_dicts=errors, data=data
146
+ )
147
+
148
+ return cast(dict[str, Any], data)
149
+
150
+ async def execute_ws(
151
+ self,
152
+ query: str,
153
+ operation_name: Optional[str] = None,
154
+ variables: Optional[dict[str, Any]] = None,
155
+ **kwargs: Any,
156
+ ) -> AsyncIterator[dict[str, Any]]:
157
+ headers = self.ws_headers.copy()
158
+ headers.update(kwargs.pop("additional_headers", {}))
159
+
160
+ merged_kwargs: dict[str, Any] = {"origin": self.ws_origin}
161
+ merged_kwargs.update(kwargs)
162
+ merged_kwargs["additional_headers"] = headers
163
+
164
+ operation_id = str(uuid4())
165
+ async with ws_connect(
166
+ self.ws_url,
167
+ subprotocols=[Subprotocol(GRAPHQL_TRANSPORT_WS)],
168
+ **merged_kwargs,
169
+ ) as websocket:
170
+ await self._send_connection_init(websocket)
171
+ # Wait for connection_ack; some servers (e.g. Hasura) send ping before
172
+ # connection_ack, so we loop and handle pings until we get ack.
173
+ try:
174
+ await asyncio.wait_for(
175
+ self._wait_for_connection_ack(websocket),
176
+ timeout=5.0,
177
+ )
178
+ except asyncio.TimeoutError as exc:
179
+ raise GraphQLClientError(
180
+ "Connection ack not received within 5 seconds"
181
+ ) from exc
182
+ await self._send_subscribe(
183
+ websocket,
184
+ operation_id=operation_id,
185
+ query=query,
186
+ operation_name=operation_name,
187
+ variables=variables,
188
+ )
189
+
190
+ async for message in websocket:
191
+ data = await self._handle_ws_message(message, websocket)
192
+ if data and "connection_ack" not in data:
193
+ yield data
194
+
195
+ def _process_variables(
196
+ self, variables: Optional[dict[str, Any]]
197
+ ) -> tuple[
198
+ dict[str, Any], dict[str, tuple[str, IO[bytes], str]], dict[str, list[str]]
199
+ ]:
200
+ if not variables:
201
+ return {}, {}, {}
202
+
203
+ serializable_variables = self._convert_dict_to_json_serializable(variables)
204
+ return self._get_files_from_variables(serializable_variables)
205
+
206
+ def _convert_dict_to_json_serializable(
207
+ self, dict_: dict[str, Any]
208
+ ) -> dict[str, Any]:
209
+ return {
210
+ key: self._convert_value(value)
211
+ for key, value in dict_.items()
212
+ if value is not UNSET
213
+ }
214
+
215
+ def _convert_value(self, value: Any) -> Any:
216
+ if isinstance(value, BaseModel):
217
+ return value.model_dump(by_alias=True, exclude_unset=True)
218
+ if isinstance(value, list):
219
+ return [self._convert_value(item) for item in value]
220
+ return value
221
+
222
+ def _get_files_from_variables(
223
+ self, variables: dict[str, Any]
224
+ ) -> tuple[
225
+ dict[str, Any], dict[str, tuple[str, IO[bytes], str]], dict[str, list[str]]
226
+ ]:
227
+ files_map: dict[str, list[str]] = {}
228
+ files_list: list[Upload] = []
229
+
230
+ def separate_files(path: str, obj: Any) -> Any:
231
+ if isinstance(obj, list):
232
+ nulled_list = []
233
+ for index, value in enumerate(obj):
234
+ value = separate_files(f"{path}.{index}", value)
235
+ nulled_list.append(value)
236
+ return nulled_list
237
+
238
+ if isinstance(obj, dict):
239
+ nulled_dict = {}
240
+ for key, value in obj.items():
241
+ value = separate_files(f"{path}.{key}", value)
242
+ nulled_dict[key] = value
243
+ return nulled_dict
244
+
245
+ if isinstance(obj, Upload):
246
+ if obj in files_list:
247
+ file_index = files_list.index(obj)
248
+ files_map[str(file_index)].append(path)
249
+ else:
250
+ file_index = len(files_list)
251
+ files_list.append(obj)
252
+ files_map[str(file_index)] = [path]
253
+ return None
254
+
255
+ return obj
256
+
257
+ nulled_variables = separate_files("variables", variables)
258
+ files: dict[str, tuple[str, IO[bytes], str]] = {
259
+ str(i): (file_.filename, cast(IO[bytes], file_.content), file_.content_type)
260
+ for i, file_ in enumerate(files_list)
261
+ }
262
+ return nulled_variables, files, files_map
263
+
264
+ async def _execute_multipart(
265
+ self,
266
+ query: str,
267
+ operation_name: Optional[str],
268
+ variables: dict[str, Any],
269
+ files: dict[str, tuple[str, IO[bytes], str]],
270
+ files_map: dict[str, list[str]],
271
+ **kwargs: Any,
272
+ ) -> httpx.Response:
273
+ data = {
274
+ "operations": json.dumps(
275
+ {
276
+ "query": query,
277
+ "operationName": operation_name,
278
+ "variables": variables,
279
+ },
280
+ default=to_jsonable_python,
281
+ ),
282
+ "map": json.dumps(files_map, default=to_jsonable_python),
283
+ }
284
+
285
+ return await self.http_client.post(
286
+ url=self.url, data=data, files=files, **kwargs
287
+ )
288
+
289
+ async def _execute_json(
290
+ self,
291
+ query: str,
292
+ operation_name: Optional[str],
293
+ variables: dict[str, Any],
294
+ **kwargs: Any,
295
+ ) -> httpx.Response:
296
+ headers: dict[str, str] = {"Content-type": "application/json"}
297
+ headers.update(kwargs.get("headers", {}))
298
+
299
+ merged_kwargs: dict[str, Any] = kwargs.copy()
300
+ merged_kwargs["headers"] = headers
301
+
302
+ return await self.http_client.post(
303
+ url=self.url,
304
+ content=json.dumps(
305
+ {
306
+ "query": query,
307
+ "operationName": operation_name,
308
+ "variables": variables,
309
+ },
310
+ default=to_jsonable_python,
311
+ ),
312
+ **merged_kwargs,
313
+ )
314
+
315
+ async def _send_connection_init(self, websocket: ClientConnection) -> None:
316
+ payload: dict[str, Any] = {
317
+ "type": GraphQLTransportWSMessageType.CONNECTION_INIT.value
318
+ }
319
+ if self.ws_connection_init_payload:
320
+ payload["payload"] = self.ws_connection_init_payload
321
+ await websocket.send(json.dumps(payload))
322
+
323
+ async def _wait_for_connection_ack(self, websocket: ClientConnection) -> None:
324
+ """Read messages until connection_ack; handle ping/pong in between."""
325
+ async for message in websocket:
326
+ data = await self._handle_ws_message(message, websocket)
327
+ if data is not None and "connection_ack" in data:
328
+ return
329
+
330
+ async def _send_subscribe(
331
+ self,
332
+ websocket: ClientConnection,
333
+ operation_id: str,
334
+ query: str,
335
+ operation_name: Optional[str] = None,
336
+ variables: Optional[dict[str, Any]] = None,
337
+ ) -> None:
338
+ payload_inner: dict[str, Any] = {
339
+ "query": query,
340
+ "operationName": operation_name,
341
+ }
342
+ if variables:
343
+ payload_inner["variables"] = self._convert_dict_to_json_serializable(
344
+ variables
345
+ )
346
+ payload: dict[str, Any] = {
347
+ "id": operation_id,
348
+ "type": GraphQLTransportWSMessageType.SUBSCRIBE.value,
349
+ "payload": payload_inner,
350
+ }
351
+ await websocket.send(json.dumps(payload))
352
+
353
+ async def _handle_ws_message(
354
+ self,
355
+ message: Data,
356
+ websocket: ClientConnection,
357
+ expected_type: Optional[GraphQLTransportWSMessageType] = None,
358
+ ) -> Optional[dict[str, Any]]:
359
+ try:
360
+ message_dict = json.loads(message)
361
+ except json.JSONDecodeError as exc:
362
+ raise GraphQLClientInvalidMessageFormat(message=message) from exc
363
+
364
+ type_ = message_dict.get("type")
365
+ payload = message_dict.get("payload", {})
366
+
367
+ if not type_ or type_ not in {t.value for t in GraphQLTransportWSMessageType}:
368
+ raise GraphQLClientInvalidMessageFormat(message=message)
369
+
370
+ if expected_type and expected_type != type_:
371
+ raise GraphQLClientInvalidMessageFormat(
372
+ f"Invalid message received. Expected: {expected_type.value}"
373
+ )
374
+
375
+ if type_ == GraphQLTransportWSMessageType.NEXT:
376
+ if "data" not in payload:
377
+ raise GraphQLClientInvalidMessageFormat(message=message)
378
+ return cast(dict[str, Any], payload["data"])
379
+
380
+ if type_ == GraphQLTransportWSMessageType.COMPLETE:
381
+ await websocket.close()
382
+ elif type_ == GraphQLTransportWSMessageType.PING:
383
+ await websocket.send(
384
+ json.dumps({"type": GraphQLTransportWSMessageType.PONG.value})
385
+ )
386
+ elif type_ == GraphQLTransportWSMessageType.ERROR:
387
+ raise GraphQLClientGraphQLMultiError.from_errors_dicts(
388
+ errors_dicts=payload, data=message_dict
389
+ )
390
+ elif type_ == GraphQLTransportWSMessageType.CONNECTION_ACK:
391
+ return {"connection_ack": True}
392
+
393
+ return None
@@ -0,0 +1,18 @@
1
+ from typing import Optional
2
+
3
+ from pydantic import Field
4
+
5
+ from .base_model import BaseModel
6
+
7
+
8
+ class AutomaticEvents(BaseModel):
9
+ query_todays_events: Optional["AutomaticEventsQueryTodaysEvents"] = Field(
10
+ alias="queryTodaysEvents"
11
+ )
12
+
13
+
14
+ class AutomaticEventsQueryTodaysEvents(BaseModel):
15
+ id: Optional[str]
16
+
17
+
18
+ AutomaticEvents.model_rebuild()
@@ -0,0 +1,28 @@
1
+ from io import IOBase
2
+
3
+ from pydantic import BaseModel as PydanticBaseModel
4
+ from pydantic import ConfigDict
5
+
6
+
7
+ class UnsetType:
8
+ def __bool__(self) -> bool:
9
+ return False
10
+
11
+
12
+ UNSET = UnsetType()
13
+
14
+
15
+ class BaseModel(PydanticBaseModel):
16
+ model_config = ConfigDict(
17
+ populate_by_name=True,
18
+ validate_assignment=True,
19
+ arbitrary_types_allowed=True,
20
+ protected_namespaces=(),
21
+ )
22
+
23
+
24
+ class Upload:
25
+ def __init__(self, filename: str, content: IOBase, content_type: str):
26
+ self.filename = filename
27
+ self.content = content
28
+ self.content_type = content_type