Skip to content

Commit

Permalink
Merge branch 'm-kovalsky/environmentapis'
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kovalsky committed Sep 16, 2024
2 parents c9fc690 + 9082b48 commit ea3c838
Show file tree
Hide file tree
Showing 8 changed files with 1,155 additions and 900 deletions.
50 changes: 35 additions & 15 deletions src/sempy_labs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
from sempy_labs._environments import (
create_environment,
delete_environment,
publish_environment,
)

from sempy_labs._spark import (
get_spark_settings,
update_spark_settings,
list_custom_pools,
create_custom_pool,
delete_custom_pool,
update_custom_pool,
)

from sempy_labs._workspaces import (
list_workspace_users,
update_workspace_user,
add_user_to_workspace,
delete_user_from_workspace,
assign_workspace_to_capacity,
unassign_workspace_from_capacity,
list_workspace_role_assignments,
)
from sempy_labs._notebooks import (
get_notebook_definition,
import_notebook_from_web,
)
from sempy_labs._sql import (
ConnectWarehouse,
)
Expand Down Expand Up @@ -51,7 +79,6 @@
)
from sempy_labs._list_functions import (
list_reports_using_semantic_model,
delete_custom_pool,
list_semantic_model_objects,
list_shortcuts,
get_object_level_security,
Expand All @@ -73,25 +100,13 @@
# list_sqlendpoints,
# list_tables,
list_warehouses,
list_workspace_role_assignments,
create_warehouse,
update_item,
list_custom_pools,
create_custom_pool,
update_custom_pool,
assign_workspace_to_capacity,
unassign_workspace_from_capacity,
get_spark_settings,
update_spark_settings,
add_user_to_workspace,
delete_user_from_workspace,
update_workspace_user,
list_workspace_users,
get_notebook_definition,
import_notebook_from_web,
)

from sempy_labs._helper_functions import (
resolve_environment_id,
resolve_capacity_id,
resolve_warehouse_id,
resolve_workspace_capacity,
create_abfss_path,
Expand Down Expand Up @@ -264,4 +279,9 @@
"update_from_git",
"connect_workspace_to_git",
"disconnect_workspace_from_git",
"create_environment",
"delete_environment",
"publish_environment",
"resolve_capacity_id",
"resolve_environment_id",
]
156 changes: 156 additions & 0 deletions src/sempy_labs/_environments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import sempy.fabric as fabric
import pandas as pd
import sempy_labs._icons as icons
from typing import Optional
from sempy_labs._helper_functions import (
resolve_workspace_name_and_id,
lro,
pagination,
)
from sempy.fabric.exceptions import FabricHTTPException


def create_environment(
environment: str, description: Optional[str] = None, workspace: Optional[str] = None
):
"""
Creates a Fabric environment.
Parameters
----------
environment: str
Name of the environment.
description : str, default=None
A description of the environment.
workspace : str, default=None
The Fabric workspace name.
Defaults to None which resolves to the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the workspace of the notebook.
"""

(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)

request_body = {"displayName": environment}

if description:
request_body["description"] = description

client = fabric.FabricRestClient()
response = client.post(
f"/v1/workspaces/{workspace_id}/environments", json=request_body
)

lro(client, response, status_codes=[201, 202])

print(
f"{icons.green_dot} The '{environment}' environment has been created within the '{workspace}' workspace."
)


def list_environments(workspace: Optional[str] = None) -> pd.DataFrame:
"""
Shows the environments within a workspace.
Parameters
----------
workspace : str, default=None
The Fabric workspace name.
Defaults to None which resolves to the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the workspace of the notebook.
Returns
-------
pandas.DataFrame
A pandas dataframe showing the environments within a workspace.
"""

df = pd.DataFrame(columns=["Environment Name", "Environment Id", "Description"])

(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)

client = fabric.FabricRestClient()
response = client.get(f"/v1/workspaces/{workspace_id}/environments")
if response.status_code != 200:
raise FabricHTTPException(response)

responses = pagination(client, response)

for r in responses:
for v in r.get("value", []):
new_data = {
"Environment Name": v.get("displayName"),
"Environment Id": v.get("id"),
"Description": v.get("description"),
}
df = pd.concat([df, pd.DataFrame(new_data, index=[0])], ignore_index=True)

return df


def delete_environment(environment: str, workspace: Optional[str] = None):
"""
Deletes a Fabric environment.
Parameters
----------
environment: str
Name of the environment.
workspace : str, default=None
The Fabric workspace name.
Defaults to None which resolves to the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the workspace of the notebook.
"""

from sempy_labs._helper_functions import resolve_environment_id

(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
environment_id = resolve_environment_id(
environment=environment, workspace=workspace
)

client = fabric.FabricRestClient()
response = client.delete(
f"/v1/workspaces/{workspace_id}/environments/{environment_id}"
)

if response.status_code != 200:
raise FabricHTTPException(response)

print(
f"{icons.green_dot} The '{environment}' environment within the '{workspace}' workspace has been deleted."
)


def publish_environment(environment: str, workspace: Optional[str] = None):
"""
Publishes a Fabric environment.
Parameters
----------
environment: str
Name of the environment.
workspace : str, default=None
The Fabric workspace name.
Defaults to None which resolves to the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the workspace of the notebook.
"""

# https://learn.microsoft.com/en-us/rest/api/fabric/environment/spark-libraries/publish-environment?tabs=HTTP

from sempy_labs._helper_functions import resolve_environment_id

(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)
environment_id = resolve_environment_id(
environment=environment, workspace=workspace
)

client = fabric.FabricRestClient()
response = client.post(
f"/v1/workspaces/{workspace_id}/environments/{environment_id}/staging/publish"
)

lro(client, response)

print(
f"{icons.green_dot} The '{environment}' environment within the '{workspace}' workspace has been published."
)
59 changes: 59 additions & 0 deletions src/sempy_labs/_helper_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,37 @@ def resolve_capacity_name(capacity_id: Optional[UUID] = None) -> str:
return dfC_filt["Display Name"].iloc[0]


def resolve_capacity_id(capacity_name: Optional[str] = None) -> UUID:
"""
Obtains the capacity Id for a given capacity name.
Parameters
----------
capacity_name : str, default=None
The capacity name.
Defaults to None which resolves to the capacity id of the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the capacity name of the workspace of the notebook.
Returns
-------
UUID
The capacity Id.
"""

if capacity_name is None:
return get_capacity_id()

dfC = fabric.list_capacities()
dfC_filt = dfC[dfC["Display Name"] == capacity_name]

if len(dfC_filt) == 0:
raise ValueError(
f"{icons.red_dot} The '{capacity_name}' capacity does not exist."
)

return dfC_filt["Id"].iloc[0]


def retry(sleep_time: int, timeout_error_message: str):
def decorator(func):
@wraps(func)
Expand Down Expand Up @@ -959,3 +990,31 @@ def get_language_codes(languages: str | List[str]):
break

return languages


def resolve_environment_id(environment: str, workspace: Optional[str] = None) -> UUID:
"""
Obtains the environment Id for a given environment.
Parameters
----------
environment: str
Name of the environment.
workspace : str, default=None
The Fabric workspace name.
Defaults to None which resolves to the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the workspace of the notebook.
"""

from sempy_labs._environments import list_environments

(workspace, workspace_id) = resolve_workspace_name_and_id(workspace)

dfE = list_environments(workspace=workspace)
dfE_filt = dfE[dfE["Environment Name"] == environment]
if len(dfE_filt) == 0:
raise ValueError(
f"{icons.red_dot} The '{environment}' environment does not exist within the '{workspace}' workspace."
)

return dfE_filt["Environment Id"].iloc[0]
2 changes: 2 additions & 0 deletions src/sempy_labs/_icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,5 @@
"ca-ES": "Catalan",
"fi-FI": "Finnish",
}
workspace_roles = ["Admin", "Member", "Viewer", "Contributor"]
principal_types = ["App", "Group", "None", "User"]
Loading

0 comments on commit ea3c838

Please sign in to comment.