anaplan-sdk 0.2.6__tar.gz → 0.2.8__tar.gz
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-0.2.6 → anaplan_sdk-0.2.8}/PKG-INFO +9 -8
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/README.md +8 -7
- anaplan_sdk-0.2.8/anaplan_sdk/_async_clients/__init__.py +6 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_async_clients/_audit.py +9 -2
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_async_clients/_bulk.py +13 -3
- anaplan_sdk-0.2.8/anaplan_sdk/_clients/__init__.py +6 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_clients/_audit.py +8 -1
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_clients/_bulk.py +8 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/docs/anaplan_explained.md +13 -14
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/alm_client.md +1 -1
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/async_alm_client.md +1 -1
- anaplan_sdk-0.2.8/docs/api/async_audit_client.md +5 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/async_transactional_client.md +1 -1
- anaplan_sdk-0.2.8/docs/api/audit_client.md +5 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/transactional_client.md +1 -1
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/guides}/alm.md +2 -4
- anaplan_sdk-0.2.8/docs/guides/audit.md +42 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/guides}/bulk.md +114 -49
- anaplan_sdk-0.2.8/docs/guides/transactional.md +242 -0
- anaplan_sdk-0.2.8/docs/img/anaplan-overview.webp +0 -0
- anaplan_sdk-0.2.8/docs/index.md +31 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/docs/installation.md +10 -3
- anaplan_sdk-0.2.8/docs/quickstart.md +102 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/mkdocs.yml +17 -14
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/pyproject.toml +1 -1
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/uv.lock +1 -2
- anaplan_sdk-0.2.6/anaplan_sdk/_async_clients/__init__.py +0 -5
- anaplan_sdk-0.2.6/anaplan_sdk/_clients/__init__.py +0 -5
- anaplan_sdk-0.2.6/docs/img/anaplan-overview.webp +0 -0
- anaplan_sdk-0.2.6/docs/index.md +0 -31
- anaplan_sdk-0.2.6/docs/quickstart.md +0 -162
- anaplan_sdk-0.2.6/docs/transactional.md +0 -119
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/.github/dependabot.yml +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/.github/workflows/docs.yml +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/.github/workflows/lint.yml +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/.github/workflows/tests.yml +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/.gitignore +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/.pre-commit-config.yaml +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/LICENSE +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/__init__.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_async_clients/_alm.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_async_clients/_transactional.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_auth.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_base.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_clients/_alm.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/_clients/_transactional.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/exceptions.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/anaplan_sdk/models.py +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/async_client.md +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/client.md +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/exceptions.md +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/api}/models.md +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/docs/css/styles.css +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/guides}/bulk_vs_transactional.md +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/guides}/logging.md +0 -0
- {anaplan_sdk-0.2.6/docs → anaplan_sdk-0.2.8/docs/guides}/multiple_models.md +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/docs/img/anaplan-sdk.webp +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/tests/test_alm_client.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/tests/test_async_alm_client.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/tests/test_async_client.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/tests/test_async_transactional_client.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/tests/test_client.py +0 -0
- {anaplan_sdk-0.2.6 → anaplan_sdk-0.2.8}/tests/test_transactional_client.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: anaplan-sdk
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.8
|
4
4
|
Summary: Provides pythonic access to the Anaplan API
|
5
5
|
Project-URL: Homepage, https://vinzenzklass.github.io/anaplan-sdk/
|
6
6
|
Project-URL: Repository, https://github.com/VinzenzKlass/anaplan-sdk
|
@@ -22,6 +22,7 @@ Description-Content-Type: text/markdown
|
|
22
22
|
<h1 align="center" style="font-size: 3rem; font-weight: 400; margin: -15px 0">
|
23
23
|
Anaplan SDK
|
24
24
|
</h1>
|
25
|
+
|
25
26
|
<p align="center" style="margin-top: 15px">
|
26
27
|
<a href="https://pepy.tech/project/anaplan-sdk">
|
27
28
|
<img align="center" src="https://static.pepy.tech/badge/anaplan-sdk/month" alt="Downloads Badge"/>
|
@@ -30,15 +31,15 @@ Anaplan SDK
|
|
30
31
|
|
31
32
|
---
|
32
33
|
|
33
|
-
Anaplan SDK is an independent, unofficial project providing pythonic access to
|
34
|
-
the
|
35
|
-
|
36
|
-
Requests, Authentication, JSON Parsing, Compression, Chunking and so on.
|
34
|
+
Anaplan SDK is an independent, unofficial project providing pythonic access to Anaplan. Anaplan SDK provides high-level
|
35
|
+
abstractions over the various Anaplan APIs, so you can focus on you requirements rather than spend time on
|
36
|
+
implementation details like authentication, error handling, chunking, compression and data formatting.
|
37
37
|
|
38
38
|
This Projects supports
|
39
|
-
the [Bulk
|
40
|
-
the [Transactional
|
41
|
-
the [ALM
|
39
|
+
the [Bulk APIs](https://help.anaplan.com/use-the-bulk-apis-93218e5e-00e5-406e-8361-09ab861889a7),
|
40
|
+
the [Transactional APIs](https://help.anaplan.com/use-the-transactional-apis-cc1c1e91-39fc-4272-a4b5-16bc91e9c313) and
|
41
|
+
the [ALM APsI](https://help.anaplan.com/application-lifecycle-management-api-2565cfa6-e0c2-4e24-884e-d0df957184d6),
|
42
|
+
the [Audit APIs](https://auditservice.docs.apiary.io/#),
|
42
43
|
providing both synchronous and asynchronous Clients.
|
43
44
|
|
44
45
|
Visit [Anaplan SDK](https://vinzenzklass.github.io/anaplan-sdk/) for documentation.
|
@@ -5,6 +5,7 @@
|
|
5
5
|
<h1 align="center" style="font-size: 3rem; font-weight: 400; margin: -15px 0">
|
6
6
|
Anaplan SDK
|
7
7
|
</h1>
|
8
|
+
|
8
9
|
<p align="center" style="margin-top: 15px">
|
9
10
|
<a href="https://pepy.tech/project/anaplan-sdk">
|
10
11
|
<img align="center" src="https://static.pepy.tech/badge/anaplan-sdk/month" alt="Downloads Badge"/>
|
@@ -13,15 +14,15 @@ Anaplan SDK
|
|
13
14
|
|
14
15
|
---
|
15
16
|
|
16
|
-
Anaplan SDK is an independent, unofficial project providing pythonic access to
|
17
|
-
the
|
18
|
-
|
19
|
-
Requests, Authentication, JSON Parsing, Compression, Chunking and so on.
|
17
|
+
Anaplan SDK is an independent, unofficial project providing pythonic access to Anaplan. Anaplan SDK provides high-level
|
18
|
+
abstractions over the various Anaplan APIs, so you can focus on you requirements rather than spend time on
|
19
|
+
implementation details like authentication, error handling, chunking, compression and data formatting.
|
20
20
|
|
21
21
|
This Projects supports
|
22
|
-
the [Bulk
|
23
|
-
the [Transactional
|
24
|
-
the [ALM
|
22
|
+
the [Bulk APIs](https://help.anaplan.com/use-the-bulk-apis-93218e5e-00e5-406e-8361-09ab861889a7),
|
23
|
+
the [Transactional APIs](https://help.anaplan.com/use-the-transactional-apis-cc1c1e91-39fc-4272-a4b5-16bc91e9c313) and
|
24
|
+
the [ALM APsI](https://help.anaplan.com/application-lifecycle-management-api-2565cfa6-e0c2-4e24-884e-d0df957184d6),
|
25
|
+
the [Audit APIs](https://auditservice.docs.apiary.io/#),
|
25
26
|
providing both synchronous and asynchronous Clients.
|
26
27
|
|
27
28
|
Visit [Anaplan SDK](https://vinzenzklass.github.io/anaplan-sdk/) for documentation.
|
@@ -10,7 +10,7 @@ from anaplan_sdk._base import _AsyncBaseClient
|
|
10
10
|
Event = Literal["all", "byok", "user_activity"]
|
11
11
|
|
12
12
|
|
13
|
-
class
|
13
|
+
class _AsyncAuditClient(_AsyncBaseClient):
|
14
14
|
def __init__(self, client: httpx.AsyncClient, retry_count: int) -> None:
|
15
15
|
self._client = client
|
16
16
|
self._limit = 10_000
|
@@ -49,11 +49,18 @@ class _AuditClient(_AsyncBaseClient):
|
|
49
49
|
).get("response", [])
|
50
50
|
|
51
51
|
async def get_events(self, days_into_past: int = 30, event_type: Event = "all") -> list:
|
52
|
+
"""
|
53
|
+
Get audit events from Anaplan Audit API.
|
54
|
+
:param days_into_past: The nuber of days into the past to get events for. The API provides
|
55
|
+
data for up to 30 days.
|
56
|
+
:param event_type: The type of events to get.
|
57
|
+
:return: A list of audit events.
|
58
|
+
"""
|
52
59
|
total = await self._get_total(days_into_past, event_type)
|
53
60
|
if total == 0:
|
54
61
|
return []
|
55
62
|
if total <= 10_000:
|
56
|
-
return await self._get_result_page(
|
63
|
+
return await self._get_result_page(days_into_past, event_type)
|
57
64
|
|
58
65
|
return list(
|
59
66
|
chain.from_iterable(
|
@@ -17,7 +17,7 @@ from anaplan_sdk.exceptions import AnaplanActionError, InvalidIdentifierExceptio
|
|
17
17
|
from anaplan_sdk.models import Action, Export, File, Import, Model, Process, Workspace
|
18
18
|
|
19
19
|
from ._alm import _AsyncAlmClient
|
20
|
-
from ._audit import
|
20
|
+
from ._audit import _AsyncAuditClient
|
21
21
|
from ._transactional import _AsyncTransactionalClient
|
22
22
|
|
23
23
|
logging.getLogger("httpx").setLevel(logging.CRITICAL)
|
@@ -110,7 +110,7 @@ class AsyncClient(_AsyncBaseClient):
|
|
110
110
|
self._alm_client = (
|
111
111
|
_AsyncAlmClient(self._client, model_id, self._retry_count) if model_id else None
|
112
112
|
)
|
113
|
-
self.audit =
|
113
|
+
self.audit = _AsyncAuditClient(self._client, self._retry_count)
|
114
114
|
self.status_poll_delay = status_poll_delay
|
115
115
|
self.upload_chunk_size = upload_chunk_size
|
116
116
|
self.allow_file_creation = allow_file_creation
|
@@ -381,7 +381,7 @@ class AsyncClient(_AsyncBaseClient):
|
|
381
381
|
|
382
382
|
async def export_and_download(self, action_id: int) -> bytes:
|
383
383
|
"""
|
384
|
-
Convenience wrapper around `run_action()`
|
384
|
+
Convenience wrapper around `run_action()` and `get_file()` to run an export action and
|
385
385
|
download the exported content in one call.
|
386
386
|
:param action_id: The identifier of the action to run.
|
387
387
|
:return: The content of the exported file.
|
@@ -389,6 +389,16 @@ class AsyncClient(_AsyncBaseClient):
|
|
389
389
|
await self.run_action(action_id)
|
390
390
|
return await self.get_file(action_id)
|
391
391
|
|
392
|
+
async def list_task_status(self, action_id: int) -> list:
|
393
|
+
"""
|
394
|
+
Retrieves the status of all tasks spawned by the specified action.
|
395
|
+
:param action_id: The identifier of the action that was invoked.
|
396
|
+
:return: The list of tasks spawned by the action.
|
397
|
+
"""
|
398
|
+
return (await self._get(f"{self._url}/{action_url(action_id)}/{action_id}/tasks")).get(
|
399
|
+
"tasks", []
|
400
|
+
)
|
401
|
+
|
392
402
|
async def get_task_status(
|
393
403
|
self, action_id: int, task_id: str
|
394
404
|
) -> dict[str, float | int | str | list | dict | bool]:
|
@@ -49,11 +49,18 @@ class _AuditClient(_BaseClient):
|
|
49
49
|
).get("response", [])
|
50
50
|
|
51
51
|
def get_events(self, days_into_past: int = 30, event_type: Event = "all") -> list:
|
52
|
+
"""
|
53
|
+
Get audit events from Anaplan Audit API.
|
54
|
+
:param days_into_past: The nuber of days into the past to get events for. The API provides
|
55
|
+
data for up to 30 days.
|
56
|
+
:param event_type: The type of events to get.
|
57
|
+
:return: A list of audit events.
|
58
|
+
"""
|
52
59
|
total = self._get_total(days_into_past, event_type)
|
53
60
|
if total == 0:
|
54
61
|
return []
|
55
62
|
if total <= 10_000:
|
56
|
-
return self._get_result_page(
|
63
|
+
return self._get_result_page(days_into_past, event_type)
|
57
64
|
|
58
65
|
from concurrent.futures import ThreadPoolExecutor
|
59
66
|
|
@@ -382,6 +382,14 @@ class Client(_BaseClient):
|
|
382
382
|
self.run_action(action_id)
|
383
383
|
return self.get_file(action_id)
|
384
384
|
|
385
|
+
def list_task_status(self, action_id: int) -> list:
|
386
|
+
"""
|
387
|
+
Retrieves the status of all tasks spawned by the specified action.
|
388
|
+
:param action_id: The identifier of the action that was invoked.
|
389
|
+
:return: The list of tasks spawned by the action.
|
390
|
+
"""
|
391
|
+
return self._get(f"{self._url}/{action_url(action_id)}/{action_id}/tasks").get("tasks", [])
|
392
|
+
|
385
393
|
def get_task_status(
|
386
394
|
self, action_id: int, task_id: str
|
387
395
|
) -> dict[str, float | int | str | list | dict | bool]:
|
@@ -1,19 +1,18 @@
|
|
1
|
-
This section tries to explain Anaplan specific concepts and design choices to Developers
|
2
|
-
|
3
|
-
|
1
|
+
This section tries to explain Anaplan specific concepts and design choices to Developers. It is less interesting for
|
2
|
+
people already familiar with Anaplan. Most of this page applies to the Bulk API, but some concepts are also
|
3
|
+
applicable to the Transactional API. To understand how Anaplan handles data, you are going to have to wrap your head
|
4
|
+
around some fundamental concepts, as well as gain a basic understanding of some Anaplan specific terminology.
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
dataflows and structures are the way they are, obtaining a well-founded understanding of how Anaplan handles data, is
|
8
|
-
essential.
|
9
|
-
|
10
|
-
This page list tries to condense the fundamentals of using the Anaplan Bulk API. The transactional API is different
|
11
|
-
in many ways.
|
12
|
-
|
13
|
-
|
14
|
-
<p align="center" style="margin: 40px 0 40px 0;">
|
6
|
+
The basic high-level view of any Anaplan Integration looks like this:
|
7
|
+
<p align="center" style="margin: 20px 0 40px 0;">
|
15
8
|
<img src="../img/anaplan-overview.webp" alt='Anaplan high-level view' style="border-radius: 15px">
|
16
9
|
</p>
|
10
|
+
!!! tip "TLDR"
|
11
|
+
You upload contents to files. Import Actions import the content from these files into Lists and Modules. Export
|
12
|
+
Actions export the content of Lists and Modules to files. You can download these files. Processes are just sequences
|
13
|
+
of actions. Anything that references the same file must not be run concurrently.
|
14
|
+
|
15
|
+
|
17
16
|
|
18
17
|
## Basic Concepts
|
19
18
|
|
@@ -26,7 +25,7 @@ in many ways.
|
|
26
25
|
- Exports - 116000000000 IDs.
|
27
26
|
- Processes - 118000000000 IDs.
|
28
27
|
- Other Actions - 117000000000 IDs.
|
29
|
-
|
28
|
+
|
30
29
|
- Imports read data from a file and load it into a module. Exports conversely load data from a module to a file. The
|
31
30
|
file id of the resulting file is identical to the export id. "Other Actions" move things around in Anaplan and can
|
32
31
|
also delete data etc. Processes are simply a sequence of the other three.
|
@@ -1,5 +1,5 @@
|
|
1
1
|
!!! note
|
2
2
|
This Class is not meant to be instantiated directly, but rather accessed through the `alm` Property on an
|
3
|
-
instance of [Client](client.md). For more details, see the [Guide](alm.md).
|
3
|
+
instance of [Client](client.md). For more details, see the [Guide](../guides/alm.md).
|
4
4
|
|
5
5
|
::: anaplan_sdk._clients._AlmClient
|
@@ -1,5 +1,5 @@
|
|
1
1
|
!!! note
|
2
2
|
This Class is not meant to be instantiated directly, but rather accessed through the `alm` Property on an
|
3
|
-
instance of [Client](client.md). For more details, see the [Guide](alm.md).
|
3
|
+
instance of [Client](client.md). For more details, see the [Guide](../guides/alm.md).
|
4
4
|
|
5
5
|
::: anaplan_sdk._async_clients._AsyncAlmClient
|
@@ -1,5 +1,5 @@
|
|
1
1
|
!!! note
|
2
2
|
This Class is not meant to be instantiated directly, but rather accessed through the `alm` Property on an
|
3
|
-
instance of [AsyncClient](async_client.md). For more details, see the [Guide](transactional.md).
|
3
|
+
instance of [AsyncClient](async_client.md). For more details, see the [Guide](../guides/transactional.md).
|
4
4
|
|
5
5
|
::: anaplan_sdk._async_clients._alm._AsyncAlmClient
|
@@ -1,5 +1,5 @@
|
|
1
1
|
!!! note
|
2
2
|
This Class is not meant to be instantiated directly, but rather accessed through the `transactional` Property on an
|
3
|
-
instance of [Client](client.md). For more details, see the [Guide](transactional.md).
|
3
|
+
instance of [Client](client.md). For more details, see the [Guide](../guides/transactional.md).
|
4
4
|
|
5
5
|
::: anaplan_sdk._clients._TransactionalClient
|
@@ -1,5 +1,3 @@
|
|
1
|
-
## Intro
|
2
|
-
|
3
1
|
The purpose of the Application Lifecycle Management (ALM) API is to make model change management more scalable,
|
4
2
|
automatable, and integrate with other systems.
|
5
3
|
|
@@ -80,5 +78,5 @@ revisions, syncs = await asyncio.gather(alm.get_revisions(), alm.get_sync_tasks(
|
|
80
78
|
///
|
81
79
|
|
82
80
|
!!! note
|
83
|
-
While you can instantiate a [Client](client.md) without the workspace or model parameters, trying to access
|
84
|
-
the [Transactional Client](transactional_client.md) on an instance without the `model_id` will raise a `ValueError`.
|
81
|
+
While you can instantiate a [Client](../api/client.md) without the workspace or model parameters, trying to access
|
82
|
+
the [Transactional Client](../api/transactional_client.md) on an instance without the `model_id` will raise a `ValueError`.
|
@@ -0,0 +1,42 @@
|
|
1
|
+
You can use the Audit API to get fine-grained information about the changes made to any model, usage, user sign-ins,
|
2
|
+
most frequently visited pages and much more. The Audit API exposes most the logs collected by Anaplan.
|
3
|
+
|
4
|
+
For details refer to
|
5
|
+
[the Documentation](https://auditservice.docs.apiary.io/#).
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
The method for the Audit API reside in a different namespace for better API navigability and
|
10
|
+
comprehensiveness, but are accessible through the same client for convenience. For e.g., you can call
|
11
|
+
the `.get_events()` method like so:
|
12
|
+
|
13
|
+
/// tab | Synchronous
|
14
|
+
|
15
|
+
```python
|
16
|
+
import anaplan_sdk
|
17
|
+
|
18
|
+
anaplan = anaplan_sdk.Client(
|
19
|
+
workspace_id="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
20
|
+
model_id="11111111111111111111111111111111",
|
21
|
+
certificate="~/certs/anaplan.pem",
|
22
|
+
private_key="~/keys/anaplan.pem",
|
23
|
+
)
|
24
|
+
events = anaplan.audit.get_events()
|
25
|
+
```
|
26
|
+
|
27
|
+
///
|
28
|
+
/// tab | Asynchronous
|
29
|
+
|
30
|
+
```python
|
31
|
+
import anaplan_sdk
|
32
|
+
|
33
|
+
anaplan = anaplan_sdk.AsyncClient(
|
34
|
+
workspace_id="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
35
|
+
model_id="11111111111111111111111111111111",
|
36
|
+
certificate="~/certs/anaplan.pem",
|
37
|
+
private_key="~/keys/anaplan.pem",
|
38
|
+
)
|
39
|
+
events = await anaplan.audit.get_events()
|
40
|
+
```
|
41
|
+
|
42
|
+
///
|
@@ -1,106 +1,172 @@
|
|
1
|
-
!!! tip "Client Settings"
|
2
|
-
Anaplan SDK comes with a set of default options that are efficient for most use cases and general purpose. Mainly, it
|
3
|
-
will compress all data before uploading and leverage Concurrency to speed up- and downloads. with a chunk size of 25MB.
|
4
|
-
However, you can tune the client to better suit your needs. For more information,
|
5
|
-
see [Client Parameters](client.md#anaplan_sdk.Client.__init__).
|
6
|
-
|
7
|
-
## Intro
|
8
|
-
|
9
1
|
When using this SDK you would never know it, but the workflow of performing an import of data into or export from
|
10
2
|
Anaplan is actually quite involved. To give you the full context and allow you to make informed choices, let's take a
|
11
3
|
look at the individual steps, how to perform them individually and how one can put these together to use the Bulk API to
|
12
4
|
the greatest efficiency.
|
13
5
|
|
14
|
-
|
6
|
+
!!! tip "Client Settings"
|
7
|
+
Anaplan SDK comes with a set of default options that are efficient for most use cases and general purpose. Mainly, it
|
8
|
+
will compress all data before uploading and leverage Concurrency to speed up- and downloads, with a chunk size of 25MB.
|
9
|
+
However, you can configure the client to better fit your needs. For more information,
|
10
|
+
see [Client Parameters](../api/client.md#anaplan_sdk.Client.__init__).
|
11
|
+
|
12
|
+
## Basic Usage
|
15
13
|
|
16
|
-
|
14
|
+
### Instantiate a Client
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
Clients are instantiated with the workspace, model and authentication information. There are two primary means of
|
17
|
+
Authentication.
|
18
|
+
|
19
|
+
#### Basic Authentication
|
20
|
+
|
21
|
+
Basic Authentication is unsuitable for Production. Anaplan password policies force password changes every 30, 60 or 90
|
22
|
+
days, depending on tenant settings, making this approach annoying to maintain and error-prone and is thus not
|
23
|
+
recommended for production.
|
24
|
+
|
25
|
+
/// tab | Synchronous
|
26
|
+
|
27
|
+
```python
|
28
|
+
import anaplan_sdk
|
29
|
+
|
30
|
+
anaplan = anaplan_sdk.Client(
|
31
|
+
workspace_id="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
32
|
+
model_id="11111111111111111111111111111111",
|
33
|
+
user_email="admin@company.com",
|
34
|
+
password="my_super_secret_password",
|
35
|
+
)
|
36
|
+
```
|
26
37
|
|
27
38
|
///
|
28
39
|
|
29
|
-
/// tab |
|
40
|
+
/// tab | Asynchronous
|
41
|
+
|
42
|
+
```python
|
43
|
+
import anaplan_sdk
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
45
|
+
anaplan = anaplan_sdk.AsyncClient(
|
46
|
+
workspace_id="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
47
|
+
model_id="11111111111111111111111111111111",
|
48
|
+
user_email="admin@company.com",
|
49
|
+
password="my_super_secret_password",
|
50
|
+
)
|
51
|
+
```
|
36
52
|
|
37
53
|
///
|
38
54
|
|
39
|
-
|
55
|
+
#### Certificate Authentication
|
40
56
|
|
41
57
|
/// tab | Synchronous
|
42
58
|
|
43
59
|
```python
|
60
|
+
import anaplan_sdk
|
61
|
+
|
44
62
|
anaplan = anaplan_sdk.Client(
|
45
63
|
workspace_id="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
46
64
|
model_id="11111111111111111111111111111111",
|
47
65
|
certificate="~/certs/anaplan.pem",
|
48
66
|
private_key="~/keys/anaplan.pem",
|
67
|
+
private_key_password="my_super_secret_password",
|
49
68
|
)
|
50
|
-
|
51
|
-
export_content = anaplan.export_and_download(116000000000)
|
69
|
+
|
52
70
|
```
|
53
71
|
|
54
72
|
///
|
55
73
|
/// tab | Asynchronous
|
56
74
|
|
57
75
|
```python
|
76
|
+
import anaplan_sdk
|
77
|
+
|
58
78
|
anaplan = anaplan_sdk.AsyncClient(
|
59
79
|
workspace_id="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
60
80
|
model_id="11111111111111111111111111111111",
|
61
81
|
certificate="~/certs/anaplan.pem",
|
62
82
|
private_key="~/keys/anaplan.pem",
|
83
|
+
private_key_password="my_super_secret_password",
|
63
84
|
)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
85
|
+
|
86
|
+
```
|
87
|
+
|
88
|
+
///
|
89
|
+
|
90
|
+
### Importing data
|
91
|
+
|
92
|
+
/// tab | Synchronous
|
93
|
+
|
94
|
+
```python
|
95
|
+
anaplan.upload_file(113000000000, b"Hello Anaplan")
|
96
|
+
anaplan.run_action(112000000000)
|
97
|
+
|
98
|
+
# Or in short:
|
99
|
+
anaplan.upload_and_import(113000000000, b"Hello Anaplan", 112000000000)
|
68
100
|
```
|
69
101
|
|
70
|
-
|
71
|
-
|
102
|
+
///
|
103
|
+
/// tab | Asynchronous
|
104
|
+
|
105
|
+
```python
|
106
|
+
await anaplan.upload_file(113000000000, b"Hello Anaplan")
|
107
|
+
await anaplan.run_action(112000000000)
|
108
|
+
|
109
|
+
# Or in short:
|
110
|
+
await anaplan.upload_and_import(113000000000, b"Hello Anaplan", 112000000000)
|
111
|
+
|
112
|
+
```
|
72
113
|
|
73
114
|
///
|
74
115
|
|
75
|
-
|
76
|
-
|
116
|
+
### Exporting data
|
117
|
+
|
118
|
+
/// tab | Synchronous
|
119
|
+
|
120
|
+
```python
|
121
|
+
anaplan.run_action(116000000000)
|
122
|
+
content = anaplan.get_file(116000000000)
|
123
|
+
|
124
|
+
# Or in short:
|
125
|
+
content = anaplan.export_and_download(116000000000)
|
126
|
+
```
|
127
|
+
|
128
|
+
///
|
129
|
+
/// tab | Asynchronous
|
130
|
+
|
131
|
+
```python
|
132
|
+
await anaplan.run_action(116000000000)
|
133
|
+
content = await anaplan.get_file(116000000000)
|
134
|
+
|
135
|
+
# Or in short:
|
136
|
+
content = await anaplan.export_and_download(116000000000)
|
137
|
+
```
|
138
|
+
|
139
|
+
///
|
77
140
|
|
78
141
|
## Applications
|
79
142
|
|
80
143
|
### One source with multiple Actions
|
81
144
|
|
82
|
-
One of the most common patterns you'll find working with Anaplan is
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
those.
|
145
|
+
One of the most common patterns you'll find working with Anaplan is:
|
146
|
+
|
147
|
+
1. Upload content
|
148
|
+
2. Import into a list
|
149
|
+
3. Import into a module
|
88
150
|
|
89
|
-
The
|
90
|
-
into the list and the other one importing into the module and then
|
91
|
-
like this:
|
151
|
+
The recommended way to do this is to have your model builder create two actions that reference the same file, one
|
152
|
+
importing into the list and the other one importing into the module and then wrap them into a process. This would again
|
153
|
+
just look like this:
|
92
154
|
|
93
155
|
/// tab | Synchronous
|
94
156
|
|
95
157
|
```python
|
96
|
-
anaplan.upload_and_import(
|
158
|
+
anaplan.upload_and_import(
|
159
|
+
file_id=113000000000, content=b"Hello World!", action_id=118000000000
|
160
|
+
)
|
97
161
|
```
|
98
162
|
|
99
163
|
///
|
100
164
|
/// tab | Asynchronous
|
101
165
|
|
102
166
|
```python
|
103
|
-
await anaplan.upload_and_import(
|
167
|
+
await anaplan.upload_and_import(
|
168
|
+
file_id=113000000000, content=b"Hello World!", action_id=118000000000
|
169
|
+
)
|
104
170
|
```
|
105
171
|
|
106
172
|
///
|
@@ -159,7 +225,7 @@ await anaplan.run_action(118000000000)
|
|
159
225
|
If you have a file that is larger than your available RAM, or you are consuming chunks from i.e. a queue until it is
|
160
226
|
exhausted and thus cannot know the number of expected chunks ahead of time, you can use the `upload_file_stream` method.
|
161
227
|
You can pass an Iterator - in this case a Generator - that yields the chunks to this method, and it will handle the
|
162
|
-
rest. The `upload_file_stream` method on the [AsyncClient](async_client.md#anaplan_sdk.AsyncClient.upload_file_stream)
|
228
|
+
rest. The `upload_file_stream` method on the [AsyncClient](../api/async_client.md#anaplan_sdk.AsyncClient.upload_file_stream)
|
163
229
|
accepts both `AsyncIterator[bytes | str]` and `Iterator[str | bytes]`.
|
164
230
|
|
165
231
|
This will work nicely with i.e. [`scan_parquet()`](https://docs.pola.rs/user-guide/io/parquet/#scan)
|
@@ -205,14 +271,13 @@ This will allow you to upload files of arbitrary size without running into memor
|
|
205
271
|
small enough to fit into memory. It will work equally well with any other source that can be read in chunks and
|
206
272
|
especially well with sources that can be read lazily or return the results sets in chunks by default.
|
207
273
|
|
208
|
-
|
209
274
|
You can in the same way use the `get_file_stream` method to download files in chunks.
|
210
275
|
|
211
276
|
/// tab | Synchronous
|
212
277
|
|
213
278
|
```python
|
214
279
|
for chunk in anaplan.get_file_stream(113000000040):
|
215
|
-
|
280
|
+
... # do something with the chunk
|
216
281
|
```
|
217
282
|
|
218
283
|
///
|