Forum Discussion
Checking if semantic model is composite
- 9 months ago
kinsin5 As far as I know, there isn’t a first-class “IsComposite” flag in SemPy right now; you infer it from things like partition storage modes and data source types.
Below is a pattern that might work in Fabric notebooks.
1. Basic semantic model metadata with SemPy
From a Fabric notebook:
%pip install semantic-link -q %load_ext sempy import sempy.fabric as fabricTypical metadata calls for a single semantic model:
dataset = "My Semantic Model" workspace = "My Workspace" # or workspace ID # Tables / columns / measures tables = fabric.list_tables(dataset=dataset, workspace=workspace) columns = fabric.list_columns(dataset=dataset, workspace=workspace) measures = fabric.list_measures(dataset=dataset, workspace=workspace) # Relationships relationships = fabric.list_relationships(dataset=dataset, workspace=workspace) # Partitions (this is where storage mode lives) partitions = fabric.list_partitions(dataset=dataset, workspace=workspace, extended=True) # Data sources (for checking Analysis Services / other PBI models, etc.) datasources = fabric.list_datasources(dataset=dataset, workspace=workspace)These all come back as pandas DataFrames, so you can query them however you like.
2. Listing all composite models across all Fabric workspaces
A semantic model is “composite” if, for example:
It has different storage modes across tables/partitions (Import + DirectQuery, DirectLake + Import, etc.), or
It uses another semantic model / AAS as a data source (via AnalysisServices / PowerBI source types).
SemPy gives you enough to derive that:
fabric.list_workspaces() -> all workspaces you can see
fabric.list_datasets(workspace=...) -> semantic models in a workspace
fabric.list_partitions(...) + fabric.list_datasources(...) -> storage modes & source types per model
So maybe something along these lines:
%load_ext sempy import sempy.fabric as fabric import pandas as pd def classify_composite_for_dataset(workspace_name: str, dataset_name: str) -> dict: # Partitions: storage mode per table parts = fabric.list_partitions( workspace=workspace_name, dataset=dataset_name, extended=True ) if parts is None or parts.empty: modes = set() else: modes = set(parts["Mode"].dropna().unique()) # Data sources: where the data is coming from try: ds_df = fabric.list_datasources( workspace=workspace_name, dataset=dataset_name ) except Exception: ds_df = pd.DataFrame() if ds_df is None or ds_df.empty: source_types = set() else: # Column name is typically "Type" in list_datasources output source_types = set(ds_df["Type"].dropna().unique()) # Heuristics for "composite" has_import = "Import" in modes has_directquery = "DirectQuery" in modes has_directlake = "DirectLake" in modes has_multiple_modes = len(modes) > 1 # Remote semantic models / AAS as datasources uses_remote_semantic = any( t in source_types for t in ["AnalysisServices", "PowerBI"] ) is_composite = ( has_multiple_modes or (has_directquery and (modes - {"DirectQuery"})) # DQ + something else or (has_directlake and (has_import or "Dual" in modes)) or uses_remote_semantic ) return { "Workspace": workspace_name, "Dataset": dataset_name, "Modes": ", ".join(sorted(modes)) if modes else "", "SourceTypes": ", ".join(sorted(source_types)) if source_types else "", "IsComposite": is_composite, } def list_composite_models(include_personal_workspaces: bool = False) -> pd.DataFrame: workspaces = fabric.list_workspaces() # all workspaces you can access # Optional: filter out personal workspaces if the column exists if not include_personal_workspaces and "Type" in workspaces.columns: workspaces = workspaces[workspaces["Type"] != "Personal"] rows = [] for _, ws in workspaces.iterrows(): ws_name = ws["Name"] # could also use ws["Id"]; sempy accepts name or ID in most functions datasets = fabric.list_datasets(workspace=ws_name) if datasets is None or datasets.empty: continue for _, ds in datasets.iterrows(): ds_name = ds["Name"] info = classify_composite_for_dataset(ws_name, ds_name) rows.append(info) return pd.DataFrame(rows) # Run the scan all_models = list_composite_models(include_personal_workspaces=False) # Only composite semantic models composite_models = all_models[all_models["IsComposite"]].copy() display(composite_models)That composite_models DataFrame will give you, per semantic model:
Workspace name
Dataset / semantic model name
All storage modes it uses (from list_partitions)
All data source types (from list_datasources)
A boolean IsComposite based on the rules above
You can then:
Write it to a Lakehouse table and build a governance semantic model on top,
Or slice and dice it directly in the notebook.
Notes:
Permissions: You’ll only see workspaces and semantic models you have rights to. For full-tenant scanning you typically combine this with admin or scanner APIs (often via Semantic Link Labs, not plain SemPy).
Definition of “composite”: If you want to be super strict (e.g., “DQ over PBI dataset + local tables only”), tweak the heuristic in classify_composite_for_dataset.
Performance: On big tenants, you may want to:
Filter list_workspaces() first (e.g., only dedicated capacities, only certain domains), and/or
Parallelize per-workspace scans with multiprocessing in Python.
Hi kinsin5,
I would also take a moment to thank GeraldGEmerick , for actively participating in the community forum and for the solutions you’ve been sharing in the community forum. Your contributions make a real difference.
I wanted to check if you had the opportunity to review the information provided. Please feel free to contact us if you have any further questions.
Regards,
Community Support Team.
Hi kinsin5,
I hope the information provided above assists you in resolving the issue. If you have any additional questions or concerns, please do not hesitate to contact us. We are here to support you and will be happy to help with any further assistance you may need.
Regards,
Community Support Team.