2020from sempy .fabric .exceptions import FabricHTTPException
2121import ast
2222from uuid import UUID
23+ from sempy .fabric ._token_provider import TokenProvider
2324
2425if TYPE_CHECKING :
2526 import Microsoft .AnalysisServices .Tabular
@@ -42,21 +43,91 @@ class TOMWrapper:
4243 _table_map = dict
4344 _column_map = dict
4445
45- def __init__ (self , dataset , workspace , readonly ):
46-
47- (workspace_name , workspace_id ) = resolve_workspace_name_and_id (workspace )
48- (dataset_name , dataset_id ) = resolve_dataset_name_and_id (dataset , workspace_id )
49- self ._dataset_id = dataset_id
50- self ._dataset_name = dataset_name
51- self ._workspace_name = workspace_name
52- self ._workspace_id = workspace_id
46+ def __init__ (self , dataset , workspace , readonly , token_provider ):
47+
48+ self ._is_azure_as = False
49+ prefix = "asazure"
50+ prefix_full = f"{ prefix } ://"
51+ read_write = ":rw"
52+
53+ # Azure AS workspace logic
54+ if workspace .startswith (prefix_full ):
55+ # Set read or read/write accordingly
56+ if readonly is False and not workspace .endswith (read_write ):
57+ workspace += read_write
58+ elif readonly is True and workspace .endswith (read_write ):
59+ workspace = workspace [: - len (read_write )]
60+ self ._workspace_name = workspace
61+ self ._workspace_id
62+ self ._dataset_id = dataset
63+ self ._dataset_name = dataset
64+ self ._is_azure_as = True
65+ if token_provider is None :
66+ raise ValueError (
67+ f"{ icons .red_dot } A token provider must be provided when connecting to an Azure AS workspace."
68+ )
69+ else :
70+ (workspace_name , workspace_id ) = resolve_workspace_name_and_id (workspace )
71+ (dataset_name , dataset_id ) = resolve_dataset_name_and_id (
72+ dataset , workspace_id
73+ )
74+ self ._dataset_id = dataset_id
75+ self ._dataset_name = dataset_name
76+ self ._workspace_name = workspace_name
77+ self ._workspace_id = workspace_id
5378 self ._readonly = readonly
5479 self ._tables_added = []
80+ self ._token_provider = token_provider
5581
56- self ._tom_server = fabric .create_tom_server (
57- readonly = readonly , workspace = workspace_id
58- )
59- self .model = self ._tom_server .Databases [dataset_id ].Model
82+ # No token provider (standard authentication)
83+ if self ._token_provider is None :
84+ self ._tom_server = fabric .create_tom_server (
85+ readonly = readonly , workspace = workspace_id
86+ )
87+ # Service Principal Authentication for Azure AS via token provider
88+ elif self ._is_azure_as :
89+ import Microsoft .AnalysisServices .Tabular as TOM
90+
91+ # Extract region from the workspace
92+ match = re .search (rf"{ prefix_full } (.*?).{ prefix } " , self ._workspace_name )
93+ if match :
94+ region = match .group (1 )
95+ if self ._token_provider is None :
96+ raise ValueError (f"{ icons .red_dot } A token provider must be provided when connecting to Azure Analysis Services." )
97+ token = self ._token_provider (audience = "asazure" , region = region )
98+ connection_str = f'Provider=MSOLAP;Data Source={ self ._workspace_name } ;Password="{ token } ";Persist Security Info=True;Impersonation Level=Impersonate'
99+ self ._tom_server = TOM .Server ()
100+ self ._tom_server .Connect (connection_str )
101+ # Service Principal Authentication for Power BI via token provider
102+ else :
103+ from sempy .fabric ._client ._utils import _build_adomd_connection_string
104+ import Microsoft .AnalysisServices .Tabular as TOM
105+ from Microsoft .AnalysisServices import AccessToken
106+ from sempy .fabric ._token_provider import (
107+ create_on_access_token_expired_callback ,
108+ ConstantTokenProvider ,
109+ )
110+ from System import Func
111+
112+ token = token_provider (audience = "pbi" )
113+ self ._tom_server = TOM .Server ()
114+ get_access_token = create_on_access_token_expired_callback (
115+ ConstantTokenProvider (token )
116+ )
117+ self ._tom_server .AccessToken = get_access_token (None )
118+ self ._tom_server .OnAccessTokenExpired = Func [AccessToken , AccessToken ](
119+ get_access_token
120+ )
121+ workspace_url = f"powerbi://api.powerbi.com/v1.0/myorg/{ workspace } "
122+ connection_str = _build_adomd_connection_string (
123+ workspace_url , readonly = readonly
124+ )
125+ self ._tom_server .Connect (connection_str )
126+
127+ if self ._is_azure_as :
128+ self .model = self ._tom_server .Databases .GetByName (self ._dataset_name ).Model
129+ else :
130+ self .model = self ._tom_server .Databases [dataset_id ].Model
60131
61132 self ._table_map = {}
62133 self ._column_map = {}
@@ -4666,7 +4737,10 @@ def close(self):
46664737@log
46674738@contextmanager
46684739def connect_semantic_model (
4669- dataset : str | UUID , readonly : bool = True , workspace : Optional [str ] = None
4740+ dataset : str | UUID ,
4741+ readonly : bool = True ,
4742+ workspace : Optional [str | UUID ] = None ,
4743+ token_provider : Optional [TokenProvider ] = None ,
46704744) -> Iterator [TOMWrapper ]:
46714745 """
46724746 Connects to the Tabular Object Model (TOM) within a semantic model.
@@ -4678,10 +4752,12 @@ def connect_semantic_model(
46784752 readonly: bool, default=True
46794753 Whether the connection is read-only or read/write. Setting this to False enables read/write which saves the changes made back to the server.
46804754 workspace : str | uuid.UUID, default=None
4681- The Fabric workspace name or ID.
4755+ The Fabric workspace name or ID. Also supports Azure Analysis Services (token_provider required).
4756+ If connecting to Azure Analysis Services, enter the workspace parameter in the following format: 'asazure://<region>.asazure.windows.net/<server_name>'.
46824757 Defaults to None which resolves to the workspace of the attached lakehouse
46834758 or if no lakehouse attached, resolves to the workspace of the notebook.
4684-
4759+ token_provider : TokenProvider, default=None
4760+ The token provider for authentication, created by using the ServicePrincipalTokenProvider class. Required when connecting to Azure Analysis Services.
46854761 Returns
46864762 -------
46874763 typing.Iterator[TOMWrapper]
@@ -4691,7 +4767,12 @@ def connect_semantic_model(
46914767 # initialize .NET to make sure System and Microsoft.AnalysisServices.Tabular is defined
46924768 sempy .fabric ._client ._utils ._init_analysis_services ()
46934769
4694- tw = TOMWrapper (dataset = dataset , workspace = workspace , readonly = readonly )
4770+ tw = TOMWrapper (
4771+ dataset = dataset ,
4772+ workspace = workspace ,
4773+ readonly = readonly ,
4774+ token_provider = token_provider ,
4775+ )
46954776 try :
46964777 yield tw
46974778 finally :
0 commit comments