anaplan-sdk 0.4.2__tar.gz → 0.4.3a1__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 (102) hide show
  1. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/.gitignore +1 -0
  2. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/PKG-INFO +1 -1
  3. anaplan_sdk-0.4.3a1/anaplan_sdk/__init__.py +5 -0
  4. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/_bulk.py +6 -2
  5. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_auth.py +32 -2
  6. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/_bulk.py +6 -2
  7. anaplan_sdk-0.4.3a1/anaplan_sdk/_oauth.py +198 -0
  8. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/async/async_alm_client.md +6 -0
  9. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/async/async_audit_client.md +6 -0
  10. anaplan_sdk-0.4.3a1/docs/api/async/async_client.md +9 -0
  11. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/async/async_cw_client.md +6 -0
  12. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/async/async_flows_client.md +6 -0
  13. anaplan_sdk-0.4.3a1/docs/api/async/async_oauth_client.md +9 -0
  14. anaplan_sdk-0.4.3a1/docs/api/async/async_transactional_client.md +11 -0
  15. anaplan_sdk-0.4.3a1/docs/api/exceptions.md +9 -0
  16. anaplan_sdk-0.4.3a1/docs/api/models/alm.md +7 -0
  17. anaplan_sdk-0.4.3a1/docs/api/models/bulk.md +7 -0
  18. anaplan_sdk-0.4.3a1/docs/api/models/cloud_works.md +7 -0
  19. anaplan_sdk-0.4.3a1/docs/api/models/flows.md +7 -0
  20. anaplan_sdk-0.4.3a1/docs/api/models/transactional.md +7 -0
  21. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/sync/sync_alm_client.md +6 -0
  22. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/sync/sync_audit_client.md +6 -0
  23. anaplan_sdk-0.4.3a1/docs/api/sync/sync_client.md +9 -0
  24. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/sync/sync_cw_client.md +6 -0
  25. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/sync/sync_flows_client.md +6 -0
  26. anaplan_sdk-0.4.3a1/docs/api/sync/sync_oauth_client.md +10 -0
  27. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/api/sync/sync_transactional_client.md +6 -0
  28. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/css/styles.css +3 -3
  29. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/authentication.md +84 -3
  30. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/index.md +1 -1
  31. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/quickstart.md +3 -3
  32. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/mkdocs.yml +10 -2
  33. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/pyproject.toml +101 -102
  34. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/uv.lock +1162 -1180
  35. anaplan_sdk-0.4.2/anaplan_sdk/__init__.py +0 -4
  36. anaplan_sdk-0.4.2/docs/api/async/async_client.md +0 -1
  37. anaplan_sdk-0.4.2/docs/api/async/async_transactional_client.md +0 -5
  38. anaplan_sdk-0.4.2/docs/api/exceptions.md +0 -4
  39. anaplan_sdk-0.4.2/docs/api/models.md +0 -4
  40. anaplan_sdk-0.4.2/docs/api/sync/sync_client.md +0 -1
  41. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/.github/dependabot.yml +0 -0
  42. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/.github/workflows/docs.yml +0 -0
  43. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/.github/workflows/lint.yml +0 -0
  44. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/.github/workflows/tests.yml +0 -0
  45. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/.pre-commit-config.yaml +0 -0
  46. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/LICENSE +0 -0
  47. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/README.md +0 -0
  48. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/__init__.py +0 -0
  49. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/_alm.py +0 -0
  50. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/_audit.py +0 -0
  51. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/_cloud_works.py +0 -0
  52. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/_cw_flow.py +0 -0
  53. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_async_clients/_transactional.py +0 -0
  54. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_base.py +0 -0
  55. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/__init__.py +0 -0
  56. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/_alm.py +0 -0
  57. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/_audit.py +0 -0
  58. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/_cloud_works.py +0 -0
  59. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/_cw_flow.py +0 -0
  60. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/_clients/_transactional.py +0 -0
  61. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/exceptions.py +0 -0
  62. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/__init__.py +0 -0
  63. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/_alm.py +0 -0
  64. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/_base.py +0 -0
  65. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/_bulk.py +0 -0
  66. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/_transactional.py +0 -0
  67. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/cloud_works.py +0 -0
  68. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/anaplan_sdk/models/flows.py +0 -0
  69. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/anaplan_explained.md +0 -0
  70. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/assets/overview.html +0 -0
  71. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/alm.md +0 -0
  72. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/audit.md +0 -0
  73. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/bulk.md +0 -0
  74. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/bulk_vs_transactional.md +0 -0
  75. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/cloud_works.md +0 -0
  76. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/logging.md +0 -0
  77. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/multiple_models.md +0 -0
  78. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/guides/transactional.md +0 -0
  79. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/img/anaplan-sdk.webp +0 -0
  80. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/index.md +0 -0
  81. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/installation.md +0 -0
  82. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/js/assets/hljs.js +0 -0
  83. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/js/assets/hljs.min.js +0 -0
  84. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/js/assets/python.js +0 -0
  85. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/js/assets/python.min.js +0 -0
  86. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/js/highlight.js +0 -0
  87. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/docs/js/highlight.min.js +0 -0
  88. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/conftest.py +0 -0
  89. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/test_async_alm_client.py +0 -0
  90. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/test_async_audit_client.py +0 -0
  91. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/test_async_client.py +0 -0
  92. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/test_async_cloud_works_client.py +0 -0
  93. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/test_async_flows_client.py +0 -0
  94. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/async/test_async_transactional_client.py +0 -0
  95. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/conftest.py +0 -0
  96. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/conftest.py +0 -0
  97. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/test_alm_client.py +0 -0
  98. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/test_audit_client.py +0 -0
  99. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/test_client.py +0 -0
  100. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/test_cloud_works_client.py +0 -0
  101. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/test_flows_client.py +0 -0
  102. {anaplan_sdk-0.4.2 → anaplan_sdk-0.4.3a1}/tests/sync/test_transactional_client.py +0 -0
@@ -9,6 +9,7 @@ __pycache__/
9
9
  .idea
10
10
  .iml
11
11
 
12
+ app.py
12
13
  debug.py
13
14
  # Distribution / packaging
14
15
  .Python
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anaplan-sdk
3
- Version: 0.4.2
3
+ Version: 0.4.3a1
4
4
  Summary: Streamlined Python Interface for Anaplan
5
5
  Project-URL: Homepage, https://vinzenzklass.github.io/anaplan-sdk/
6
6
  Project-URL: Repository, https://github.com/VinzenzKlass/anaplan-sdk
@@ -0,0 +1,5 @@
1
+ from ._async_clients import AsyncClient
2
+ from ._clients import Client
3
+ from ._oauth import AsyncOauth, Oauth
4
+
5
+ __all__ = ["AsyncClient", "AsyncOauth", "Client", "Oauth", "models", "exceptions"]
@@ -6,7 +6,7 @@ from typing import AsyncIterator, Iterator
6
6
  import httpx
7
7
  from typing_extensions import Self
8
8
 
9
- from anaplan_sdk._auth import AuthCodeCallback, AuthTokenRefreshCallback, create_auth
9
+ from anaplan_sdk._auth import AuthCodeCallback, AuthTokenRefreshCallback, _create_auth
10
10
  from anaplan_sdk._base import _AsyncBaseClient, action_url
11
11
  from anaplan_sdk.exceptions import AnaplanActionError, InvalidIdentifierException
12
12
  from anaplan_sdk.models import (
@@ -58,6 +58,8 @@ class AsyncClient(_AsyncBaseClient):
58
58
  oauth2_scope: str = "openid profile email offline_access",
59
59
  on_auth_code: AuthCodeCallback = None,
60
60
  on_token_refresh: AuthTokenRefreshCallback = None,
61
+ oauth_token: dict[str, str] | None = None,
62
+ token: str | None = None,
61
63
  timeout: float | httpx.Timeout = 30,
62
64
  retry_count: int = 2,
63
65
  status_poll_delay: int = 1,
@@ -130,7 +132,9 @@ class AsyncClient(_AsyncBaseClient):
130
132
  """
131
133
  _client = httpx.AsyncClient(
132
134
  auth=(
133
- create_auth(
135
+ _create_auth(
136
+ token=token,
137
+ oauth_token=oauth_token,
134
138
  user_email=user_email,
135
139
  password=password,
136
140
  certificate=certificate,
@@ -50,6 +50,18 @@ class _AnaplanAuth(httpx.Auth):
50
50
  self._token: str = response.json()["tokenInfo"]["tokenValue"]
51
51
 
52
52
 
53
+ class StaticTokenAuth(httpx.Auth):
54
+ def __init__(self, token: str):
55
+ logger.warning("Using static token authentication. Tokens will not be refreshed.")
56
+ self._token = token
57
+
58
+ def auth_flow(self, request):
59
+ request.headers["Authorization"] = f"AnaplanAuthToken {self._token}"
60
+ response = yield request
61
+ if response.status_code == 401:
62
+ raise InvalidCredentialsException("Your token is invalid or expired.")
63
+
64
+
53
65
  class AnaplanBasicAuth(_AnaplanAuth):
54
66
  def __init__(self, user_email: str, password: str):
55
67
  self.user_email = user_email
@@ -229,7 +241,7 @@ class AnaplanOauth2AuthCodeAuth(_AnaplanAuth):
229
241
  raise InvalidCredentialsException("Error during OAuth2 authorization flow.") from error
230
242
 
231
243
 
232
- def create_auth(
244
+ def _create_auth(
233
245
  user_email: str | None = None,
234
246
  password: str | None = None,
235
247
  certificate: str | bytes | None = None,
@@ -242,7 +254,25 @@ def create_auth(
242
254
  oauth2_scope: str = "openid profile email offline_access",
243
255
  on_auth_code: AuthCodeCallback = None,
244
256
  on_token_refresh: AuthTokenRefreshCallback = None,
245
- ) -> _AnaplanAuth:
257
+ token: str | None = None,
258
+ oauth_token: dict[str, str] | None = None,
259
+ ) -> httpx.Auth:
260
+ if token:
261
+ # TODO: If other parameters are provided that allow refreshing the token, use them to create
262
+ # use them to create one of the other auth classes instead.
263
+ return StaticTokenAuth(token)
264
+ if oauth_token:
265
+ if not isinstance(oauth_token, dict) and all(
266
+ f in oauth_token for f in ("access_token", "refresh_token", "token_type", "scope")
267
+ ):
268
+ raise ValueError(
269
+ "oauth_token must be a dictionary with at least 'access_token', 'refresh_token', "
270
+ "'token_type', and 'scope' keys."
271
+ )
272
+ # TODO: If client_id, client_secret, and redirect_uri are provided, use them to create an
273
+ # AnaplanOauth2AuthCodeAuth (extend to accept existing `access_token` instance. Else, use
274
+ # the StaticTokenAuth directly.
275
+ return StaticTokenAuth(oauth_token["access_token"])
246
276
  if certificate and private_key:
247
277
  return AnaplanCertAuth(certificate, private_key, private_key_password)
248
278
  if user_email and password:
@@ -8,7 +8,7 @@ from typing import Callable, Iterator
8
8
  import httpx
9
9
  from typing_extensions import Self
10
10
 
11
- from anaplan_sdk._auth import create_auth
11
+ from anaplan_sdk._auth import _create_auth
12
12
  from anaplan_sdk._base import _BaseClient, action_url
13
13
  from anaplan_sdk.exceptions import AnaplanActionError, InvalidIdentifierException
14
14
  from anaplan_sdk.models import (
@@ -60,6 +60,8 @@ class Client(_BaseClient):
60
60
  oauth2_scope: str = "openid profile email offline_access",
61
61
  on_auth_code: Callable[[str], str] | None = None,
62
62
  on_token_refresh: Callable[[dict[str, str]], None] | None = None,
63
+ oauth_token: dict[str, str] | None = None,
64
+ token: str | None = None,
63
65
  timeout: float | httpx.Timeout = 30,
64
66
  retry_count: int = 2,
65
67
  status_poll_delay: int = 1,
@@ -124,7 +126,9 @@ class Client(_BaseClient):
124
126
  """
125
127
  _client = httpx.Client(
126
128
  auth=(
127
- create_auth(
129
+ _create_auth(
130
+ token=token,
131
+ oauth_token=oauth_token,
128
132
  user_email=user_email,
129
133
  password=password,
130
134
  certificate=certificate,
@@ -0,0 +1,198 @@
1
+ import logging
2
+ from typing import Callable
3
+
4
+ import httpx
5
+
6
+ from .exceptions import AnaplanException, InvalidCredentialsException
7
+
8
+ logger = logging.getLogger("anaplan_sdk")
9
+
10
+
11
+ class _BaseOauth:
12
+ def __init__(
13
+ self,
14
+ client_id: str,
15
+ client_secret: str,
16
+ redirect_url: str,
17
+ authorization_url: str = "https://us1a.app.anaplan.com/auth/prelogin",
18
+ token_url: str = "https://us1a.app.anaplan.com/oauth/token",
19
+ validation_url: str = "https://auth.anaplan.com/token/validate",
20
+ scope: str = "openid profile email offline_access",
21
+ state_generator: Callable[[], str] | None = None,
22
+ ):
23
+ """
24
+ Initializes the OAuth Client. This class provides the two utilities needed to implement
25
+ the OAuth 2.0 authorization code flow for user-facing Web Applications. It differs from the
26
+ other Authentication Strategies in this SDK in two main ways:
27
+
28
+ 1. You must implement the actual authentication flow in your application. You cannot pass
29
+ the credentials directly to the `Client` or `AsyncClient`, and this class does not
30
+ implement the SDK internal authentication flow, i.e. it does not subclass `httpx.Auth`.
31
+
32
+ 2. You then simply pass the resulting token to the `Client` or `AsyncClient`, rather than
33
+ passing the credentials directly, which will internally construct an `httpx.Auth` instance
34
+
35
+ Note that this class exist for convenience only, and you can implement the OAuth 2.0 Flow
36
+ yourself in your preferred library, or bring an existing implementation. For details on the
37
+ Anaplan OAuth 2.0 Flow, see the [the Docs](https://anaplanoauth2service.docs.apiary.io/#reference/overview-of-the-authorization-code-grant).
38
+ :param client_id: The client ID of your Anaplan Oauth 2.0 application. This Application
39
+ must be an Authorization Code Grant application.
40
+ :param client_secret: The client secret of your Anaplan Oauth 2.0 application.
41
+ :param redirect_url: The URL to which the user will be redirected after authorizing the
42
+ application.
43
+ :param authorization_url: The URL to which the user will be redirected to authorize the
44
+ application. Defaults to the Anaplan Prelogin Page, where the user can select the
45
+ login method.
46
+ :param token_url: The URL to post the authorization code to in order to fetch the access
47
+ token.
48
+ :param validation_url: The URL to validate the access token.
49
+ :param scope: The scope of the access request.
50
+ :param state_generator: A callable that generates a random state string. You can optionally
51
+ pass this if you need to customize the state generation logic. If not provided,
52
+ the state will be generated by `oauthlib`.
53
+ """
54
+ self._client_id = client_id
55
+ self._client_secret = client_secret
56
+ self._redirect_url = redirect_url
57
+ self._authorization_url = authorization_url
58
+ self._token_url = token_url
59
+ self._validation_url = validation_url
60
+ self._scope = scope
61
+
62
+ try:
63
+ from oauthlib.oauth2 import WebApplicationClient
64
+ except ImportError as e:
65
+ raise AnaplanException(
66
+ "oauthlib is not available. Please install anaplan-sdk with the oauth extra "
67
+ "`pip install anaplan-sdk[oauth]` or install oauthlib separately."
68
+ ) from e
69
+ self._oauth = WebApplicationClient(client_id=client_id, client_secret=client_secret)
70
+ self._state_generator = state_generator if state_generator else self._oauth.state_generator
71
+
72
+ def authorization_url(
73
+ self, authorization_url: str | None = None, state: str | None = None
74
+ ) -> tuple[str, str]:
75
+ """
76
+ Generates the authorization URL for the OAuth 2.0 flow.
77
+ :param authorization_url: You can optionally pass a custom authorization URL. This is
78
+ useful if you want to redirect i.e. redirect the user directly to the Anaplan login
79
+ page rather than the Prelogin page in only one scenario, while still reusing the
80
+ Client.
81
+ :param state: You can optionally pass a custom state string. If not provided, a random
82
+ state string will be generated by the `oauthlib` library, or by the
83
+ `state_generator` callable if provided.
84
+ :return: A tuple containing the authorization URL and the state string.
85
+ """
86
+ auth_url = authorization_url or self._authorization_url
87
+ state = state or self._state_generator()
88
+ url, _, _ = self._oauth.prepare_authorization_request(
89
+ auth_url, state, self._redirect_url, self._scope
90
+ )
91
+ return url, state
92
+
93
+
94
+ class AsyncOauth(_BaseOauth):
95
+ """
96
+ Asynchronous Variant of the Anaplan OAuth client for interactive OAuth Flows in Web
97
+ Applications.
98
+ """
99
+
100
+ async def fetch_token(self, authorization_response: str) -> dict[str, str]:
101
+ """
102
+ Fetches the token using the authorization response from the OAuth 2.0 flow.
103
+ :param authorization_response: The full URL that the user was redirected to after
104
+ authorizing the application. This URL will contain the authorization code and state.
105
+ :return: The token as a dictionary containing the access token, refresh token, scope,
106
+ expires_in, and type.
107
+ """
108
+ from oauthlib.oauth2 import OAuth2Error
109
+
110
+ try:
111
+ url, headers, body = self._oauth.prepare_token_request(
112
+ authorization_response=authorization_response,
113
+ token_url=self._token_url,
114
+ redirect_url=self._redirect_url,
115
+ client_secret=self._client_secret,
116
+ )
117
+ async with httpx.AsyncClient() as client:
118
+ response = await client.post(url=url, headers=headers, content=body)
119
+ if not response.is_success:
120
+ raise InvalidCredentialsException(
121
+ f"Token request failed: {response.status_code} {response.text}"
122
+ )
123
+ return response.json()
124
+ except (httpx.HTTPError, ValueError, TypeError, OAuth2Error) as error:
125
+ logger.error(error)
126
+ raise AnaplanException("Error during token creation.") from error
127
+
128
+ async def validate_token(self, token: str) -> dict[str, str | dict[str, str]]:
129
+ """
130
+ Validates the provided token by checking its validity with the Anaplan Authentication API.
131
+ If the token is not valid, an `InvalidCredentialsException` is raised.
132
+ :param token: The access token to validate.
133
+ :return: The Token information as a dictionary containing the token's details.
134
+ """
135
+ try:
136
+ async with httpx.AsyncClient() as client:
137
+ response = await client.get(
138
+ url=self._validation_url, headers={"Authorization": f"AnaplanAuthToken {token}"}
139
+ )
140
+ if not response.is_success:
141
+ raise InvalidCredentialsException
142
+ return response.json()
143
+ except httpx.HTTPError as error:
144
+ logger.error(error)
145
+ raise AnaplanException("Error during token validation.") from error
146
+
147
+
148
+ class Oauth(_BaseOauth):
149
+ """
150
+ Synchronous Variant of the Anaplan OAuth client for interactive OAuth Flows in Web
151
+ Applications.
152
+ """
153
+
154
+ def fetch_token(self, authorization_response: str) -> dict[str, str]:
155
+ """
156
+ Fetches the token using the authorization response from the OAuth 2.0 flow.
157
+ :param authorization_response: The full URL that the user was redirected to after
158
+ authorizing the application. This URL will contain the authorization code and state.
159
+ :return: The token as a dictionary containing the access token, refresh token, scope,
160
+ expires_in, and type.
161
+ """
162
+ from oauthlib.oauth2 import OAuth2Error
163
+
164
+ try:
165
+ url, headers, body = self._oauth.prepare_token_request(
166
+ authorization_response=authorization_response,
167
+ token_url=self._token_url,
168
+ redirect_url=self._redirect_url,
169
+ client_secret=self._client_secret,
170
+ )
171
+ with httpx.Client() as client:
172
+ response = client.post(url=url, headers=headers, content=body)
173
+ if not response.is_success:
174
+ raise AnaplanException(
175
+ f"Token request failed: {response.status_code} {response.text}"
176
+ )
177
+ return response.json()
178
+ except (httpx.HTTPError, ValueError, TypeError, OAuth2Error) as error:
179
+ raise AnaplanException("Error during token creation.") from error
180
+
181
+ def validate_token(self, token: str) -> dict[str, str | dict[str, str]]:
182
+ """
183
+ Validates the provided token by checking its validity with the Anaplan Authentication API.
184
+ If the token is not valid, an `InvalidCredentialsException` is raised.
185
+ :param token: The access token to validate.
186
+ :return: The Token information as a dictionary containing the token's details.
187
+ """
188
+ try:
189
+ with httpx.Client() as client:
190
+ response = client.get(
191
+ url=self._validation_url, headers={"Authorization": f"AnaplanAuthToken {token}"}
192
+ )
193
+ if not response.is_success:
194
+ raise InvalidCredentialsException
195
+ return response.json()
196
+ except httpx.HTTPError as error:
197
+ logger.error(error)
198
+ raise AnaplanException("Error during token validation.") from error
@@ -3,3 +3,9 @@
3
3
  instance of [AsyncClient](async_client.md). For more details, see the [Guide](../../guides/alm.md).
4
4
 
5
5
  ::: anaplan_sdk._async_clients._AsyncAlmClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [AsyncClient](async_client.md). For more details, see the [Guide](../../guides/audit.md).
4
4
 
5
5
  ::: anaplan_sdk._async_clients._AsyncAuditClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -0,0 +1,9 @@
1
+ # Bulk API Client (`AsyncClient`)
2
+
3
+ ::: anaplan_sdk.AsyncClient
4
+
5
+ <style>
6
+ [data-md-component="toc"] li:first-of-type{
7
+ display: none!important;
8
+ }
9
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [AsyncClient](async_client.md). For more details, see the [Guide](../../guides/cloud_works.md).
4
4
 
5
5
  ::: anaplan_sdk._async_clients._AsyncCloudWorksClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [AsyncClient](async_client.md). For more details, see the [Guide](../../guides/cloud_works.md).
4
4
 
5
5
  ::: anaplan_sdk._async_clients._cw_flow._AsyncFlowClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -0,0 +1,9 @@
1
+ # AsyncOauth
2
+
3
+ ::: anaplan_sdk._oauth.AsyncOauth
4
+ options:
5
+ inherited_members: true
6
+ members:
7
+ - __init__
8
+ - authorization_url
9
+ - fetch_token
@@ -0,0 +1,11 @@
1
+ ???+ note
2
+ This Class is not meant to be instantiated directly, but rather accessed through the `transactional` Property on an
3
+ instance of [AsyncClient](async_client.md). For more details, see the [Guide](../../guides/transactional.md).
4
+
5
+ ::: anaplan_sdk._async_clients._AsyncTransactionalClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -0,0 +1,9 @@
1
+ ::: anaplan_sdk.exceptions
2
+ options:
3
+ show_bases: true
4
+
5
+ <style>
6
+ [data-md-component="toc"] li:first-of-type{
7
+ display: none!important;
8
+ }
9
+ </style>
@@ -0,0 +1,7 @@
1
+ ::: anaplan_sdk.models._alm
2
+
3
+ <style>
4
+ [data-md-component="toc"] li:first-of-type{
5
+ display: none!important;
6
+ }
7
+ </style>
@@ -0,0 +1,7 @@
1
+ ::: anaplan_sdk.models._bulk
2
+
3
+ <style>
4
+ [data-md-component="toc"] li:first-of-type{
5
+ display: none!important;
6
+ }
7
+ </style>
@@ -0,0 +1,7 @@
1
+ ::: anaplan_sdk.models.cloud_works
2
+
3
+ <style>
4
+ [data-md-component="toc"] li:first-of-type{
5
+ display: none!important;
6
+ }
7
+ </style>
@@ -0,0 +1,7 @@
1
+ ::: anaplan_sdk.models.flows
2
+
3
+ <style>
4
+ [data-md-component="toc"] li:first-of-type{
5
+ display: none!important;
6
+ }
7
+ </style>
@@ -0,0 +1,7 @@
1
+ ::: anaplan_sdk.models._transactional
2
+
3
+ <style>
4
+ [data-md-component="toc"] li:first-of-type{
5
+ display: none!important;
6
+ }
7
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [Client](sync_client.md). For more details, see the [Guide](../../guides/alm.md).
4
4
 
5
5
  ::: anaplan_sdk._clients._AlmClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [Client](sync_client.md). For more details, see the [Guide](../../guides/audit.md).
4
4
 
5
5
  ::: anaplan_sdk._clients._AuditClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -0,0 +1,9 @@
1
+ # Bulk API Client (`Client`)
2
+
3
+ ::: anaplan_sdk.Client
4
+
5
+ <style>
6
+ [data-md-component="toc"] li:first-of-type{
7
+ display: none!important;
8
+ }
9
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [Client](sync_client.md). For more details, see the [Guide](../../guides/cloud_works.md).
4
4
 
5
5
  ::: anaplan_sdk._async_clients._AsyncCloudWorksClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -3,3 +3,9 @@
3
3
  instance of [Client](sync_client.md). For more details, see the [Guide](../../guides/cloud_works.md).
4
4
 
5
5
  ::: anaplan_sdk._async_clients._cw_flow._AsyncFlowClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -0,0 +1,10 @@
1
+ # Oauth
2
+
3
+ ::: anaplan_sdk._oauth.Oauth
4
+ options:
5
+ inherited_members: true
6
+ members:
7
+ - __init__
8
+ - authorization_url
9
+ - fetch_token
10
+
@@ -3,3 +3,9 @@
3
3
  instance of [Client](sync_client.md). For more details, see the [Guide](../../guides/transactional.md).
4
4
 
5
5
  ::: anaplan_sdk._clients._TransactionalClient
6
+
7
+ <style>
8
+ [data-md-component="toc"] li:first-of-type{
9
+ display: none!important;
10
+ }
11
+ </style>
@@ -35,7 +35,7 @@
35
35
  color: #D55FDE
36
36
  }
37
37
 
38
- .hljs-addition, .hljs-attribute, .hljs-meta .hljs-string, .hljs-regexp, .hljs-string {
38
+ .hljs-addition, .hljs-attribute, .hljs-string, .hljs-regexp, .hljs-string {
39
39
  color: #2fb170
40
40
  }
41
41
 
@@ -43,7 +43,7 @@
43
43
  color: #abb2bf
44
44
  }
45
45
 
46
- .hljs-type {
46
+ .hljs-type, .hljs-meta {
47
47
  color: #E4B962;
48
48
  }
49
49
 
@@ -51,7 +51,7 @@
51
51
  color: #d0864a
52
52
  }
53
53
 
54
- .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-symbol, .hljs-title, .hljs-class .hljs-title, .hljs-title.class_ {
54
+ .hljs-bullet, .hljs-link, .hljs-selector-id, .hljs-symbol, .hljs-title, .hljs-class .hljs-title, .hljs-title.class_ {
55
55
  color: #5488e8
56
56
  }
57
57