Skip to main content

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 a lineage_guidance prompt.
  • Env vars: PBIX_LINEAGE_HOST (default 0.0.0.0), PBIX_LINEAGE_PORT (default 8080).

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 ... in query.
  • 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

Metadata

Release files for pbix-lineage 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pbix-lineage 0.1.2
File Size Uploaded Provenance Actions
pbix_lineage-0.1.2.tar.gz 16.2 kB Without provenance Details for pbix_lineage-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pbix-lineage 0.1.2
File Interpreter ABI Platform Actions
pbix_lineage-0.1.2-py3-none-any.whl Python 3 none any Details for pbix_lineage-0.1.2-py3-none-any.whl

Total release size: 34.9 kB

Release files / pbix_lineage-0.1.2.tar.gz

Download URL pbix_lineage-0.1.2.tar.gz
Size 16.2 kB
Tags Source
SHA-256 checksum
How to use checksums
1723dd100a475a1e22f1c4ab867cd7c62a10e4f25bdc4986d5302bd97e67be98
BLAKE2b-256 checksum
How to use checksums
3faf3a6b24bf422774adaf347e18c6b8bec8668f6e5ba829aab0779da3f041da
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / pbix_lineage-0.1.2-py3-none-any.whl

Download URL pbix_lineage-0.1.2-py3-none-any.whl
Size 18.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8950b22f1f05ad0b739494e884408ee112e9112b883726902e476aac1af64e89
BLAKE2b-256 checksum
How to use checksums
0e11d34f754f98aae1b178d71a45f3ce71d75f29eab2dd3b12411a9f73cecc5a
Upload date
Uploaded using Trusted Publishing?
What is 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}

Security for pbix-lineage 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page