anaplan-sdk 0.4.5__py3-none-any.whl → 0.5.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anaplan_sdk/_async_clients/_alm.py +248 -44
- anaplan_sdk/_async_clients/_audit.py +13 -13
- anaplan_sdk/_async_clients/_bulk.py +181 -135
- anaplan_sdk/_async_clients/_cloud_works.py +57 -38
- anaplan_sdk/_async_clients/_cw_flow.py +25 -16
- anaplan_sdk/_async_clients/_transactional.py +251 -53
- anaplan_sdk/_clients/_alm.py +246 -45
- anaplan_sdk/_clients/_audit.py +13 -14
- anaplan_sdk/_clients/_bulk.py +180 -123
- anaplan_sdk/_clients/_cloud_works.py +54 -36
- anaplan_sdk/_clients/_cw_flow.py +25 -16
- anaplan_sdk/_clients/_transactional.py +246 -50
- anaplan_sdk/_services.py +392 -0
- anaplan_sdk/models/__init__.py +49 -2
- anaplan_sdk/models/_alm.py +64 -6
- anaplan_sdk/models/_bulk.py +16 -9
- anaplan_sdk/models/_transactional.py +221 -4
- {anaplan_sdk-0.4.5.dist-info → anaplan_sdk-0.5.0a2.dist-info}/METADATA +1 -1
- anaplan_sdk-0.5.0a2.dist-info/RECORD +30 -0
- anaplan_sdk/_base.py +0 -297
- anaplan_sdk-0.4.5.dist-info/RECORD +0 -30
- {anaplan_sdk-0.4.5.dist-info → anaplan_sdk-0.5.0a2.dist-info}/WHEEL +0 -0
- {anaplan_sdk-0.4.5.dist-info → anaplan_sdk-0.5.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -1,3 +1,5 @@
|
|
1
|
+
from typing import Literal, TypeAlias, Union
|
2
|
+
|
1
3
|
from pydantic import Field
|
2
4
|
|
3
5
|
from ._base import AnaplanModel
|
@@ -34,6 +36,120 @@ class Module(AnaplanModel):
|
|
34
36
|
name: str = Field(description="The name of this module.")
|
35
37
|
|
36
38
|
|
39
|
+
class Dimension(AnaplanModel):
|
40
|
+
id: int = Field(description="The unique identifier of this dimension.")
|
41
|
+
name: str = Field(description="The name of this dimension.")
|
42
|
+
|
43
|
+
|
44
|
+
class DimensionWithCode(Dimension):
|
45
|
+
code: str = Field(description="The code of this dimension.")
|
46
|
+
|
47
|
+
|
48
|
+
class View(AnaplanModel):
|
49
|
+
code: str = Field(description="The code of this view.")
|
50
|
+
id: int = Field(description="The unique identifier of this view.")
|
51
|
+
name: str = Field(description="The name of this views.")
|
52
|
+
moduleId: int = Field(description="The unique identifier of the module this view belongs to.")
|
53
|
+
|
54
|
+
|
55
|
+
class ViewInfo(AnaplanModel):
|
56
|
+
view_id: int = Field(description="The unique identifier of this view.")
|
57
|
+
view_name: str = Field(description="The name of this view.")
|
58
|
+
rows: list[Dimension] = Field(
|
59
|
+
[], description="The list of dimensions in the rows of this view."
|
60
|
+
)
|
61
|
+
pages: list[Dimension] = Field(
|
62
|
+
[], description="The list of dimensions in the pages of this view."
|
63
|
+
)
|
64
|
+
|
65
|
+
|
66
|
+
class PeriodType(AnaplanModel):
|
67
|
+
entity_id: Literal["YEAR", "HALF_YEAR", "MONTH", "QUARTER", "WEEK", "DAY"] = Field(
|
68
|
+
description="The type of period entity."
|
69
|
+
)
|
70
|
+
entity_label: Literal["Year", "Half-Year", "Month", "Quarter", "Week", "Day"] = Field(
|
71
|
+
description="The type of period entity."
|
72
|
+
)
|
73
|
+
entity_index: int = Field(description="The index of the period entity")
|
74
|
+
|
75
|
+
|
76
|
+
class EntityFormatFilter(AnaplanModel):
|
77
|
+
source_line_item_or_property: str = Field(
|
78
|
+
description="The unique identifier of the source line item or property."
|
79
|
+
)
|
80
|
+
mapping_hierarchy: str = Field(description="The unique identifier of the mapping hierarchy.")
|
81
|
+
key_property: str = Field(description="The unique identifier of the key property.")
|
82
|
+
value_property: str = Field(description="The unique identifier of the value property.")
|
83
|
+
|
84
|
+
|
85
|
+
class TextMetadata(AnaplanModel):
|
86
|
+
data_type: Literal["TEXT"] = Field(
|
87
|
+
description="The data type. Literal for the tagged union discriminator."
|
88
|
+
)
|
89
|
+
text_type: Literal["DRILLTHRU_URI", "EMAIL_ADDRESS", "GENERAL"] = Field(
|
90
|
+
description="The text type."
|
91
|
+
)
|
92
|
+
|
93
|
+
|
94
|
+
class ListMetadata(AnaplanModel):
|
95
|
+
data_type: Literal["ENTITY"] = Field(
|
96
|
+
description="The data type. Literal for the tagged union discriminator."
|
97
|
+
)
|
98
|
+
hierarchy_entity_id: int = Field(
|
99
|
+
validation_alias="hierarchyEntityLongId",
|
100
|
+
description="The unique identifier of the hierarchy entity, like Lists or List Subsets.",
|
101
|
+
)
|
102
|
+
selective_access_applied: bool = Field(
|
103
|
+
description="Whether selective access is applied or not."
|
104
|
+
)
|
105
|
+
show_all: bool = Field(description="Whether to show all values or not.")
|
106
|
+
entity_format_filter: EntityFormatFilter | None = Field(
|
107
|
+
None, description="Entity format filter configuration."
|
108
|
+
)
|
109
|
+
|
110
|
+
|
111
|
+
class TimePeriodMetadata(AnaplanModel):
|
112
|
+
data_type: Literal["TIME_ENTITY"] = Field(
|
113
|
+
description="The data type. Literal for the tagged union discriminator."
|
114
|
+
)
|
115
|
+
period_type: PeriodType = Field(description="The period type.")
|
116
|
+
|
117
|
+
|
118
|
+
class NumberMetadata(AnaplanModel):
|
119
|
+
data_type: Literal["NUMBER"] = Field(
|
120
|
+
description="The data type. Literal for the tagged union discriminator."
|
121
|
+
)
|
122
|
+
comparison_increase: Literal["GOOD", "BAD", "NEUTRAL"] | None = Field(
|
123
|
+
description="The comparison increase setting."
|
124
|
+
)
|
125
|
+
custom_units: str | None = Field(None, description="Custom units for display.")
|
126
|
+
decimal_places: int = Field(description="Number of decimal places.")
|
127
|
+
decimal_separator: Literal["COMMA", "FULL_STOP"] = Field(description="The decimal separator.")
|
128
|
+
units_display_type: Literal[
|
129
|
+
"CUSTOM_SUFFIX",
|
130
|
+
"CUSTOM_PREFIX",
|
131
|
+
"CURRENCY_CODE",
|
132
|
+
"CURRENCY_SYMBOL",
|
133
|
+
"PERCENTAGE_SUFFIX",
|
134
|
+
"NONE",
|
135
|
+
] = Field(description="Units display type.")
|
136
|
+
units_type: Literal["CUSTOM", "CURRENCY", "PERCENTAGE", "NONE"] = Field(
|
137
|
+
description="Units type."
|
138
|
+
)
|
139
|
+
zero_format: Literal["HYPHEN", "ZERO", "BLANK"] = Field(description="Zero format display.")
|
140
|
+
grouping_separator: Literal["COMMA", "FULL_STOP", "SPACE", "NONE"] = Field(
|
141
|
+
description="The grouping separator."
|
142
|
+
)
|
143
|
+
minimum_significant_digits: int = Field(description="Minimum significant digits.")
|
144
|
+
negative_number_notation: Literal["MINUS_SIGN", "PARENTHESES"] = Field(
|
145
|
+
description="Negative number notation."
|
146
|
+
)
|
147
|
+
|
148
|
+
|
149
|
+
class GenericTypeMetadata(AnaplanModel):
|
150
|
+
data_type: Literal["BOOLEAN", "NONE", "DATE"] = Field(description="The data type.")
|
151
|
+
|
152
|
+
|
37
153
|
class LineItem(AnaplanModel):
|
38
154
|
id: int = Field(description="The unique identifier of this line item.")
|
39
155
|
name: str = Field(description="The name of this line item.")
|
@@ -41,16 +157,33 @@ class LineItem(AnaplanModel):
|
|
41
157
|
description="The unique identifier of the module this line item belongs to."
|
42
158
|
)
|
43
159
|
module_name: str = Field(description="The name of the module this line item belongs to.")
|
44
|
-
format:
|
45
|
-
|
160
|
+
format: Literal["NUMBER", "BOOLEAN", "TEXT", "NONE", "DATE", "LIST", "TIME PERIOD"] = Field(
|
161
|
+
description="The format of this line item."
|
162
|
+
)
|
163
|
+
format_metadata: (
|
164
|
+
NumberMetadata | ListMetadata | TimePeriodMetadata | TextMetadata | GenericTypeMetadata
|
165
|
+
) = Field(
|
166
|
+
description="The format metadata of this line item. Each Type provides different metadata.",
|
167
|
+
discriminator="data_type",
|
168
|
+
)
|
46
169
|
summary: str = Field(description="The summary of this line item.")
|
47
|
-
applies_to: list[
|
170
|
+
applies_to: list[Dimension] = Field([], description="The applies to value of this line item.")
|
171
|
+
data_tags: list[Dimension] = Field([], description="The data tags of this line item.")
|
172
|
+
referenced_by: list[Dimension] = Field([], description="List of references to this line item.")
|
48
173
|
time_scale: str = Field(description="The time scale of this line item.")
|
49
174
|
time_range: str = Field(description="The time range of this line item.")
|
50
|
-
version:
|
175
|
+
version: Dimension = Field(description="The version of this line item.")
|
176
|
+
parent: Dimension | None = Field(None, description="The Parent of this line item.")
|
177
|
+
read_access_driver: Dimension | None = Field(
|
178
|
+
None, description="The read access driver of this line item."
|
179
|
+
)
|
180
|
+
write_access_driver: Dimension | None = Field(
|
181
|
+
None, description="The write access driver of this line item."
|
182
|
+
)
|
51
183
|
style: str = Field(description="The style of this line item.")
|
52
184
|
cell_count: int | None = Field(None, description="The cell count of this line item.")
|
53
185
|
notes: str = Field(description="The notes of this line item.")
|
186
|
+
code: str | None = Field(None, description="The code of this line item.")
|
54
187
|
is_summary: bool = Field(description="Whether this line item is a summary or not.")
|
55
188
|
formula: str | None = Field(None, description="The formula of this line item.")
|
56
189
|
formula_scope: str = Field(description="The formula scope of this line item.")
|
@@ -92,3 +225,87 @@ class InsertionResult(AnaplanModel):
|
|
92
225
|
ignored: int = Field(description="The number of items ignored, or items that failed.")
|
93
226
|
total: int = Field(description="The total number of items.")
|
94
227
|
failures: list[Failure] = Field([], description="The list of failures.")
|
228
|
+
|
229
|
+
|
230
|
+
class ListDeletionResult(AnaplanModel):
|
231
|
+
deleted: int = Field(description="The number of items successfully deleted.")
|
232
|
+
failures: list[Failure] = Field([], description="The list of failures.")
|
233
|
+
|
234
|
+
|
235
|
+
class PartialCurrentPeriod(AnaplanModel):
|
236
|
+
period_text: str = Field(description="The text representation of the current period.")
|
237
|
+
last_day: str = Field(description="The last day of the current period in YYYY-MM-DD format.")
|
238
|
+
|
239
|
+
|
240
|
+
class CurrentPeriod(PartialCurrentPeriod):
|
241
|
+
calendar_type: str = Field(description="The type of calendar used for the current period.")
|
242
|
+
|
243
|
+
|
244
|
+
class FiscalYear(AnaplanModel):
|
245
|
+
year: str = Field(description="The fiscal year in the format set in the model, e.g. FY24.")
|
246
|
+
start_date: str = Field(description="The start date of the fiscal year in YYYY-MM-DD format.")
|
247
|
+
end_date: str = Field(description="The end date of the fiscal year in YYYY-MM-DD format.")
|
248
|
+
|
249
|
+
|
250
|
+
class TotalsSelection(AnaplanModel):
|
251
|
+
quarter_totals: bool = Field(description="Whether quarter totals are enabled.")
|
252
|
+
half_year_totals: bool = Field(description="Whether half year totals are enabled.")
|
253
|
+
year_to_date_summary: bool = Field(description="Whether year to date summary is enabled.")
|
254
|
+
year_to_go_summary: bool = Field(description="Whether year to go summary is enabled.")
|
255
|
+
total_of_all_periods: bool = Field(description="Whether total of all periods is enabled.")
|
256
|
+
|
257
|
+
|
258
|
+
class TotalsSelectionWithQuarter(TotalsSelection):
|
259
|
+
extra_month_quarter: Literal[1, 2, 3, 4] = Field(
|
260
|
+
description="The quarter in which the extra month is included."
|
261
|
+
)
|
262
|
+
|
263
|
+
|
264
|
+
class BaseCalendar(AnaplanModel):
|
265
|
+
calendar_type: Literal[
|
266
|
+
"Calendar Months/Quarters/Years",
|
267
|
+
"Weeks: 4-4-5, 4-5-4 or 5-4-4",
|
268
|
+
"Weeks: General",
|
269
|
+
"Weeks: 13 4-week Periods",
|
270
|
+
] = Field(description="The type of calendar used.")
|
271
|
+
current_period: PartialCurrentPeriod = Field(description="The current period configuration.")
|
272
|
+
|
273
|
+
|
274
|
+
class MonthsQuartersYearsCalendar(BaseCalendar):
|
275
|
+
past_years_count: int = Field(description="The number of past years included.")
|
276
|
+
fiscal_year: FiscalYear = Field(description="The fiscal year configuration.")
|
277
|
+
totals_selection: TotalsSelection = Field(
|
278
|
+
description="The totals selection configuration for the calendar."
|
279
|
+
)
|
280
|
+
|
281
|
+
|
282
|
+
class WeeksGeneralCalendar(BaseCalendar):
|
283
|
+
start_date: str = Field(description="The start date of the calendar in YYYY-MM-DD format.")
|
284
|
+
weeks_count: int = Field(description="The number of weeks in the calendar.")
|
285
|
+
|
286
|
+
|
287
|
+
class WeeksPeriodsCalendar(BaseCalendar):
|
288
|
+
fiscal_year: FiscalYear = Field(description="The fiscal year configuration.")
|
289
|
+
past_years_count: int = Field(description="The number of past years included.")
|
290
|
+
future_years_count: int = Field(description="The number of future years included.")
|
291
|
+
extra_week_month: int = Field(description="The month in which the extra week is included.")
|
292
|
+
week_format: Literal["Numbered", "Week Commencing", "Week Ending"] = Field(
|
293
|
+
description="The format of the week."
|
294
|
+
)
|
295
|
+
totals_selection: TotalsSelectionWithQuarter = Field(
|
296
|
+
description="The totals selection configuration for the calendar."
|
297
|
+
)
|
298
|
+
|
299
|
+
|
300
|
+
class WeeksGroupingCalendar(WeeksPeriodsCalendar):
|
301
|
+
week_grouping: str = Field(
|
302
|
+
description="The week grouping configuration, e.g. '4-4-5', '4-5-4', or '5-4-4'."
|
303
|
+
)
|
304
|
+
totals_selection: TotalsSelection = Field(
|
305
|
+
description="The totals selection configuration for the calendar."
|
306
|
+
)
|
307
|
+
|
308
|
+
|
309
|
+
ModelCalendar: TypeAlias = Union[
|
310
|
+
MonthsQuartersYearsCalendar, WeeksGeneralCalendar, WeeksGroupingCalendar, WeeksPeriodsCalendar
|
311
|
+
]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: anaplan-sdk
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0a2
|
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,30 @@
|
|
1
|
+
anaplan_sdk/__init__.py,sha256=WScEKtXlnRLjCb-j3qW9W4kEACTyPsTLFs-L54et2TQ,351
|
2
|
+
anaplan_sdk/_auth.py,sha256=l5z2WCcfQ05OkuQ1dcmikp6dB87Rw1qy2zu8bbaAQTs,16620
|
3
|
+
anaplan_sdk/_oauth.py,sha256=AynlJDrGIinQT0jwxI2RSvtU4D7Wasyw3H1uicdlLVI,12672
|
4
|
+
anaplan_sdk/_services.py,sha256=slsFFx_fCQSfKZo_G0HzEFGErvmEerSMyaVwLXUPCtU,17158
|
5
|
+
anaplan_sdk/exceptions.py,sha256=ALkA9fBF0NQ7dufFxV6AivjmHyuJk9DOQ9jtJV2n7f0,1809
|
6
|
+
anaplan_sdk/_async_clients/__init__.py,sha256=pZXgMMg4S9Aj_pxQCaSiPuNG-sePVGBtNJ0133VjqW4,364
|
7
|
+
anaplan_sdk/_async_clients/_alm.py,sha256=rhVhykUo6wIvA1SBQkpEAviSsVLURumi_3XQlxTf7z8,12788
|
8
|
+
anaplan_sdk/_async_clients/_audit.py,sha256=dipSzp4jMvRCHJAVMQfO854_wpmIcYEDinEPSGdoms4,2342
|
9
|
+
anaplan_sdk/_async_clients/_bulk.py,sha256=sUDWT01JcN-IWc5RY0thcAA45k54x6lO-lN2WMoCrZE,27278
|
10
|
+
anaplan_sdk/_async_clients/_cloud_works.py,sha256=ecm7DqT39J56xQwYxJMKd_ZVqxzXZdpmagwJUvqKBj4,17613
|
11
|
+
anaplan_sdk/_async_clients/_cw_flow.py,sha256=PTi-jKeRtYgibqrcE7SCsEgus18nE7ZCs7Awzk4u6Dk,3981
|
12
|
+
anaplan_sdk/_async_clients/_transactional.py,sha256=dRh4poYLWcV0kJyCG0MSFzJCzLW7fZ_1-j3c_Lx7zHY,17203
|
13
|
+
anaplan_sdk/_clients/__init__.py,sha256=FsbwvZC1FHrxuRXwbPxUzbhz_lO1DpXIxEOjx6-3QuA,219
|
14
|
+
anaplan_sdk/_clients/_alm.py,sha256=_LlZIRCE3HxZ4OzU13LOGnX4MQ26j2puSPTy9WGJa3o,12515
|
15
|
+
anaplan_sdk/_clients/_audit.py,sha256=9mq7VGYsl6wOdIU7G3GvzP3O7r1ZDCFg5eAu7k4RgxM,2154
|
16
|
+
anaplan_sdk/_clients/_bulk.py,sha256=Aw2cu8fAQ0lb4kc0kuYtVXr1BMuEry2yR7dlPR8CBEc,27330
|
17
|
+
anaplan_sdk/_clients/_cloud_works.py,sha256=b7LpFcRbUxcN7_9_5GgVIlGf1X1ZmQWFZgnCQKaU55s,17405
|
18
|
+
anaplan_sdk/_clients/_cw_flow.py,sha256=rwoQRdtxaigdBavr4LHtnrWsNpAgzt2zuIJOFV9ZE50,3870
|
19
|
+
anaplan_sdk/_clients/_transactional.py,sha256=avqww59ccM3FqYMeK1oE-8UH4jyk_pKSCETzhSGKyxA,16936
|
20
|
+
anaplan_sdk/models/__init__.py,sha256=zfwDQJQrXuLEXSpbJcm08a_YK1P7a7u-kMhwtJiJFmA,1783
|
21
|
+
anaplan_sdk/models/_alm.py,sha256=oeENd0YM7-LoIRBq2uATIQTxVgIP9rXx3UZE2UnQAp0,4670
|
22
|
+
anaplan_sdk/models/_base.py,sha256=6AZc9CfireUKgpZfMxYKu4MbwiyHQOsGLjKrxGXBLic,508
|
23
|
+
anaplan_sdk/models/_bulk.py,sha256=S72qujNr5STdiyKaCEvrQjKYHik_aemiJFNKE7docpI,8405
|
24
|
+
anaplan_sdk/models/_transactional.py,sha256=2bH10zvtMb5Lfh6DC7iQk72aEwq6tyLQ-XnH_0wYSqI,14172
|
25
|
+
anaplan_sdk/models/cloud_works.py,sha256=nfn_LHPR-KmW7Tpvz-5qNCzmR8SYgvsVV-lx5iDlyqI,19425
|
26
|
+
anaplan_sdk/models/flows.py,sha256=SuLgNj5-2SeE3U1i8iY8cq2IkjuUgd_3M1n2ENructk,3625
|
27
|
+
anaplan_sdk-0.5.0a2.dist-info/METADATA,sha256=82p3Dx0kw_5MNBdZYtbNzsCC8s7GM6hnFqpdpan-Ggo,3669
|
28
|
+
anaplan_sdk-0.5.0a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
29
|
+
anaplan_sdk-0.5.0a2.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
30
|
+
anaplan_sdk-0.5.0a2.dist-info/RECORD,,
|
anaplan_sdk/_base.py
DELETED
@@ -1,297 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import logging
|
3
|
-
import random
|
4
|
-
import time
|
5
|
-
from asyncio import gather
|
6
|
-
from concurrent.futures import ThreadPoolExecutor
|
7
|
-
from gzip import compress
|
8
|
-
from itertools import chain
|
9
|
-
from math import ceil
|
10
|
-
from typing import Any, Callable, Coroutine, Iterator, Literal, Type, TypeVar
|
11
|
-
|
12
|
-
import httpx
|
13
|
-
from httpx import HTTPError, Response
|
14
|
-
|
15
|
-
from .exceptions import AnaplanException, AnaplanTimeoutException, InvalidIdentifierException
|
16
|
-
from .models import AnaplanModel
|
17
|
-
from .models.cloud_works import (
|
18
|
-
AmazonS3ConnectionInput,
|
19
|
-
AzureBlobConnectionInput,
|
20
|
-
ConnectionBody,
|
21
|
-
GoogleBigQueryConnectionInput,
|
22
|
-
IntegrationInput,
|
23
|
-
IntegrationProcessInput,
|
24
|
-
ScheduleInput,
|
25
|
-
)
|
26
|
-
|
27
|
-
logger = logging.getLogger("anaplan_sdk")
|
28
|
-
|
29
|
-
_json_header = {"Content-Type": "application/json"}
|
30
|
-
_gzip_header = {"Content-Type": "application/x-gzip"}
|
31
|
-
|
32
|
-
T = TypeVar("T", bound=AnaplanModel)
|
33
|
-
|
34
|
-
|
35
|
-
class _BaseClient:
|
36
|
-
def __init__(self, retry_count: int, client: httpx.Client):
|
37
|
-
self._retry_count = retry_count
|
38
|
-
self._client = client
|
39
|
-
|
40
|
-
def _get(self, url: str, **kwargs) -> dict[str, Any]:
|
41
|
-
return self._run_with_retry(self._client.get, url, **kwargs).json()
|
42
|
-
|
43
|
-
def _get_binary(self, url: str) -> bytes:
|
44
|
-
return self._run_with_retry(self._client.get, url).content
|
45
|
-
|
46
|
-
def _post(self, url: str, json: dict | list) -> dict[str, Any]:
|
47
|
-
return self._run_with_retry(self._client.post, url, headers=_json_header, json=json).json()
|
48
|
-
|
49
|
-
def _put(self, url: str, json: dict | list) -> dict[str, Any]:
|
50
|
-
return (self._run_with_retry(self._client.put, url, headers=_json_header, json=json)).json()
|
51
|
-
|
52
|
-
def _patch(self, url: str, json: dict | list) -> dict[str, Any]:
|
53
|
-
return (
|
54
|
-
self._run_with_retry(self._client.patch, url, headers=_json_header, json=json)
|
55
|
-
).json()
|
56
|
-
|
57
|
-
def _delete(self, url: str) -> dict[str, Any]:
|
58
|
-
return (self._run_with_retry(self._client.delete, url, headers=_json_header)).json()
|
59
|
-
|
60
|
-
def _post_empty(self, url: str) -> dict[str, Any]:
|
61
|
-
res = self._run_with_retry(self._client.post, url)
|
62
|
-
return res.json() if res.num_bytes_downloaded > 0 else {}
|
63
|
-
|
64
|
-
def _put_binary_gzip(self, url: str, content: bytes) -> Response:
|
65
|
-
return self._run_with_retry(
|
66
|
-
self._client.put, url, headers=_gzip_header, content=compress(content)
|
67
|
-
)
|
68
|
-
|
69
|
-
def __get_page(self, url: str, limit: int, offset: int, result_key: str, **kwargs) -> list:
|
70
|
-
kwargs["params"] = kwargs.get("params") or {} | {"limit": limit, "offset": offset}
|
71
|
-
return self._get(url, **kwargs).get(result_key, [])
|
72
|
-
|
73
|
-
def __get_first_page(self, url: str, limit: int, result_key: str, **kwargs) -> tuple[list, int]:
|
74
|
-
kwargs["params"] = kwargs.get("params") or {} | {"limit": limit}
|
75
|
-
res = self._get(url, **kwargs)
|
76
|
-
return res.get(result_key, []), res["meta"]["paging"]["totalSize"]
|
77
|
-
|
78
|
-
def _get_paginated(
|
79
|
-
self, url: str, result_key: str, page_size: int = 5_000, **kwargs
|
80
|
-
) -> Iterator[dict[str, Any]]:
|
81
|
-
first_page, total_items = self.__get_first_page(url, page_size, result_key, **kwargs)
|
82
|
-
if total_items <= page_size:
|
83
|
-
return iter(first_page)
|
84
|
-
|
85
|
-
with ThreadPoolExecutor() as executor:
|
86
|
-
pages = executor.map(
|
87
|
-
lambda n: self.__get_page(url, page_size, n * page_size, result_key, **kwargs),
|
88
|
-
range(1, ceil(total_items / page_size)),
|
89
|
-
)
|
90
|
-
|
91
|
-
return chain(first_page, *pages)
|
92
|
-
|
93
|
-
def _run_with_retry(self, func: Callable[..., Response], *args, **kwargs) -> Response:
|
94
|
-
for i in range(max(self._retry_count, 1)):
|
95
|
-
try:
|
96
|
-
response = func(*args, **kwargs)
|
97
|
-
if response.status_code == 429:
|
98
|
-
if i >= self._retry_count - 1:
|
99
|
-
raise AnaplanException("Rate limit exceeded.")
|
100
|
-
backoff_time = max(i, 1) * random.randint(2, 5)
|
101
|
-
logger.info(f"Rate limited. Retrying in {backoff_time} seconds.")
|
102
|
-
time.sleep(backoff_time)
|
103
|
-
continue
|
104
|
-
response.raise_for_status()
|
105
|
-
return response
|
106
|
-
except HTTPError as error:
|
107
|
-
if i >= self._retry_count - 1:
|
108
|
-
raise_error(error)
|
109
|
-
url = args[0] or kwargs.get("url")
|
110
|
-
logger.info(f"Retrying for: {url}")
|
111
|
-
|
112
|
-
raise AnaplanException("Exhausted all retries without a successful response or Error.")
|
113
|
-
|
114
|
-
|
115
|
-
class _AsyncBaseClient:
|
116
|
-
def __init__(self, retry_count: int, client: httpx.AsyncClient):
|
117
|
-
self._retry_count = retry_count
|
118
|
-
self._client = client
|
119
|
-
|
120
|
-
async def _get(self, url: str, **kwargs) -> dict[str, Any]:
|
121
|
-
return (await self._run_with_retry(self._client.get, url, **kwargs)).json()
|
122
|
-
|
123
|
-
async def _get_binary(self, url: str) -> bytes:
|
124
|
-
return (await self._run_with_retry(self._client.get, url)).content
|
125
|
-
|
126
|
-
async def _post(self, url: str, json: dict | list) -> dict[str, Any]:
|
127
|
-
return (
|
128
|
-
await self._run_with_retry(self._client.post, url, headers=_json_header, json=json)
|
129
|
-
).json()
|
130
|
-
|
131
|
-
async def _put(self, url: str, json: dict | list) -> dict[str, Any]:
|
132
|
-
return (
|
133
|
-
await self._run_with_retry(self._client.put, url, headers=_json_header, json=json)
|
134
|
-
).json()
|
135
|
-
|
136
|
-
async def _patch(self, url: str, json: dict | list) -> dict[str, Any]:
|
137
|
-
return (
|
138
|
-
await self._run_with_retry(self._client.patch, url, headers=_json_header, json=json)
|
139
|
-
).json()
|
140
|
-
|
141
|
-
async def _delete(self, url: str) -> dict[str, Any]:
|
142
|
-
return (await self._run_with_retry(self._client.delete, url, headers=_json_header)).json()
|
143
|
-
|
144
|
-
async def _post_empty(self, url: str) -> dict[str, Any]:
|
145
|
-
res = await self._run_with_retry(self._client.post, url)
|
146
|
-
return res.json() if res.num_bytes_downloaded > 0 else {}
|
147
|
-
|
148
|
-
async def _put_binary_gzip(self, url: str, content: bytes) -> Response:
|
149
|
-
return await self._run_with_retry(
|
150
|
-
self._client.put, url, headers=_gzip_header, content=compress(content)
|
151
|
-
)
|
152
|
-
|
153
|
-
async def __get_page(
|
154
|
-
self, url: str, limit: int, offset: int, result_key: str, **kwargs
|
155
|
-
) -> list:
|
156
|
-
kwargs["params"] = kwargs.get("params") or {} | {"limit": limit, "offset": offset}
|
157
|
-
return (await self._get(url, **kwargs)).get(result_key, [])
|
158
|
-
|
159
|
-
async def __get_first_page(
|
160
|
-
self, url: str, limit: int, result_key: str, **kwargs
|
161
|
-
) -> tuple[list, int]:
|
162
|
-
kwargs["params"] = kwargs.get("params") or {} | {"limit": limit}
|
163
|
-
res = await self._get(url, **kwargs)
|
164
|
-
return res.get(result_key, []), res["meta"]["paging"]["totalSize"]
|
165
|
-
|
166
|
-
async def _get_paginated(
|
167
|
-
self, url: str, result_key: str, page_size: int = 5_000, **kwargs
|
168
|
-
) -> Iterator[dict[str, Any]]:
|
169
|
-
first_page, total_items = await self.__get_first_page(url, page_size, result_key, **kwargs)
|
170
|
-
if total_items <= page_size:
|
171
|
-
return iter(first_page)
|
172
|
-
pages = await gather(
|
173
|
-
*(
|
174
|
-
self.__get_page(url, page_size, n * page_size, result_key, **kwargs)
|
175
|
-
for n in range(1, ceil(total_items / page_size))
|
176
|
-
)
|
177
|
-
)
|
178
|
-
return chain(first_page, *pages)
|
179
|
-
|
180
|
-
async def _run_with_retry(
|
181
|
-
self, func: Callable[..., Coroutine[Any, Any, Response]], *args, **kwargs
|
182
|
-
) -> Response:
|
183
|
-
for i in range(max(self._retry_count, 1)):
|
184
|
-
try:
|
185
|
-
response = await func(*args, **kwargs)
|
186
|
-
if response.status_code == 429:
|
187
|
-
if i >= self._retry_count - 1:
|
188
|
-
raise AnaplanException("Rate limit exceeded.")
|
189
|
-
backoff_time = (i + 1) * random.randint(3, 5)
|
190
|
-
logger.info(f"Rate limited. Retrying in {backoff_time} seconds.")
|
191
|
-
await asyncio.sleep(backoff_time)
|
192
|
-
continue
|
193
|
-
response.raise_for_status()
|
194
|
-
return response
|
195
|
-
except HTTPError as error:
|
196
|
-
if i >= self._retry_count - 1:
|
197
|
-
raise_error(error)
|
198
|
-
url = args[0] or kwargs.get("url")
|
199
|
-
logger.info(f"Retrying for: {url}")
|
200
|
-
|
201
|
-
raise AnaplanException("Exhausted all retries without a successful response or Error.")
|
202
|
-
|
203
|
-
|
204
|
-
def construct_payload(model: Type[T], body: T | dict[str, Any]) -> dict[str, Any]:
|
205
|
-
"""
|
206
|
-
Construct a payload for the given model and body.
|
207
|
-
:param model: The model class to use for validation.
|
208
|
-
:param body: The body to validate and optionally convert to a dictionary.
|
209
|
-
:return: A dictionary representation of the validated body.
|
210
|
-
"""
|
211
|
-
if isinstance(body, dict):
|
212
|
-
body = model.model_validate(body)
|
213
|
-
return body.model_dump(exclude_none=True, by_alias=True)
|
214
|
-
|
215
|
-
|
216
|
-
def connection_body_payload(body: ConnectionBody | dict[str, Any]) -> dict[str, Any]:
|
217
|
-
"""
|
218
|
-
Construct a payload for the given integration body.
|
219
|
-
:param body: The body to validate and optionally convert to a dictionary.
|
220
|
-
:return: A dictionary representation of the validated body.
|
221
|
-
"""
|
222
|
-
if isinstance(body, dict):
|
223
|
-
if "sasToken" in body:
|
224
|
-
body = AzureBlobConnectionInput.model_validate(body)
|
225
|
-
elif "secretAccessKey" in body:
|
226
|
-
body = AmazonS3ConnectionInput.model_validate(body)
|
227
|
-
else:
|
228
|
-
body = GoogleBigQueryConnectionInput.model_validate(body)
|
229
|
-
return body.model_dump(exclude_none=True, by_alias=True)
|
230
|
-
|
231
|
-
|
232
|
-
def integration_payload(
|
233
|
-
body: IntegrationInput | IntegrationProcessInput | dict[str, Any],
|
234
|
-
) -> dict[str, Any]:
|
235
|
-
"""
|
236
|
-
Construct a payload for the given integration body.
|
237
|
-
:param body: The body to validate and optionally convert to a dictionary.
|
238
|
-
:return: A dictionary representation of the validated body.
|
239
|
-
"""
|
240
|
-
if isinstance(body, dict):
|
241
|
-
body = (
|
242
|
-
IntegrationInput.model_validate(body)
|
243
|
-
if "jobs" in body
|
244
|
-
else IntegrationProcessInput.model_validate(body)
|
245
|
-
)
|
246
|
-
return body.model_dump(exclude_none=True, by_alias=True)
|
247
|
-
|
248
|
-
|
249
|
-
def schedule_payload(
|
250
|
-
integration_id: str, schedule: ScheduleInput | dict[str, Any]
|
251
|
-
) -> dict[str, Any]:
|
252
|
-
"""
|
253
|
-
Construct a payload for the given integration ID and schedule.
|
254
|
-
:param integration_id: The ID of the integration.
|
255
|
-
:param schedule: The schedule to validate and optionally convert to a dictionary.
|
256
|
-
:return: A dictionary representation of the validated schedule.
|
257
|
-
"""
|
258
|
-
if isinstance(schedule, dict):
|
259
|
-
schedule = ScheduleInput.model_validate(schedule)
|
260
|
-
return {
|
261
|
-
"integrationId": integration_id,
|
262
|
-
"schedule": schedule.model_dump(exclude_none=True, by_alias=True),
|
263
|
-
}
|
264
|
-
|
265
|
-
|
266
|
-
def action_url(action_id: int) -> Literal["imports", "exports", "actions", "processes"]:
|
267
|
-
"""
|
268
|
-
Determine the type of action based on its identifier.
|
269
|
-
:param action_id: The identifier of the action.
|
270
|
-
:return: The type of action.
|
271
|
-
"""
|
272
|
-
if 12000000000 <= action_id < 113000000000:
|
273
|
-
return "imports"
|
274
|
-
if 116000000000 <= action_id < 117000000000:
|
275
|
-
return "exports"
|
276
|
-
if 117000000000 <= action_id < 118000000000:
|
277
|
-
return "actions"
|
278
|
-
if 118000000000 <= action_id < 119000000000:
|
279
|
-
return "processes"
|
280
|
-
raise InvalidIdentifierException(f"Action '{action_id}' is not a valid identifier.")
|
281
|
-
|
282
|
-
|
283
|
-
def raise_error(error: HTTPError) -> None:
|
284
|
-
"""
|
285
|
-
Raise an appropriate exception based on the error.
|
286
|
-
:param error: The error to raise an exception for.
|
287
|
-
"""
|
288
|
-
if isinstance(error, httpx.TimeoutException):
|
289
|
-
raise AnaplanTimeoutException from error
|
290
|
-
if isinstance(error, httpx.HTTPStatusError):
|
291
|
-
if error.response.status_code == 404:
|
292
|
-
raise InvalidIdentifierException from error
|
293
|
-
logger.error(f"Anaplan Error: [{error.response.status_code}]: {error.response.text}")
|
294
|
-
raise AnaplanException(error.response.text) from error
|
295
|
-
|
296
|
-
logger.error(f"Error: {error}")
|
297
|
-
raise AnaplanException from error
|
@@ -1,30 +0,0 @@
|
|
1
|
-
anaplan_sdk/__init__.py,sha256=WScEKtXlnRLjCb-j3qW9W4kEACTyPsTLFs-L54et2TQ,351
|
2
|
-
anaplan_sdk/_auth.py,sha256=l5z2WCcfQ05OkuQ1dcmikp6dB87Rw1qy2zu8bbaAQTs,16620
|
3
|
-
anaplan_sdk/_base.py,sha256=9CdLshORWsLixOyoFa3A0Bka5lhLwlZrQI5sEdBcGFI,12298
|
4
|
-
anaplan_sdk/_oauth.py,sha256=AynlJDrGIinQT0jwxI2RSvtU4D7Wasyw3H1uicdlLVI,12672
|
5
|
-
anaplan_sdk/exceptions.py,sha256=ALkA9fBF0NQ7dufFxV6AivjmHyuJk9DOQ9jtJV2n7f0,1809
|
6
|
-
anaplan_sdk/_async_clients/__init__.py,sha256=pZXgMMg4S9Aj_pxQCaSiPuNG-sePVGBtNJ0133VjqW4,364
|
7
|
-
anaplan_sdk/_async_clients/_alm.py,sha256=O1_r-O1tNDq7vXRwE2UEFE5S2bPmPh4IAQPQ8bmZfQE,3297
|
8
|
-
anaplan_sdk/_async_clients/_audit.py,sha256=a92RY0B3bWxp2CCAWjzqKfvBjG1LJGlai0Hn5qmwgF8,2312
|
9
|
-
anaplan_sdk/_async_clients/_bulk.py,sha256=Bpq5HT8tT48YznN7gfycGb4LNR5WW5QBVXgo_kZsEj0,24295
|
10
|
-
anaplan_sdk/_async_clients/_cloud_works.py,sha256=KPX9W55SF6h8fJd4Rx-HLq6eaRA-Vo3rFu343UiiaGQ,16642
|
11
|
-
anaplan_sdk/_async_clients/_cw_flow.py,sha256=ZTNAbKDwb59Wg3u68hbtt1kpd-LNz9K0sftT-gvYzJQ,3651
|
12
|
-
anaplan_sdk/_async_clients/_transactional.py,sha256=Mvr7OyBPjQRpBtzkJNfRzV4aNCzUiaYmm0zQubo62Wo,8035
|
13
|
-
anaplan_sdk/_clients/__init__.py,sha256=FsbwvZC1FHrxuRXwbPxUzbhz_lO1DpXIxEOjx6-3QuA,219
|
14
|
-
anaplan_sdk/_clients/_alm.py,sha256=UAdQxgHfax-VquC0YtbqrRBku2Rn35tVgwJdxYFScps,3202
|
15
|
-
anaplan_sdk/_clients/_audit.py,sha256=xQQiwWIb4QQefolPvxNwBFE-pkRzzi8fYPyewjF63lc,2181
|
16
|
-
anaplan_sdk/_clients/_bulk.py,sha256=_-kb50yL-I-AjLtvhdvLpNyMVb4luRlfBEtxT_q3jO0,23900
|
17
|
-
anaplan_sdk/_clients/_cloud_works.py,sha256=KAMnLoeMJ2iwMXlDSbKynCE57BtkCfOgM5O8wT1kkSs,16291
|
18
|
-
anaplan_sdk/_clients/_cw_flow.py,sha256=5IFWFT-qbyGvaSOOtaFOjHnOlyYbj4Rj3xiavfTlm8c,3527
|
19
|
-
anaplan_sdk/_clients/_transactional.py,sha256=YUVbA54uhMloQcahwMtmZO3YooO6qQzwZN3ZRSu_z_c,7976
|
20
|
-
anaplan_sdk/models/__init__.py,sha256=nSplwPG_74CG9CKbv1PzP9bsA9v5-daS4azpTCvCQTI,925
|
21
|
-
anaplan_sdk/models/_alm.py,sha256=IqsTPvkx_ujLpaqZgIrTcr44KHJyKc4dyeRs9rkDjms,2307
|
22
|
-
anaplan_sdk/models/_base.py,sha256=6AZc9CfireUKgpZfMxYKu4MbwiyHQOsGLjKrxGXBLic,508
|
23
|
-
anaplan_sdk/models/_bulk.py,sha256=_lHARGGjJgi-AmA7u5ZfCmGpLecPnr73LSAsZSX-a_A,8276
|
24
|
-
anaplan_sdk/models/_transactional.py,sha256=_0UbVR9D5QABI29yloYrJTSgL-K0EU7PzPeJu5LdhnY,4854
|
25
|
-
anaplan_sdk/models/cloud_works.py,sha256=nfn_LHPR-KmW7Tpvz-5qNCzmR8SYgvsVV-lx5iDlyqI,19425
|
26
|
-
anaplan_sdk/models/flows.py,sha256=SuLgNj5-2SeE3U1i8iY8cq2IkjuUgd_3M1n2ENructk,3625
|
27
|
-
anaplan_sdk-0.4.5.dist-info/METADATA,sha256=drUkXHMRjawxKTPMzL2bPTxCWx2XCwQCD9hrm1LNriw,3667
|
28
|
-
anaplan_sdk-0.4.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
29
|
-
anaplan_sdk-0.4.5.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
30
|
-
anaplan_sdk-0.4.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|