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,10 +1,8 @@
|
|
1
1
|
import logging
|
2
2
|
from typing import Any, Literal
|
3
3
|
|
4
|
-
import
|
5
|
-
|
6
|
-
from anaplan_sdk._base import (
|
7
|
-
_AsyncBaseClient,
|
4
|
+
from anaplan_sdk._services import (
|
5
|
+
_AsyncHttpService,
|
8
6
|
connection_body_payload,
|
9
7
|
construct_payload,
|
10
8
|
integration_payload,
|
@@ -31,11 +29,11 @@ from ._cw_flow import _AsyncFlowClient
|
|
31
29
|
logger = logging.getLogger("anaplan_sdk")
|
32
30
|
|
33
31
|
|
34
|
-
class _AsyncCloudWorksClient
|
35
|
-
def __init__(self,
|
32
|
+
class _AsyncCloudWorksClient:
|
33
|
+
def __init__(self, http: _AsyncHttpService) -> None:
|
34
|
+
self._http = http
|
36
35
|
self._url = "https://api.cloudworks.anaplan.com/2/0/integrations"
|
37
|
-
self._flow = _AsyncFlowClient(
|
38
|
-
super().__init__(retry_count, client)
|
36
|
+
self._flow = _AsyncFlowClient(http)
|
39
37
|
|
40
38
|
@property
|
41
39
|
def flows(self) -> _AsyncFlowClient:
|
@@ -51,7 +49,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
51
49
|
"""
|
52
50
|
return [
|
53
51
|
Connection.model_validate(e)
|
54
|
-
for e in await self.
|
52
|
+
for e in await self._http.get_paginated(f"{self._url}/connections", "connections")
|
55
53
|
]
|
56
54
|
|
57
55
|
async def create_connection(self, con_info: ConnectionInput | dict[str, Any]) -> str:
|
@@ -62,7 +60,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
62
60
|
against the ConnectionInput model before sending the request.
|
63
61
|
:return: The ID of the new connection.
|
64
62
|
"""
|
65
|
-
res = await self.
|
63
|
+
res = await self._http.post(
|
66
64
|
f"{self._url}/connections", json=construct_payload(ConnectionInput, con_info)
|
67
65
|
)
|
68
66
|
connection_id = res["connections"]["connectionId"]
|
@@ -79,7 +77,9 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
79
77
|
as when initially creating the connection again. If you want to update only some of
|
80
78
|
the details, use the `patch_connection` method instead.
|
81
79
|
"""
|
82
|
-
await self.
|
80
|
+
await self._http.put(
|
81
|
+
f"{self._url}/connections/{con_id}", json=connection_body_payload(con_info)
|
82
|
+
)
|
83
83
|
|
84
84
|
async def patch_connection(self, con_id: str, body: dict[str, Any]) -> None:
|
85
85
|
"""
|
@@ -88,14 +88,14 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
88
88
|
:param body: The name and details of the connection. You can pass all the same details as
|
89
89
|
when initially creating the connection again, or just any one of them.
|
90
90
|
"""
|
91
|
-
await self.
|
91
|
+
await self._http.patch(f"{self._url}/connections/{con_id}", json=body)
|
92
92
|
|
93
93
|
async def delete_connection(self, con_id: str) -> None:
|
94
94
|
"""
|
95
95
|
Delete an existing connection in CloudWorks.
|
96
96
|
:param con_id: The ID of the connection to delete.
|
97
97
|
"""
|
98
|
-
await self.
|
98
|
+
await self._http.delete(f"{self._url}/connections/{con_id}")
|
99
99
|
logger.info(f"Deleted connection '{con_id}'.")
|
100
100
|
|
101
101
|
async def get_integrations(
|
@@ -109,7 +109,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
109
109
|
params = {"sortBy": "name" if sort_by_name == "ascending" else "-name"}
|
110
110
|
return [
|
111
111
|
Integration.model_validate(e)
|
112
|
-
for e in await self.
|
112
|
+
for e in await self._http.get_paginated(f"{self._url}", "integrations", params=params)
|
113
113
|
]
|
114
114
|
|
115
115
|
async def get_integration(self, integration_id: str) -> SingleIntegration:
|
@@ -122,7 +122,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
122
122
|
:return: The details of the integration, without the integration type.
|
123
123
|
"""
|
124
124
|
return SingleIntegration.model_validate(
|
125
|
-
(await self.
|
125
|
+
(await self._http.get(f"{self._url}/{integration_id}"))["integration"]
|
126
126
|
)
|
127
127
|
|
128
128
|
async def create_integration(
|
@@ -149,7 +149,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
149
149
|
:return: The ID of the new integration.
|
150
150
|
"""
|
151
151
|
json = integration_payload(body)
|
152
|
-
res = await self.
|
152
|
+
res = await self._http.post(f"{self._url}", json=json)
|
153
153
|
integration_id = res["integration"]["integrationId"]
|
154
154
|
logger.info(f"Created integration '{integration_id}'.")
|
155
155
|
return integration_id
|
@@ -165,7 +165,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
165
165
|
of the details, use the `patch_integration` method instead.
|
166
166
|
"""
|
167
167
|
json = integration_payload(body)
|
168
|
-
await self.
|
168
|
+
await self._http.put(f"{self._url}/{integration_id}", json=json)
|
169
169
|
|
170
170
|
async def run_integration(self, integration_id: str) -> str:
|
171
171
|
"""
|
@@ -173,7 +173,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
173
173
|
:param integration_id: The ID of the integration to run.
|
174
174
|
:return: The ID of the run instance.
|
175
175
|
"""
|
176
|
-
run_id = (await self.
|
176
|
+
run_id = (await self._http.post_empty(f"{self._url}/{integration_id}/run"))["run"]["id"]
|
177
177
|
logger.info(f"Started integration run '{run_id}' for integration '{integration_id}'.")
|
178
178
|
return run_id
|
179
179
|
|
@@ -182,7 +182,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
182
182
|
Delete an existing integration in CloudWorks.
|
183
183
|
:param integration_id: The ID of the integration to delete.
|
184
184
|
"""
|
185
|
-
await self.
|
185
|
+
await self._http.delete(f"{self._url}/{integration_id}")
|
186
186
|
logger.info(f"Deleted integration '{integration_id}'.")
|
187
187
|
|
188
188
|
async def get_run_history(self, integration_id: str) -> list[RunSummary]:
|
@@ -193,9 +193,9 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
193
193
|
"""
|
194
194
|
return [
|
195
195
|
RunSummary.model_validate(e)
|
196
|
-
for e in (await self.
|
197
|
-
"
|
198
|
-
)
|
196
|
+
for e in (await self._http.get(f"{self._url}/runs/{integration_id}"))[
|
197
|
+
"history_of_runs"
|
198
|
+
].get("runs", [])
|
199
199
|
]
|
200
200
|
|
201
201
|
async def get_run_status(self, run_id: str) -> RunStatus:
|
@@ -204,7 +204,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
204
204
|
:param run_id: The ID of the run to retrieve.
|
205
205
|
:return: The details of the run.
|
206
206
|
"""
|
207
|
-
return RunStatus.model_validate((await self.
|
207
|
+
return RunStatus.model_validate((await self._http.get(f"{self._url}/run/{run_id}"))["run"])
|
208
208
|
|
209
209
|
async def get_run_error(self, run_id: str) -> RunError | None:
|
210
210
|
"""
|
@@ -213,7 +213,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
213
213
|
:param run_id: The ID of the run to retrieve.
|
214
214
|
:return: The details of the run error.
|
215
215
|
"""
|
216
|
-
run = await self.
|
216
|
+
run = await self._http.get(f"{self._url}/runerror/{run_id}")
|
217
217
|
return RunError.model_validate(run["runs"]) if run.get("runs") else None
|
218
218
|
|
219
219
|
async def create_schedule(
|
@@ -226,7 +226,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
226
226
|
dictionary as per the documentation. If a dictionary is passed, it will be validated
|
227
227
|
against the ScheduleInput model before sending the request.
|
228
228
|
"""
|
229
|
-
await self.
|
229
|
+
await self._http.post(
|
230
230
|
f"{self._url}/{integration_id}/schedule",
|
231
231
|
json=schedule_payload(integration_id, schedule),
|
232
232
|
)
|
@@ -242,7 +242,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
242
242
|
dictionary as per the documentation. If a dictionary is passed, it will be validated
|
243
243
|
against the ScheduleInput model before sending the request.
|
244
244
|
"""
|
245
|
-
await self.
|
245
|
+
await self._http.put(
|
246
246
|
f"{self._url}/{integration_id}/schedule",
|
247
247
|
json=schedule_payload(integration_id, schedule),
|
248
248
|
)
|
@@ -255,14 +255,14 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
255
255
|
:param integration_id: The ID of the integration to schedule.
|
256
256
|
:param status: The status of the schedule. This can be either "enabled" or "disabled".
|
257
257
|
"""
|
258
|
-
await self.
|
258
|
+
await self._http.post_empty(f"{self._url}/{integration_id}/schedule/status/{status}")
|
259
259
|
|
260
260
|
async def delete_schedule(self, integration_id: str) -> None:
|
261
261
|
"""
|
262
262
|
Delete an integration schedule in CloudWorks. A schedule must already exist.
|
263
263
|
:param integration_id: The ID of the integration to schedule.
|
264
264
|
"""
|
265
|
-
await self.
|
265
|
+
await self._http.delete(f"{self._url}/{integration_id}/schedule")
|
266
266
|
logger.info(f"Deleted schedule for integration '{integration_id}'.")
|
267
267
|
|
268
268
|
async def get_notification_config(
|
@@ -282,7 +282,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
282
282
|
if integration_id:
|
283
283
|
notification_id = (await self.get_integration(integration_id)).notification_id
|
284
284
|
return NotificationConfig.model_validate(
|
285
|
-
(await self.
|
285
|
+
(await self._http.get(f"{self._url}/notification/{notification_id}"))["notifications"]
|
286
286
|
)
|
287
287
|
|
288
288
|
async def create_notification_config(self, config: NotificationInput | dict[str, Any]) -> str:
|
@@ -296,7 +296,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
296
296
|
validated against the NotificationConfig model before sending the request.
|
297
297
|
:return: The ID of the new notification configuration.
|
298
298
|
"""
|
299
|
-
res = await self.
|
299
|
+
res = await self._http.post(
|
300
300
|
f"{self._url}/notification", json=construct_payload(NotificationInput, config)
|
301
301
|
)
|
302
302
|
notification_id = res["notification"]["notificationId"]
|
@@ -316,7 +316,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
316
316
|
a dictionary as per the documentation. If a dictionary is passed, it will be
|
317
317
|
validated against the NotificationConfig model before sending the request.
|
318
318
|
"""
|
319
|
-
await self.
|
319
|
+
await self._http.put(
|
320
320
|
f"{self._url}/notification/{notification_id}",
|
321
321
|
json=construct_payload(NotificationInput, config),
|
322
322
|
)
|
@@ -335,7 +335,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
335
335
|
raise ValueError("Either notification_id or integration_id must be specified.")
|
336
336
|
if integration_id:
|
337
337
|
notification_id = (await self.get_integration(integration_id)).notification_id
|
338
|
-
await self.
|
338
|
+
await self._http.delete(f"{self._url}/notification/{notification_id}")
|
339
339
|
logger.info(f"Deleted notification configuration '{notification_id}'.")
|
340
340
|
|
341
341
|
async def get_import_error_dump(self, run_id: str) -> bytes:
|
@@ -348,7 +348,7 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
348
348
|
:param run_id: The ID of the run to retrieve.
|
349
349
|
:return: The error dump.
|
350
350
|
"""
|
351
|
-
return await self.
|
351
|
+
return await self._http.get_binary(f"{self._url}/run/{run_id}/dump")
|
352
352
|
|
353
353
|
async def get_process_error_dump(self, run_id: str, action_id: int | str) -> bytes:
|
354
354
|
"""
|
@@ -358,4 +358,6 @@ class _AsyncCloudWorksClient(_AsyncBaseClient):
|
|
358
358
|
:param action_id: The ID of the action to retrieve. This can be found in the RunError.
|
359
359
|
:return: The error dump.
|
360
360
|
"""
|
361
|
-
return await self.
|
361
|
+
return await self._http.get_binary(
|
362
|
+
f"{self._url}/run/{run_id}/process/import/{action_id}/dumps"
|
363
|
+
)
|
@@ -1,18 +1,16 @@
|
|
1
1
|
import logging
|
2
2
|
from typing import Any
|
3
3
|
|
4
|
-
import
|
5
|
-
|
6
|
-
from anaplan_sdk._base import _AsyncBaseClient, construct_payload
|
4
|
+
from anaplan_sdk._services import _AsyncHttpService, construct_payload
|
7
5
|
from anaplan_sdk.models.flows import Flow, FlowInput, FlowSummary
|
8
6
|
|
9
7
|
logger = logging.getLogger("anaplan_sdk")
|
10
8
|
|
11
9
|
|
12
|
-
class _AsyncFlowClient
|
13
|
-
def __init__(self,
|
10
|
+
class _AsyncFlowClient:
|
11
|
+
def __init__(self, http: _AsyncHttpService) -> None:
|
12
|
+
self._http = http
|
14
13
|
self._url = "https://api.cloudworks.anaplan.com/2/0/integrationflows"
|
15
|
-
super().__init__(retry_count, client)
|
16
14
|
|
17
15
|
async def get_flows(self, current_user_only: bool = False) -> list[FlowSummary]:
|
18
16
|
"""
|
@@ -23,9 +21,7 @@ class _AsyncFlowClient(_AsyncBaseClient):
|
|
23
21
|
params = {"myIntegrations": 1 if current_user_only else 0}
|
24
22
|
return [
|
25
23
|
FlowSummary.model_validate(e)
|
26
|
-
for e in await self.
|
27
|
-
self._url, "integrationFlows", page_size=25, params=params
|
28
|
-
)
|
24
|
+
for e in await self._http.get_paginated(self._url, "integrationFlows", params=params)
|
29
25
|
]
|
30
26
|
|
31
27
|
async def get_flow(self, flow_id: str) -> Flow:
|
@@ -35,7 +31,9 @@ class _AsyncFlowClient(_AsyncBaseClient):
|
|
35
31
|
:param flow_id: The ID of the flow to get.
|
36
32
|
:return: The Flow object.
|
37
33
|
"""
|
38
|
-
return Flow.model_validate(
|
34
|
+
return Flow.model_validate(
|
35
|
+
(await self._http.get(f"{self._url}/{flow_id}"))["integrationFlow"]
|
36
|
+
)
|
39
37
|
|
40
38
|
async def run_flow(self, flow_id: str, only_steps: list[str] = None) -> str:
|
41
39
|
"""
|
@@ -48,9 +46,9 @@ class _AsyncFlowClient(_AsyncBaseClient):
|
|
48
46
|
"""
|
49
47
|
url = f"{self._url}/{flow_id}/run"
|
50
48
|
res = await (
|
51
|
-
self.
|
49
|
+
self._http.post(url, json={"stepsToRun": only_steps})
|
52
50
|
if only_steps
|
53
|
-
else self.
|
51
|
+
else self._http.post_empty(url)
|
54
52
|
)
|
55
53
|
run_id = res["run"]["id"]
|
56
54
|
logger.info(f"Started flow run '{run_id}' for flow '{flow_id}'.")
|
@@ -64,7 +62,7 @@ class _AsyncFlowClient(_AsyncBaseClient):
|
|
64
62
|
:param flow: The flow to create. This can be a FlowInput object or a dictionary.
|
65
63
|
:return: The ID of the created flow.
|
66
64
|
"""
|
67
|
-
res = await self.
|
65
|
+
res = await self._http.post(self._url, json=construct_payload(FlowInput, flow))
|
68
66
|
flow_id = res["integrationFlow"]["integrationFlowId"]
|
69
67
|
logger.info(f"Created flow '{flow_id}'.")
|
70
68
|
return flow_id
|
@@ -76,7 +74,7 @@ class _AsyncFlowClient(_AsyncBaseClient):
|
|
76
74
|
:param flow_id: The ID of the flow to update.
|
77
75
|
:param flow: The flow to update. This can be a FlowInput object or a dictionary.
|
78
76
|
"""
|
79
|
-
await self.
|
77
|
+
await self._http.put(f"{self._url}/{flow_id}", json=construct_payload(FlowInput, flow))
|
80
78
|
logger.info(f"Updated flow '{flow_id}'.")
|
81
79
|
|
82
80
|
async def delete_flow(self, flow_id: str) -> None:
|
@@ -85,5 +83,5 @@ class _AsyncFlowClient(_AsyncBaseClient):
|
|
85
83
|
the flow is running or if it has any running steps.
|
86
84
|
:param flow_id: The ID of the flow to delete.
|
87
85
|
"""
|
88
|
-
await self.
|
86
|
+
await self._http.delete(f"{self._url}/{flow_id}")
|
89
87
|
logger.info(f"Deleted flow '{flow_id}'.")
|
@@ -3,12 +3,11 @@ from asyncio import gather
|
|
3
3
|
from itertools import chain
|
4
4
|
from typing import Any, Literal, overload
|
5
5
|
|
6
|
-
import
|
7
|
-
|
8
|
-
from anaplan_sdk._base import (
|
9
|
-
_AsyncBaseClient,
|
6
|
+
from anaplan_sdk._services import (
|
7
|
+
_AsyncHttpService,
|
10
8
|
parse_calendar_response,
|
11
9
|
parse_insertion_response,
|
10
|
+
sort_params,
|
12
11
|
validate_dimension_id,
|
13
12
|
)
|
14
13
|
from anaplan_sdk.exceptions import InvalidIdentifierException
|
@@ -20,6 +19,7 @@ from anaplan_sdk.models import (
|
|
20
19
|
InsertionResult,
|
21
20
|
LineItem,
|
22
21
|
List,
|
22
|
+
ListDeletionResult,
|
23
23
|
ListItem,
|
24
24
|
ListMetadata,
|
25
25
|
Model,
|
@@ -29,23 +29,22 @@ from anaplan_sdk.models import (
|
|
29
29
|
View,
|
30
30
|
ViewInfo,
|
31
31
|
)
|
32
|
-
from anaplan_sdk.models._transactional import ListDeletionResult
|
33
32
|
|
34
33
|
logger = logging.getLogger("anaplan_sdk")
|
35
34
|
|
36
35
|
|
37
|
-
class _AsyncTransactionalClient
|
38
|
-
def __init__(self,
|
36
|
+
class _AsyncTransactionalClient:
|
37
|
+
def __init__(self, http: _AsyncHttpService, model_id: str) -> None:
|
38
|
+
self._http = http
|
39
39
|
self._url = f"https://api.anaplan.com/2/0/models/{model_id}"
|
40
40
|
self._model_id = model_id
|
41
|
-
super().__init__(retry_count, client)
|
42
41
|
|
43
42
|
async def get_model_details(self) -> Model:
|
44
43
|
"""
|
45
44
|
Retrieves the Model details for the current Model.
|
46
45
|
:return: The Model details.
|
47
46
|
"""
|
48
|
-
res = await self.
|
47
|
+
res = await self._http.get(self._url, params={"modelDetails": "true"})
|
49
48
|
return Model.model_validate(res["model"])
|
50
49
|
|
51
50
|
async def get_model_status(self) -> ModelStatus:
|
@@ -53,39 +52,51 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
53
52
|
Gets the current status of the Model.
|
54
53
|
:return: The current status of the Model.
|
55
54
|
"""
|
56
|
-
res = await self.
|
55
|
+
res = await self._http.get(f"{self._url}/status")
|
57
56
|
return ModelStatus.model_validate(res["requestStatus"])
|
58
57
|
|
59
58
|
async def wake_model(self) -> None:
|
60
59
|
"""Wake up the current model."""
|
61
|
-
await self.
|
60
|
+
await self._http.post_empty(
|
61
|
+
f"{self._url}/open", headers={"Content-Type": "application/text"}
|
62
|
+
)
|
62
63
|
logger.info(f"Woke up model '{self._model_id}'.")
|
63
64
|
|
64
65
|
async def close_model(self) -> None:
|
65
66
|
"""Close the current model."""
|
66
|
-
await self.
|
67
|
+
await self._http.post_empty(
|
68
|
+
f"{self._url}/close", headers={"Content-Type": "application/text"}
|
69
|
+
)
|
67
70
|
logger.info(f"Closed model '{self._model_id}'.")
|
68
71
|
|
69
|
-
async def get_modules(
|
72
|
+
async def get_modules(
|
73
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
74
|
+
) -> list[Module]:
|
70
75
|
"""
|
71
76
|
Lists all the Modules in the Model.
|
77
|
+
:param sort_by: The field to sort the results by.
|
78
|
+
:param descending: If True, the results will be sorted in descending order.
|
72
79
|
:return: The List of Modules.
|
73
80
|
"""
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
]
|
81
|
+
res = await self._http.get_paginated(
|
82
|
+
f"{self._url}/modules", "modules", params=sort_params(sort_by, descending)
|
83
|
+
)
|
84
|
+
return [Module.model_validate(e) for e in res]
|
78
85
|
|
79
|
-
async def get_views(
|
86
|
+
async def get_views(
|
87
|
+
self, sort_by: Literal["id", "module_id", "name"] = "id", descending: bool = False
|
88
|
+
) -> list[View]:
|
80
89
|
"""
|
81
90
|
Lists all the Views in the Model. This will include all Modules and potentially other saved
|
82
91
|
views.
|
92
|
+
:param sort_by: The field to sort the results by.
|
93
|
+
:param descending: If True, the results will be sorted in descending order.
|
83
94
|
:return: The List of Views.
|
84
95
|
"""
|
85
|
-
params = {"includesubsidiaryviews": True}
|
96
|
+
params = {"includesubsidiaryviews": True} | sort_params(sort_by, descending)
|
86
97
|
return [
|
87
98
|
View.model_validate(e)
|
88
|
-
for e in await self.
|
99
|
+
for e in await self._http.get_paginated(f"{self._url}/views", "views", params=params)
|
89
100
|
]
|
90
101
|
|
91
102
|
async def get_view_info(self, view_id: int) -> ViewInfo:
|
@@ -94,7 +105,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
94
105
|
:param view_id: The ID of the View.
|
95
106
|
:return: The information about the View.
|
96
107
|
"""
|
97
|
-
return ViewInfo.model_validate((await self.
|
108
|
+
return ViewInfo.model_validate((await self._http.get(f"{self._url}/views/{view_id}")))
|
98
109
|
|
99
110
|
async def get_line_items(self, only_module_id: int | None = None) -> list[LineItem]:
|
100
111
|
"""
|
@@ -102,21 +113,26 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
102
113
|
:param only_module_id: If provided, only Line Items from this Module will be returned.
|
103
114
|
:return: All Line Items on this Model or only from the specified Module.
|
104
115
|
"""
|
105
|
-
res = await self.
|
116
|
+
res = await self._http.get(
|
106
117
|
f"{self._url}/modules/{only_module_id}/lineItems?includeAll=true"
|
107
118
|
if only_module_id
|
108
119
|
else f"{self._url}/lineItems?includeAll=true"
|
109
120
|
)
|
110
121
|
return [LineItem.model_validate(e) for e in res.get("items", [])]
|
111
122
|
|
112
|
-
async def get_lists(
|
123
|
+
async def get_lists(
|
124
|
+
self, sort_by: Literal["id", "name"] = "id", descending: bool = False
|
125
|
+
) -> list[List]:
|
113
126
|
"""
|
114
127
|
Lists all the Lists in the Model.
|
128
|
+
:param sort_by: The field to sort the results by.
|
129
|
+
:param descending: If True, the results will be sorted in descending order.
|
115
130
|
:return: All Lists on this model.
|
116
131
|
"""
|
117
|
-
|
118
|
-
|
119
|
-
|
132
|
+
res = await self._http.get_paginated(
|
133
|
+
f"{self._url}/lists", "lists", params=sort_params(sort_by, descending)
|
134
|
+
)
|
135
|
+
return [List.model_validate(e) for e in res]
|
120
136
|
|
121
137
|
async def get_list_metadata(self, list_id: int) -> ListMetadata:
|
122
138
|
"""
|
@@ -126,7 +142,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
126
142
|
"""
|
127
143
|
|
128
144
|
return ListMetadata.model_validate(
|
129
|
-
(await self.
|
145
|
+
(await self._http.get(f"{self._url}/lists/{list_id}")).get("metadata")
|
130
146
|
)
|
131
147
|
|
132
148
|
@overload
|
@@ -150,7 +166,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
150
166
|
data, you will want to set this to avoid unnecessary (de-)serialization.
|
151
167
|
:return: All items in the List.
|
152
168
|
"""
|
153
|
-
res = await self.
|
169
|
+
res = await self._http.get(f"{self._url}/lists/{list_id}/items?includeAll=true")
|
154
170
|
if return_raw:
|
155
171
|
return res.get("listItems", [])
|
156
172
|
return [ListItem.model_validate(e) for e in res.get("listItems", [])]
|
@@ -179,7 +195,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
179
195
|
return InsertionResult(added=0, ignored=0, failures=[], total=0)
|
180
196
|
if len(items) <= 100_000:
|
181
197
|
result = InsertionResult.model_validate(
|
182
|
-
await self.
|
198
|
+
await self._http.post(
|
183
199
|
f"{self._url}/lists/{list_id}/items?action=add", json={"items": items}
|
184
200
|
)
|
185
201
|
)
|
@@ -187,7 +203,9 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
187
203
|
return result
|
188
204
|
responses = await gather(
|
189
205
|
*(
|
190
|
-
self.
|
206
|
+
self._http.post(
|
207
|
+
f"{self._url}/lists/{list_id}/items?action=add", json={"items": chunk}
|
208
|
+
)
|
191
209
|
for chunk in (items[i : i + 100_000] for i in range(0, len(items), 100_000))
|
192
210
|
)
|
193
211
|
)
|
@@ -217,7 +235,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
217
235
|
if not items:
|
218
236
|
return ListDeletionResult(deleted=0, failures=[])
|
219
237
|
if len(items) <= 100_000:
|
220
|
-
res = await self.
|
238
|
+
res = await self._http.post(
|
221
239
|
f"{self._url}/lists/{list_id}/items?action=delete", json={"items": items}
|
222
240
|
)
|
223
241
|
info = ListDeletionResult.model_validate(res)
|
@@ -226,7 +244,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
226
244
|
|
227
245
|
responses = await gather(
|
228
246
|
*(
|
229
|
-
self.
|
247
|
+
self._http.post(
|
230
248
|
f"{self._url}/lists/{list_id}/items?action=delete", json={"items": chunk}
|
231
249
|
)
|
232
250
|
for chunk in (items[i : i + 100_000] for i in range(0, len(items), 100_000))
|
@@ -244,7 +262,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
244
262
|
Resets the index of a List. The List must be empty to do so.
|
245
263
|
:param list_id: The ID of the List.
|
246
264
|
"""
|
247
|
-
await self.
|
265
|
+
await self._http.post_empty(f"{self._url}/lists/{list_id}/resetIndex")
|
248
266
|
logger.info(f"Reset index for list '{list_id}'.")
|
249
267
|
|
250
268
|
async def update_module_data(
|
@@ -264,7 +282,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
264
282
|
:param data: The data to write to the Module.
|
265
283
|
:return: The number of cells changed or the response with the according error details.
|
266
284
|
"""
|
267
|
-
res = await self.
|
285
|
+
res = await self._http.post(f"{self._url}/modules/{module_id}/data", json=data)
|
268
286
|
if "failures" not in res:
|
269
287
|
logger.info(f"Updated {res['numberOfCellsChanged']} cells in module '{module_id}'.")
|
270
288
|
return res if "failures" in res else res["numberOfCellsChanged"]
|
@@ -274,7 +292,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
274
292
|
Gets the current period of the model.
|
275
293
|
:return: The current period of the model.
|
276
294
|
"""
|
277
|
-
res = await self.
|
295
|
+
res = await self._http.get(f"{self._url}/currentPeriod")
|
278
296
|
return CurrentPeriod.model_validate(res["currentPeriod"])
|
279
297
|
|
280
298
|
async def set_current_period(self, date: str) -> CurrentPeriod:
|
@@ -283,7 +301,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
283
301
|
:param date: The date to set the current period to, in the format 'YYYY-MM-DD'.
|
284
302
|
:return: The updated current period of the model.
|
285
303
|
"""
|
286
|
-
res = await self.
|
304
|
+
res = await self._http.put(f"{self._url}/currentPeriod", {"date": date})
|
287
305
|
logger.info(f"Set current period to '{date}'.")
|
288
306
|
return CurrentPeriod.model_validate(res["currentPeriod"])
|
289
307
|
|
@@ -293,7 +311,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
293
311
|
:param year: The fiscal year to set, in the format specified in the model, e.g. FY24.
|
294
312
|
:return: The updated fiscal year of the model.
|
295
313
|
"""
|
296
|
-
res = await self.
|
314
|
+
res = await self._http.put(f"{self._url}/modelCalendar/fiscalYear", {"year": year})
|
297
315
|
logger.info(f"Set current fiscal year to '{year}'.")
|
298
316
|
return FiscalYear.model_validate(res["modelCalendar"]["fiscalYear"])
|
299
317
|
|
@@ -302,7 +320,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
302
320
|
Get the calendar settings of the model.
|
303
321
|
:return: The calendar settings of the model.
|
304
322
|
"""
|
305
|
-
return parse_calendar_response(await self.
|
323
|
+
return parse_calendar_response(await self._http.get(f"{self._url}/modelCalendar"))
|
306
324
|
|
307
325
|
async def get_dimension_items(self, dimension_id: int) -> list[DimensionWithCode]:
|
308
326
|
"""
|
@@ -318,7 +336,9 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
318
336
|
:param dimension_id: The ID of the dimension to list items for.
|
319
337
|
:return: A list of Dimension items.
|
320
338
|
"""
|
321
|
-
res = await self.
|
339
|
+
res = await self._http.get(
|
340
|
+
f"{self._url}/dimensions/{validate_dimension_id(dimension_id)}/items"
|
341
|
+
)
|
322
342
|
return [DimensionWithCode.model_validate(e) for e in res.get("items", [])]
|
323
343
|
|
324
344
|
async def lookup_dimension_items(
|
@@ -350,7 +370,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
350
370
|
"Invalid dimension_id. Must be a List (101xxxxxxxxx), Time (20000000003), "
|
351
371
|
"Version (20000000020), or Users (101999999999)."
|
352
372
|
)
|
353
|
-
res = await self.
|
373
|
+
res = await self._http.post(
|
354
374
|
f"{self._url}/dimensions/{dimension_id}/items", json={"codes": codes, "names": names}
|
355
375
|
)
|
356
376
|
return [DimensionWithCode.model_validate(e) for e in res.get("items", [])]
|
@@ -367,7 +387,7 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
367
387
|
:param dimension_id: The ID of the Dimension to get items for.
|
368
388
|
:return: A list of Dimensions used in the View.
|
369
389
|
"""
|
370
|
-
res = await self.
|
390
|
+
res = await self._http.get(f"{self._url}/views/{view_id}/dimensions/{dimension_id}/items")
|
371
391
|
return [Dimension.model_validate(e) for e in res.get("items", [])]
|
372
392
|
|
373
393
|
async def get_line_item_dimensions(self, line_item_id: int) -> list[Dimension]:
|
@@ -377,5 +397,5 @@ class _AsyncTransactionalClient(_AsyncBaseClient):
|
|
377
397
|
:param line_item_id: The ID of the Line Item.
|
378
398
|
:return: A list of Dimensions used in the Line Item.
|
379
399
|
"""
|
380
|
-
res = await self.
|
400
|
+
res = await self._http.get(f"{self._url}/lineItems/{line_item_id}/dimensions")
|
381
401
|
return [Dimension.model_validate(e) for e in res.get("dimensions", [])]
|