msfabricpysdkcore 0.0.3__py3-none-any.whl → 0.0.5__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.
@@ -0,0 +1,378 @@
1
+ import json
2
+ from time import sleep
3
+
4
+ import requests
5
+ from msfabricpysdkcore.long_running_operation import check_long_running_operation
6
+
7
+ class Domain:
8
+ """Class to represent a domain in Microsoft Fabric"""
9
+
10
+ def __init__(self, id, display_name, description, parent_domain_id, contributors_scope, auth):
11
+ """Constructor for the Domain class
12
+
13
+ Args:
14
+ id (str): The ID of the domain
15
+ display_name (str): The display name of the domain
16
+ description (str): The description of the domain
17
+ parent_domain_id (str): The parent domain ID of the domain
18
+ contributors_scope (str): The contributors scope of the domain
19
+ Returns:
20
+ Domain: The Domain object created"""
21
+
22
+ self.id = id
23
+ self.display_name = display_name
24
+ self.description = description
25
+ self.parent_domain_id = parent_domain_id
26
+ self.contributors_scope = contributors_scope
27
+
28
+ self.auth = auth
29
+
30
+ def __str__(self):
31
+ """Method to return a string representation of the Domain object
32
+
33
+ Returns:
34
+ str: The string representation of the Domain object
35
+ """
36
+ dic = {
37
+ 'id': self.id,
38
+ 'display_name': self.display_name,
39
+ 'description': self.description,
40
+ 'parent_domain_id': self.parent_domain_id,
41
+ 'contributors_scope': self.contributors_scope
42
+ }
43
+ return json.dumps(dic, indent=2)
44
+
45
+ def __repr__(self) -> str:
46
+ return self.__str__()
47
+
48
+ def from_dict(dic, auth):
49
+ """Method to create a Domain object from a dictionary
50
+
51
+ Args:
52
+ dic (dict): The dictionary containing the domain information
53
+ Returns:
54
+ Domain: The Domain object created from the dictionary
55
+
56
+ """
57
+ if "display_name" not in dic:
58
+ dic["display_name"] = dic["displayName"]
59
+ if "parent_domain_id" not in dic:
60
+ dic["parent_domain_id"] = dic["parentDomainId"]
61
+ if "contributors_scope" not in dic:
62
+ dic["contributors_scope"] = dic["contributorsScope"]
63
+ return Domain(id=dic['id'], display_name=dic['display_name'],
64
+ description=dic['description'], parent_domain_id=dic['parent_domain_id'],
65
+ contributors_scope=dic['contributors_scope'], auth=auth)
66
+
67
+ def list_domain_workspaces(self, workspace_objects = False, continuationToken = None):
68
+ """Method to list the workspaces in the domain
69
+
70
+ Args:
71
+ continuationToken (str): The continuation token to use for pagination
72
+ Returns:
73
+ list: The list of workspaces in the domain
74
+ """
75
+ if workspace_objects:
76
+ from msfabricpysdkcore import FabricClientCore
77
+ fc = FabricClientCore()
78
+
79
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/workspaces"
80
+ if continuationToken:
81
+ url = f"{url}?continuationToken={continuationToken}"
82
+
83
+ for _ in range(10):
84
+ response = requests.get(url=url, headers=self.auth.get_headers())
85
+ if response.status_code == 429:
86
+ print("Too many requests, waiting 10 seconds")
87
+ sleep(10)
88
+ continue
89
+ if response.status_code not in (200, 429):
90
+ print(response.status_code)
91
+ print(response.text)
92
+ raise Exception(f"Error listing workspaces: {response.text}")
93
+ break
94
+
95
+ resp_dict = json.loads(response.text)
96
+ workspaces = resp_dict["value"]
97
+
98
+ if workspace_objects:
99
+ workspaces = [fc.get_workspace_by_id(workspace["id"]) for workspace in workspaces]
100
+
101
+ if "continuationToken" in resp_dict:
102
+ workspaces_next = self.list_domain_workspaces(continuationToken=resp_dict["continuationToken"])
103
+ workspaces.extend(workspaces_next)
104
+
105
+ return workspaces
106
+
107
+ def delete(self):
108
+ """Method to delete the domain
109
+
110
+ Returns:
111
+ int: The status code of the response
112
+ """
113
+ # DELETE https://api.fabric.microsoft.com/v1/admin/domains/{domainId}
114
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}"
115
+ for _ in range(10):
116
+ response = requests.delete(url=url, headers=self.auth.get_headers())
117
+ if response.status_code == 429:
118
+ print("Too many requests, waiting 10 seconds")
119
+ sleep(10)
120
+ continue
121
+ if response.status_code not in (200, 429):
122
+ print(response.status_code)
123
+ print(response.text)
124
+ raise Exception(f"Error deleting domain: {response.text}")
125
+ break
126
+
127
+ return response.status_code
128
+
129
+
130
+ # PATCH https://api.fabric.microsoft.com/v1/admin/domains/{domainId}
131
+
132
+ def update(self, description = None, display_name = None, contributors_scope = None):
133
+ """Method to update the domain
134
+
135
+ Args:
136
+ description (str): The description of the domain
137
+ display_name (str): The display name of the domain
138
+ contributors_scope (str): The contributors scope of the domain
139
+ Returns:
140
+ Domain: The Domain object created from the dictionary
141
+ """
142
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}"
143
+ body = {}
144
+ if description:
145
+ body["description"] = description
146
+ else:
147
+ body["description"] = self.description
148
+
149
+ if display_name:
150
+ body["displayName"] = display_name
151
+ else:
152
+ body["displayName"] = self.display_name
153
+
154
+ if contributors_scope:
155
+ body["contributorsScope"] = contributors_scope
156
+ else:
157
+ body["contributorsScope"] = self.contributors_scope
158
+
159
+ for _ in range(10):
160
+ response = requests.patch(url=url, headers=self.auth.get_headers(), json=body)
161
+ if response.status_code == 429:
162
+ print("Too many requests, waiting 10 seconds")
163
+ sleep(10)
164
+ continue
165
+ if response.status_code not in (200, 429):
166
+ print(response.status_code)
167
+ print(response.text)
168
+ raise Exception(f"Error updating domain: {response.text}")
169
+ break
170
+
171
+ self.description = body["description"]
172
+ self.display_name = body["displayName"]
173
+ self.contributors_scope = body["contributorsScope"]
174
+
175
+ return self
176
+
177
+ def assign_workspaces_by_capacities(self, capacities_ids, wait_for_completion=True):
178
+ """Method to assign workspaces to the domain based on capacities_ids
179
+
180
+ Args:
181
+ capacities_ids (list): The list of capacitiy ids to assign workspaces
182
+ Returns:
183
+ int: The status code of the response
184
+ """
185
+ # POST https://api.fabric.microsoft.com/v1/admin/domains/{domainId}/assignWorkspacesByCapacities
186
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/assignWorkspacesByCapacities"
187
+
188
+ body = {
189
+ "capacitiesIds": capacities_ids
190
+ }
191
+
192
+ for _ in range(10):
193
+ response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
194
+ if response.status_code == 429:
195
+ print("Too many requests, waiting 10 seconds")
196
+ sleep(10)
197
+ continue
198
+ if response.status_code == 202 and wait_for_completion:
199
+ check_long_running_operation(response.headers, self.auth)
200
+ if response.status_code not in (202, 429):
201
+ print(response.status_code)
202
+ print(response.text)
203
+ raise Exception(f"Error assigning workspaces by capacities: {response.text}")
204
+ break
205
+
206
+ return response.status_code
207
+
208
+
209
+ def assign_workspaces_by_ids(self, workspaces_ids):
210
+
211
+ """Method to assign workspaces to the domain based on workspaces_ids
212
+
213
+ Args:
214
+ workspaces_ids (list): The list of workspace ids to assign workspaces
215
+ Returns:
216
+ int: The status code of the response
217
+ """
218
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/assignWorkspaces"
219
+ body = {
220
+ "workspacesIds": workspaces_ids
221
+ }
222
+
223
+ for _ in range(10):
224
+ response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
225
+ if response.status_code == 429:
226
+ print("Too many requests, waiting 10 seconds")
227
+ sleep(10)
228
+ continue
229
+ if response.status_code not in (200, 429):
230
+ print(response.status_code)
231
+ print(response.text)
232
+ raise Exception(f"Error assigning workspaces by ids: {response.text}")
233
+ break
234
+
235
+ return response.status_code
236
+
237
+
238
+ def assign_workspaces_by_principals(self, principals, wait_for_completion=True):
239
+ """Method to assign workspaces to the domain based on principals
240
+
241
+ Args:
242
+ principals (list): The list of principals to assign workspaces
243
+ Returns:
244
+ int: The status code of the response
245
+ """
246
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/assignWorkspacesByPrincipals"
247
+ body = {
248
+ "principals": principals
249
+ }
250
+
251
+ for _ in range(10):
252
+ response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
253
+ if response.status_code == 429:
254
+ print("Too many requests, waiting 10 seconds")
255
+ sleep(10)
256
+ continue
257
+ if response.status_code == 202 and wait_for_completion:
258
+ check_long_running_operation(response.headers, self.auth)
259
+ if response.status_code not in (202, 429):
260
+ print(response.status_code)
261
+ print(response.text)
262
+ raise Exception(f"Error assigning workspaces by principals: {response.text}")
263
+ break
264
+
265
+ return response.status_code
266
+
267
+ # POST https://api.fabric.microsoft.com/v1/admin/domains/{domainId}/roleAssignments/bulkAssign
268
+
269
+ def role_assignments_bulk_assign(self, type, principals):
270
+ """Method to bulk assign role assignments
271
+
272
+ Args:
273
+ type (str): The type of the role assignment
274
+ principals (list): The list of principals to assign the role
275
+ Returns:
276
+ int: The status code of the response
277
+ """
278
+
279
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/roleAssignments/bulkAssign"
280
+ body = {
281
+ "type": type,
282
+ "principals": principals
283
+ }
284
+
285
+ for _ in range(10):
286
+ response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
287
+ if response.status_code == 429:
288
+ print("Too many requests, waiting 10 seconds")
289
+ sleep(10)
290
+ continue
291
+ if response.status_code not in (200, 429):
292
+ print(response.status_code)
293
+ print(response.text)
294
+ raise Exception(f"Error bulk assigning role assignments: {response.text}")
295
+ break
296
+
297
+ return response.status_code
298
+
299
+
300
+ def role_assignments_bulk_unassign(self, type, principals):
301
+ """Method to bulk unassign role assignments
302
+
303
+ Args:
304
+ type (str): The type of the role assignment
305
+ principals (list): The list of principals to unassign the role
306
+ Returns:
307
+ int: The status code of the response
308
+ """
309
+
310
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/roleAssignments/bulkUnassign"
311
+ body = {
312
+ "type": type,
313
+ "principals": principals
314
+ }
315
+
316
+ for _ in range(10):
317
+ response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
318
+ if response.status_code == 429:
319
+ print("Too many requests, waiting 10 seconds")
320
+ sleep(10)
321
+ continue
322
+ if response.status_code not in (200, 429):
323
+ print(response.status_code)
324
+ print(response.text)
325
+ raise Exception(f"Error bulk unassigning role assignments: {response.text}")
326
+ break
327
+
328
+ return response.status_code
329
+
330
+
331
+ def unassign_all_workspaces(self):
332
+ """Method to unassign all workspaces from the domain
333
+
334
+ Returns:
335
+ int: The status code of the response
336
+ """
337
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/unassignAllWorkspaces"
338
+
339
+ for _ in range(10):
340
+ response = requests.post(url=url, headers=self.auth.get_headers())
341
+ if response.status_code == 429:
342
+ print("Too many requests, waiting 10 seconds")
343
+ sleep(10)
344
+ continue
345
+ if response.status_code not in (200, 429):
346
+ print(response.status_code)
347
+ print(response.text)
348
+ raise Exception(f"Error unassigning all workspaces: {response.text}")
349
+ break
350
+
351
+ return response.status_code
352
+
353
+ def unassign_workspaces_by_ids(self, workspace_ids):
354
+ """Method to unassign workspaces from the domain
355
+
356
+ Args:
357
+ workspace_ids (list): The list of workspace ids to unassign
358
+ Returns:
359
+ int: The status code of the response
360
+ """
361
+ url = f"https://api.fabric.microsoft.com/v1/admin/domains/{self.id}/unassignWorkspaces"
362
+ body = {
363
+ "workspacesIds": workspace_ids
364
+ }
365
+
366
+ for _ in range(10):
367
+ response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
368
+ if response.status_code == 429:
369
+ print("Too many requests, waiting 10 seconds")
370
+ sleep(10)
371
+ continue
372
+ if response.status_code not in (200, 429):
373
+ print(response.status_code)
374
+ print(response.text)
375
+ raise Exception(f"Error unassigning workspaces by ids: {response.text}")
376
+ break
377
+
378
+ return response.status_code
msfabricpysdkcore/item.py CHANGED
@@ -35,6 +35,9 @@ class Item:
35
35
  }
36
36
  return json.dumps(dict_, indent=2)
37
37
 
38
+ def __repr__(self) -> str:
39
+ return self.__str__()
40
+
38
41
  def from_dict(item_dict, auth):
39
42
  """Create Item object from dictionary"""
40
43
 
@@ -77,7 +80,9 @@ class Item:
77
80
  sleep(10)
78
81
  continue
79
82
  if response.status_code == 202:
80
- check_long_running_operation( response.headers, self.auth)
83
+ operation_result = check_long_running_operation( response.headers, self.auth)
84
+ self.definition = operation_result['definition']
85
+ return operation_result
81
86
 
82
87
  if response.status_code not in (200, 202, 429):
83
88
  print(response.status_code)
@@ -85,9 +90,9 @@ class Item:
85
90
  raise Exception(f"Error getting item definition: {response.text}")
86
91
  break
87
92
 
88
- print(response.text)
89
- print(response.status_code)
90
- return json.loads(response.text)
93
+ resp_dict = json.loads(response.text)
94
+ self.definition = resp_dict['definition']
95
+ return resp_dict
91
96
 
92
97
  def update(self, display_name = None, description = None):
93
98
  """Update the item"""
@@ -1,7 +1,6 @@
1
1
  import json
2
2
  import requests
3
3
  from time import sleep
4
- from msfabricpysdkcore.long_running_operation import check_long_running_operation
5
4
 
6
5
  class JobInstance:
7
6
  """Class to represent a job instance in Microsoft Fabric"""
@@ -39,6 +38,9 @@ class JobInstance:
39
38
  }
40
39
  return json.dumps(dict_, indent=2)
41
40
 
41
+ def __repr__(self) -> str:
42
+ return self.__str__()
43
+
42
44
  def from_dict(job_dict, auth):
43
45
  """Create JobInstance object from dictionary"""
44
46
  return JobInstance(id=job_dict['id'], item_id=job_dict['itemId'], workspace_id=job_dict['workspaceId'],
@@ -2,7 +2,6 @@ import json
2
2
  import requests
3
3
  from time import sleep
4
4
 
5
- from msfabricpysdkcore.long_running_operation import check_long_running_operation
6
5
  from msfabricpysdkcore.item import Item
7
6
 
8
7
  class Lakehouse(Item):
@@ -22,13 +22,14 @@ class LongRunningOperation:
22
22
  print("Too many requests, waiting 10 seconds")
23
23
  sleep(10)
24
24
  continue
25
+ if response.status_code == 400:
26
+ return None
25
27
  if response.status_code not in (200, 429):
26
28
  print(response.status_code)
27
29
  print(response.text)
28
30
  raise Exception(f"Error getting operation results: {response.text}")
29
31
  break
30
32
 
31
- print(json.loads(response.text))
32
33
  return json.loads(response.text)
33
34
 
34
35
  def get_operation_state(self):
@@ -47,7 +48,6 @@ class LongRunningOperation:
47
48
  raise Exception(f"Error getting operation state: {response.text}")
48
49
  break
49
50
 
50
- print(json.loads(response.text))
51
51
  return json.loads(response.text)
52
52
 
53
53
  def wait_for_completion(self):
@@ -72,10 +72,7 @@ def check_long_running_operation(headers, auth):
72
72
  if not operation_id:
73
73
  print("Operation initiated, no operation id found")
74
74
  return None
75
- else:
76
- print("Operation initiated, waiting for completion")
77
- lro = LongRunningOperation(operation_id=operation_id, auth=auth)
78
- lro.wait_for_completion()
79
- print("Operation completed")
80
- lro = LongRunningOperation(operation_id, auth)
81
- return lro.wait_for_completion()
75
+ lro = LongRunningOperation(operation_id=operation_id, auth=auth)
76
+ lro.wait_for_completion()
77
+
78
+ return lro.get_operation_results()
@@ -27,6 +27,9 @@ class OneLakeShortcut:
27
27
  }
28
28
  return json.dumps(dict_, indent=2)
29
29
 
30
+ def __repr__(self) -> str:
31
+ return self.__str__()
32
+
30
33
  def from_dict(short_dict, auth):
31
34
  """Create OneLakeShortCut object from dictionary"""
32
35
  return OneLakeShortcut(name=short_dict['name'],
@@ -0,0 +1,17 @@
1
+ from time import sleep
2
+
3
+ from msfabricpysdkcore.item import Item
4
+
5
+ class SparkJobDefinition(Item):
6
+ """Class to represent a spark job definition in Microsoft Fabric"""
7
+
8
+ def __init__(self, id, display_name, type, workspace_id, auth, properties = None, definition=None, description=""):
9
+ super().__init__(id, display_name, type, workspace_id, auth, properties, definition, description)
10
+
11
+ class Warehouse(Item):
12
+ """Class to represent a warehouse in Microsoft Fabric"""
13
+
14
+ def __init__(self, id, display_name, type, workspace_id, auth, properties = None, definition=None, description=""):
15
+ super().__init__(id, display_name, type, workspace_id, auth, properties, definition, description)
16
+
17
+
@@ -0,0 +1,69 @@
1
+ import unittest
2
+ from dotenv import load_dotenv
3
+ from msfabricpysdkcore import FabricClientAdmin
4
+
5
+ load_dotenv()
6
+
7
+ class TestFabricClientCore(unittest.TestCase):
8
+
9
+ def __init__(self, *args, **kwargs):
10
+ super(TestFabricClientCore, self).__init__(*args, **kwargs)
11
+
12
+
13
+ def test_domains(self):
14
+ fca = FabricClientAdmin()
15
+
16
+ user_id = 'b4f4e299-e6e1-4667-886c-57e4a8dde1c2'
17
+
18
+ # List workspaces
19
+ ws = fca.list_workspaces(name="testworkspace")[0]
20
+
21
+ self.assertEqual(ws.name, "testworkspace")
22
+
23
+ # Get workspace
24
+ ws_clone = fca.get_workspace(workspace_id=ws.id)
25
+
26
+ self.assertEqual(ws.id, ws_clone.id)
27
+
28
+ # Get workspace access details
29
+
30
+ ws_access = fca.get_workspace_access_details(ws.id)
31
+ principials = ws_access["accessDetails"]
32
+ principials_ids = [p["principal"]["id"] for p in principials]
33
+ self.assertIn(user_id, principials_ids)
34
+
35
+ # Get access entities
36
+
37
+ access_entities = fca.get_access_entities(user_id, type="Notebook")
38
+ self.assertGreater(len(access_entities), 0)
39
+
40
+ # Get tenant settings
41
+
42
+ tenant_settings = fca.get_tenant_settings()
43
+ self.assertGreater(len(tenant_settings["tenantSettings"]), 0)
44
+
45
+ # Get capacity tenant settings overrides
46
+
47
+ overrides = fca.get_capacities_tenant_settings_overrides()
48
+ self.assertGreater(len(overrides), -1)
49
+
50
+ # List items
51
+
52
+ item_list = fca.list_items(workspace_id=ws.id)
53
+ self.assertGreater(len(item_list), 0)
54
+
55
+ # Get item
56
+
57
+ item = fca.get_item(workspace_id=ws.id, item_id=item_list[0].id)
58
+ self.assertEqual(item.id, item_list[0].id)
59
+
60
+ # Get item access details
61
+
62
+ item_access = fca.get_item_access_details(workspace_id=ws.id, item_id=item_list[0].id)
63
+ principials = item_access["accessDetails"]
64
+
65
+ principials_ids = [p["principal"]["id"] for p in principials]
66
+
67
+ self.assertIn(user_id, principials_ids)
68
+
69
+