anaplan-sdk 0.5.0a2__tar.gz → 0.5.0a4__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 (97) hide show
  1. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/PKG-INFO +2 -2
  2. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/_alm.py +12 -4
  3. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/_audit.py +17 -9
  4. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/_bulk.py +85 -44
  5. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/_cloud_works.py +4 -3
  6. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/_cw_flow.py +1 -3
  7. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/_transactional.py +23 -12
  8. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/_alm.py +12 -4
  9. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/_audit.py +19 -11
  10. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/_bulk.py +87 -46
  11. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/_cloud_works.py +5 -4
  12. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/_cw_flow.py +1 -3
  13. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/_transactional.py +25 -11
  14. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_services.py +103 -45
  15. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/cloud_works.py +6 -2
  16. anaplan_sdk-0.5.0a4/docs/guides/sorting.md +41 -0
  17. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/mkdocs.yml +1 -0
  18. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/pyproject.toml +108 -108
  19. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/conftest.py +1 -0
  20. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/test_async_client.py +2 -1
  21. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/test_async_cloud_works_client.py +1 -1
  22. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/conftest.py +1 -0
  23. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/test_client.py +2 -1
  24. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/test_cloud_works_client.py +1 -1
  25. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/uv.lock +1469 -1469
  26. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/.github/dependabot.yml +0 -0
  27. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/.github/workflows/docs.yml +0 -0
  28. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/.github/workflows/lint.yml +0 -0
  29. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/.github/workflows/tests.yml +0 -0
  30. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/.gitignore +0 -0
  31. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/.pre-commit-config.yaml +0 -0
  32. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/LICENSE +0 -0
  33. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/README.md +0 -0
  34. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/__init__.py +0 -0
  35. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_async_clients/__init__.py +0 -0
  36. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_auth.py +0 -0
  37. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_clients/__init__.py +0 -0
  38. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/_oauth.py +0 -0
  39. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/exceptions.py +0 -0
  40. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/__init__.py +0 -0
  41. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/_alm.py +0 -0
  42. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/_base.py +0 -0
  43. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/_bulk.py +0 -0
  44. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/_transactional.py +0 -0
  45. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/anaplan_sdk/models/flows.py +0 -0
  46. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_alm_client.md +0 -0
  47. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_audit_client.md +0 -0
  48. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_client.md +0 -0
  49. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_cw_client.md +0 -0
  50. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_flows_client.md +0 -0
  51. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_oauth_client.md +0 -0
  52. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/async/async_transactional_client.md +0 -0
  53. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/exceptions.md +0 -0
  54. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/models/alm.md +0 -0
  55. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/models/bulk.md +0 -0
  56. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/models/cloud_works.md +0 -0
  57. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/models/flows.md +0 -0
  58. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/models/transactional.md +0 -0
  59. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_alm_client.md +0 -0
  60. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_audit_client.md +0 -0
  61. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_client.md +0 -0
  62. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_cw_client.md +0 -0
  63. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_flows_client.md +0 -0
  64. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_oauth_client.md +0 -0
  65. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/api/sync/sync_transactional_client.md +0 -0
  66. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/assets/overview.html +0 -0
  67. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/concepts.md +0 -0
  68. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/css/styles.css +0 -0
  69. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/alm.md +0 -0
  70. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/audit.md +0 -0
  71. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/authentication.md +0 -0
  72. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/bulk.md +0 -0
  73. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/bulk_vs_transactional.md +0 -0
  74. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/cloud_works.md +0 -0
  75. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/index.md +0 -0
  76. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/logging.md +0 -0
  77. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/multiple_models.md +0 -0
  78. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/guides/transactional.md +0 -0
  79. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/img/anaplan-sdk.webp +0 -0
  80. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/index.md +0 -0
  81. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/installation.md +0 -0
  82. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/js/assets/hljs.js +0 -0
  83. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/js/assets/hljs.min.js +0 -0
  84. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/js/assets/python.js +0 -0
  85. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/js/assets/python.min.js +0 -0
  86. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/js/highlight.js +0 -0
  87. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/js/highlight.min.js +0 -0
  88. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/docs/quickstart.md +0 -0
  89. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/test_async_alm_client.py +0 -0
  90. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/test_async_audit_client.py +0 -0
  91. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/test_async_flows_client.py +0 -0
  92. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/async/test_async_transactional_client.py +0 -0
  93. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/conftest.py +0 -0
  94. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/test_alm_client.py +0 -0
  95. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/test_audit_client.py +0 -0
  96. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/test_flows_client.py +0 -0
  97. {anaplan_sdk-0.5.0a2 → anaplan_sdk-0.5.0a4}/tests/sync/test_transactional_client.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anaplan-sdk
3
- Version: 0.5.0a2
4
- Summary: Streamlined Python Interface for Anaplan
3
+ Version: 0.5.0a4
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
7
7
  Project-URL: Documentation, https://vinzenzklass.github.io/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,29 @@ 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
24
  :param search_pattern: Optionally filter for specific users. When provided,
19
25
  case-insensitive matches users with emails or names containing this string.
20
26
  You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
21
27
  When None (default), returns all users.
28
+ :param sort_by: The field to sort the results by.
29
+ :param descending: If True, the results will be sorted in descending order.
22
30
  :return: The List of Users.
23
31
  """
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
- ]
32
+ params = sort_params(sort_by, descending)
33
+ if search_pattern:
34
+ params["s"] = search_pattern
35
+ res = await self._http.get_paginated(
36
+ "https://api.anaplan.com/2/0/users", "users", params=params
37
+ )
38
+ return [User.model_validate(e) for e in res]
31
39
 
32
40
  async def get_user(self, user_id: str = "me") -> User:
33
41
  """
@@ -1,13 +1,13 @@
1
1
  import logging
2
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._services import _AsyncHttpService, action_url
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,
@@ -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
 
@@ -49,6 +51,8 @@ class AsyncClient:
49
51
  auth: httpx.Auth | None = None,
50
52
  timeout: float | httpx.Timeout = 30,
51
53
  retry_count: int = 2,
54
+ backoff: float = 1.0,
55
+ backoff_factor: float = 2.0,
52
56
  page_size: int = 5_000,
53
57
  status_poll_delay: int = 1,
54
58
  upload_chunk_size: int = 25_000_000,
@@ -86,6 +90,11 @@ class AsyncClient:
86
90
  :param retry_count: The number of times to retry an HTTP request if it fails. Set this to 0
87
91
  to never retry. Defaults to 2, meaning each HTTP Operation will be tried a total
88
92
  number of 2 times.
93
+ :param backoff: The initial backoff time in seconds for the retry mechanism. This is the
94
+ time to wait before the first retry.
95
+ :param backoff_factor: The factor by which the backoff time is multiplied after each retry.
96
+ For example, if the initial backoff is 1 second and the factor is 2, the second
97
+ retry will wait 2 seconds, the third retry will wait 4 seconds, and so on.
89
98
  :param page_size: The number of items to return per page when paginating through results.
90
99
  Defaults to 5000. This is the maximum number of items that can be returned per
91
100
  request. If you pass a value greater than 5000, it will be capped to 5000.
@@ -110,7 +119,14 @@ class AsyncClient:
110
119
  private_key_password=private_key_password,
111
120
  )
112
121
  _client = httpx.AsyncClient(auth=_auth, timeout=timeout, **httpx_kwargs)
113
- self._http = _AsyncHttpService(_client, retry_count, page_size, status_poll_delay)
122
+ self._http = _AsyncHttpService(
123
+ _client,
124
+ retry_count=retry_count,
125
+ backoff=backoff,
126
+ backoff_factor=backoff_factor,
127
+ page_size=page_size,
128
+ poll_delay=status_poll_delay,
129
+ )
114
130
  self._workspace_id = workspace_id
115
131
  self._model_id = model_id
116
132
  self._url = f"https://api.anaplan.com/2/0/workspaces/{workspace_id}/models/{model_id}"
@@ -122,6 +138,9 @@ class AsyncClient:
122
138
  self._cloud_works = _AsyncCloudWorksClient(self._http)
123
139
  self.upload_chunk_size = upload_chunk_size
124
140
  self.allow_file_creation = allow_file_creation
141
+ logger.debug(
142
+ f"Initialized AsyncClient with workspace_id={workspace_id}, model_id={model_id}"
143
+ )
125
144
 
126
145
  @classmethod
127
146
  def from_existing(
@@ -208,43 +227,53 @@ class AsyncClient:
208
227
  )
209
228
  return self._alm_client
210
229
 
211
- async def get_workspaces(self, search_pattern: str | None = None) -> list[Workspace]:
230
+ async def get_workspaces(
231
+ self,
232
+ search_pattern: str | None = None,
233
+ sort_by: Literal["size_allowance", "name"] | None = None,
234
+ descending: bool = False,
235
+ ) -> list[Workspace]:
212
236
  """
213
237
  Lists all the Workspaces the authenticated user has access to.
214
238
  :param search_pattern: Optionally filter for specific workspaces. When provided,
215
239
  case-insensitive matches workspaces with names containing this string.
216
240
  You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
217
241
  When None (default), returns all users.
242
+ :param sort_by: The field to sort the results by.
243
+ :param descending: If True, the results will be sorted in descending order.
218
244
  :return: The List of Workspaces.
219
245
  """
220
- params = {"tenantDetails": "true"}
246
+ params = {"tenantDetails": "true"} | sort_params(sort_by, descending)
221
247
  if search_pattern:
222
248
  params["s"] = search_pattern
223
- return [
224
- Workspace.model_validate(e)
225
- for e in await self._http.get_paginated(
226
- "https://api.anaplan.com/2/0/workspaces", "workspaces", params=params
227
- )
228
- ]
249
+ res = await self._http.get_paginated(
250
+ "https://api.anaplan.com/2/0/workspaces", "workspaces", params=params
251
+ )
252
+ return [Workspace.model_validate(e) for e in res]
229
253
 
230
- async def get_models(self, search_pattern: str | None = None) -> list[Model]:
254
+ async def get_models(
255
+ self,
256
+ search_pattern: str | None = None,
257
+ sort_by: Literal["active_state", "name"] | None = None,
258
+ descending: bool = False,
259
+ ) -> list[Model]:
231
260
  """
232
261
  Lists all the Models the authenticated user has access to.
233
262
  :param search_pattern: Optionally filter for specific models. When provided,
234
263
  case-insensitive matches model names containing this string.
235
264
  You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
236
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.
237
268
  :return: The List of Models.
238
269
  """
239
- params = {"modelDetails": "true"}
270
+ params = {"modelDetails": "true"} | sort_params(sort_by, descending)
240
271
  if search_pattern:
241
272
  params["s"] = search_pattern
242
- return [
243
- Model.model_validate(e)
244
- for e in await self._http.get_paginated(
245
- "https://api.anaplan.com/2/0/models", "models", params=params
246
- )
247
- ]
273
+ res = await self._http.get_paginated(
274
+ "https://api.anaplan.com/2/0/models", "models", params=params
275
+ )
276
+ return [Model.model_validate(e) for e in res]
248
277
 
249
278
  async def delete_models(self, model_ids: list[str]) -> ModelDeletionResult:
250
279
  """
@@ -260,57 +289,69 @@ class AsyncClient:
260
289
  )
261
290
  return ModelDeletionResult.model_validate(res)
262
291
 
263
- async def get_files(self) -> list[File]:
292
+ async def get_files(self, sort_by: SortBy = None, descending: bool = False) -> list[File]:
264
293
  """
265
294
  Lists all the Files in the Model.
295
+ :param sort_by: The field to sort the results by.
296
+ :param descending: If True, the results will be sorted in descending order.
266
297
  :return: The List of Files.
267
298
  """
268
- return [
269
- File.model_validate(e)
270
- for e in await self._http.get_paginated(f"{self._url}/files", "files")
271
- ]
299
+ res = await self._http.get_paginated(
300
+ f"{self._url}/files", "files", params=sort_params(sort_by, descending)
301
+ )
302
+ return [File.model_validate(e) for e in res]
272
303
 
273
- async def get_actions(self) -> list[Action]:
304
+ async def get_actions(self, sort_by: SortBy = None, descending: bool = False) -> list[Action]:
274
305
  """
275
306
  Lists all the Actions in the Model. This will only return the Actions listed under
276
307
  `Other Actions` in Anaplan. For Imports, exports, and processes, see their respective
277
308
  methods instead.
309
+ :param sort_by: The field to sort the results by.
310
+ :param descending: If True, the results will be sorted in descending order.
278
311
  :return: The List of Actions.
279
312
  """
280
- return [
281
- Action.model_validate(e)
282
- for e in await self._http.get_paginated(f"{self._url}/actions", "actions")
283
- ]
313
+ res = await self._http.get_paginated(
314
+ f"{self._url}/actions", "actions", params=sort_params(sort_by, descending)
315
+ )
316
+ return [Action.model_validate(e) for e in res]
284
317
 
285
- async def get_processes(self) -> list[Process]:
318
+ async def get_processes(
319
+ self, sort_by: SortBy = None, descending: bool = False
320
+ ) -> list[Process]:
286
321
  """
287
322
  Lists all the Processes in the Model.
323
+ :param sort_by: The field to sort the results by.
324
+ :param descending: If True, the results will be sorted in descending order.
288
325
  :return: The List of Processes.
289
326
  """
290
- return [
291
- Process.model_validate(e)
292
- for e in await self._http.get_paginated(f"{self._url}/processes", "processes")
293
- ]
327
+ res = await self._http.get_paginated(
328
+ f"{self._url}/processes", "processes", params=sort_params(sort_by, descending)
329
+ )
330
+ return [Process.model_validate(e) for e in res]
294
331
 
295
- async def get_imports(self) -> list[Import]:
332
+ async def get_imports(self, sort_by: SortBy = None, descending: bool = False) -> list[Import]:
296
333
  """
297
334
  Lists all the Imports in the Model.
335
+ :param sort_by: The field to sort the results by.
336
+ :param descending: If True, the results will be sorted in descending order.
298
337
  :return: The List of Imports.
299
338
  """
300
- return [
301
- Import.model_validate(e)
302
- for e in await self._http.get_paginated(f"{self._url}/imports", "imports")
303
- ]
339
+ res = await self._http.get_paginated(
340
+ f"{self._url}/imports", "imports", params=sort_params(sort_by, descending)
341
+ )
342
+ return [Import.model_validate(e) for e in res]
304
343
 
305
- async def get_exports(self) -> list[Export]:
344
+ async def get_exports(self, sort_by: SortBy = None, descending: bool = False) -> list[Export]:
306
345
  """
307
346
  Lists all the Exports in the Model.
347
+ :param sort_by: The field to sort the results by.
348
+ :param descending: If True, the results will be sorted in descending order.
308
349
  :return: The List of Exports.
309
350
  """
310
- return [
311
- Export.model_validate(e)
312
- for e in await self._http.get_paginated(f"{self._url}/exports", "exports")
313
- ]
351
+ res = await self._http.get_paginated(
352
+ f"{self._url}/exports", "exports", params=sort_params(sort_by, descending)
353
+ )
354
+ return [Export.model_validate(e) for e in res]
314
355
 
315
356
  async def run_action(self, action_id: int, wait_for_completion: bool = True) -> TaskStatus:
316
357
  """
@@ -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)
@@ -21,9 +21,7 @@ class _AsyncFlowClient:
21
21
  params = {"myIntegrations": 1 if current_user_only else 0}
22
22
  return [
23
23
  FlowSummary.model_validate(e)
24
- for e in await self._http.get_paginated(
25
- self._url, "integrationFlows", page_size=25, params=params
26
- )
24
+ for e in await self._http.get_paginated(self._url, "integrationFlows", params=params)
27
25
  ]
28
26
 
29
27
  async def get_flow(self, flow_id: str) -> Flow:
@@ -7,6 +7,7 @@ from anaplan_sdk._services import (
7
7
  _AsyncHttpService,
8
8
  parse_calendar_response,
9
9
  parse_insertion_response,
10
+ sort_params,
10
11
  validate_dimension_id,
11
12
  )
12
13
  from anaplan_sdk.exceptions import InvalidIdentifierException
@@ -29,6 +30,8 @@ from anaplan_sdk.models import (
29
30
  ViewInfo,
30
31
  )
31
32
 
33
+ SortBy = Literal["id", "name"] | None
34
+
32
35
  logger = logging.getLogger("anaplan_sdk")
33
36
 
34
37
 
@@ -68,23 +71,29 @@ class _AsyncTransactionalClient:
68
71
  )
69
72
  logger.info(f"Closed model '{self._model_id}'.")
70
73
 
71
- async def get_modules(self) -> list[Module]:
74
+ async def get_modules(self, sort_by: SortBy = None, descending: bool = False) -> list[Module]:
72
75
  """
73
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.
74
79
  :return: The List of Modules.
75
80
  """
76
- return [
77
- Module.model_validate(e)
78
- for e in await self._http.get_paginated(f"{self._url}/modules", "modules")
79
- ]
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]
80
85
 
81
- async def get_views(self) -> list[View]:
86
+ async def get_views(
87
+ self, sort_by: Literal["id", "module_id", "name"] | None = None, descending: bool = False
88
+ ) -> list[View]:
82
89
  """
83
90
  Lists all the Views in the Model. This will include all Modules and potentially other saved
84
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.
85
94
  :return: The List of Views.
86
95
  """
87
- params = {"includesubsidiaryviews": True}
96
+ params = {"includesubsidiaryviews": True} | sort_params(sort_by, descending)
88
97
  return [
89
98
  View.model_validate(e)
90
99
  for e in await self._http.get_paginated(f"{self._url}/views", "views", params=params)
@@ -111,15 +120,17 @@ class _AsyncTransactionalClient:
111
120
  )
112
121
  return [LineItem.model_validate(e) for e in res.get("items", [])]
113
122
 
114
- async def get_lists(self) -> list[List]:
123
+ async def get_lists(self, sort_by: SortBy = None, descending: bool = False) -> list[List]:
115
124
  """
116
125
  Lists all the Lists in the Model.
126
+ :param sort_by: The field to sort the results by.
127
+ :param descending: If True, the results will be sorted in descending order.
117
128
  :return: All Lists on this model.
118
129
  """
119
- return [
120
- List.model_validate(e)
121
- for e in await self._http.get_paginated(f"{self._url}/lists", "lists")
122
- ]
130
+ res = await self._http.get_paginated(
131
+ f"{self._url}/lists", "lists", params=sort_params(sort_by, descending)
132
+ )
133
+ return [List.model_validate(e) for e in res]
123
134
 
124
135
  async def get_list_metadata(self, list_id: int) -> ListMetadata:
125
136
  """
@@ -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,27 @@ 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: Optionally filter for specific users. When provided,
25
+ case-insensitive matches users with emails or names containing this string.
26
+ You can use the wildcards `%` for 0-n characters, and `_` for exactly 1 character.
27
+ When None (default), returns all users.
28
+ :param sort_by: The field to sort the results by.
29
+ :param descending: If True, the results will be sorted in descending order.
20
30
  :return: The List of Users.
21
31
  """
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
- ]
32
+ params = sort_params(sort_by, descending)
33
+ if search_pattern:
34
+ params["s"] = search_pattern
35
+ res = self._http.get_paginated("https://api.anaplan.com/2/0/users", "users", params=params)
36
+ return [User.model_validate(e) for e in res]
29
37
 
30
38
  def get_user(self, user_id: str = "me") -> User:
31
39
  """