anaplan-sdk 0.5.0a1__py3-none-any.whl → 0.5.0a3__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.
- anaplan_sdk/_async_clients/_alm.py +24 -31
- anaplan_sdk/_async_clients/_audit.py +7 -9
- anaplan_sdk/_async_clients/_bulk.py +141 -88
- anaplan_sdk/_async_clients/_cloud_works.py +36 -34
- anaplan_sdk/_async_clients/_cw_flow.py +13 -15
- anaplan_sdk/_async_clients/_transactional.py +62 -42
- anaplan_sdk/_clients/_alm.py +22 -31
- anaplan_sdk/_clients/_audit.py +7 -10
- anaplan_sdk/_clients/_bulk.py +78 -62
- anaplan_sdk/_clients/_cloud_works.py +33 -33
- anaplan_sdk/_clients/_cw_flow.py +11 -13
- anaplan_sdk/_clients/_transactional.py +42 -33
- anaplan_sdk/{_base.py → _services.py} +145 -87
- anaplan_sdk/models/__init__.py +2 -0
- anaplan_sdk/models/_bulk.py +2 -9
- anaplan_sdk/models/cloud_works.py +6 -2
- {anaplan_sdk-0.5.0a1.dist-info → anaplan_sdk-0.5.0a3.dist-info}/METADATA +2 -2
- anaplan_sdk-0.5.0a3.dist-info/RECORD +30 -0
- anaplan_sdk-0.5.0a1.dist-info/RECORD +0 -30
- {anaplan_sdk-0.5.0a1.dist-info → anaplan_sdk-0.5.0a3.dist-info}/WHEEL +0 -0
- {anaplan_sdk-0.5.0a1.dist-info → anaplan_sdk-0.5.0a3.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
import logging
|
2
|
-
from asyncio import gather
|
2
|
+
from asyncio import gather
|
3
3
|
from copy import copy
|
4
|
-
from typing import AsyncIterator, Iterator
|
4
|
+
from typing import AsyncIterator, Iterator, Literal
|
5
5
|
|
6
6
|
import httpx
|
7
7
|
from typing_extensions import Self
|
8
8
|
|
9
9
|
from anaplan_sdk._auth import _create_auth
|
10
|
-
from anaplan_sdk.
|
10
|
+
from anaplan_sdk._services import _AsyncHttpService, action_url, sort_params
|
11
11
|
from anaplan_sdk.exceptions import AnaplanActionError, InvalidIdentifierException
|
12
12
|
from anaplan_sdk.models import (
|
13
13
|
Action,
|
@@ -30,7 +30,7 @@ from ._transactional import _AsyncTransactionalClient
|
|
30
30
|
logger = logging.getLogger("anaplan_sdk")
|
31
31
|
|
32
32
|
|
33
|
-
class AsyncClient
|
33
|
+
class AsyncClient:
|
34
34
|
"""
|
35
35
|
Asynchronous Anaplan Client. For guides and examples
|
36
36
|
refer to https://vinzenzklass.github.io/anaplan-sdk.
|
@@ -49,9 +49,13 @@ class AsyncClient(_AsyncBaseClient):
|
|
49
49
|
auth: httpx.Auth | None = None,
|
50
50
|
timeout: float | httpx.Timeout = 30,
|
51
51
|
retry_count: int = 2,
|
52
|
+
backoff: float = 1.0,
|
53
|
+
backoff_factor: float = 2.0,
|
54
|
+
page_size: int = 5_000,
|
52
55
|
status_poll_delay: int = 1,
|
53
56
|
upload_chunk_size: int = 25_000_000,
|
54
57
|
allow_file_creation: bool = False,
|
58
|
+
**httpx_kwargs,
|
55
59
|
) -> None:
|
56
60
|
"""
|
57
61
|
Asynchronous Anaplan Client. For guides and examples
|
@@ -84,6 +88,14 @@ class AsyncClient(_AsyncBaseClient):
|
|
84
88
|
:param retry_count: The number of times to retry an HTTP request if it fails. Set this to 0
|
85
89
|
to never retry. Defaults to 2, meaning each HTTP Operation will be tried a total
|
86
90
|
number of 2 times.
|
91
|
+
:param backoff: The initial backoff time in seconds for the retry mechanism. This is the
|
92
|
+
time to wait before the first retry.
|
93
|
+
:param backoff_factor: The factor by which the backoff time is multiplied after each retry.
|
94
|
+
For example, if the initial backoff is 1 second and the factor is 2, the second
|
95
|
+
retry will wait 2 seconds, the third retry will wait 4 seconds, and so on.
|
96
|
+
:param page_size: The number of items to return per page when paginating through results.
|
97
|
+
Defaults to 5000. This is the maximum number of items that can be returned per
|
98
|
+
request. If you pass a value greater than 5000, it will be capped to 5000.
|
87
99
|
:param status_poll_delay: The delay between polling the status of a task.
|
88
100
|
:param upload_chunk_size: The size of the chunks to upload. This is the maximum size of
|
89
101
|
each chunk. Defaults to 25MB.
|
@@ -92,39 +104,41 @@ class AsyncClient(_AsyncBaseClient):
|
|
92
104
|
altogether. A file that is created this way will not be referenced by any action in
|
93
105
|
anaplan until manually assigned so there is typically no value in dynamically
|
94
106
|
creating new files and uploading content to them.
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
:param httpx_kwargs: Additional keyword arguments to pass to the `httpx.AsyncClient`.
|
108
|
+
This can be used to set additional options such as proxies, headers, etc. See
|
109
|
+
https://www.python-httpx.org/api/#asyncclient for the full list of arguments.
|
110
|
+
"""
|
111
|
+
_auth = auth or _create_auth(
|
112
|
+
token=token,
|
113
|
+
user_email=user_email,
|
114
|
+
password=password,
|
115
|
+
certificate=certificate,
|
116
|
+
private_key=private_key,
|
117
|
+
private_key_password=private_key_password,
|
118
|
+
)
|
119
|
+
_client = httpx.AsyncClient(auth=_auth, timeout=timeout, **httpx_kwargs)
|
120
|
+
self._http = _AsyncHttpService(
|
121
|
+
_client,
|
122
|
+
retry_count=retry_count,
|
123
|
+
backoff=backoff,
|
124
|
+
backoff_factor=backoff_factor,
|
125
|
+
page_size=page_size,
|
126
|
+
poll_delay=status_poll_delay,
|
109
127
|
)
|
110
128
|
self._workspace_id = workspace_id
|
111
129
|
self._model_id = model_id
|
112
|
-
self._retry_count = retry_count
|
113
130
|
self._url = f"https://api.anaplan.com/2/0/workspaces/{workspace_id}/models/{model_id}"
|
114
131
|
self._transactional_client = (
|
115
|
-
_AsyncTransactionalClient(
|
116
|
-
)
|
117
|
-
self._alm_client = (
|
118
|
-
_AsyncAlmClient(_client, model_id, self._retry_count, status_poll_delay)
|
119
|
-
if model_id
|
120
|
-
else None
|
132
|
+
_AsyncTransactionalClient(self._http, model_id) if model_id else None
|
121
133
|
)
|
122
|
-
self.
|
123
|
-
self.
|
124
|
-
self.
|
134
|
+
self._alm_client = _AsyncAlmClient(self._http, model_id) if model_id else None
|
135
|
+
self._audit = _AsyncAuditClient(self._http)
|
136
|
+
self._cloud_works = _AsyncCloudWorksClient(self._http)
|
125
137
|
self.upload_chunk_size = upload_chunk_size
|
126
138
|
self.allow_file_creation = allow_file_creation
|
127
|
-
|
139
|
+
logger.debug(
|
140
|
+
f"Initialized AsyncClient with workspace_id={workspace_id}, model_id={model_id}"
|
141
|
+
)
|
128
142
|
|
129
143
|
@classmethod
|
130
144
|
def from_existing(
|
@@ -152,12 +166,8 @@ class AsyncClient(_AsyncBaseClient):
|
|
152
166
|
f"with workspace_id={new_ws_id}, model_id={new_model_id}."
|
153
167
|
)
|
154
168
|
client._url = f"https://api.anaplan.com/2/0/workspaces/{new_ws_id}/models/{new_model_id}"
|
155
|
-
client._transactional_client = _AsyncTransactionalClient(
|
156
|
-
|
157
|
-
)
|
158
|
-
client._alm_client = _AsyncAlmClient(
|
159
|
-
existing._client, new_model_id, existing._retry_count, existing.status_poll_delay
|
160
|
-
)
|
169
|
+
client._transactional_client = _AsyncTransactionalClient(existing._http, new_model_id)
|
170
|
+
client._alm_client = _AsyncAlmClient(existing._http, new_model_id)
|
161
171
|
return client
|
162
172
|
|
163
173
|
@property
|
@@ -177,14 +187,14 @@ class AsyncClient(_AsyncBaseClient):
|
|
177
187
|
return self._cloud_works
|
178
188
|
|
179
189
|
@property
|
180
|
-
def
|
190
|
+
def tr(self) -> _AsyncTransactionalClient:
|
181
191
|
"""
|
182
192
|
The Transactional Client provides access to the Anaplan Transactional API. This is useful
|
183
193
|
for more advanced use cases where you need to interact with the Anaplan Model in a more
|
184
194
|
granular way.
|
185
195
|
|
186
196
|
If you instantiated the client without the field `model_id`, this will raise a
|
187
|
-
|
197
|
+
`ValueError`, since none of the endpoints can be invoked without the model Id.
|
188
198
|
:return: The Transactional Client.
|
189
199
|
"""
|
190
200
|
if not self._transactional_client:
|
@@ -215,40 +225,54 @@ class AsyncClient(_AsyncBaseClient):
|
|
215
225
|
)
|
216
226
|
return self._alm_client
|
217
227
|
|
218
|
-
async def get_workspaces(
|
228
|
+
async def get_workspaces(
|
229
|
+
self,
|
230
|
+
search_pattern: str | None = None,
|
231
|
+
sort_by: Literal["size_allowance", "name"] = "name",
|
232
|
+
descending: bool = False,
|
233
|
+
) -> list[Workspace]:
|
219
234
|
"""
|
220
235
|
Lists all the Workspaces the authenticated user has access to.
|
221
236
|
:param search_pattern: Optionally filter for specific workspaces. When provided,
|
222
237
|
case-insensitive matches workspaces with names containing this string.
|
223
238
|
You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
|
224
239
|
When None (default), returns all users.
|
240
|
+
:param sort_by: The field to sort the results by.
|
241
|
+
:param descending: If True, the results will be sorted in descending order.
|
225
242
|
:return: The List of Workspaces.
|
226
243
|
"""
|
227
|
-
params = {"tenantDetails": "true"}
|
244
|
+
params = {"tenantDetails": "true"} | sort_params(sort_by, descending)
|
228
245
|
if search_pattern:
|
229
246
|
params["s"] = search_pattern
|
230
247
|
return [
|
231
248
|
Workspace.model_validate(e)
|
232
|
-
for e in await self.
|
249
|
+
for e in await self._http.get_paginated(
|
233
250
|
"https://api.anaplan.com/2/0/workspaces", "workspaces", params=params
|
234
251
|
)
|
235
252
|
]
|
236
253
|
|
237
|
-
async def get_models(
|
254
|
+
async def get_models(
|
255
|
+
self,
|
256
|
+
search_pattern: str | None = None,
|
257
|
+
sort_by: Literal["active_state", "name"] = "name",
|
258
|
+
descending: bool = False,
|
259
|
+
) -> list[Model]:
|
238
260
|
"""
|
239
261
|
Lists all the Models the authenticated user has access to.
|
240
262
|
:param search_pattern: Optionally filter for specific models. When provided,
|
241
263
|
case-insensitive matches model names containing this string.
|
242
264
|
You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
|
243
265
|
When None (default), returns all models.
|
266
|
+
:param sort_by: The field to sort the results by.
|
267
|
+
:param descending: If True, the results will be sorted in descending order.
|
244
268
|
:return: The List of Models.
|
245
269
|
"""
|
246
|
-
params = {"modelDetails": "true"}
|
270
|
+
params = {"modelDetails": "true"} | sort_params(sort_by, descending)
|
247
271
|
if search_pattern:
|
248
272
|
params["s"] = search_pattern
|
249
273
|
return [
|
250
274
|
Model.model_validate(e)
|
251
|
-
for e in await self.
|
275
|
+
for e in await self._http.get_paginated(
|
252
276
|
"https://api.anaplan.com/2/0/models", "models", params=params
|
253
277
|
)
|
254
278
|
]
|
@@ -261,62 +285,83 @@ class AsyncClient(_AsyncBaseClient):
|
|
261
285
|
:return:
|
262
286
|
"""
|
263
287
|
logger.info(f"Deleting Models: {', '.join(model_ids)}.")
|
264
|
-
res = await self.
|
288
|
+
res = await self._http.post(
|
265
289
|
f"https://api.anaplan.com/2/0/workspaces/{self._workspace_id}/bulkDeleteModels",
|
266
290
|
json={"modelIdsToDelete": model_ids},
|
267
291
|
)
|
268
292
|
return ModelDeletionResult.model_validate(res)
|
269
293
|
|
270
|
-
async def get_files(
|
294
|
+
async def get_files(
|
295
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
296
|
+
) -> list[File]:
|
271
297
|
"""
|
272
298
|
Lists all the Files in the Model.
|
299
|
+
:param sort_by: The field to sort the results by.
|
300
|
+
:param descending: If True, the results will be sorted in descending order.
|
273
301
|
:return: The List of Files.
|
274
302
|
"""
|
275
|
-
|
276
|
-
|
277
|
-
|
303
|
+
res = await self._http.get_paginated(
|
304
|
+
f"{self._url}/files", "files", params=sort_params(sort_by, descending)
|
305
|
+
)
|
306
|
+
return [File.model_validate(e) for e in res]
|
278
307
|
|
279
|
-
async def get_actions(
|
308
|
+
async def get_actions(
|
309
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
310
|
+
) -> list[Action]:
|
280
311
|
"""
|
281
312
|
Lists all the Actions in the Model. This will only return the Actions listed under
|
282
313
|
`Other Actions` in Anaplan. For Imports, exports, and processes, see their respective
|
283
314
|
methods instead.
|
315
|
+
:param sort_by: The field to sort the results by.
|
316
|
+
:param descending: If True, the results will be sorted in descending order.
|
284
317
|
:return: The List of Actions.
|
285
318
|
"""
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
]
|
319
|
+
res = await self._http.get_paginated(
|
320
|
+
f"{self._url}/actions", "actions", params=sort_params(sort_by, descending)
|
321
|
+
)
|
322
|
+
return [Action.model_validate(e) for e in res]
|
290
323
|
|
291
|
-
async def get_processes(
|
324
|
+
async def get_processes(
|
325
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
326
|
+
) -> list[Process]:
|
292
327
|
"""
|
293
328
|
Lists all the Processes in the Model.
|
329
|
+
:param sort_by: The field to sort the results by.
|
330
|
+
:param descending: If True, the results will be sorted in descending order.
|
294
331
|
:return: The List of Processes.
|
295
332
|
"""
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
]
|
333
|
+
res = await self._http.get_paginated(
|
334
|
+
f"{self._url}/processes", "processes", params=sort_params(sort_by, descending)
|
335
|
+
)
|
336
|
+
return [Process.model_validate(e) for e in res]
|
300
337
|
|
301
|
-
async def get_imports(
|
338
|
+
async def get_imports(
|
339
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
340
|
+
) -> list[Import]:
|
302
341
|
"""
|
303
342
|
Lists all the Imports in the Model.
|
343
|
+
:param sort_by: The field to sort the results by.
|
344
|
+
:param descending: If True, the results will be sorted in descending order.
|
304
345
|
:return: The List of Imports.
|
305
346
|
"""
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
]
|
347
|
+
res = await self._http.get_paginated(
|
348
|
+
f"{self._url}/imports", "imports", params=sort_params(sort_by, descending)
|
349
|
+
)
|
350
|
+
return [Import.model_validate(e) for e in res]
|
310
351
|
|
311
|
-
async def get_exports(
|
352
|
+
async def get_exports(
|
353
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
354
|
+
) -> list[Export]:
|
312
355
|
"""
|
313
356
|
Lists all the Exports in the Model.
|
357
|
+
:param sort_by: The field to sort the results by.
|
358
|
+
:param descending: If True, the results will be sorted in descending order.
|
314
359
|
:return: The List of Exports.
|
315
360
|
"""
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
]
|
361
|
+
res = await self._http.get_paginated(
|
362
|
+
f"{self._url}/exports", "exports", params=sort_params(sort_by, descending)
|
363
|
+
)
|
364
|
+
return [Export.model_validate(e) for e in res]
|
320
365
|
|
321
366
|
async def run_action(self, action_id: int, wait_for_completion: bool = True) -> TaskStatus:
|
322
367
|
"""
|
@@ -330,18 +375,17 @@ class AsyncClient(_AsyncBaseClient):
|
|
330
375
|
until the task is complete. If False, it will spawn the task and return immediately.
|
331
376
|
"""
|
332
377
|
body = {"localeName": "en_US"}
|
333
|
-
res = await self.
|
378
|
+
res = await self._http.post(
|
379
|
+
f"{self._url}/{action_url(action_id)}/{action_id}/tasks", json=body
|
380
|
+
)
|
334
381
|
task_id = res["task"]["taskId"]
|
335
382
|
logger.info(f"Invoked Action '{action_id}', spawned Task: '{task_id}'.")
|
336
383
|
|
337
384
|
if not wait_for_completion:
|
338
385
|
return TaskStatus.model_validate(await self.get_task_status(action_id, task_id))
|
339
|
-
|
340
|
-
while (status := await self.get_task_status(action_id, task_id)).task_state != "COMPLETE":
|
341
|
-
await sleep(self.status_poll_delay)
|
342
|
-
|
386
|
+
status = await self._http.poll_task(self.get_task_status, action_id, task_id)
|
343
387
|
if status.task_state == "COMPLETE" and not status.result.successful:
|
344
|
-
logger.error(f"Task '{task_id}' completed with errors
|
388
|
+
logger.error(f"Task '{task_id}' completed with errors.")
|
345
389
|
raise AnaplanActionError(f"Task '{task_id}' completed with errors.")
|
346
390
|
|
347
391
|
logger.info(f"Task '{task_id}' of '{action_id}' completed successfully.")
|
@@ -356,11 +400,11 @@ class AsyncClient(_AsyncBaseClient):
|
|
356
400
|
chunk_count = await self._file_pre_check(file_id)
|
357
401
|
logger.info(f"File {file_id} has {chunk_count} chunks.")
|
358
402
|
if chunk_count <= 1:
|
359
|
-
return await self.
|
403
|
+
return await self._http.get_binary(f"{self._url}/files/{file_id}")
|
360
404
|
return b"".join(
|
361
405
|
await gather(
|
362
406
|
*(
|
363
|
-
self.
|
407
|
+
self._http.get_binary(f"{self._url}/files/{file_id}/chunks/{i}")
|
364
408
|
for i in range(chunk_count)
|
365
409
|
)
|
366
410
|
)
|
@@ -380,13 +424,13 @@ class AsyncClient(_AsyncBaseClient):
|
|
380
424
|
chunk_count = await self._file_pre_check(file_id)
|
381
425
|
logger.info(f"File {file_id} has {chunk_count} chunks.")
|
382
426
|
if chunk_count <= 1:
|
383
|
-
yield await self.
|
427
|
+
yield await self._http.get_binary(f"{self._url}/files/{file_id}")
|
384
428
|
return
|
385
429
|
|
386
430
|
for batch_start in range(0, chunk_count, batch_size):
|
387
431
|
batch_chunks = await gather(
|
388
432
|
*(
|
389
|
-
self.
|
433
|
+
self._http.get_binary(f"{self._url}/files/{file_id}/chunks/{i}")
|
390
434
|
for i in range(batch_start, min(batch_start + batch_size, chunk_count))
|
391
435
|
)
|
392
436
|
)
|
@@ -462,21 +506,26 @@ class AsyncClient(_AsyncBaseClient):
|
|
462
506
|
logger.info(
|
463
507
|
f"Completed final upload stream batch of size {len(tasks)} for file {file_id}."
|
464
508
|
)
|
465
|
-
await self.
|
509
|
+
await self._http.post(f"{self._url}/files/{file_id}/complete", json={"id": file_id})
|
466
510
|
logger.info(f"Completed upload stream for '{file_id}'.")
|
467
511
|
|
468
|
-
async def upload_and_import(
|
512
|
+
async def upload_and_import(
|
513
|
+
self, file_id: int, content: str | bytes, action_id: int, wait_for_completion: bool = True
|
514
|
+
) -> TaskStatus:
|
469
515
|
"""
|
470
516
|
Convenience wrapper around `upload_file()` and `run_action()` to upload content to a file
|
471
517
|
and run an import action in one call.
|
472
518
|
:param file_id: The identifier of the file to upload to.
|
473
519
|
:param content: The content to upload. **This Content will be compressed before uploading.
|
474
|
-
|
475
|
-
|
520
|
+
If you are passing the Input as bytes, pass it uncompressed to avoid redundant
|
521
|
+
work.**
|
476
522
|
:param action_id: The identifier of the action to run after uploading the content.
|
523
|
+
:param wait_for_completion: If True, the method will poll the import task status and not
|
524
|
+
return until the task is complete. If False, it will spawn the import task and
|
525
|
+
return immediately.
|
477
526
|
"""
|
478
527
|
await self.upload_file(file_id, content)
|
479
|
-
await self.run_action(action_id)
|
528
|
+
return await self.run_action(action_id, wait_for_completion)
|
480
529
|
|
481
530
|
async def export_and_download(self, action_id: int) -> bytes:
|
482
531
|
"""
|
@@ -496,7 +545,7 @@ class AsyncClient(_AsyncBaseClient):
|
|
496
545
|
"""
|
497
546
|
return [
|
498
547
|
TaskSummary.model_validate(e)
|
499
|
-
for e in await self.
|
548
|
+
for e in await self._http.get_paginated(
|
500
549
|
f"{self._url}/{action_url(action_id)}/{action_id}/tasks", "tasks"
|
501
550
|
)
|
502
551
|
]
|
@@ -510,7 +559,9 @@ class AsyncClient(_AsyncBaseClient):
|
|
510
559
|
"""
|
511
560
|
return TaskStatus.model_validate(
|
512
561
|
(
|
513
|
-
await self.
|
562
|
+
await self._http.get(
|
563
|
+
f"{self._url}/{action_url(action_id)}/{action_id}/tasks/{task_id}"
|
564
|
+
)
|
514
565
|
).get("task")
|
515
566
|
)
|
516
567
|
|
@@ -521,7 +572,7 @@ class AsyncClient(_AsyncBaseClient):
|
|
521
572
|
:param task_id: The Task identifier, sometimes also referred to as the Correlation Id.
|
522
573
|
:return: The content of the solution logs.
|
523
574
|
"""
|
524
|
-
return await self.
|
575
|
+
return await self._http.get_binary(
|
525
576
|
f"{self._url}/optimizeActions/{action_id}/tasks/{task_id}/solutionLogs"
|
526
577
|
)
|
527
578
|
|
@@ -532,7 +583,7 @@ class AsyncClient(_AsyncBaseClient):
|
|
532
583
|
return file.chunk_count
|
533
584
|
|
534
585
|
async def _upload_chunk(self, file_id: int, index: int, chunk: str | bytes) -> None:
|
535
|
-
await self.
|
586
|
+
await self._http.put_binary_gzip(f"{self._url}/files/{file_id}/chunks/{index}", chunk)
|
536
587
|
logger.debug(f"Chunk {index} loaded to file '{file_id}'.")
|
537
588
|
|
538
589
|
async def _set_chunk_count(self, file_id: int, num_chunks: int) -> None:
|
@@ -542,7 +593,9 @@ class AsyncClient(_AsyncBaseClient):
|
|
542
593
|
"to avoid this error, set `allow_file_creation=True` on the calling instance. "
|
543
594
|
"Make sure you have understood the implications of this before doing so. "
|
544
595
|
)
|
545
|
-
response = await self.
|
596
|
+
response = await self._http.post(
|
597
|
+
f"{self._url}/files/{file_id}", json={"chunkCount": num_chunks}
|
598
|
+
)
|
546
599
|
optionally_new_file = int(response.get("file").get("id"))
|
547
600
|
if optionally_new_file != file_id:
|
548
601
|
if self.allow_file_creation:
|