Quick Answer
Semantic link (sempy) turns Power BI semantic models into first-class Python objects. In a Fabric notebook you can read tables, run DAX, refresh datasets, and manage metadata with a few lines of code. Combined with sempy-labs for administrative operations, it becomes the primary automation surface for enterprise Power BI governance and data science integration.
1. Installation and Setup
Sempy is pre-installed in every Fabric notebook runtime. Sempy-labs must be installed explicitly.
# In a Fabric notebook cell
%pip install semantic-link-labs
# Import
import sempy.fabric as fabric
import sempy_labs as labs
import pandas as pdRunning outside Fabric requires azure-identity for authentication and an explicit connection string. For this guide, all examples assume a Fabric notebook runtime.
2. Reading Model Tables
# List all datasets in a workspace
datasets = fabric.list_datasets(workspace="Sales Workspace")
print(datasets)
# Read a table from a dataset into a DataFrame
df = fabric.read_table(
dataset="Sales Analytics",
table="Customer",
workspace="Sales Workspace"
)
# Filter, slice, and feature-engineer with pandas
active_customers = df[df['Status'] == 'Active']
print(f"Active customers: {len(active_customers):,}")read_table loads the entire table including all visible columns. For large tables, prefer evaluate_dax with SUMMARIZECOLUMNS to aggregate server-side before transferring results.
3. Executing DAX Queries
dax = '''
EVALUATE
SUMMARIZECOLUMNS(
'Calendar'[Year],
'Region'[Region Name],
"Total Revenue", [Total Revenue],
"Total Customers", [Distinct Customers]
)
ORDER BY 'Calendar'[Year], 'Region'[Region Name]
'''
result = fabric.evaluate_dax(
dataset="Sales Analytics",
dax_string=dax,
workspace="Sales Workspace"
)
# result is a pandas DataFrame
result.plot(x='Calendar[Year]', y='[Total Revenue]', kind='bar')evaluate_dax accepts any valid DAX query statement. Use it for aggregated reads, ad-hoc exploration, and to reuse existing measures as the analytic backbone of Python pipelines.
4. Data Quality Testing Pattern
A production-grade semantic model should have automated data quality tests that run after every refresh. Below is a minimal test suite using semantic link and pytest-style assertions.
import sempy.fabric as fabric
def assert_equal(actual, expected, test_name):
if actual != expected:
raise AssertionError(f"{test_name}: expected {expected}, got {actual}")
print(f"PASS: {test_name}")
# Test 1: total revenue matches source system
dax = 'EVALUATE ROW("Revenue", [Total Revenue])'
r = fabric.evaluate_dax("Sales Analytics", dax)
assert_equal(
int(r.iloc[0, 0]),
43215000,
"Total Revenue 2025"
)
# Test 2: no orphaned fact rows
dax_orphans = '''
EVALUATE
ROW(
"Orphans",
COUNTROWS(
FILTER('Sales', ISBLANK(RELATED('Customer'[Customer Key])))
)
)
'''
r = fabric.evaluate_dax("Sales Analytics", dax_orphans)
assert_equal(int(r.iloc[0, 0]), 0, "No orphan sales rows")
# Test 3: RLS returns expected row count for Northeast manager
import sempy_labs as labs
r = labs.evaluate_dax_impersonated(
dataset="Sales Analytics",
dax_string="EVALUATE ROW(\"Customers\", [Distinct Customers])",
user_name="[email protected]"
)
assert_equal(int(r.iloc[0, 0]), 1247, "Northeast manager RLS customer count")
print("All tests passed.")Schedule this notebook to run after every refresh. Integrate with Teams or Outlook notifications to alert when a test fails. This pattern catches data corruption, ETL bugs, and RLS regressions within minutes of deployment.
5. ML Integration: Forecasting Example
A typical closed-loop ML pattern pulls historical data from a semantic model, trains a model, writes predictions to OneLake, and the semantic model picks up the predictions through Direct Lake or a refresh.
import sempy.fabric as fabric
from sklearn.linear_model import LinearRegression
import pandas as pd
# Read historical monthly revenue
dax = '''
EVALUATE
SUMMARIZECOLUMNS(
'Calendar'[Year Month],
"Revenue", [Total Revenue]
)
ORDER BY 'Calendar'[Year Month] ASC
'''
history = fabric.evaluate_dax("Sales Analytics", dax)
history.columns = ['YearMonth', 'Revenue']
history['Period'] = range(len(history))
# Train
model = LinearRegression()
model.fit(history[['Period']], history['Revenue'])
# Forecast next 12 months
future = pd.DataFrame({
'Period': range(len(history), len(history) + 12)
})
future['ForecastRevenue'] = model.predict(future[['Period']])
# Write predictions to Fabric Lakehouse
(spark.createDataFrame(future)
.write.format("delta").mode("overwrite")
.saveAsTable("Lakehouse.RevenueForecast"))
# Refresh the semantic model to pick up the new forecast table
fabric.refresh_dataset(
dataset="Sales Analytics",
workspace="Sales Workspace"
)For production systems, replace LinearRegression with Prophet, ARIMA, or a deep learning model appropriate to your data. The pattern is identical: read from semantic model, train, write predictions to a Lakehouse, refresh the model.
6. Administrative Operations with SemPy-Labs
Sempy-labs exposes hundreds of administrative operations. A few high-value examples:
import sempy_labs as labs
# Run Best Practice Analyzer on all datasets in a workspace
bpa_results = labs.run_model_bpa(workspace="Sales Workspace")
print(bpa_results[bpa_results['Severity'] >= 2]) # Major and Critical
# List all measures and their descriptions
measures = labs.list_measures(dataset="Sales Analytics")
undocumented = measures[measures['Description'].isna()]
print(f"{len(undocumented)} undocumented measures")
# Audit RLS role definitions
roles = labs.list_roles(dataset="Sales Analytics")
for _, role in roles.iterrows():
print(f"{role['Name']}: {role['DAX Expression']}")
# Export entire model as TMDL to source control
labs.export_model_to_tmdl(
dataset="Sales Analytics",
workspace="Sales Workspace",
path="/lakehouse/default/Files/models/sales-analytics"
)These operations enable fleet-scale governance. A single notebook can audit every semantic model in a tenant and produce a compliance report in minutes, where the manual equivalent would take days.
7. Common Enterprise Patterns
Pattern A: Nightly regression tests
Schedule a notebook to run after refresh that validates row counts, totals, and RLS behavior. Failures trigger Teams alerts and block deployment pipelines.
Pattern B: Documentation generation
A notebook pulls every measure, description, table, and column definition, then generates a Markdown doc committed to a wiki. Run on every deployment so documentation never drifts from the live model.
Pattern C: Predictive KPIs
Notebooks train ML models on historical data and write predictions back to the Lakehouse. The semantic model consumes predictions through Direct Lake and exposes them as measures alongside actuals.
Pattern D: Tenant-wide audit
A governance-team notebook iterates all workspaces, lists all datasets, runs BPA, and compiles a monthly health report. This is the only practical way to govern large Fabric tenants with hundreds or thousands of semantic models.
Frequently Asked Questions
What is semantic link in Microsoft Fabric?
Semantic link is a Python library (package name sempy) available in Microsoft Fabric notebooks that allows programmatic interaction with Power BI semantic models. It wraps the XMLA endpoint and exposes familiar pandas-style interfaces. With semantic link you can list models in a workspace, read tables as pandas DataFrames, execute DAX queries, refresh datasets, list measures, and inspect model metadata. It is the foundation for integrating Power BI with machine learning, data quality testing, and custom automation workflows.
What is the difference between sempy and sempy-labs?
Sempy is the official Microsoft package shipped with every Fabric runtime, providing the core read-path API for semantic models. Sempy-labs is a community package maintained by a Microsoft PM that adds administrative capabilities: list roles, deploy datasets, manage capacity, run Best Practice Analyzer programmatically, and orchestrate deployment-pipeline style operations. Most production notebooks use both together. Install sempy-labs with pip install semantic-link-labs.
Can I write data back to a Power BI model from a notebook?
Semantic link is read-primarily: it reads semantic model data into DataFrames and can trigger refreshes, but it does not directly modify model definitions. For write-path operations such as editing DAX measures, adding tables, or modifying RLS, use sempy-labs combined with the Fabric REST API. A common pattern is to generate TMDL definitions in a notebook, write them to the PBIP folder in Fabric Git, commit, and trigger a sync to the workspace.
How does semantic link authenticate?
When running inside a Fabric notebook, semantic link authenticates as the user who executed the notebook, using the delegated identity provided by the Fabric runtime. No credentials are stored in the notebook. For scheduled notebook runs, Fabric executes under a service principal that you can assign to workspace roles. Running semantic link outside Fabric (for example, in Visual Studio Code) requires manual authentication through az login or interactive Microsoft Entra flow.
Can I use semantic link for data quality testing?
Yes. A common pattern is to use fabric.evaluate_dax to run assertions against a semantic model: expected total revenue, expected distinct customer count, expected row count per RLS role. Combine with pytest or Great Expectations in a notebook to run a suite of data quality checks on every refresh. Any failing assertion raises an alert. This replaces the manual "someone checks the dashboard each morning" pattern with automated validation.
Does semantic link support machine learning workflows?
Yes. Read semantic model data into DataFrames using fabric.read_table or fabric.evaluate_measure, then feed into scikit-learn, PyTorch, or MLflow pipelines. A typical ML workflow reads transactional data, trains a forecasting model, writes predictions back to a Fabric Lakehouse table, and the semantic model consumes the predictions via Direct Lake. This closes the loop between production BI and data science.
What performance considerations apply to semantic link notebooks?
Every DAX query through semantic link executes against the Fabric XMLA endpoint and consumes CU in the workspace capacity. Large result sets can bottleneck on network transfer between the analysis services engine and the notebook kernel. Best practices: use SUMMARIZECOLUMNS to aggregate inside DAX rather than pulling raw fact rows, limit columns returned to only what the notebook needs, and batch multiple queries rather than iterating row-by-row.
Can semantic link replace Power Automate for Power BI automation?
For complex logic yes, for simple workflows probably not. Power Automate is better for event-driven automation that needs connectors to Outlook, Teams, or approval flows. Semantic link is better for analytical automation: running validation suites, orchestrating ML pipelines, generating documentation, and executing bulk administrative operations across many workspaces. A mature Fabric deployment usually uses Power Automate for user-facing workflows and semantic link notebooks for data-engineering-style automation.
Building a Semantic Link Automation Practice?
Our consultants design notebook-based automation for data quality, governance, and ML closed-loop. Contact us for an automation assessment.