msfabricpysdkcore 0.0.2__tar.gz → 0.0.3__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.
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/PKG-INFO +43 -9
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/README.md +42 -8
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/capacity.py +53 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/client.py +69 -16
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/item.py +16 -1
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/lakehouse.py +96 -0
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/tests/__init__.py +0 -0
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/tests/test_git.py +62 -0
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/tests/test_items_incl_lakehouse.py +69 -0
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/tests/test_jobs.py +41 -0
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/tests/test_shortcuts.py +53 -0
- msfabricpysdkcore-0.0.3/msfabricpysdkcore/tests/test_workspaces_capacities.py +146 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/workspace.py +44 -7
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/PKG-INFO +43 -9
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/SOURCES.txt +9 -1
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/pyproject.toml +1 -1
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/setup.py +1 -1
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/LICENSE +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/__init__.py +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/auth.py +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/job_instance.py +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/long_running_operation.py +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/onelakeshortcut.py +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/dependency_links.txt +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/requires.txt +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/top_level.txt +0 -0
- {msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: msfabricpysdkcore
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: A Python SDK for Microsoft Fabric
|
5
5
|
Author: Andreas Rederer
|
6
6
|
Project-URL: Homepage, https://github.com/DaSenf1860/ms-fabric-sdk-core
|
@@ -15,7 +15,7 @@ Requires-Dist: azure-identity>=1.15.0
|
|
15
15
|
|
16
16
|
# A Python SDK for Microsoft Fabric
|
17
17
|
|
18
|
-
This is a Python SDK for Microsoft Fabric. It is a wrapper around the REST APIs of Fabric*.
|
18
|
+
This is a Python SDK for Microsoft Fabric. It is a wrapper around the REST APIs (v1) of Fabric*.
|
19
19
|
|
20
20
|

|
21
21
|
|
@@ -29,10 +29,12 @@ Additionally it brings some extra features like:
|
|
29
29
|
- Retry logic when hitting the API rate limits
|
30
30
|
- Referencing objects by name instead of ID
|
31
31
|
- More granular objects, e.g. a Workspace and Item object instead of referencing IDs all the time
|
32
|
-
- Do bulk operations
|
33
|
-
- Pagination support
|
32
|
+
- Do bulk operations (see [Usage Patterns](usage_patterns.md))
|
33
|
+
- Pagination support
|
34
34
|
|
35
|
-
|
35
|
+
See the latest release notes [here](releasenotes/release_notes.md).
|
36
|
+
|
37
|
+
Currently it supports all Core APIs and Lakehouse APIs, i.e.:
|
36
38
|
- [Capacities](#working-with-capacities)
|
37
39
|
- [Git](#working-with-git)
|
38
40
|
- [Items](#working-with-items)
|
@@ -40,13 +42,13 @@ Currently it supports all Core APIs, i.e.:
|
|
40
42
|
- Long Running Operations
|
41
43
|
- [OneLakeShortcuts](#working-with-one-lake-shortcuts)
|
42
44
|
- [Workspaces](#working-with-workspaces)
|
45
|
+
- [Lakehouse APIs](#lakehouse-apis)
|
43
46
|
|
44
|
-
It is planned to support also the Admin
|
47
|
+
It is planned to support also the Admin APIs and new APIs which are not released yet.
|
45
48
|
Eventually Power BI APIs like the Scanner API will be covered as well.
|
46
49
|
|
47
50
|
*Because this SDK uses the API in the background, all limitations and restrictions of the API apply to this SDK as well. This includes rate limits, permissions, etc.
|
48
51
|
|
49
|
-
**These features are not yet implemented but are planned for the near future.
|
50
52
|
|
51
53
|
|
52
54
|
|
@@ -160,11 +162,16 @@ ws.delete_role_assignment(principal_id = "abadfbafb")
|
|
160
162
|
|
161
163
|
```python
|
162
164
|
|
165
|
+
|
166
|
+
capacity_object = fc.get_capacity(capacity_id = "0129389012u8938491")
|
167
|
+
#or
|
168
|
+
capacity_object = fc.get_capacity(capacity_name = "sandboxcapacitygermanywc")
|
169
|
+
|
163
170
|
# Assign a capaycity to a workspace
|
164
171
|
fc.assign_to_capacity(workspace_id=workspace_id,
|
165
|
-
capacity_id=
|
172
|
+
capacity_id=capacity_object.id)
|
166
173
|
# or
|
167
|
-
ws.assign_to_capacity(capacity_id=
|
174
|
+
ws.assign_to_capacity(capacity_id=capacity_object.id)
|
168
175
|
|
169
176
|
# Unassign from capacity
|
170
177
|
fc.unassign_from_capacity(workspace_id=ws.id)
|
@@ -359,7 +366,34 @@ item.cancel_item_job_instance(job_instance_id="job_instance_id")
|
|
359
366
|
|
360
367
|
```
|
361
368
|
|
369
|
+
## Lakehouse APIs
|
362
370
|
|
371
|
+
# List tables in a Lakehouse
|
372
|
+
|
373
|
+
```python
|
374
|
+
from msfabricpysdkcore import FabricClientCore
|
375
|
+
|
376
|
+
fc = FabricClientCore()
|
377
|
+
ws = fc.get_workspace_by_name("testworkspace")
|
378
|
+
lakehouse = ws.get_item_by_name(item_name="lakehouse1", item_type="Lakehouse")
|
379
|
+
table_list = lakehouse.list_tables()
|
380
|
+
# or
|
381
|
+
table_list = ws.list_tables(item_id = "someitemid")
|
382
|
+
# or
|
383
|
+
table_list = fc.list_tables(workspace_id = "someworkspaceid", item_id = "someitemid")
|
384
|
+
|
385
|
+
|
386
|
+
# Load a file (like a csv) into a Lakehouse table
|
387
|
+
|
388
|
+
lakehouse.load_table(table_name="testtable", path_type= "File", relative_path="Files/folder1/titanic.csv")
|
389
|
+
# or
|
390
|
+
ws.load_table(item_id = "someitemid", table_name="testtable",
|
391
|
+
path_type= "File", relative_path="Files/folder1/titanic.csv")
|
392
|
+
# or
|
393
|
+
fc.load_table(workspace_id = "someworkspaceid", item_id = "someitemid", table_name="testtable",
|
394
|
+
path_type= "File", relative_path="Files/folder1/titanic.csv")
|
395
|
+
|
396
|
+
```
|
363
397
|
|
364
398
|
Note: This SDK is not an official SDK from Microsoft. It is a community project and not supported by Microsoft. Use it at your own risk.
|
365
399
|
Also the API is still in preview and might change. This SDK is not yet feature complete and might not cover all APIs yet. Feel free to contribute to this project to make it better.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# A Python SDK for Microsoft Fabric
|
2
2
|
|
3
|
-
This is a Python SDK for Microsoft Fabric. It is a wrapper around the REST APIs of Fabric*.
|
3
|
+
This is a Python SDK for Microsoft Fabric. It is a wrapper around the REST APIs (v1) of Fabric*.
|
4
4
|
|
5
5
|

|
6
6
|
|
@@ -14,10 +14,12 @@ Additionally it brings some extra features like:
|
|
14
14
|
- Retry logic when hitting the API rate limits
|
15
15
|
- Referencing objects by name instead of ID
|
16
16
|
- More granular objects, e.g. a Workspace and Item object instead of referencing IDs all the time
|
17
|
-
- Do bulk operations
|
18
|
-
- Pagination support
|
17
|
+
- Do bulk operations (see [Usage Patterns](usage_patterns.md))
|
18
|
+
- Pagination support
|
19
19
|
|
20
|
-
|
20
|
+
See the latest release notes [here](releasenotes/release_notes.md).
|
21
|
+
|
22
|
+
Currently it supports all Core APIs and Lakehouse APIs, i.e.:
|
21
23
|
- [Capacities](#working-with-capacities)
|
22
24
|
- [Git](#working-with-git)
|
23
25
|
- [Items](#working-with-items)
|
@@ -25,13 +27,13 @@ Currently it supports all Core APIs, i.e.:
|
|
25
27
|
- Long Running Operations
|
26
28
|
- [OneLakeShortcuts](#working-with-one-lake-shortcuts)
|
27
29
|
- [Workspaces](#working-with-workspaces)
|
30
|
+
- [Lakehouse APIs](#lakehouse-apis)
|
28
31
|
|
29
|
-
It is planned to support also the Admin
|
32
|
+
It is planned to support also the Admin APIs and new APIs which are not released yet.
|
30
33
|
Eventually Power BI APIs like the Scanner API will be covered as well.
|
31
34
|
|
32
35
|
*Because this SDK uses the API in the background, all limitations and restrictions of the API apply to this SDK as well. This includes rate limits, permissions, etc.
|
33
36
|
|
34
|
-
**These features are not yet implemented but are planned for the near future.
|
35
37
|
|
36
38
|
|
37
39
|
|
@@ -145,11 +147,16 @@ ws.delete_role_assignment(principal_id = "abadfbafb")
|
|
145
147
|
|
146
148
|
```python
|
147
149
|
|
150
|
+
|
151
|
+
capacity_object = fc.get_capacity(capacity_id = "0129389012u8938491")
|
152
|
+
#or
|
153
|
+
capacity_object = fc.get_capacity(capacity_name = "sandboxcapacitygermanywc")
|
154
|
+
|
148
155
|
# Assign a capaycity to a workspace
|
149
156
|
fc.assign_to_capacity(workspace_id=workspace_id,
|
150
|
-
capacity_id=
|
157
|
+
capacity_id=capacity_object.id)
|
151
158
|
# or
|
152
|
-
ws.assign_to_capacity(capacity_id=
|
159
|
+
ws.assign_to_capacity(capacity_id=capacity_object.id)
|
153
160
|
|
154
161
|
# Unassign from capacity
|
155
162
|
fc.unassign_from_capacity(workspace_id=ws.id)
|
@@ -344,7 +351,34 @@ item.cancel_item_job_instance(job_instance_id="job_instance_id")
|
|
344
351
|
|
345
352
|
```
|
346
353
|
|
354
|
+
## Lakehouse APIs
|
347
355
|
|
356
|
+
# List tables in a Lakehouse
|
357
|
+
|
358
|
+
```python
|
359
|
+
from msfabricpysdkcore import FabricClientCore
|
360
|
+
|
361
|
+
fc = FabricClientCore()
|
362
|
+
ws = fc.get_workspace_by_name("testworkspace")
|
363
|
+
lakehouse = ws.get_item_by_name(item_name="lakehouse1", item_type="Lakehouse")
|
364
|
+
table_list = lakehouse.list_tables()
|
365
|
+
# or
|
366
|
+
table_list = ws.list_tables(item_id = "someitemid")
|
367
|
+
# or
|
368
|
+
table_list = fc.list_tables(workspace_id = "someworkspaceid", item_id = "someitemid")
|
369
|
+
|
370
|
+
|
371
|
+
# Load a file (like a csv) into a Lakehouse table
|
372
|
+
|
373
|
+
lakehouse.load_table(table_name="testtable", path_type= "File", relative_path="Files/folder1/titanic.csv")
|
374
|
+
# or
|
375
|
+
ws.load_table(item_id = "someitemid", table_name="testtable",
|
376
|
+
path_type= "File", relative_path="Files/folder1/titanic.csv")
|
377
|
+
# or
|
378
|
+
fc.load_table(workspace_id = "someworkspaceid", item_id = "someitemid", table_name="testtable",
|
379
|
+
path_type= "File", relative_path="Files/folder1/titanic.csv")
|
380
|
+
|
381
|
+
```
|
348
382
|
|
349
383
|
Note: This SDK is not an official SDK from Microsoft. It is a community project and not supported by Microsoft. Use it at your own risk.
|
350
384
|
Also the API is still in preview and might change. This SDK is not yet feature complete and might not cover all APIs yet. Feel free to contribute to this project to make it better.
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import json
|
2
|
+
|
3
|
+
class Capacity:
|
4
|
+
"""Class to represent a capacity in Microsoft Fabric"""
|
5
|
+
|
6
|
+
|
7
|
+
def __init__(self, id, display_name, sku, region, state):
|
8
|
+
"""Constructor for the Capacity class
|
9
|
+
|
10
|
+
Args:
|
11
|
+
id (str): The ID of the capacity
|
12
|
+
display_name (str): The display name of the capacity
|
13
|
+
sku (str): The SKU of the capacity
|
14
|
+
region (str): The region of the capacity
|
15
|
+
state (str): The state of the capacity
|
16
|
+
|
17
|
+
Returns:
|
18
|
+
Capacity: The Capacity object created
|
19
|
+
"""
|
20
|
+
self.id = id
|
21
|
+
self.display_name = display_name
|
22
|
+
self.sku = sku
|
23
|
+
self.region = region
|
24
|
+
self.state = state
|
25
|
+
|
26
|
+
def __str__(self):
|
27
|
+
"""Method to return a string representation of the Capacity object
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
str: The string representation of the Capacity object
|
31
|
+
"""
|
32
|
+
dic = {
|
33
|
+
'id': self.id,
|
34
|
+
'display_name': self.display_name,
|
35
|
+
'sku': self.sku,
|
36
|
+
'region': self.region,
|
37
|
+
'state': self.state
|
38
|
+
}
|
39
|
+
return json.dumps(dic, indent=2)
|
40
|
+
|
41
|
+
def from_dict(dic):
|
42
|
+
"""Method to create a Capacity object from a dictionary
|
43
|
+
|
44
|
+
Args:
|
45
|
+
dic (dict): The dictionary containing the capacity information
|
46
|
+
Returns:
|
47
|
+
Capacity: The Capacity object created from the dictionary
|
48
|
+
|
49
|
+
"""
|
50
|
+
if "display_name" not in dic:
|
51
|
+
dic["display_name"] = dic["displayName"]
|
52
|
+
return Capacity(dic['id'], dic['display_name'], dic['sku'], dic['region'], dic['state'])
|
53
|
+
|
@@ -3,6 +3,7 @@ import json
|
|
3
3
|
import os
|
4
4
|
from time import sleep
|
5
5
|
|
6
|
+
from msfabricpysdkcore.capacity import Capacity
|
6
7
|
from msfabricpysdkcore.workspace import Workspace
|
7
8
|
from msfabricpysdkcore.auth import FabricAuthClient, FabricServicePrincipal
|
8
9
|
|
@@ -25,10 +26,12 @@ class FabricClientCore():
|
|
25
26
|
self.scope = "https://api.fabric.microsoft.com/.default"
|
26
27
|
|
27
28
|
|
28
|
-
def list_workspaces(self):
|
29
|
+
def list_workspaces(self, continuationToken = None):
|
29
30
|
"""List all workspaces in the tenant"""
|
30
31
|
|
31
32
|
url = "https://api.fabric.microsoft.com/v1/workspaces"
|
33
|
+
if continuationToken:
|
34
|
+
url = f"{url}?continuationToken={continuationToken}"
|
32
35
|
|
33
36
|
for _ in range(10):
|
34
37
|
response = requests.get(url=url, headers=self.auth.get_headers())
|
@@ -39,13 +42,16 @@ class FabricClientCore():
|
|
39
42
|
if response.status_code not in (200, 429):
|
40
43
|
print(response.status_code)
|
41
44
|
print(response.text)
|
42
|
-
|
45
|
+
raise Exception(f"Error listing workspaces: {response.status_code}, {response.text}")
|
43
46
|
break
|
47
|
+
resp_dict = json.loads(response.text)
|
48
|
+
ws_list = resp_dict["value"]
|
49
|
+
ws_list = [Workspace.from_dict(ws, auth=self.auth) for ws in ws_list]
|
50
|
+
|
51
|
+
if "continuationToken" in resp_dict:
|
52
|
+
ws_list_next = self.list_workspaces(continuationToken=resp_dict["continuationToken"])
|
53
|
+
ws_list.extend(ws_list_next)
|
44
54
|
|
45
|
-
ws_list = []
|
46
|
-
for i in items:
|
47
|
-
ws = Workspace.from_dict(i, auth=self.auth)
|
48
|
-
ws_list.append(ws)
|
49
55
|
return ws_list
|
50
56
|
|
51
57
|
def get_workspace_by_name(self, name):
|
@@ -69,12 +75,12 @@ class FabricClientCore():
|
|
69
75
|
if response.status_code not in (200, 429):
|
70
76
|
print(response.status_code)
|
71
77
|
print(response.text)
|
72
|
-
ws_dict = json.loads(response.text)
|
73
|
-
if "id" not in ws_dict:
|
74
78
|
raise Exception(f"Error getting workspace: {response.status_code} {response.text}")
|
75
|
-
|
79
|
+
break
|
80
|
+
ws_dict = json.loads(response.text)
|
81
|
+
ws = Workspace.from_dict(ws_dict, auth=self.auth)
|
76
82
|
|
77
|
-
|
83
|
+
return ws
|
78
84
|
|
79
85
|
|
80
86
|
def get_workspace(self, id = None, name = None):
|
@@ -158,10 +164,13 @@ class FabricClientCore():
|
|
158
164
|
ws = self.get_workspace_by_id(workspace_id)
|
159
165
|
return ws.unassign_from_capacity()
|
160
166
|
|
161
|
-
def list_capacities(self):
|
167
|
+
def list_capacities(self, continuationToken = None):
|
162
168
|
"""List all capacities in the tenant"""
|
163
169
|
url = "https://api.fabric.microsoft.com/v1/capacities"
|
164
170
|
|
171
|
+
if continuationToken:
|
172
|
+
url = f"{url}?continuationToken={continuationToken}"
|
173
|
+
|
165
174
|
for _ in range(10):
|
166
175
|
response = requests.get(url=url, headers=self.auth.get_headers())
|
167
176
|
if response.status_code == 429:
|
@@ -174,9 +183,17 @@ class FabricClientCore():
|
|
174
183
|
raise Exception(f"Error listing capacities: {response.text}")
|
175
184
|
break
|
176
185
|
|
177
|
-
|
186
|
+
resp_dict = json.loads(response.text)
|
187
|
+
items = resp_dict["value"]
|
188
|
+
|
189
|
+
if "continuationToken" in resp_dict:
|
190
|
+
cap_list_next = self.list_capacities(continuationToken=resp_dict["continuationToken"])
|
191
|
+
items.extend(cap_list_next)
|
178
192
|
|
193
|
+
items = json.loads(response.text)["value"]
|
194
|
+
items = [Capacity.from_dict(i) for i in items]
|
179
195
|
return items
|
196
|
+
|
180
197
|
|
181
198
|
def create_item(self, workspace_id, display_name, type, definition = None, description = None):
|
182
199
|
"""Create an item in a workspace"""
|
@@ -187,10 +204,11 @@ class FabricClientCore():
|
|
187
204
|
definition = definition,
|
188
205
|
description = description)
|
189
206
|
|
190
|
-
def get_item(self, workspace_id,
|
207
|
+
def get_item(self, workspace_id = None,
|
208
|
+
item_id = None, workspace_name = None, item_name = None, item_type = None):
|
191
209
|
"""Get an item from a workspace"""
|
192
|
-
ws = self.
|
193
|
-
return ws.get_item(item_id)
|
210
|
+
ws = self.get_workspace(id = workspace_id, name = workspace_name)
|
211
|
+
return ws.get_item(item_id = item_id, item_name = item_name, item_type = item_type)
|
194
212
|
|
195
213
|
def delete_item(self, workspace_id, item_id):
|
196
214
|
"""Delete an item from a workspace"""
|
@@ -280,4 +298,39 @@ class FabricClientCore():
|
|
280
298
|
return ws.update_from_git(remote_commit_hash=remote_commit_hash,
|
281
299
|
conflict_resolution=conflict_resolution,
|
282
300
|
options=options,
|
283
|
-
workspace_head=workspace_head)
|
301
|
+
workspace_head=workspace_head)
|
302
|
+
|
303
|
+
def get_capacity(self, capacity_id = None, capacity_name = None):
|
304
|
+
"""Get a capacity
|
305
|
+
|
306
|
+
Args:
|
307
|
+
capacity_id (str): The ID of the capacity
|
308
|
+
capacity_name (str): The name of the capacity
|
309
|
+
|
310
|
+
Returns:
|
311
|
+
Capacity: The capacity object
|
312
|
+
|
313
|
+
Raises:
|
314
|
+
ValueError: If no capacity is found
|
315
|
+
"""
|
316
|
+
if capacity_id is None and capacity_name is None:
|
317
|
+
raise ValueError("Either capacity_id or capacity_name must be provided")
|
318
|
+
caps = self.list_capacities()
|
319
|
+
for cap in caps:
|
320
|
+
if capacity_id and cap.id == capacity_id:
|
321
|
+
return cap
|
322
|
+
if capacity_name and cap.display_name == capacity_name:
|
323
|
+
return cap
|
324
|
+
raise ValueError("No capacity found")
|
325
|
+
|
326
|
+
def list_tables(self, workspace_id, item_id):
|
327
|
+
ws = self.get_workspace_by_id(workspace_id)
|
328
|
+
return ws.list_tables(item_id=item_id)
|
329
|
+
|
330
|
+
def load_table(self, workspace_id, item_id, table_name, path_type, relative_path,
|
331
|
+
file_extension = None, format_options = None,
|
332
|
+
mode = None, recursive = None, wait_for_completion = True):
|
333
|
+
ws = self.get_workspace_by_id(workspace_id)
|
334
|
+
return ws.load_table(item_id, table_name, path_type, relative_path,
|
335
|
+
file_extension, format_options,
|
336
|
+
mode, recursive, wait_for_completion)
|
@@ -6,6 +6,7 @@ from msfabricpysdkcore.onelakeshortcut import OneLakeShortcut
|
|
6
6
|
from msfabricpysdkcore.job_instance import JobInstance
|
7
7
|
from msfabricpysdkcore.long_running_operation import check_long_running_operation
|
8
8
|
|
9
|
+
|
9
10
|
class Item:
|
10
11
|
"""Class to represent a item in Microsoft Fabric"""
|
11
12
|
|
@@ -36,6 +37,12 @@ class Item:
|
|
36
37
|
|
37
38
|
def from_dict(item_dict, auth):
|
38
39
|
"""Create Item object from dictionary"""
|
40
|
+
|
41
|
+
if item_dict['type'] == "Lakehouse":
|
42
|
+
from msfabricpysdkcore.lakehouse import Lakehouse
|
43
|
+
return Lakehouse(id=item_dict['id'], display_name=item_dict['displayName'], type=item_dict['type'], workspace_id=item_dict['workspaceId'],
|
44
|
+
properties=item_dict.get('properties', None),
|
45
|
+
definition=item_dict.get('definition', None), description=item_dict.get('description', ""), auth=auth)
|
39
46
|
return Item(id=item_dict['id'], display_name=item_dict['displayName'], type=item_dict['type'], workspace_id=item_dict['workspaceId'],
|
40
47
|
properties=item_dict.get('properties', None),
|
41
48
|
definition=item_dict.get('definition', None), description=item_dict.get('description', ""), auth=auth)
|
@@ -52,6 +59,7 @@ class Item:
|
|
52
59
|
if response.status_code not in (200, 429):
|
53
60
|
print(response.status_code)
|
54
61
|
print(response.text)
|
62
|
+
print(self)
|
55
63
|
raise Exception(f"Error deleting item: {response.text}")
|
56
64
|
break
|
57
65
|
|
@@ -243,4 +251,11 @@ class Item:
|
|
243
251
|
def cancel_item_job_instance(self, job_instance_id):
|
244
252
|
"""Cancel a job instance ofjob the item"""
|
245
253
|
return self.get_item_job_instance(job_instance_id=job_instance_id).cancel()
|
246
|
-
|
254
|
+
|
255
|
+
def list_tables(self):
|
256
|
+
raise NotImplementedError("List tables only works on Lakehouse Items")
|
257
|
+
|
258
|
+
def load_table(self, table_name, path_type, relative_path,
|
259
|
+
file_extension = None, format_options = None,
|
260
|
+
mode = None, recursive = None, wait_for_completion = True):
|
261
|
+
raise NotImplementedError("Load table only works on Lakehouse Items")
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import json
|
2
|
+
import requests
|
3
|
+
from time import sleep
|
4
|
+
|
5
|
+
from msfabricpysdkcore.long_running_operation import check_long_running_operation
|
6
|
+
from msfabricpysdkcore.item import Item
|
7
|
+
|
8
|
+
class Lakehouse(Item):
|
9
|
+
"""Class to represent a item in Microsoft Fabric"""
|
10
|
+
|
11
|
+
def __init__(self, id, display_name, type, workspace_id, auth, properties = None, definition=None, description=""):
|
12
|
+
super().__init__(id, display_name, type, workspace_id, auth, properties, definition, description)
|
13
|
+
|
14
|
+
|
15
|
+
def list_tables(self, continuationToken = None):
|
16
|
+
"""List all tables in the lakehouse"""
|
17
|
+
# GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses/{lakehouseId}/tables
|
18
|
+
url = f"https://api.fabric.microsoft.com/v1/workspaces/{self.workspace_id}/lakehouses/{self.id}/tables"
|
19
|
+
|
20
|
+
if continuationToken:
|
21
|
+
url = f"{url}?continuationToken={continuationToken}"
|
22
|
+
|
23
|
+
for _ in range(10):
|
24
|
+
response = requests.get(url=url, headers=self.auth.get_headers())
|
25
|
+
if response.status_code == 429:
|
26
|
+
print("Too many requests, waiting 10 seconds")
|
27
|
+
sleep(10)
|
28
|
+
continue
|
29
|
+
if response.status_code not in (200, 429):
|
30
|
+
print(response.status_code)
|
31
|
+
print(response.text)
|
32
|
+
raise Exception(f"Error listing tables: {response.status_code}, {response.text}")
|
33
|
+
break
|
34
|
+
resp_dict = json.loads(response.text)
|
35
|
+
|
36
|
+
table_list = resp_dict["data"]
|
37
|
+
|
38
|
+
if "continuationToken" in resp_dict and resp_dict["continuationToken"] is not None:
|
39
|
+
table_list_next = self.list_tables(continuationToken=resp_dict["continuationToken"])
|
40
|
+
table_list.extend(table_list_next)
|
41
|
+
|
42
|
+
return table_list
|
43
|
+
|
44
|
+
def load_table(self, table_name, path_type, relative_path,
|
45
|
+
file_extension = None, format_options = None,
|
46
|
+
mode = None, recursive = None, wait_for_completion = True):
|
47
|
+
"""Load a table in the lakehouse"""
|
48
|
+
# POST https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/lakehouses/{lakehouseId}/tables/{tableName}/load
|
49
|
+
url = f"https://api.fabric.microsoft.com/v1/workspaces/{self.workspace_id}/lakehouses/{self.id}/tables/{table_name}/load"
|
50
|
+
|
51
|
+
body = {
|
52
|
+
"relativePath": relative_path,
|
53
|
+
"pathType": path_type,
|
54
|
+
}
|
55
|
+
|
56
|
+
if file_extension:
|
57
|
+
body["fileExtension"] = file_extension
|
58
|
+
if format_options:
|
59
|
+
body["formatOptions"] = format_options
|
60
|
+
if mode:
|
61
|
+
body["mode"] = mode
|
62
|
+
if recursive:
|
63
|
+
body["recursive"] = recursive
|
64
|
+
|
65
|
+
for _ in range(10):
|
66
|
+
response = requests.post(url=url, headers=self.auth.get_headers(), json=body)
|
67
|
+
if response.status_code == 429:
|
68
|
+
print("Too many requests, waiting 10 seconds")
|
69
|
+
sleep(10)
|
70
|
+
continue
|
71
|
+
if response.status_code == 202:
|
72
|
+
if wait_for_completion:
|
73
|
+
success = self.check_if_table_is_created(table_name)
|
74
|
+
|
75
|
+
if not success:
|
76
|
+
print("Warning: Table not created after 3 minutes")
|
77
|
+
else:
|
78
|
+
print("Table created")
|
79
|
+
if response.status_code not in (202, 429):
|
80
|
+
print(response.status_code)
|
81
|
+
print(response.text)
|
82
|
+
raise Exception(f"Error loading table: {response.status_code}, {response.text}")
|
83
|
+
break
|
84
|
+
|
85
|
+
return response.status_code
|
86
|
+
|
87
|
+
def check_if_table_is_created(self, table_name):
|
88
|
+
"""Check if the table is created"""
|
89
|
+
for _ in range(60):
|
90
|
+
table_names = [table["name"] for table in self.list_tables()]
|
91
|
+
if table_name in table_names:
|
92
|
+
return True
|
93
|
+
|
94
|
+
sleep(3)
|
95
|
+
return False
|
96
|
+
|
File without changes
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import unittest
|
2
|
+
from msfabricpysdkcore.client import FabricClientCore
|
3
|
+
from datetime import datetime
|
4
|
+
from dotenv import load_dotenv
|
5
|
+
|
6
|
+
class TestFabricClientCore(unittest.TestCase):
|
7
|
+
|
8
|
+
def __init__(self, *args, **kwargs):
|
9
|
+
super(TestFabricClientCore, self).__init__(*args, **kwargs)
|
10
|
+
#load_dotenv()
|
11
|
+
self.fc = FabricClientCore()
|
12
|
+
self.workspace_id = "fd3ba978-0b94-43e2-9f23-f65761e9ff34"
|
13
|
+
|
14
|
+
def test_git(self):
|
15
|
+
|
16
|
+
datetime_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
17
|
+
ws2_name = "git" + datetime_str
|
18
|
+
self.fc.create_workspace(display_name=ws2_name)
|
19
|
+
ws2 = self.fc.get_workspace_by_name(name=ws2_name)
|
20
|
+
self.fc.assign_to_capacity(workspace_id=ws2.id, capacity_id="a089a991-221c-49be-a41e-9020198cf7af")
|
21
|
+
|
22
|
+
git_provider_details = {'organizationName': 'dasenf1860',
|
23
|
+
'projectName': 'fabrictest',
|
24
|
+
'gitProviderType': 'AzureDevOps',
|
25
|
+
'repositoryName': 'fabrictest',
|
26
|
+
'branchName': 'main',
|
27
|
+
'directoryName': '/folder1'}
|
28
|
+
|
29
|
+
status_code = self.fc.git_connect(workspace_id=ws2.id, git_provider_details=git_provider_details)
|
30
|
+
|
31
|
+
self.assertEqual(status_code, 204)
|
32
|
+
|
33
|
+
initialization_strategy = "PreferWorkspace"
|
34
|
+
|
35
|
+
status_code = self.fc.git_initialize_connection(workspace_id=ws2.id, initialization_strategy=initialization_strategy)
|
36
|
+
self.assertEqual(status_code, 200)
|
37
|
+
|
38
|
+
connection_details = self.fc.git_get_connection(workspace_id=ws2.id)
|
39
|
+
self.assertEqual(connection_details['gitConnectionState'], 'ConnectedAndInitialized')
|
40
|
+
|
41
|
+
status = self.fc.git_get_status(workspace_id=ws2.id)
|
42
|
+
self.assertTrue(len(status["changes"]) > 0)
|
43
|
+
|
44
|
+
status_code = self.fc.update_from_git(workspace_id=ws2.id, remote_commit_hash=status["remoteCommitHash"])
|
45
|
+
|
46
|
+
self.assertEqual(status_code, 202)
|
47
|
+
|
48
|
+
blubb_lakehouse = False
|
49
|
+
for item in ws2.list_items():
|
50
|
+
if item.type == "Lakehouse" and item.display_name == "blubb":
|
51
|
+
blubb_lakehouse = True
|
52
|
+
|
53
|
+
self.assertTrue(blubb_lakehouse)
|
54
|
+
|
55
|
+
status_code = self.fc.git_disconnect(workspace_id=ws2.id)
|
56
|
+
|
57
|
+
self.assertEqual(status_code, 204)
|
58
|
+
|
59
|
+
ws2.delete()
|
60
|
+
|
61
|
+
if __name__ == "__main__":
|
62
|
+
unittest.main()
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import unittest
|
2
|
+
from datetime import datetime
|
3
|
+
from dotenv import load_dotenv
|
4
|
+
from time import sleep
|
5
|
+
from msfabricpysdkcore.client import FabricClientCore
|
6
|
+
|
7
|
+
class TestFabricClientCore(unittest.TestCase):
|
8
|
+
|
9
|
+
def __init__(self, *args, **kwargs):
|
10
|
+
super(TestFabricClientCore, self).__init__(*args, **kwargs)
|
11
|
+
#load_dotenv()
|
12
|
+
self.fc = FabricClientCore()
|
13
|
+
self.workspace_id = "c3352d34-0b54-40f0-b204-cc964b1beb8d"
|
14
|
+
|
15
|
+
datetime_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
16
|
+
self.item_name = "testitem" + datetime_str
|
17
|
+
self.item_type = "Notebook"
|
18
|
+
|
19
|
+
def test_item_end_to_end(self):
|
20
|
+
|
21
|
+
item = self.fc.create_item(display_name=self.item_name, type=self.item_type, workspace_id=self.workspace_id)
|
22
|
+
self.assertEqual(item.display_name, self.item_name)
|
23
|
+
self.assertEqual(item.type, self.item_type)
|
24
|
+
self.assertEqual(item.workspace_id, self.workspace_id)
|
25
|
+
self.assertEqual(item.description, "")
|
26
|
+
|
27
|
+
item = self.fc.get_item(workspace_id=self.workspace_id, item_id=item.id)
|
28
|
+
item_ = self.fc.get_item(workspace_id=self.workspace_id,
|
29
|
+
item_name=self.item_name, item_type=self.item_type)
|
30
|
+
self.assertEqual(item.id, item_.id)
|
31
|
+
self.assertEqual(item.display_name, self.item_name)
|
32
|
+
self.assertEqual(item.type, self.item_type)
|
33
|
+
self.assertEqual(item.workspace_id, self.workspace_id)
|
34
|
+
self.assertEqual(item.description, "")
|
35
|
+
|
36
|
+
item_list = self.fc.list_items(workspace_id=self.workspace_id)
|
37
|
+
self.assertTrue(len(item_list) > 0)
|
38
|
+
|
39
|
+
item_ids = [item_.id for item_ in item_list]
|
40
|
+
self.assertIn(item.id, item_ids)
|
41
|
+
|
42
|
+
self.fc.update_item(workspace_id=self.workspace_id, item_id=item.id, display_name=f"u{self.item_name}")
|
43
|
+
item = self.fc.get_item(workspace_id=self.workspace_id, item_id=item.id)
|
44
|
+
self.assertEqual(item.display_name, f"u{self.item_name}")
|
45
|
+
|
46
|
+
status_code = self.fc.delete_item(workspace_id=self.workspace_id, item_id=item.id)
|
47
|
+
|
48
|
+
self.assertAlmostEqual(status_code, 200)
|
49
|
+
|
50
|
+
def test_lakehouse(self):
|
51
|
+
|
52
|
+
lakehouse = self.fc.get_item(workspace_id=self.workspace_id, item_name="lakehouse1", item_type="Lakehouse")
|
53
|
+
item_id = lakehouse.id
|
54
|
+
date_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
55
|
+
table_name = f"table{date_str}"
|
56
|
+
|
57
|
+
|
58
|
+
status_code = self.fc.load_table(workspace_id=self.workspace_id, item_id=item_id, table_name=table_name,
|
59
|
+
path_type="File", relative_path="Files/folder1/titanic.csv")
|
60
|
+
|
61
|
+
self.assertEqual(status_code, 202)
|
62
|
+
|
63
|
+
table_list = self.fc.list_tables(workspace_id=self.workspace_id, item_id=item_id)
|
64
|
+
table_names = [table["name"] for table in table_list]
|
65
|
+
|
66
|
+
self.assertIn(table_name, table_names)
|
67
|
+
|
68
|
+
if __name__ == "__main__":
|
69
|
+
unittest.main()
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import unittest
|
2
|
+
from msfabricpysdkcore.client import FabricClientCore
|
3
|
+
from datetime import datetime
|
4
|
+
from dotenv import load_dotenv
|
5
|
+
|
6
|
+
class TestFabricClientCore(unittest.TestCase):
|
7
|
+
|
8
|
+
def __init__(self, *args, **kwargs):
|
9
|
+
super(TestFabricClientCore, self).__init__(*args, **kwargs)
|
10
|
+
#load_dotenv()
|
11
|
+
self.fc = FabricClientCore()
|
12
|
+
self.workspace_id = "c3352d34-0b54-40f0-b204-cc964b1beb8d"
|
13
|
+
self.item_id = "7e38f344-81df-4805-83b6-b9cc16830500"
|
14
|
+
|
15
|
+
|
16
|
+
def test_jobs_end_to_end(self):
|
17
|
+
job = self.fc.run_on_demand_item_job(workspace_id=self.workspace_id,
|
18
|
+
item_id=self.item_id,
|
19
|
+
job_type="RunNotebook")
|
20
|
+
|
21
|
+
self.assertEqual(job.item_id, self.item_id)
|
22
|
+
self.assertEqual(job.workspace_id, self.workspace_id)
|
23
|
+
self.assertEqual(job.job_type, "RunNotebook")
|
24
|
+
self.assertIn(job.status, ["NotStarted", "InProgress"])
|
25
|
+
self.assertEqual(job.invoke_type, "Manual")
|
26
|
+
|
27
|
+
job2 = self.fc.get_item_job_instance(workspace_id=self.workspace_id,
|
28
|
+
item_id=self.item_id,
|
29
|
+
job_instance_id=job.id)
|
30
|
+
|
31
|
+
self.assertEqual(job.id, job2.id)
|
32
|
+
|
33
|
+
status_code = self.fc.cancel_item_job_instance(workspace_id=self.workspace_id,
|
34
|
+
item_id=self.item_id,
|
35
|
+
job_instance_id=job.id)
|
36
|
+
|
37
|
+
self.assertEqual(status_code, 202)
|
38
|
+
|
39
|
+
if __name__ == "__main__":
|
40
|
+
unittest.main()
|
41
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import unittest
|
2
|
+
from msfabricpysdkcore.client import FabricClientCore
|
3
|
+
from datetime import datetime
|
4
|
+
from dotenv import load_dotenv
|
5
|
+
|
6
|
+
class TestFabricClientCore(unittest.TestCase):
|
7
|
+
|
8
|
+
def __init__(self, *args, **kwargs):
|
9
|
+
super(TestFabricClientCore, self).__init__(*args, **kwargs)
|
10
|
+
#load_dotenv()
|
11
|
+
self.fc = FabricClientCore()
|
12
|
+
self.workspace_id = "c3352d34-0b54-40f0-b204-cc964b1beb8d"
|
13
|
+
|
14
|
+
self.lakehouse_target = "cb4ca0b5-b53b-4879-b206-a53c35cbff55"
|
15
|
+
self.lakehouse_shortcut = "e2c09c89-bf97-4f71-bdeb-36338795ec36"
|
16
|
+
|
17
|
+
datetime_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
18
|
+
self.shortcutname = "shortcut" + datetime_str
|
19
|
+
self.path_target = "Files/folder1"
|
20
|
+
self.path_shortcut = "Files/shortcutfolder"
|
21
|
+
|
22
|
+
self.target = {'oneLake': {'itemId': self.lakehouse_target,
|
23
|
+
'path': self.path_target,
|
24
|
+
'workspaceId': self.workspace_id}}
|
25
|
+
|
26
|
+
def test_shortcut_end_to_end(self):
|
27
|
+
|
28
|
+
item = self.fc.create_shortcut(workspace_id=self.workspace_id,
|
29
|
+
item_id=self.lakehouse_shortcut,
|
30
|
+
path=self.path_shortcut,
|
31
|
+
name=self.shortcutname,
|
32
|
+
target=self.target)
|
33
|
+
self.assertEqual(item.name, self.shortcutname)
|
34
|
+
self.assertEqual(item.path, self.path_shortcut)
|
35
|
+
self.assertEqual(item.target, self.target)
|
36
|
+
|
37
|
+
item = self.fc.get_shortcut(workspace_id=self.workspace_id,
|
38
|
+
item_id=self.lakehouse_shortcut,
|
39
|
+
path=self.path_shortcut,
|
40
|
+
name=self.shortcutname)
|
41
|
+
self.assertEqual(item.name, self.shortcutname)
|
42
|
+
self.assertEqual(item.path, self.path_shortcut)
|
43
|
+
self.assertEqual(item.target, self.target)
|
44
|
+
|
45
|
+
status_code = self.fc.delete_shortcut(workspace_id=self.workspace_id,
|
46
|
+
item_id=self.lakehouse_shortcut,
|
47
|
+
path=self.path_shortcut,
|
48
|
+
name=self.shortcutname)
|
49
|
+
|
50
|
+
self.assertAlmostEqual(status_code, 200)
|
51
|
+
|
52
|
+
if __name__ == "__main__":
|
53
|
+
unittest.main()
|
@@ -0,0 +1,146 @@
|
|
1
|
+
import unittest
|
2
|
+
from dotenv import load_dotenv
|
3
|
+
from datetime import datetime
|
4
|
+
from msfabricpysdkcore.client import FabricClientCore
|
5
|
+
|
6
|
+
load_dotenv()
|
7
|
+
|
8
|
+
class TestFabricClientCore(unittest.TestCase):
|
9
|
+
|
10
|
+
def __init__(self, *args, **kwargs):
|
11
|
+
super(TestFabricClientCore, self).__init__(*args, **kwargs)
|
12
|
+
self.fc = FabricClientCore()
|
13
|
+
datetime_str = datetime.now().strftime("%Y%m%d%H%M%S")
|
14
|
+
self.display_name = "testws" + datetime_str
|
15
|
+
self.workspace_id = None
|
16
|
+
|
17
|
+
def test_end_to_end_workspace(self):
|
18
|
+
|
19
|
+
ws_created = self.fc.create_workspace(display_name=self.display_name,
|
20
|
+
description="test workspace",
|
21
|
+
exists_ok=False)
|
22
|
+
# Add assertions here to verify the result
|
23
|
+
self.assertEqual(ws_created.display_name, self.display_name)
|
24
|
+
self.workspace_id = ws_created.id
|
25
|
+
ws = self.fc.get_workspace_by_id(id = self.workspace_id)
|
26
|
+
self.assertEqual(ws.display_name, self.display_name)
|
27
|
+
self.assertEqual(ws.description, "test workspace")
|
28
|
+
|
29
|
+
# def test_assign_to_capacity(self):
|
30
|
+
|
31
|
+
result_status_code = self.fc.assign_to_capacity(workspace_id=ws.id,
|
32
|
+
capacity_id="41cb829c-c231-4e9f-b4fc-f9042a6f9840")
|
33
|
+
self.assertEqual(result_status_code, 202)
|
34
|
+
|
35
|
+
|
36
|
+
# def test_list_workspaces(self):
|
37
|
+
|
38
|
+
result = self.fc.list_workspaces()
|
39
|
+
display_names = [ws.display_name for ws in result]
|
40
|
+
self.assertIn(self.display_name, display_names)
|
41
|
+
|
42
|
+
for ws in result:
|
43
|
+
if ws.display_name == self.display_name:
|
44
|
+
self.assertEqual(ws.capacity_id, "41cb829c-c231-4e9f-b4fc-f9042a6f9840")
|
45
|
+
|
46
|
+
|
47
|
+
# def test_get_workspace_by_name(self):
|
48
|
+
|
49
|
+
workspace_name = self.display_name
|
50
|
+
ws = self.fc.get_workspace_by_name(name = workspace_name)
|
51
|
+
self.assertEqual(ws.display_name, self.display_name)
|
52
|
+
|
53
|
+
# def test_get_workspace_by_id(self):
|
54
|
+
ws = self.fc.get_workspace_by_id(id = self.workspace_id)
|
55
|
+
self.assertEqual(self.display_name, ws.display_name)
|
56
|
+
|
57
|
+
|
58
|
+
# def test_get_workspace(self):
|
59
|
+
result = self.fc.get_workspace_by_id(id = self.workspace_id)
|
60
|
+
self.assertEqual(result.display_name, self.display_name)
|
61
|
+
|
62
|
+
# def test_add_role_assignment(self):
|
63
|
+
result_status = self.fc.add_workspace_role_assignment(workspace_id = ws.id,
|
64
|
+
principal = {"id" : "fe9dee5d-d244-4c93-8ea1-d5e6a2225c69",
|
65
|
+
"type" : "ServicePrincipal"},
|
66
|
+
role = 'Member')
|
67
|
+
|
68
|
+
self.assertEqual(result_status, 200)
|
69
|
+
|
70
|
+
# def test_get_workspace_role_assignments(self):
|
71
|
+
result = self.fc.get_workspace_role_assignments(workspace_id = ws.id)
|
72
|
+
self.assertTrue("value" in result)
|
73
|
+
self.assertTrue(len(result["value"]) == 2)
|
74
|
+
for user in result["value"]:
|
75
|
+
if user["principal"]["displayName"] == "fabrictestuser":
|
76
|
+
self.assertTrue(user["role"] == "Member")
|
77
|
+
|
78
|
+
# def test_update_workspace_role_assignment(self):
|
79
|
+
|
80
|
+
result_status_code = self.fc.update_workspace_role_assignment(workspace_id = ws.id,
|
81
|
+
role = "Contributor",
|
82
|
+
principal_id = "fe9dee5d-d244-4c93-8ea1-d5e6a2225c69")
|
83
|
+
|
84
|
+
self.assertEqual(result_status_code, 200)
|
85
|
+
|
86
|
+
result = self.fc.get_workspace_role_assignments(workspace_id = ws.id)
|
87
|
+
self.assertTrue("value" in result)
|
88
|
+
self.assertTrue(len(result["value"]) == 2)
|
89
|
+
for user in result["value"]:
|
90
|
+
if user["principal"]["displayName"] == "fabrictestuser":
|
91
|
+
self.assertTrue(user["role"] == "Contributor")
|
92
|
+
|
93
|
+
# def test_delete_role_assignment(self):
|
94
|
+
result_status_code = self.fc.delete_workspace_role_assignment(workspace_id = ws.id,
|
95
|
+
principal_id = "fe9dee5d-d244-4c93-8ea1-d5e6a2225c69")
|
96
|
+
self.assertEqual(result_status_code, 200)
|
97
|
+
|
98
|
+
# def test_get_workspace_role_assignments(self):
|
99
|
+
result = self.fc.get_workspace_role_assignments(workspace_id = ws.id)
|
100
|
+
self.assertTrue("value" in result)
|
101
|
+
self.assertTrue(len(result["value"]) == 1)
|
102
|
+
user = result["value"][0]
|
103
|
+
# self.assertTrue(user["principal"]["displayName"] == "fabricapi")
|
104
|
+
self.assertTrue(user["role"] == "Admin")
|
105
|
+
|
106
|
+
# def test_update_workspace(self):
|
107
|
+
ws_updated = self.fc.update_workspace(workspace_id=ws.id,
|
108
|
+
display_name="newname8912389u1293",
|
109
|
+
description="new description")
|
110
|
+
self.assertEqual(ws_updated.display_name, "newname8912389u1293")
|
111
|
+
self.assertEqual(ws_updated.description, "new description")
|
112
|
+
ws = self.fc.get_workspace_by_id(id = ws.id)
|
113
|
+
self.assertEqual(ws.display_name, "newname8912389u1293")
|
114
|
+
self.assertEqual(ws.description, "new description")
|
115
|
+
|
116
|
+
# def test_unassign_from_capacity(self):
|
117
|
+
|
118
|
+
result_status_code = self.fc.unassign_from_capacity(workspace_id=ws.id)
|
119
|
+
self.assertEqual(result_status_code, 202)
|
120
|
+
ws = self.fc.get_workspace_by_id(ws.id)
|
121
|
+
self.assertEqual(ws.capacity_id, None)
|
122
|
+
|
123
|
+
# def test_delete_workspace(self):
|
124
|
+
result_status = self.fc.delete_workspace(display_name="newname8912389u1293")
|
125
|
+
self.assertEqual(result_status, 200)
|
126
|
+
|
127
|
+
def test_list_capacities(self):
|
128
|
+
result = self.fc.list_capacities()
|
129
|
+
self.assertTrue(len(result) > 0)
|
130
|
+
cap_ids = [cap.id for cap in result]
|
131
|
+
self.assertIn("41cb829c-c231-4e9f-b4fc-f9042a6f9840", cap_ids)
|
132
|
+
|
133
|
+
def test_get_capacity(self):
|
134
|
+
capacity = self.fc.get_capacity(capacity_id = "41cb829c-c231-4e9f-b4fc-f9042a6f9840")
|
135
|
+
self.assertEqual(capacity.id, "41cb829c-c231-4e9f-b4fc-f9042a6f9840")
|
136
|
+
|
137
|
+
cap = self.fc.get_capacity(capacity_name= capacity.display_name)
|
138
|
+
|
139
|
+
self.assertEqual(capacity.id, cap.id)
|
140
|
+
self.assertIsNotNone(cap.state)
|
141
|
+
self.assertIsNotNone(cap.sku)
|
142
|
+
self.assertIsNotNone(cap.region)
|
143
|
+
|
144
|
+
|
145
|
+
if __name__ == "__main__":
|
146
|
+
unittest.main()
|
@@ -240,14 +240,29 @@ class Workspace:
|
|
240
240
|
print(response.text)
|
241
241
|
raise Exception(f"Error creating item: {response.text}")
|
242
242
|
break
|
243
|
-
|
243
|
+
|
244
244
|
item_dict = json.loads(response.text)
|
245
|
+
if item_dict is None:
|
246
|
+
print("Item not returned by API, trying to get it by name")
|
247
|
+
return self.get_item_by_name(display_name, type)
|
245
248
|
return Item.from_dict(item_dict, auth=self.auth)
|
246
249
|
|
247
250
|
|
248
|
-
def
|
251
|
+
def get_item_by_name(self, item_name, item_type):
|
252
|
+
"""Get an item from a workspace by name"""
|
253
|
+
ws_items = self.list_items()
|
254
|
+
for item in ws_items:
|
255
|
+
if item.display_name == item_name and item.type == item_type:
|
256
|
+
return item
|
257
|
+
|
258
|
+
def get_item(self, item_id = None, item_name = None, item_type = None):
|
249
259
|
# GET https://api.fabric.microsoft.com/v1/workspaces/{workspaceId}/items/{itemId}
|
250
260
|
"""Get an item from a workspace"""
|
261
|
+
if item_id is None and item_name is not None and item_type is not None:
|
262
|
+
return self.get_item_by_name(item_name, item_type)
|
263
|
+
elif item_id is None:
|
264
|
+
raise Exception("item_id or the combination item_name + item_type is required")
|
265
|
+
|
251
266
|
url = f"https://api.fabric.microsoft.com/v1/workspaces/{self.id}/items/{item_id}"
|
252
267
|
|
253
268
|
for _ in range(10):
|
@@ -259,7 +274,7 @@ class Workspace:
|
|
259
274
|
if response.status_code not in (200, 429):
|
260
275
|
print(response.status_code)
|
261
276
|
print(response.text)
|
262
|
-
raise Exception(f"Error getting item
|
277
|
+
raise Exception(f"Error getting item: {response.text}")
|
263
278
|
break
|
264
279
|
|
265
280
|
item_dict = json.loads(response.text)
|
@@ -268,11 +283,15 @@ class Workspace:
|
|
268
283
|
def delete_item(self, item_id):
|
269
284
|
"""Delete an item from a workspace"""
|
270
285
|
return self.get_item(item_id).delete()
|
286
|
+
|
271
287
|
|
272
|
-
def list_items(self):
|
288
|
+
def list_items(self, continuationToken = None):
|
273
289
|
"""List items in a workspace"""
|
274
290
|
url = f"https://api.fabric.microsoft.com/v1/workspaces/{self.id}/items"
|
275
291
|
|
292
|
+
if continuationToken:
|
293
|
+
url = f"{url}?continuationToken={continuationToken}"
|
294
|
+
|
276
295
|
for _ in range(10):
|
277
296
|
response = requests.get(url=url, headers=self.auth.get_headers())
|
278
297
|
if response.status_code == 429:
|
@@ -284,8 +303,16 @@ class Workspace:
|
|
284
303
|
print(response.text)
|
285
304
|
raise Exception(f"Error listing items: {response.text}")
|
286
305
|
break
|
287
|
-
|
288
|
-
|
306
|
+
|
307
|
+
resp_dict = json.loads(response.text)
|
308
|
+
items = resp_dict["value"]
|
309
|
+
items = [Item.from_dict(item, auth=self.auth) for item in items]
|
310
|
+
|
311
|
+
if "continuationToken" in resp_dict:
|
312
|
+
item_list_next = self.list_items(continuationToken=resp_dict["continuationToken"])
|
313
|
+
items.extend(item_list_next)
|
314
|
+
|
315
|
+
return items
|
289
316
|
|
290
317
|
def get_item_definition(self, item_id):
|
291
318
|
"""Get the definition of an item from a workspace"""
|
@@ -478,4 +505,14 @@ class Workspace:
|
|
478
505
|
raise Exception(f"Error updating from git: {response.text}")
|
479
506
|
break
|
480
507
|
|
481
|
-
return response.status_code
|
508
|
+
return response.status_code
|
509
|
+
|
510
|
+
def list_tables(self, item_id):
|
511
|
+
return self.get_item(item_id=item_id).list_tables()
|
512
|
+
|
513
|
+
def load_table(self, item_id, table_name, path_type, relative_path,
|
514
|
+
file_extension = None, format_options = None,
|
515
|
+
mode = None, recursive = None, wait_for_completion = True):
|
516
|
+
return self.get_item(item_id).load_table(table_name, path_type, relative_path,
|
517
|
+
file_extension, format_options,
|
518
|
+
mode, recursive, wait_for_completion)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: msfabricpysdkcore
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: A Python SDK for Microsoft Fabric
|
5
5
|
Author: Andreas Rederer
|
6
6
|
Project-URL: Homepage, https://github.com/DaSenf1860/ms-fabric-sdk-core
|
@@ -15,7 +15,7 @@ Requires-Dist: azure-identity>=1.15.0
|
|
15
15
|
|
16
16
|
# A Python SDK for Microsoft Fabric
|
17
17
|
|
18
|
-
This is a Python SDK for Microsoft Fabric. It is a wrapper around the REST APIs of Fabric*.
|
18
|
+
This is a Python SDK for Microsoft Fabric. It is a wrapper around the REST APIs (v1) of Fabric*.
|
19
19
|
|
20
20
|

|
21
21
|
|
@@ -29,10 +29,12 @@ Additionally it brings some extra features like:
|
|
29
29
|
- Retry logic when hitting the API rate limits
|
30
30
|
- Referencing objects by name instead of ID
|
31
31
|
- More granular objects, e.g. a Workspace and Item object instead of referencing IDs all the time
|
32
|
-
- Do bulk operations
|
33
|
-
- Pagination support
|
32
|
+
- Do bulk operations (see [Usage Patterns](usage_patterns.md))
|
33
|
+
- Pagination support
|
34
34
|
|
35
|
-
|
35
|
+
See the latest release notes [here](releasenotes/release_notes.md).
|
36
|
+
|
37
|
+
Currently it supports all Core APIs and Lakehouse APIs, i.e.:
|
36
38
|
- [Capacities](#working-with-capacities)
|
37
39
|
- [Git](#working-with-git)
|
38
40
|
- [Items](#working-with-items)
|
@@ -40,13 +42,13 @@ Currently it supports all Core APIs, i.e.:
|
|
40
42
|
- Long Running Operations
|
41
43
|
- [OneLakeShortcuts](#working-with-one-lake-shortcuts)
|
42
44
|
- [Workspaces](#working-with-workspaces)
|
45
|
+
- [Lakehouse APIs](#lakehouse-apis)
|
43
46
|
|
44
|
-
It is planned to support also the Admin
|
47
|
+
It is planned to support also the Admin APIs and new APIs which are not released yet.
|
45
48
|
Eventually Power BI APIs like the Scanner API will be covered as well.
|
46
49
|
|
47
50
|
*Because this SDK uses the API in the background, all limitations and restrictions of the API apply to this SDK as well. This includes rate limits, permissions, etc.
|
48
51
|
|
49
|
-
**These features are not yet implemented but are planned for the near future.
|
50
52
|
|
51
53
|
|
52
54
|
|
@@ -160,11 +162,16 @@ ws.delete_role_assignment(principal_id = "abadfbafb")
|
|
160
162
|
|
161
163
|
```python
|
162
164
|
|
165
|
+
|
166
|
+
capacity_object = fc.get_capacity(capacity_id = "0129389012u8938491")
|
167
|
+
#or
|
168
|
+
capacity_object = fc.get_capacity(capacity_name = "sandboxcapacitygermanywc")
|
169
|
+
|
163
170
|
# Assign a capaycity to a workspace
|
164
171
|
fc.assign_to_capacity(workspace_id=workspace_id,
|
165
|
-
capacity_id=
|
172
|
+
capacity_id=capacity_object.id)
|
166
173
|
# or
|
167
|
-
ws.assign_to_capacity(capacity_id=
|
174
|
+
ws.assign_to_capacity(capacity_id=capacity_object.id)
|
168
175
|
|
169
176
|
# Unassign from capacity
|
170
177
|
fc.unassign_from_capacity(workspace_id=ws.id)
|
@@ -359,7 +366,34 @@ item.cancel_item_job_instance(job_instance_id="job_instance_id")
|
|
359
366
|
|
360
367
|
```
|
361
368
|
|
369
|
+
## Lakehouse APIs
|
362
370
|
|
371
|
+
# List tables in a Lakehouse
|
372
|
+
|
373
|
+
```python
|
374
|
+
from msfabricpysdkcore import FabricClientCore
|
375
|
+
|
376
|
+
fc = FabricClientCore()
|
377
|
+
ws = fc.get_workspace_by_name("testworkspace")
|
378
|
+
lakehouse = ws.get_item_by_name(item_name="lakehouse1", item_type="Lakehouse")
|
379
|
+
table_list = lakehouse.list_tables()
|
380
|
+
# or
|
381
|
+
table_list = ws.list_tables(item_id = "someitemid")
|
382
|
+
# or
|
383
|
+
table_list = fc.list_tables(workspace_id = "someworkspaceid", item_id = "someitemid")
|
384
|
+
|
385
|
+
|
386
|
+
# Load a file (like a csv) into a Lakehouse table
|
387
|
+
|
388
|
+
lakehouse.load_table(table_name="testtable", path_type= "File", relative_path="Files/folder1/titanic.csv")
|
389
|
+
# or
|
390
|
+
ws.load_table(item_id = "someitemid", table_name="testtable",
|
391
|
+
path_type= "File", relative_path="Files/folder1/titanic.csv")
|
392
|
+
# or
|
393
|
+
fc.load_table(workspace_id = "someworkspaceid", item_id = "someitemid", table_name="testtable",
|
394
|
+
path_type= "File", relative_path="Files/folder1/titanic.csv")
|
395
|
+
|
396
|
+
```
|
363
397
|
|
364
398
|
Note: This SDK is not an official SDK from Microsoft. It is a community project and not supported by Microsoft. Use it at your own risk.
|
365
399
|
Also the API is still in preview and might change. This SDK is not yet feature complete and might not cover all APIs yet. Feel free to contribute to this project to make it better.
|
@@ -4,9 +4,11 @@ pyproject.toml
|
|
4
4
|
setup.py
|
5
5
|
msfabricpysdkcore/__init__.py
|
6
6
|
msfabricpysdkcore/auth.py
|
7
|
+
msfabricpysdkcore/capacity.py
|
7
8
|
msfabricpysdkcore/client.py
|
8
9
|
msfabricpysdkcore/item.py
|
9
10
|
msfabricpysdkcore/job_instance.py
|
11
|
+
msfabricpysdkcore/lakehouse.py
|
10
12
|
msfabricpysdkcore/long_running_operation.py
|
11
13
|
msfabricpysdkcore/onelakeshortcut.py
|
12
14
|
msfabricpysdkcore/workspace.py
|
@@ -14,4 +16,10 @@ msfabricpysdkcore.egg-info/PKG-INFO
|
|
14
16
|
msfabricpysdkcore.egg-info/SOURCES.txt
|
15
17
|
msfabricpysdkcore.egg-info/dependency_links.txt
|
16
18
|
msfabricpysdkcore.egg-info/requires.txt
|
17
|
-
msfabricpysdkcore.egg-info/top_level.txt
|
19
|
+
msfabricpysdkcore.egg-info/top_level.txt
|
20
|
+
msfabricpysdkcore/tests/__init__.py
|
21
|
+
msfabricpysdkcore/tests/test_git.py
|
22
|
+
msfabricpysdkcore/tests/test_items_incl_lakehouse.py
|
23
|
+
msfabricpysdkcore/tests/test_jobs.py
|
24
|
+
msfabricpysdkcore/tests/test_shortcuts.py
|
25
|
+
msfabricpysdkcore/tests/test_workspaces_capacities.py
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore/long_running_operation.py
RENAMED
File without changes
|
File without changes
|
{msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
{msfabricpysdkcore-0.0.2 → msfabricpysdkcore-0.0.3}/msfabricpysdkcore.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|