Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Power BI Parser

A Python library that parses Power BI .pbix files and extracts structured JSON output. Works with file-like objects for maximum flexibility.

Features

  • 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

Installation

From GitHub

# 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]"

Usage

Command Line

# 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.pbix

Python API

Parse from a file

from 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'])}")

Parse from BytesIO (in-memory)

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')

Advanced usage with PbixParser class

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()

Parse without filename (title fallback)

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 title

API Reference

parse(file: BinaryIO, *, filename: str | None = None) -> dict

Convenience 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. Uses Path(filename).stem as fallback.

Returns: Dictionary with report structure (see Output Format below)

PbixParser(file: BinaryIO, *, filename: str | None = None)

Main parser class for more control.

Methods:

  • parse() -> Report: Parse and return a Report model

Report Model:

  • id: int — Report ID
  • title: str — Report title (from embedded metadata or filename fallback)
  • filters: list[Filter] — Report-level filters
  • pages: list[Page] — All pages in the report
  • to_dict() -> dict — Convert to dictionary

Output Format

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": []
        }
      ]
    }
  ]
}

Field Types

  • column — Table column
  • measure — Calculated measure
  • hierarchy — Hierarchical field

Filter Types

  • Advanced — Advanced filter with condition tree
  • Categorical — Category/value filter

Filter Conditions

Operators: Equal, NotEqual, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, In, NotIn, Between

Logical: And, Or, Not

Development

Setup

# 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 Tests

# Run all tests
pytest

# Run with verbose output
pytest -v

# Run specific test file
pytest tests/test_parser.py

Project Structure

src/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

How It Works

  1. ZIP Extraction: .pbix files are ZIP archives containing JSON files
  2. Encoding Detection: Report/Layout is UTF-16 LE encoded (~17MB for large reports)
  3. JSON Parsing: Handles "JSON-in-strings" pattern where filters and config are double-encoded
  4. Field Extraction: Parses projections, prototypeQuery.Select, and columnProperties
  5. Filter Parsing: Builds condition trees from filter expressions
  6. Model Assembly: Constructs typed Python dataclasses for structured output

Known Limitations

  • 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

Contributing

This is a personal project. Feel free to fork and adapt for your needs.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages