A Python library that parses Power BI .pbix files and extracts structured JSON output. Works with file-like objects for maximum flexibility.
- Zero dependencies — stdlib only (Python >=3.10)
- Memory-based — accepts file-like objects (BinaryIO) for use with files, BytesIO, or network streams
- Complete extraction — reports, pages, visuals, fields, and filters
- Filter parsing — handles complex condition trees (AND, OR, NOT, comparisons, etc.)
- Field metadata — includes display names, entity/property, roles, and field types
# Install directly from GitHub
pip install git+https://github.com/kulltc/powerbi-parser.git
# Or clone and install in editable mode for development
git clone https://github.com/kulltc/powerbi-parser.git
cd powerbi-parser
pip install -e ".[dev]"# Parse a .pbix file and output JSON
python -m powerbi_parser report.pbix
# Save output to a file
python -m powerbi_parser report.pbix > output.json
# Or use the installed script
powerbi-parser report.pbixfrom powerbi_parser import parse
# Simple usage
with open('report.pbix', 'rb') as f:
result = parse(f, filename='report.pbix')
print(f"Report: {result['title']}")
print(f"Pages: {len(result['pages'])}")from io import BytesIO
from powerbi_parser import parse
# Example: download from URL and parse in memory
import urllib.request
url = 'https://example.com/report.pbix'
with urllib.request.urlopen(url) as response:
data = response.read()
bio = BytesIO(data)
result = parse(bio, filename='report.pbix')from powerbi_parser import PbixParser
with open('report.pbix', 'rb') as f:
parser = PbixParser(f, filename='report.pbix')
report = parser.parse() # Returns a Report model
# Access structured data
for page in report.pages:
print(f"Page: {page.displayName}")
for visual in page.visuals:
print(f" Visual: {visual.title} ({visual.visualType})")
for field in visual.fields:
print(f" Field: {field.displayName} [{field.role}]")
# Convert to dict for JSON output
result = report.to_dict()from powerbi_parser import parse
# When filename is omitted, report title uses empty string as fallback
# (if the .pbix doesn't have an embedded title)
with open('report.pbix', 'rb') as f:
result = parse(f) # No filename parameter
print(result['title']) # Empty string if no embedded titleConvenience function to parse a .pbix file and return a dict.
Parameters:
file: File-like object opened in binary mode ('rb')filename(optional): Original filename for title fallback when report has no embedded title. UsesPath(filename).stemas fallback.
Returns: Dictionary with report structure (see Output Format below)
Main parser class for more control.
Methods:
parse() -> Report: Parse and return a Report model
Report Model:
id: int— Report IDtitle: str— Report title (from embedded metadata or filename fallback)filters: list[Filter]— Report-level filterspages: list[Page]— All pages in the reportto_dict() -> dict— Convert to dictionary
The parser returns a structured dictionary:
{
"id": 0,
"title": "Operations Dashboard",
"filters": [
{
"name": "filter_id",
"entity": "Date",
"property": "Year",
"fieldType": "column",
"filterType": "Advanced",
"condition": {
"operator": "GreaterThanOrEqual",
"value": "2023"
}
}
],
"pages": [
{
"name": "page_id",
"displayName": "Overview",
"ordinal": 0,
"width": 1920,
"height": 1080,
"filters": [],
"visuals": [
{
"name": "visual_id",
"title": "Sales by Region",
"visualType": "barChart",
"x": 0,
"y": 0,
"width": 400,
"height": 300,
"fields": [
{
"entity": "Sales",
"property": "Amount",
"displayName": "Total Sales",
"fieldType": "measure",
"role": "Values",
"queryRef": "Sales.Amount"
}
],
"filters": []
}
]
}
]
}column— Table columnmeasure— Calculated measurehierarchy— Hierarchical field
Advanced— Advanced filter with condition treeCategorical— Category/value filter
Operators: Equal, NotEqual, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, In, NotIn, Between
Logical: And, Or, Not
# Clone the repository
git clone https://github.com/kulltc/powerbi-parser.git
cd powerbi-parser
# Install in editable mode with dev dependencies
pip install -e ".[dev]"# Run all tests
pytest
# Run with verbose output
pytest -v
# Run specific test file
pytest tests/test_parser.pysrc/powerbi_parser/
├── __init__.py # Public API: parse(), PbixParser
├── __main__.py # CLI entry point
├── parser.py # Main parser orchestration
├── encoding.py # UTF-16 LE / UTF-8 detection
├── models.py # Data models (Report, Page, Visual, etc.)
├── fields.py # Field extraction logic
└── filters.py # Filter expression parsing
tests/
├── conftest.py # Shared fixtures
├── test_parser.py # End-to-end tests
├── test_encoding.py # Encoding tests
├── test_fields.py # Field extraction tests
├── test_filters.py # Filter parsing tests
└── test_models.py # Model serialization tests
- ZIP Extraction:
.pbixfiles are ZIP archives containing JSON files - Encoding Detection:
Report/Layoutis UTF-16 LE encoded (~17MB for large reports) - JSON Parsing: Handles "JSON-in-strings" pattern where
filtersandconfigare double-encoded - Field Extraction: Parses
projections,prototypeQuery.Select, andcolumnProperties - Filter Parsing: Builds condition trees from filter expressions
- Model Assembly: Constructs typed Python dataclasses for structured output
- Non-data visuals are filtered out (
actionButton,shape,textbox,image) - Visual groups (
singleVisualGroup) are skipped as they contain no data - Only extracts metadata; does not evaluate DAX expressions or access data models
This is a personal project. Feel free to fork and adapt for your needs.
MIT