Universal lineage graph for Power BI (.pbix) files, from physical source to report display.
Project description
pbix-lineage
Universal lineage graph for Power BI (.pbix) files: from physical source to the field displayed in a report visual.
source (HTTP, OData, SQL, file...) --> Power Query (M)
--> column / calculated column --> measure (DAX)
--> field displayed in a report visual
The graph is a standard networkx.DiGraph, natively bidirectional: trace a visual back to its source (upstream), or list everything a source feeds (downstream).
Why
pbixray (used here) extracts the data model (tables, DAX, Power Query, schema) but says nothing about where each column or measure ends up displayed — that lives in a separate, undocumented part of the file (Report/Layout). pbix-lineage connects both into one traversable graph.
Install
pip install pbix-lineage
# or
uv add pbix-lineage
Usage
from pbix_lineage import LineageGraphBuilder, upstream, downstream, print_tree, find_nodes
graph = LineageGraphBuilder().build("my_report.pbix")
find_nodes(graph, "customer_name")
# -> ['column::DIM_CUSTOMER::customer_name']
print_tree(graph, "visual_field::my_report.pbix::Page1::16::customer_name", direction="upstream")
print_tree(graph, "source::odata::example.com/odata/", direction="downstream")
Export
from pbix_lineage import export_graphml, export_nodes_csv, export_edges_csv, graph_summary
graph_summary(graph) # {'query': 70, 'column': 183, ...}
export_graphml(graph, "lineage.graphml") # opens in Gephi / yEd
export_nodes_csv(graph, "nodes.csv")
export_edges_csv(graph, "edges.csv")
Source-agnostic
Source detection (pbix_lineage.sources) relies only on native M function names (Web.Contents, OData.Feed, Sql.Database, Folder.Files, SharePoint.Files, Excel.Workbook, AnalysisServices.Database, ...) — never a specific system or domain. Adding a new source type is one config entry in MFunctionSourceDetector.DEFAULT_PATTERNS, no other code touched.
HTTP API / MCP server
The package also exposes a FastAPI app, mounted as an MCP server via FastMCP (FastMCP.from_fastapi): every route becomes an MCP tool automatically.
uv sync --extra api
uv run pbix-lineage # starts on http://127.0.0.1:8080
- REST API:
POST /graphs,/search,/upstream,/downstream,/tree,/export,GET /graphs. - MCP server (streamable HTTP) at
http://127.0.0.1:8080/mcp/: same operations as tools (build_graph,search_nodes,get_upstream,get_downstream,get_lineage_tree,export_graph,list_loaded_graphs), plus alineage_guidanceprompt. - Env vars:
PBIX_LINEAGE_HOST(default0.0.0.0),PBIX_LINEAGE_PORT(default8080).
Each .pbix is parsed once and cached in memory (LineageGraphCache, framework-agnostic).
Publish to the MCP registry
server.json describes this server for registry.modelcontextprotocol.io. After replacing votre-org with your GitHub account everywhere:
uv build && uv publish # publish the package to PyPI first
mcp-publisher login github
mcp-publisher publish --dry-run
mcp-publisher publish
The registry verifies PyPI ownership via the <!-- mcp-name: ... --> marker at the top of this README. The name in server.json, this marker, and your authenticated GitHub namespace must all match.
Architecture
| Module | Responsibility |
|---|---|
models.py |
Node/edge types and shared data structures |
sources.py |
Physical source detection (agnostic, configurable) |
pbix_model.py |
Adapter isolating the rest of the code frompbixray |
dax.py |
DAX reference parsing (Table[Field] / [Field]) |
mquery.py |
Dependencies between Power Query queries (table-level) |
layout.py |
Parsing of the internalReport/Layout format |
graph_builder.py |
Orchestrator: builds thenetworkx.DiGraph |
navigation.py |
Upstream/downstream traversal, search, export |
api/schemas.py |
Pydantic request/response models |
api/service.py |
Graph cache, framework-agnostic |
api/app.py |
FastAPI app + MCP mount (FastMCP) |
Known limitations
- M query dependencies are resolved at table level, not step-by-step inside a single
let ... inquery. - A source reached only through a literal M parameter may be tagged with a generic system (
http) instead of the exact consumer connector (odata, etc.). - Unqualified DAX references (
[MeasureName]) are resolved same-table first, then globally; homonyms across tables resolve to the first match.
Development
uv sync --extra dev
uv run pytest # BDD tests (pytest-bdd) under tests/features/*.feature
uv build # produces dist/*.whl and dist/*.tar.gz
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pbix_lineage-0.1.2.tar.gz.
File metadata
- Download URL: pbix_lineage-0.1.2.tar.gz
- Upload date:
- Size: 16.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1723dd100a475a1e22f1c4ab867cd7c62a10e4f25bdc4986d5302bd97e67be98
|
|
| MD5 |
1393d7ccc4594316c8111a58c4d184cb
|
|
| BLAKE2b-256 |
3faf3a6b24bf422774adaf347e18c6b8bec8668f6e5ba829aab0779da3f041da
|
File details
Details for the file pbix_lineage-0.1.2-py3-none-any.whl.
File metadata
- Download URL: pbix_lineage-0.1.2-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8950b22f1f05ad0b739494e884408ee112e9112b883726902e476aac1af64e89
|
|
| MD5 |
e6aca2f9d6226e857ecb83c9fd230383
|
|
| BLAKE2b-256 |
0e11d34f754f98aae1b178d71a45f3ce71d75f29eab2dd3b12411a9f73cecc5a
|