anaplan-sdk 0.5.0a3__tar.gz → 0.5.0a5__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.
Files changed (98) hide show
  1. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/PKG-INFO +1 -1
  2. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/_alm.py +12 -4
  3. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/_audit.py +20 -10
  4. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/_bulk.py +36 -48
  5. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/_cloud_works.py +4 -3
  6. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/_transactional.py +5 -7
  7. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/_alm.py +12 -4
  8. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/_audit.py +21 -11
  9. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/_bulk.py +88 -64
  10. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/_cloud_works.py +4 -3
  11. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/_transactional.py +25 -11
  12. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_services.py +30 -2
  13. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/_bulk.py +6 -4
  14. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/alm.md +2 -6
  15. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/bulk.md +7 -2
  16. anaplan_sdk-0.5.0a5/docs/guides/multiple_models.md +37 -0
  17. anaplan_sdk-0.5.0a5/docs/guides/sorting.md +41 -0
  18. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/mkdocs.yml +1 -0
  19. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/pyproject.toml +2 -4
  20. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/conftest.py +6 -3
  21. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/test_async_client.py +5 -4
  22. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/test_async_cloud_works_client.py +1 -1
  23. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/test_async_transactional_client.py +1 -2
  24. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/conftest.py +6 -3
  25. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/test_client.py +6 -5
  26. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/test_cloud_works_client.py +1 -1
  27. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/test_transactional_client.py +1 -2
  28. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/uv.lock +1 -1
  29. anaplan_sdk-0.5.0a3/docs/guides/multiple_models.md +0 -33
  30. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/.github/dependabot.yml +0 -0
  31. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/.github/workflows/docs.yml +0 -0
  32. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/.github/workflows/lint.yml +0 -0
  33. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/.github/workflows/tests.yml +0 -0
  34. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/.gitignore +0 -0
  35. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/.pre-commit-config.yaml +0 -0
  36. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/LICENSE +0 -0
  37. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/README.md +0 -0
  38. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/__init__.py +0 -0
  39. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/__init__.py +0 -0
  40. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_async_clients/_cw_flow.py +0 -0
  41. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_auth.py +0 -0
  42. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/__init__.py +0 -0
  43. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_clients/_cw_flow.py +0 -0
  44. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/_oauth.py +0 -0
  45. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/exceptions.py +0 -0
  46. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/__init__.py +0 -0
  47. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/_alm.py +0 -0
  48. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/_base.py +0 -0
  49. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/_transactional.py +0 -0
  50. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/cloud_works.py +0 -0
  51. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/anaplan_sdk/models/flows.py +0 -0
  52. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_alm_client.md +0 -0
  53. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_audit_client.md +0 -0
  54. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_client.md +0 -0
  55. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_cw_client.md +0 -0
  56. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_flows_client.md +0 -0
  57. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_oauth_client.md +0 -0
  58. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/async/async_transactional_client.md +0 -0
  59. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/exceptions.md +0 -0
  60. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/models/alm.md +0 -0
  61. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/models/bulk.md +0 -0
  62. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/models/cloud_works.md +0 -0
  63. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/models/flows.md +0 -0
  64. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/models/transactional.md +0 -0
  65. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_alm_client.md +0 -0
  66. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_audit_client.md +0 -0
  67. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_client.md +0 -0
  68. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_cw_client.md +0 -0
  69. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_flows_client.md +0 -0
  70. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_oauth_client.md +0 -0
  71. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/api/sync/sync_transactional_client.md +0 -0
  72. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/assets/overview.html +0 -0
  73. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/concepts.md +0 -0
  74. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/css/styles.css +0 -0
  75. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/audit.md +0 -0
  76. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/authentication.md +0 -0
  77. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/bulk_vs_transactional.md +0 -0
  78. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/cloud_works.md +0 -0
  79. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/index.md +0 -0
  80. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/logging.md +0 -0
  81. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/guides/transactional.md +0 -0
  82. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/img/anaplan-sdk.webp +0 -0
  83. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/index.md +0 -0
  84. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/installation.md +0 -0
  85. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/js/assets/hljs.js +0 -0
  86. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/js/assets/hljs.min.js +0 -0
  87. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/js/assets/python.js +0 -0
  88. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/js/assets/python.min.js +0 -0
  89. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/js/highlight.js +0 -0
  90. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/js/highlight.min.js +0 -0
  91. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/docs/quickstart.md +0 -0
  92. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/test_async_alm_client.py +0 -0
  93. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/test_async_audit_client.py +0 -0
  94. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/async/test_async_flows_client.py +0 -0
  95. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/conftest.py +0 -0
  96. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/test_alm_client.py +0 -0
  97. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/test_audit_client.py +0 -0
  98. {anaplan_sdk-0.5.0a3 → anaplan_sdk-0.5.0a5}/tests/sync/test_flows_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anaplan-sdk
3
- Version: 0.5.0a3
3
+ Version: 0.5.0a5
4
4
  Summary: Streamlined Python Interface for 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
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from typing import Literal, overload
3
3
 
4
- from anaplan_sdk._services import _AsyncHttpService
4
+ from anaplan_sdk._services import _AsyncHttpService, sort_params
5
5
  from anaplan_sdk.exceptions import AnaplanActionError
6
6
  from anaplan_sdk.models import (
7
7
  ModelRevision,
@@ -29,13 +29,21 @@ class _AsyncAlmClient:
29
29
  logger.info(f"Changed model status to '{status}' for model {self._model_id}.")
30
30
  await self._http.put(f"{self._url}/onlineStatus", json={"status": status})
31
31
 
32
- async def get_revisions(self) -> list[Revision]:
32
+ async def get_revisions(
33
+ self,
34
+ sort_by: Literal["id", "name", "applied_on", "created_on"] | None = None,
35
+ descending: bool = False,
36
+ ) -> list[Revision]:
33
37
  """
34
38
  Use this call to return a list of revisions for a specific model.
39
+ :param sort_by: The field to sort the results by.
40
+ :param descending: If True, the results will be sorted in descending order.
35
41
  :return: A list of revisions for a specific model.
36
42
  """
37
- res = await self._http.get(f"{self._url}/alm/revisions")
38
- return [Revision.model_validate(e) for e in res.get("revisions", [])]
43
+ res = await self._http.get_paginated(
44
+ f"{self._url}/alm/revisions", "revisions", params=sort_params(sort_by, descending)
45
+ )
46
+ return [Revision.model_validate(e) for e in res]
39
47
 
40
48
  async def get_latest_revision(self) -> Revision | None:
41
49
  """
@@ -1,9 +1,10 @@
1
1
  from typing import Any, Literal
2
2
 
3
- from anaplan_sdk._services import _AsyncHttpService
3
+ from anaplan_sdk._services import _AsyncHttpService, sort_params
4
4
  from anaplan_sdk.models import User
5
5
 
6
6
  Event = Literal["all", "byok", "user_activity"]
7
+ UserSortBy = Literal["first_name", "last_name", "email", "active", "last_login_date"] | None
7
8
 
8
9
 
9
10
  class _AsyncAuditClient:
@@ -12,22 +13,31 @@ class _AsyncAuditClient:
12
13
  self._limit = 10_000
13
14
  self._url = "https://audit.anaplan.com/audit/api/1/events"
14
15
 
15
- async def get_users(self, search_pattern: str | None = None) -> list[User]:
16
+ async def get_users(
17
+ self,
18
+ search_pattern: str | None = None,
19
+ sort_by: UserSortBy = None,
20
+ descending: bool = False,
21
+ ) -> list[User]:
16
22
  """
17
23
  Lists all the Users in the authenticated users default tenant.
18
- :param search_pattern: Optionally filter for specific users. When provided,
24
+ :param search_pattern: **Caution: This is an undocumented Feature and may behave
25
+ unpredictably. It requires the Tenant Admin role. For non-admin users, it is
26
+ ignored.** Optionally filter for specific users. When provided,
19
27
  case-insensitive matches users with emails or names containing this string.
20
28
  You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
21
29
  When None (default), returns all users.
30
+ :param sort_by: The field to sort the results by.
31
+ :param descending: If True, the results will be sorted in descending order.
22
32
  :return: The List of Users.
23
33
  """
24
- params = {"s": search_pattern} if search_pattern else None
25
- return [
26
- User.model_validate(e)
27
- for e in await self._http.get_paginated(
28
- "https://api.anaplan.com/2/0/users", "users", params=params
29
- )
30
- ]
34
+ params = sort_params(sort_by, descending)
35
+ if search_pattern:
36
+ params["s"] = search_pattern
37
+ res = await self._http.get_paginated(
38
+ "https://api.anaplan.com/2/0/users", "users", params=params
39
+ )
40
+ return [User.model_validate(e) for e in res]
31
41
 
32
42
  async def get_user(self, user_id: str = "me") -> User:
33
43
  """
@@ -7,7 +7,7 @@ import httpx
7
7
  from typing_extensions import Self
8
8
 
9
9
  from anaplan_sdk._auth import _create_auth
10
- from anaplan_sdk._services import _AsyncHttpService, action_url, sort_params
10
+ from anaplan_sdk._services import _AsyncHttpService, action_url, models_url, sort_params
11
11
  from anaplan_sdk.exceptions import AnaplanActionError, InvalidIdentifierException
12
12
  from anaplan_sdk.models import (
13
13
  Action,
@@ -27,6 +27,8 @@ from ._audit import _AsyncAuditClient
27
27
  from ._cloud_works import _AsyncCloudWorksClient
28
28
  from ._transactional import _AsyncTransactionalClient
29
29
 
30
+ SortBy = Literal["id", "name"] | None
31
+
30
32
  logger = logging.getLogger("anaplan_sdk")
31
33
 
32
34
 
@@ -140,34 +142,24 @@ class AsyncClient:
140
142
  f"Initialized AsyncClient with workspace_id={workspace_id}, model_id={model_id}"
141
143
  )
142
144
 
143
- @classmethod
144
- def from_existing(
145
- cls, existing: Self, *, workspace_id: str | None = None, model_id: str | None = None
146
- ) -> Self:
145
+ def with_model(self, model_id: str | None = None, workspace_id: str | None = None) -> Self:
147
146
  """
148
- Create a new instance of the Client from an existing instance. This is useful if you want
149
- to interact with multiple models or workspaces in the same script but share the same
150
- authentication and configuration. This creates a shallow copy of the existing client and
151
- optionally updates the relevant attributes to the new workspace and model. You can provide
152
- either a new workspace Id or a new model Id, or both. If you do not provide one of them,
153
- the existing value will be used. If you omit both, the new instance will be an identical
154
- copy of the existing instance.
155
-
156
- :param existing: The existing instance to copy.
147
+ Create a new instance of the Client with the given model and workspace Ids. **This creates
148
+ a copy of the current client. The current instance remains unchanged.**
157
149
  :param workspace_id: The workspace Id to use or None to use the existing workspace Id.
158
150
  :param model_id: The model Id to use or None to use the existing model Id.
159
151
  :return: A new instance of the Client.
160
152
  """
161
- client = copy(existing)
162
- new_ws_id = workspace_id or existing._workspace_id
163
- new_model_id = model_id or existing._model_id
153
+ client = copy(self)
154
+ new_ws_id = workspace_id or self._workspace_id
155
+ new_model_id = model_id or self._model_id
164
156
  logger.debug(
165
157
  f"Creating a new AsyncClient from existing instance "
166
158
  f"with workspace_id={new_ws_id}, model_id={new_model_id}."
167
159
  )
168
160
  client._url = f"https://api.anaplan.com/2/0/workspaces/{new_ws_id}/models/{new_model_id}"
169
- client._transactional_client = _AsyncTransactionalClient(existing._http, new_model_id)
170
- client._alm_client = _AsyncAlmClient(existing._http, new_model_id)
161
+ client._transactional_client = _AsyncTransactionalClient(self._http, new_model_id)
162
+ client._alm_client = _AsyncAlmClient(self._http, new_model_id)
171
163
  return client
172
164
 
173
165
  @property
@@ -228,12 +220,14 @@ class AsyncClient:
228
220
  async def get_workspaces(
229
221
  self,
230
222
  search_pattern: str | None = None,
231
- sort_by: Literal["size_allowance", "name"] = "name",
223
+ sort_by: Literal["size_allowance", "name"] | None = None,
232
224
  descending: bool = False,
233
225
  ) -> list[Workspace]:
234
226
  """
235
227
  Lists all the Workspaces the authenticated user has access to.
236
- :param search_pattern: Optionally filter for specific workspaces. When provided,
228
+ :param search_pattern: **Caution: This is an undocumented Feature and may behave
229
+ unpredictably. It requires the Tenant Admin role. For non-admin users, it is
230
+ ignored.** Optionally filter for specific workspaces. When provided,
237
231
  case-insensitive matches workspaces with names containing this string.
238
232
  You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
239
233
  When None (default), returns all users.
@@ -244,22 +238,26 @@ class AsyncClient:
244
238
  params = {"tenantDetails": "true"} | sort_params(sort_by, descending)
245
239
  if search_pattern:
246
240
  params["s"] = search_pattern
247
- return [
248
- Workspace.model_validate(e)
249
- for e in await self._http.get_paginated(
250
- "https://api.anaplan.com/2/0/workspaces", "workspaces", params=params
251
- )
252
- ]
241
+ res = await self._http.get_paginated(
242
+ "https://api.anaplan.com/2/0/workspaces", "workspaces", params=params
243
+ )
244
+ return [Workspace.model_validate(e) for e in res]
253
245
 
254
246
  async def get_models(
255
247
  self,
248
+ only_in_workspace: bool | str = False,
256
249
  search_pattern: str | None = None,
257
- sort_by: Literal["active_state", "name"] = "name",
250
+ sort_by: Literal["active_state", "name"] | None = None,
258
251
  descending: bool = False,
259
252
  ) -> list[Model]:
260
253
  """
261
254
  Lists all the Models the authenticated user has access to.
262
- :param search_pattern: Optionally filter for specific models. When provided,
255
+ :param only_in_workspace: If True, only lists models in the workspace provided when
256
+ instantiating the client. If a string is provided, only lists models in the workspace
257
+ with the given Id. If False (default), lists models in all workspaces the user
258
+ :param search_pattern: **Caution: This is an undocumented Feature and may behave
259
+ unpredictably. It requires the Tenant Admin role. For non-admin users, it is
260
+ ignored.** Optionally filter for specific models. When provided,
263
261
  case-insensitive matches model names containing this string.
264
262
  You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
265
263
  When None (default), returns all models.
@@ -270,12 +268,10 @@ class AsyncClient:
270
268
  params = {"modelDetails": "true"} | sort_params(sort_by, descending)
271
269
  if search_pattern:
272
270
  params["s"] = search_pattern
273
- return [
274
- Model.model_validate(e)
275
- for e in await self._http.get_paginated(
276
- "https://api.anaplan.com/2/0/models", "models", params=params
277
- )
278
- ]
271
+ res = await self._http.get_paginated(
272
+ models_url(only_in_workspace, self._workspace_id), "models", params=params
273
+ )
274
+ return [Model.model_validate(e) for e in res]
279
275
 
280
276
  async def delete_models(self, model_ids: list[str]) -> ModelDeletionResult:
281
277
  """
@@ -291,9 +287,7 @@ class AsyncClient:
291
287
  )
292
288
  return ModelDeletionResult.model_validate(res)
293
289
 
294
- async def get_files(
295
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
296
- ) -> list[File]:
290
+ async def get_files(self, sort_by: SortBy = None, descending: bool = False) -> list[File]:
297
291
  """
298
292
  Lists all the Files in the Model.
299
293
  :param sort_by: The field to sort the results by.
@@ -305,9 +299,7 @@ class AsyncClient:
305
299
  )
306
300
  return [File.model_validate(e) for e in res]
307
301
 
308
- async def get_actions(
309
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
310
- ) -> list[Action]:
302
+ async def get_actions(self, sort_by: SortBy = None, descending: bool = False) -> list[Action]:
311
303
  """
312
304
  Lists all the Actions in the Model. This will only return the Actions listed under
313
305
  `Other Actions` in Anaplan. For Imports, exports, and processes, see their respective
@@ -322,7 +314,7 @@ class AsyncClient:
322
314
  return [Action.model_validate(e) for e in res]
323
315
 
324
316
  async def get_processes(
325
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
317
+ self, sort_by: SortBy = None, descending: bool = False
326
318
  ) -> list[Process]:
327
319
  """
328
320
  Lists all the Processes in the Model.
@@ -335,9 +327,7 @@ class AsyncClient:
335
327
  )
336
328
  return [Process.model_validate(e) for e in res]
337
329
 
338
- async def get_imports(
339
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
340
- ) -> list[Import]:
330
+ async def get_imports(self, sort_by: SortBy = None, descending: bool = False) -> list[Import]:
341
331
  """
342
332
  Lists all the Imports in the Model.
343
333
  :param sort_by: The field to sort the results by.
@@ -349,9 +339,7 @@ class AsyncClient:
349
339
  )
350
340
  return [Import.model_validate(e) for e in res]
351
341
 
352
- async def get_exports(
353
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
354
- ) -> list[Export]:
342
+ async def get_exports(self, sort_by: SortBy = None, descending: bool = False) -> list[Export]:
355
343
  """
356
344
  Lists all the Exports in the Model.
357
345
  :param sort_by: The field to sort the results by.
@@ -99,14 +99,15 @@ class _AsyncCloudWorksClient:
99
99
  logger.info(f"Deleted connection '{con_id}'.")
100
100
 
101
101
  async def get_integrations(
102
- self, sort_by_name: Literal["ascending", "descending"] = "ascending"
102
+ self, sort_by: Literal["name"] | None = None, descending: bool = False
103
103
  ) -> list[Integration]:
104
104
  """
105
105
  List all integrations in CloudWorks.
106
- :param sort_by_name: Sort the integrations by name in ascending or descending order.
106
+ :param sort_by: The field to sort the results by.
107
+ :param descending: If True, the results will be sorted in descending order.
107
108
  :return: A list of integrations.
108
109
  """
109
- params = {"sortBy": "name" if sort_by_name == "ascending" else "-name"}
110
+ params = {"sortBy": f"{'-' if descending else ''}{sort_by}"} if sort_by else None
110
111
  return [
111
112
  Integration.model_validate(e)
112
113
  for e in await self._http.get_paginated(f"{self._url}", "integrations", params=params)
@@ -30,6 +30,8 @@ from anaplan_sdk.models import (
30
30
  ViewInfo,
31
31
  )
32
32
 
33
+ SortBy = Literal["id", "name"] | None
34
+
33
35
  logger = logging.getLogger("anaplan_sdk")
34
36
 
35
37
 
@@ -69,9 +71,7 @@ class _AsyncTransactionalClient:
69
71
  )
70
72
  logger.info(f"Closed model '{self._model_id}'.")
71
73
 
72
- async def get_modules(
73
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
74
- ) -> list[Module]:
74
+ async def get_modules(self, sort_by: SortBy = None, descending: bool = False) -> list[Module]:
75
75
  """
76
76
  Lists all the Modules in the Model.
77
77
  :param sort_by: The field to sort the results by.
@@ -84,7 +84,7 @@ class _AsyncTransactionalClient:
84
84
  return [Module.model_validate(e) for e in res]
85
85
 
86
86
  async def get_views(
87
- self, sort_by: Literal["id", "module_id", "name"] = "id", descending: bool = False
87
+ self, sort_by: Literal["id", "module_id", "name"] | None = None, descending: bool = False
88
88
  ) -> list[View]:
89
89
  """
90
90
  Lists all the Views in the Model. This will include all Modules and potentially other saved
@@ -120,9 +120,7 @@ class _AsyncTransactionalClient:
120
120
  )
121
121
  return [LineItem.model_validate(e) for e in res.get("items", [])]
122
122
 
123
- async def get_lists(
124
- self, sort_by: Literal["id", "name"] = "id", descending: bool = False
125
- ) -> list[List]:
123
+ async def get_lists(self, sort_by: SortBy = None, descending: bool = False) -> list[List]:
126
124
  """
127
125
  Lists all the Lists in the Model.
128
126
  :param sort_by: The field to sort the results by.
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from typing import Literal, overload
3
3
 
4
- from anaplan_sdk._services import _HttpService
4
+ from anaplan_sdk._services import _HttpService, sort_params
5
5
  from anaplan_sdk.exceptions import AnaplanActionError
6
6
  from anaplan_sdk.models import (
7
7
  ModelRevision,
@@ -29,13 +29,21 @@ class _AlmClient:
29
29
  logger.info(f"Changed model status to '{status}' for model {self._model_id}.")
30
30
  self._http.put(f"{self._url}/onlineStatus", json={"status": status})
31
31
 
32
- def get_revisions(self) -> list[Revision]:
32
+ def get_revisions(
33
+ self,
34
+ sort_by: Literal["id", "name", "applied_on", "created_on"] | None = None,
35
+ descending: bool = False,
36
+ ) -> list[Revision]:
33
37
  """
34
38
  Use this call to return a list of revisions for a specific model.
39
+ :param sort_by: The field to sort the results by.
40
+ :param descending: If True, the results will be sorted in descending order.
35
41
  :return: A list of revisions for a specific model.
36
42
  """
37
- res = self._http.get(f"{self._url}/alm/revisions")
38
- return [Revision.model_validate(e) for e in res.get("revisions", [])]
43
+ res = self._http.get_paginated(
44
+ f"{self._url}/alm/revisions", "revisions", params=sort_params(sort_by, descending)
45
+ )
46
+ return [Revision.model_validate(e) for e in res]
39
47
 
40
48
  def get_latest_revision(self) -> Revision | None:
41
49
  """
@@ -1,9 +1,10 @@
1
1
  from typing import Any, Literal
2
2
 
3
- from anaplan_sdk._services import _HttpService
3
+ from anaplan_sdk._services import _HttpService, sort_params
4
4
  from anaplan_sdk.models import User
5
5
 
6
6
  Event = Literal["all", "byok", "user_activity"]
7
+ UserSortBy = Literal["first_name", "last_name", "email", "active", "last_login_date"] | None
7
8
 
8
9
 
9
10
  class _AuditClient:
@@ -12,20 +13,29 @@ class _AuditClient:
12
13
  self._limit = 10_000
13
14
  self._url = "https://audit.anaplan.com/audit/api/1/events"
14
15
 
15
- def get_users(self, search_pattern: str | None = None) -> list[User]:
16
+ def get_users(
17
+ self,
18
+ search_pattern: str | None = None,
19
+ sort_by: UserSortBy = None,
20
+ descending: bool = False,
21
+ ) -> list[User]:
16
22
  """
17
23
  Lists all the Users in the authenticated users default tenant.
18
- :param search_pattern: Optional filter for users. When provided, case-insensitive matches
19
- users with emails containing this string. When None (default), returns all users.
24
+ :param search_pattern: **Caution: This is an undocumented Feature and may behave
25
+ unpredictably. It requires the Tenant Admin role. For non-admin users, it is
26
+ ignored.** Optionally filter for specific users. When provided,
27
+ case-insensitive matches users with emails or names containing this string.
28
+ You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
29
+ When None (default), returns all users.
30
+ :param sort_by: The field to sort the results by.
31
+ :param descending: If True, the results will be sorted in descending order.
20
32
  :return: The List of Users.
21
33
  """
22
- params = {"s": search_pattern} if search_pattern else None
23
- return [
24
- User.model_validate(e)
25
- for e in self._http.get_paginated(
26
- "https://api.anaplan.com/2/0/users", "users", params=params
27
- )
28
- ]
34
+ params = sort_params(sort_by, descending)
35
+ if search_pattern:
36
+ params["s"] = search_pattern
37
+ res = self._http.get_paginated("https://api.anaplan.com/2/0/users", "users", params=params)
38
+ return [User.model_validate(e) for e in res]
29
39
 
30
40
  def get_user(self, user_id: str = "me") -> User:
31
41
  """