TM1py 2.2.1__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.
Files changed (72) hide show
  1. TM1py/Exceptions/Exceptions.py +201 -0
  2. TM1py/Exceptions/__init__.py +10 -0
  3. TM1py/Objects/Annotation.py +247 -0
  4. TM1py/Objects/Application.py +188 -0
  5. TM1py/Objects/Axis.py +119 -0
  6. TM1py/Objects/Chore.py +165 -0
  7. TM1py/Objects/ChoreFrequency.py +68 -0
  8. TM1py/Objects/ChoreStartTime.py +93 -0
  9. TM1py/Objects/ChoreTask.py +80 -0
  10. TM1py/Objects/Cube.py +116 -0
  11. TM1py/Objects/Dimension.py +128 -0
  12. TM1py/Objects/Element.py +110 -0
  13. TM1py/Objects/ElementAttribute.py +75 -0
  14. TM1py/Objects/Git.py +76 -0
  15. TM1py/Objects/GitCommit.py +27 -0
  16. TM1py/Objects/GitPlan.py +101 -0
  17. TM1py/Objects/GitProject.py +525 -0
  18. TM1py/Objects/GitRemote.py +28 -0
  19. TM1py/Objects/Hierarchy.py +343 -0
  20. TM1py/Objects/MDXView.py +84 -0
  21. TM1py/Objects/NativeView.py +331 -0
  22. TM1py/Objects/Process.py +512 -0
  23. TM1py/Objects/ProcessDebugBreakpoint.py +236 -0
  24. TM1py/Objects/Rules.py +100 -0
  25. TM1py/Objects/Sandbox.py +87 -0
  26. TM1py/Objects/Server.py +30 -0
  27. TM1py/Objects/Subset.py +295 -0
  28. TM1py/Objects/TM1Object.py +27 -0
  29. TM1py/Objects/User.py +179 -0
  30. TM1py/Objects/View.py +39 -0
  31. TM1py/Objects/__init__.py +28 -0
  32. TM1py/Services/AnnotationService.py +96 -0
  33. TM1py/Services/ApplicationService.py +898 -0
  34. TM1py/Services/AuditLogService.py +100 -0
  35. TM1py/Services/CellService.py +5465 -0
  36. TM1py/Services/ChoreService.py +299 -0
  37. TM1py/Services/ConfigurationService.py +80 -0
  38. TM1py/Services/CubeService.py +426 -0
  39. TM1py/Services/DimensionService.py +213 -0
  40. TM1py/Services/ElementService.py +1489 -0
  41. TM1py/Services/FileService.py +419 -0
  42. TM1py/Services/GitService.py +292 -0
  43. TM1py/Services/HierarchyService.py +895 -0
  44. TM1py/Services/JobService.py +56 -0
  45. TM1py/Services/LoggerService.py +97 -0
  46. TM1py/Services/ManageService.py +219 -0
  47. TM1py/Services/MessageLogService.py +161 -0
  48. TM1py/Services/MonitoringService.py +94 -0
  49. TM1py/Services/ObjectService.py +85 -0
  50. TM1py/Services/PowerBiService.py +81 -0
  51. TM1py/Services/ProcessService.py +753 -0
  52. TM1py/Services/RestService.py +1395 -0
  53. TM1py/Services/SandboxService.py +135 -0
  54. TM1py/Services/SecurityService.py +255 -0
  55. TM1py/Services/ServerService.py +292 -0
  56. TM1py/Services/SessionService.py +65 -0
  57. TM1py/Services/SubsetService.py +305 -0
  58. TM1py/Services/TM1Service.py +183 -0
  59. TM1py/Services/ThreadService.py +73 -0
  60. TM1py/Services/TransactionLogService.py +107 -0
  61. TM1py/Services/UserService.py +71 -0
  62. TM1py/Services/ViewService.py +308 -0
  63. TM1py/Services/__init__.py +33 -0
  64. TM1py/Utils/MDXUtils.py +248 -0
  65. TM1py/Utils/Utils.py +1833 -0
  66. TM1py/Utils/__init__.py +2 -0
  67. TM1py/__init__.py +84 -0
  68. tm1py-2.2.1.dist-info/METADATA +181 -0
  69. tm1py-2.2.1.dist-info/RECORD +72 -0
  70. tm1py-2.2.1.dist-info/WHEEL +5 -0
  71. tm1py-2.2.1.dist-info/licenses/LICENSE +22 -0
  72. tm1py-2.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,201 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # TM1py Exceptions are defined here
4
+ from typing import List, Mapping
5
+
6
+
7
+ class TM1pyTimeout(Exception):
8
+ """Exception for timeout during a REST request."""
9
+
10
+ def __init__(self, method: str, url: str, timeout: float):
11
+ """
12
+ :param method: HTTP method used
13
+ :param url: URL of the request
14
+ :param timeout: Timeout in seconds
15
+ """
16
+ self.method = method
17
+ self.url = url
18
+ self.timeout = timeout
19
+
20
+ def __str__(self):
21
+ return f"Timeout after {self.timeout} seconds for '{self.method}' request with url :'{self.url}'"
22
+
23
+
24
+ class TM1pyVersionException(Exception):
25
+ """Exception for usage of a feature requiring a higher TM1 server version."""
26
+
27
+ def __init__(self, function: str, required_version, feature: str = None):
28
+ """
29
+ :param function: Name of the function
30
+ :param required_version: Required TM1 server version
31
+ :param feature: Optional feature name
32
+ """
33
+ self.function = function
34
+ self.required_version = required_version
35
+ self.feature = feature
36
+
37
+ def __str__(self):
38
+ require_string = f"requires TM1 server version >= '{self.required_version}'"
39
+ if self.feature:
40
+ return f"'{self.feature}' feature of function '{self.function}' {require_string}"
41
+ else:
42
+ return f"Function '{self.function}' {require_string}"
43
+
44
+
45
+ class TM1pyVersionDeprecationException(Exception):
46
+ """Exception for usage of a deprecated feature."""
47
+
48
+ def __init__(self, function: str, deprecated_in_version):
49
+ """
50
+ :param function: Name of the function
51
+ :param deprecated_in_version: Version in which the function was deprecated
52
+ """
53
+ self.function = function
54
+ self.deprecated_in_version = deprecated_in_version
55
+
56
+ def __str__(self):
57
+ return f"Function '{self.function}' has been deprecated in TM1 server version >= '{self.deprecated_in_version}'"
58
+
59
+
60
+ class TM1pyPermissionException(Exception):
61
+ """Exception for missing permissions."""
62
+
63
+ def __init__(self, function: str, required_permission: str):
64
+ """
65
+ :param function: Name of the function
66
+ :param required_permission: Name of the required permission (e.g., 'admin', 'DataAdmin', 'SecurityAdmin', 'OperationsAdmin')
67
+ """
68
+ self.function = function
69
+ self.required_permission = required_permission
70
+
71
+ def __str__(self):
72
+ return f"Function '{self.function}' requires {self.required_permission} permissions"
73
+
74
+
75
+ class TM1pyNotAdminException(TM1pyPermissionException):
76
+ """Exception for missing admin permissions."""
77
+
78
+ def __init__(self, function: str):
79
+ """
80
+ :param function: Name of the function
81
+ """
82
+ super().__init__(function, "admin")
83
+
84
+
85
+ class TM1pyNotDataAdminException(TM1pyPermissionException):
86
+ """Exception for missing DataAdmin permissions."""
87
+
88
+ def __init__(self, function: str):
89
+ """
90
+ :param function: Name of the function
91
+ """
92
+ super().__init__(function, "DataAdmin")
93
+
94
+
95
+ class TM1pyNotSecurityAdminException(TM1pyPermissionException):
96
+ """Exception for missing SecurityAdmin permissions."""
97
+
98
+ def __init__(self, function: str):
99
+ """
100
+ :param function: Name of the function
101
+ """
102
+ super().__init__(function, "SecurityAdmin")
103
+
104
+
105
+ class TM1pyNotOpsAdminException(TM1pyPermissionException):
106
+ """Exception for missing OperationsAdmin permissions."""
107
+
108
+ def __init__(self, function: str):
109
+ """
110
+ :param function: Name of the function
111
+ """
112
+ super().__init__(function, "OperationsAdmin")
113
+
114
+
115
+ class TM1pyException(Exception):
116
+ """The default exception for TM1py."""
117
+
118
+ def __init__(self, message):
119
+ """
120
+ :param message: Exception message
121
+ """
122
+ self.message = message
123
+
124
+ def __str__(self):
125
+ return self.message
126
+
127
+
128
+ class TM1pyRestException(TM1pyException):
129
+ """Exception for failing REST operations."""
130
+
131
+ def __init__(self, response: str, status_code: int, reason: str, headers: Mapping):
132
+ """
133
+ :param response: Response text
134
+ :param status_code: HTTP status code
135
+ :param reason: Reason phrase
136
+ :param headers: HTTP headers
137
+ """
138
+ super(TM1pyRestException, self).__init__(response)
139
+ self._status_code = status_code
140
+ self._reason = reason
141
+ self._headers = headers
142
+
143
+ @property
144
+ def status_code(self):
145
+ """HTTP status code."""
146
+ return self._status_code
147
+
148
+ @property
149
+ def reason(self):
150
+ """Reason phrase."""
151
+ return self._reason
152
+
153
+ @property
154
+ def response(self):
155
+ """Response text."""
156
+ return self.message
157
+
158
+ @property
159
+ def headers(self):
160
+ """HTTP headers."""
161
+ return self._headers
162
+
163
+ def __str__(self):
164
+ return "Text: '{}' - Status Code: {} - Reason: '{}' - Headers: {}".format(
165
+ self.message, self._status_code, self._reason, self._headers
166
+ )
167
+
168
+
169
+ class TM1pyWriteFailureException(TM1pyException):
170
+ """Exception for complete failure of write operations."""
171
+
172
+ def __init__(self, statuses: List[str], error_log_files: List[str]):
173
+ """
174
+ :param statuses: List of failed statuses
175
+ :param error_log_files: List of error log file paths
176
+ """
177
+ self.statuses = statuses
178
+ self.error_log_files = error_log_files
179
+
180
+ message = f"All {len(self.statuses)} write operations failed. Details: {self.error_log_files}"
181
+ super(TM1pyWriteFailureException, self).__init__(message)
182
+
183
+
184
+ class TM1pyWritePartialFailureException(TM1pyException):
185
+ """Exception for partial failure of write operations."""
186
+
187
+ def __init__(self, statuses: List[str], error_log_files: List[str], attempts: int):
188
+ """
189
+ :param statuses: List of failed statuses
190
+ :param error_log_files: List of error log file paths
191
+ :param attempts: Total number of attempts
192
+ """
193
+ self.statuses = statuses
194
+ self.error_log_files = error_log_files
195
+ self.attempts = attempts
196
+
197
+ message = (
198
+ f"{len(self.statuses)} out of {self.attempts} write operations failed partially. "
199
+ f"Details: {self.error_log_files}"
200
+ )
201
+ super(TM1pyWritePartialFailureException, self).__init__(message)
@@ -0,0 +1,10 @@
1
+ # ruff: noqa: F401
2
+ from TM1py.Exceptions.Exceptions import (
3
+ TM1pyException,
4
+ TM1pyNotAdminException,
5
+ TM1pyRestException,
6
+ TM1pyTimeout,
7
+ TM1pyVersionException,
8
+ TM1pyWriteFailureException,
9
+ TM1pyWritePartialFailureException,
10
+ )
@@ -0,0 +1,247 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import collections
4
+ import json
5
+ from typing import Dict, Iterable, List
6
+
7
+ from TM1py.Objects.TM1Object import TM1Object
8
+ from TM1py.Utils import format_url
9
+
10
+
11
+ class Annotation(TM1Object):
12
+ """Abtraction of TM1 Annotation
13
+
14
+ :Notes:
15
+ - Class complete, functional and tested.
16
+ - doesn't cover Attachments though
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ comment_value: str,
22
+ object_name: str,
23
+ dimensional_context: Iterable[str],
24
+ comment_type: str = "ANNOTATION",
25
+ annotation_id: str = None,
26
+ text: str = "",
27
+ creator: str = None,
28
+ created: str = None,
29
+ last_updated_by: str = None,
30
+ last_updated: str = None,
31
+ ):
32
+ """
33
+ Initialize an Annotation object.
34
+
35
+ :param comment_value: The value of the annotation comment.
36
+ :param object_name: Name of the TM1 object the annotation is attached to.
37
+ :param dimensional_context: Iterable of dimension elements providing context.
38
+ :param comment_type: Type of the comment (default "ANNOTATION").
39
+ :param annotation_id: Unique ID of the annotation.
40
+ :param text: Text of the annotation.
41
+ :param creator: Creator of the annotation.
42
+ :param created: Creation timestamp.
43
+ :param last_updated_by: Last user who updated the annotation.
44
+ :param last_updated: Last update timestamp.
45
+ """
46
+ self._id = annotation_id
47
+ self._text = text
48
+ self._creator = creator
49
+ self._created = created
50
+ self._last_updated_by = last_updated_by
51
+ self._last_updated = last_updated
52
+ self._dimensional_context = list(dimensional_context)
53
+ self._comment_type = comment_type
54
+ self._comment_value = comment_value
55
+ self._object_name = object_name
56
+
57
+ @classmethod
58
+ def from_json(cls, annotation_as_json: str) -> "Annotation":
59
+ """Alternative constructor
60
+
61
+ :param annotation_as_json: String, JSON
62
+ :return: instance of Annotation
63
+ """
64
+ annotation_as_dict = json.loads(annotation_as_json)
65
+ annotation_id = annotation_as_dict["ID"]
66
+ text = annotation_as_dict["Text"]
67
+ creator = annotation_as_dict["Creator"]
68
+ created = annotation_as_dict["Created"]
69
+ last_updated_by = annotation_as_dict["LastUpdatedBy"]
70
+ last_updated = annotation_as_dict["LastUpdated"]
71
+ dimensional_context = [item["Name"] for item in annotation_as_dict["DimensionalContext"]]
72
+ comment_type = annotation_as_dict["commentType"]
73
+ comment_value = annotation_as_dict["commentValue"]
74
+ object_name = annotation_as_dict["objectName"]
75
+ return cls(
76
+ comment_value=comment_value,
77
+ object_name=object_name,
78
+ dimensional_context=dimensional_context,
79
+ comment_type=comment_type,
80
+ annotation_id=annotation_id,
81
+ text=text,
82
+ creator=creator,
83
+ created=created,
84
+ last_updated_by=last_updated_by,
85
+ last_updated=last_updated,
86
+ )
87
+
88
+ @property
89
+ def body(self) -> str:
90
+ """
91
+ Get the annotation body as a JSON string.
92
+
93
+ :return: JSON string representation of the annotation.
94
+ """
95
+ return json.dumps(self._construct_body())
96
+
97
+ @property
98
+ def body_as_dict(self) -> Dict:
99
+ """
100
+ Get the annotation body as a dictionary.
101
+
102
+ :return: Dictionary representation of the annotation.
103
+ """
104
+ return self._construct_body()
105
+
106
+ @property
107
+ def comment_value(self) -> str:
108
+ """
109
+ Get the comment value.
110
+
111
+ :return: The comment value string.
112
+ """
113
+ return self._comment_value
114
+
115
+ @property
116
+ def text(self) -> str:
117
+ """
118
+ Get the annotation text.
119
+
120
+ :return: The annotation text.
121
+ """
122
+ return self._text
123
+
124
+ @property
125
+ def dimensional_context(self) -> List[str]:
126
+ """
127
+ Get the dimensional context.
128
+
129
+ :return: List of dimension elements providing context.
130
+ """
131
+ return self._dimensional_context
132
+
133
+ @property
134
+ def created(self) -> str:
135
+ """
136
+ Get the creation timestamp.
137
+
138
+ :return: Creation timestamp as string.
139
+ """
140
+ return self._created
141
+
142
+ @property
143
+ def object_name(self) -> str:
144
+ """
145
+ Get the object name.
146
+
147
+ :return: Name of the TM1 object.
148
+ """
149
+ return self._object_name
150
+
151
+ @property
152
+ def last_updated(self) -> str:
153
+ """
154
+ Get the last updated timestamp.
155
+
156
+ :return: Last update timestamp as string.
157
+ """
158
+ return self._last_updated
159
+
160
+ @property
161
+ def last_updated_by(self) -> str:
162
+ """
163
+ Get the last user who updated the annotation.
164
+
165
+ :return: Username of last updater.
166
+ """
167
+ return self._last_updated_by
168
+
169
+ @comment_value.setter
170
+ def comment_value(self, value: str):
171
+ """
172
+ Set the comment value.
173
+
174
+ :param value: New comment value.
175
+ """
176
+ self._comment_value = value
177
+
178
+ @property
179
+ def id(self) -> str:
180
+ """
181
+ Get the annotation ID.
182
+
183
+ :return: Annotation ID string.
184
+ """
185
+ return self._id
186
+
187
+ def move(self, dimension_order: Iterable[str], dimension: str, target_element: str, source_element: str = None):
188
+ """
189
+ Move annotation on given dimension from source_element to target_element.
190
+
191
+ :param dimension_order: List, order of the dimensions in the cube.
192
+ :param dimension: Dimension name.
193
+ :param target_element: Target element name.
194
+ :param source_element: Source element name (optional).
195
+ :return: None
196
+ """
197
+ for i, dimension_name in enumerate(dimension_order):
198
+ if dimension_name.lower() == dimension.lower():
199
+ if not source_element or self._dimensional_context[i] == source_element:
200
+ self._dimensional_context[i] = target_element
201
+
202
+ def _construct_body(self) -> Dict:
203
+ """
204
+ Construct the ODATA conform JSON representation for the Annotation entity.
205
+
206
+ :return: Dictionary, the valid JSON.
207
+ """
208
+ dimensional_context = [{"Name": element} for element in self._dimensional_context]
209
+ body = collections.OrderedDict()
210
+ body["ID"] = self._id
211
+ body["Text"] = self._text
212
+ body["Creator"] = self._creator
213
+ body["Created"] = self._created
214
+ body["LastUpdatedBy"] = self._last_updated_by
215
+ body["LastUpdated"] = self._last_updated
216
+ body["DimensionalContext"] = dimensional_context
217
+ comment_locations = ",".join(self._dimensional_context)
218
+ body["commentLocation"] = comment_locations[1:]
219
+ body["commentType"] = self._comment_type
220
+ body["commentValue"] = self._comment_value
221
+ body["objectName"] = self._object_name
222
+ return body
223
+
224
+ def construct_body_for_post(self, cube_dimensions) -> Dict:
225
+ """
226
+ Construct the body for POST requests to create an annotation.
227
+
228
+ :param cube_dimensions: List of cube dimension names.
229
+ :return: Dictionary for POST request body.
230
+ """
231
+ body = collections.OrderedDict()
232
+ body["Text"] = self.text
233
+ body["ApplicationContext"] = [
234
+ {"Facet@odata.bind": "ApplicationContextFacets('}Cubes')", "Value": self.object_name}
235
+ ]
236
+ body["DimensionalContext@odata.bind"] = []
237
+
238
+ for dimension, element in zip(cube_dimensions, self.dimensional_context):
239
+ coordinates = format_url("Dimensions('{}')/Hierarchies('{}')/Members('{}')", dimension, dimension, element)
240
+ body["DimensionalContext@odata.bind"].append(coordinates)
241
+
242
+ body["objectName"] = self.object_name
243
+ body["commentValue"] = self.comment_value
244
+ body["commentType"] = "ANNOTATION"
245
+ body["commentLocation"] = ",".join(self.dimensional_context)
246
+
247
+ return body
@@ -0,0 +1,188 @@
1
+ # -*- coding: utf-8 -*-
2
+ import json
3
+ import warnings
4
+ from collections import OrderedDict, namedtuple
5
+ from enum import Enum
6
+ from typing import Dict, Union
7
+
8
+ from TM1py.Objects.TM1Object import TM1Object
9
+ from TM1py.Utils import format_url
10
+
11
+ ApplicationType = namedtuple("ApplicationType", ["value", "suffix", "odata_type"])
12
+
13
+
14
+ class ApplicationTypes(Enum):
15
+ CHORE = ApplicationType(1, ".chore", "tm1.ChoreReference")
16
+ CUBE = ApplicationType(2, ".cube", "tm1.CubeReference")
17
+ DIMENSION = ApplicationType(3, ".dimension", "tm1.DimensionReference")
18
+ DOCUMENT = ApplicationType(4, ".blob", "#ibm.tm1.api.v1.Document")
19
+ FOLDER = ApplicationType(5, "", "#ibm.tm1.api.v1.Folder")
20
+ LINK = ApplicationType(6, ".extr", "#ibm.tm1.api.v1.Link")
21
+ PROCESS = ApplicationType(7, ".process", "tm1.ProcessReference")
22
+ SUBSET = ApplicationType(8, ".subset", "tm1.SubsetReference")
23
+ VIEW = ApplicationType(9, ".view", "tm1.ViewReference")
24
+
25
+ @classmethod
26
+ def _missing_(cls, value: str) -> ApplicationType:
27
+ for member in cls:
28
+ if member.name.lower() == value.lower():
29
+ return member
30
+
31
+ @property
32
+ def suffix(self) -> str:
33
+ return self.value.suffix
34
+
35
+ @property
36
+ def odata_type(self) -> str:
37
+ return self.value.odata_type
38
+
39
+
40
+ class Application(TM1Object):
41
+
42
+ def __init__(self, path: str, name: str, application_type: Union[ApplicationTypes, str]):
43
+ self.path = path
44
+ # remove suffix from name
45
+ if application_type.suffix and name.endswith(application_type.suffix):
46
+ self.name = name[: -len(application_type.suffix)]
47
+ else:
48
+ self.name = name
49
+ # raise ValueError if not a valid type
50
+ self.application_type = ApplicationTypes(application_type)
51
+
52
+ @property
53
+ def application_id(self) -> str:
54
+ return self.path + self.name + self.application_type.suffix
55
+
56
+ @property
57
+ def body_as_dict(self) -> Dict:
58
+ body_as_dict = OrderedDict()
59
+ body_as_dict["@odata.type"] = self.application_type.odata_type
60
+ body_as_dict["Name"] = self.name
61
+ return body_as_dict
62
+
63
+ @property
64
+ def body(self) -> str:
65
+ body_as_dict = self.body_as_dict
66
+ return json.dumps(body_as_dict, ensure_ascii=False)
67
+
68
+
69
+ class ChoreApplication(Application):
70
+ def __init__(self, path: str, name: str, chore_name: str):
71
+ super().__init__(path, name, ApplicationTypes.CHORE)
72
+ self.chore_name = chore_name
73
+
74
+ @property
75
+ def body(self) -> str:
76
+ body_as_dict = self.body_as_dict
77
+ body_as_dict["Chore@odata.bind"] = format_url("Chores('{}')", self.chore_name)
78
+ return json.dumps(body_as_dict, ensure_ascii=False)
79
+
80
+
81
+ class CubeApplication(Application):
82
+ def __init__(self, path: str, name: str, cube_name: str):
83
+ super().__init__(path, name, ApplicationTypes.CUBE)
84
+ self.cube_name = cube_name
85
+
86
+ @property
87
+ def body(self) -> str:
88
+ body_as_dict = self.body_as_dict
89
+ body_as_dict["Cube@odata.bind"] = format_url("Cubes('{}')", self.cube_name)
90
+ return json.dumps(body_as_dict, ensure_ascii=False)
91
+
92
+
93
+ class DimensionApplication(Application):
94
+ def __init__(self, path: str, name: str, dimension_name: str):
95
+ super().__init__(path, name, ApplicationTypes.DIMENSION)
96
+ self.dimension_name = dimension_name
97
+
98
+ @property
99
+ def body(self) -> str:
100
+ body_as_dict = self.body_as_dict
101
+ body_as_dict["Dimension@odata.bind"] = format_url("Dimensions('{}')", self.dimension_name)
102
+ return json.dumps(body_as_dict, ensure_ascii=False)
103
+
104
+
105
+ class DocumentApplication(Application):
106
+ def __init__(
107
+ self, path: str, name: str, content: bytes, file_id: str = None, file_name: str = None, last_updated: str = None
108
+ ):
109
+ super().__init__(path, name, ApplicationTypes.DOCUMENT)
110
+ self.content = content
111
+ # below fields only populated for retrieved applications
112
+ self.file_id = file_id
113
+ self.file_name = file_name
114
+ self.last_updated = last_updated
115
+
116
+ def to_xlsx(self, path_to_file: str):
117
+ warnings.warn("Function 'to_xlsx' is deprecated. Use 'to_file' instead", DeprecationWarning, stacklevel=2)
118
+ return self.to_file(path_to_file=path_to_file)
119
+
120
+ def to_file(self, path_to_file: str):
121
+ """
122
+
123
+ :param path_to_file: path to newly to create file including the extension (e.g., xlsx, xlsm)
124
+ :return:
125
+ """
126
+ with open(path_to_file, "wb") as file:
127
+ file.write(self.content)
128
+
129
+
130
+ class FolderApplication(Application):
131
+ def __init__(self, path: str, name: str):
132
+ super().__init__(path, name, ApplicationTypes.FOLDER)
133
+
134
+
135
+ class LinkApplication(Application):
136
+ def __init__(self, path: str, name: str, url: str):
137
+ super().__init__(path, name, ApplicationTypes.LINK)
138
+ self.url = url
139
+
140
+ @property
141
+ def body(self) -> str:
142
+ body_as_dict = self.body_as_dict
143
+ body_as_dict["URL"] = self.url
144
+ return json.dumps(body_as_dict, ensure_ascii=False)
145
+
146
+
147
+ class ProcessApplication(Application):
148
+ def __init__(self, path: str, name: str, process_name: str):
149
+ super().__init__(path, name, ApplicationTypes.PROCESS)
150
+ self.process_name = process_name
151
+
152
+ @property
153
+ def body(self) -> str:
154
+ body_as_dict = self.body_as_dict
155
+ body_as_dict["Process@odata.bind"] = format_url("Processes('{}')", self.process_name)
156
+ return json.dumps(body_as_dict, ensure_ascii=False)
157
+
158
+
159
+ class SubsetApplication(Application):
160
+ def __init__(self, path: str, name: str, dimension_name: str, hierarchy_name: str, subset_name: str):
161
+ super().__init__(path, name, ApplicationTypes.SUBSET)
162
+ self.dimension_name = dimension_name
163
+ self.hierarchy_name = hierarchy_name
164
+ self.subset_name = subset_name
165
+
166
+ @property
167
+ def body(self) -> str:
168
+ body_as_dict = self.body_as_dict
169
+ body_as_dict["Subset@odata.bind"] = format_url(
170
+ "Dimensions('{}')/Hierarchies('{}')/Subsets('{}')",
171
+ self.dimension_name,
172
+ self.hierarchy_name,
173
+ self.subset_name,
174
+ )
175
+ return json.dumps(body_as_dict, ensure_ascii=False)
176
+
177
+
178
+ class ViewApplication(Application):
179
+ def __init__(self, path: str, name: str, cube_name: str, view_name: str):
180
+ super().__init__(path, name, ApplicationTypes.VIEW)
181
+ self.cube_name = cube_name
182
+ self.view_name = view_name
183
+
184
+ @property
185
+ def body(self) -> str:
186
+ body_as_dict = self.body_as_dict
187
+ body_as_dict["View@odata.bind"] = format_url("Cubes('{}')/Views('{}')", self.cube_name, self.view_name)
188
+ return json.dumps(body_as_dict, ensure_ascii=False)