Skip to content

Add fix_upgrade_to_pbir: upgrade PBIRLegacy reports to PBIR format#1147

Open
KornAlexander wants to merge 1 commit intomicrosoft:mainfrom
KornAlexander:feature/fix-upgrade-to-pbir
Open

Add fix_upgrade_to_pbir: upgrade PBIRLegacy reports to PBIR format#1147
KornAlexander wants to merge 1 commit intomicrosoft:mainfrom
KornAlexander:feature/fix-upgrade-to-pbir

Conversation

@KornAlexander
Copy link
Copy Markdown

Fix Upgrade to PBIR

Upgrades a report from PBIRLegacy format to PBIR format. PBIR is the newer, file-based report definition format required by all other report fixers in this contribution. This function performs a REST-based round-trip conversion.

Functions Added

Function Description
fix_upgrade_to_pbir(report, page_name=None, workspace=None, scan_only=False) Upgrades a report from PBIRLegacy format to PBIR format.

Files

  • src/sempy_labs/report/_Fix_UpgradeToPbir.py (new file)
  • src/sempy_labs/report/__init__.py (updated exports)

Usage

import sempy_labs as labs

# Check if a report needs upgrading
labs.report.fix_upgrade_to_pbir("My Report", scan_only=True)

# Upgrade to PBIR format
labs.report.fix_upgrade_to_pbir("My Report")

Notes

  • This is a prerequisite for all other report fixers — they require PBIR format.
  • The upgrade is performed via a REST API round-trip (download → re-upload in new format).

PBI Fixer Contribution — Overview

This PR is part of the PBI Fixer contribution to semantic-link-labs — an interactive ipywidgets-based UI for scanning and fixing Power BI reports and semantic models directly in Microsoft Fabric Notebooks.

The PBI Fixer provides a tabbed ipywidgets interface (Semantic Model Explorer, Report Explorer, Perspective Editor, Vertipaq Analyzer) that lets users interactively scan, inspect, and fix Power BI artifacts without leaving the notebook. All underlying fixer functions also work as standalone API calls, so users can integrate them into scripts and pipelines without the UI.

Contribution Structure

The full contribution (~17K lines across 68 files) is split into 22 focused PRs across 6 phases to keep each PR reviewable and self-contained. Only new files are added in Phases 1–4 and 6 — no existing SLL code is modified.

Phase Focus PRs Description
1 Report Fixers 7 Standalone functions that programmatically fix common Power BI report issues: replace pie charts with bar charts, standardize page sizes to Full HD, apply chart formatting best practices, migrate slicers to slicerbars, hide visual-level filters, clean up unused custom visuals, align visuals, migrate report-level measures, and upgrade reports to PBIR format. Each function operates on PBIR-format report definitions.
2 Semantic Model Fixers 4 Functions that fix and enhance semantic models via XMLA/TOM: add calculated calendar and measure tables, add calculation groups for units and time intelligence, discourage implicit measures, and 19 BPA auto-fixers covering formatting conventions, naming standards, data types, column visibility, sort order, and DAX patterns (e.g., use DIVIDE instead of /).
3 SM Setup & Analysis 3 Setup utilities: configure cache warming queries, set up incremental refresh policies, and prepare semantic models for AI/Copilot integration (descriptions, metadata enrichment).
4 Report Utilities 3 Report-level utilities: auto-generate report page prototypes from a semantic model's structure, extract and apply report themes, and generate IBCS-compliant variance charts.
5 Upstream Enhancements 3 ⚠️ These PRs modify existing SLL code (unlike Phases 1–4 which only add new files). Changes include TOM model .Find() fixes and expression capture (tom/_model.py), Vertipaq analyzer enhancements with memory/column-level analysis (_vertipaq.py, ~1000 lines changed), and various small fixes across _items.py, _item_recovery.py, _helper_functions.py, _export_report.py, _sql.py, and admin/_tenant.py. These carry higher merge conflict risk and may need closer review or discussion.
6 PBI Fixer UI 2 The interactive UI layer: shared UI components (theme, icons, tree builders, layout helpers), BPA scan runners, report helpers, and the main PBI Fixer application with its tabbed interface (SM Explorer, Report Explorer, Perspective Editor, Vertipaq Analyzer). Depends on Phases 1–5 but uses lazy imports to degrade gracefully if individual fixers aren't yet merged.

Dependencies & Review Order

  • Phases 1–4 are fully independent — they only add new files and can be reviewed/merged in any order.
  • Phase 5 is also independent but modifies existing code, so it may benefit from early discussion.
  • Phase 6 (the UI) ties everything together. It depends on the earlier phases but works standalone via lazy imports.
  • All fixer functions work without the UI — they can be called directly as sempy_labs.report.fix_piecharts(...) or sempy_labs.semantic_model.add_calculated_calendar(...).

Copilot AI review requested due to automatic review settings April 9, 2026 16:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new report “fixer” that upgrades PBIRLegacy reports to PBIR by performing a Fabric Items REST API round-trip (getDefinition → updateDefinition), with optional scan-only behavior.

Changes:

  • Added fix_upgrade_to_pbir(report, page_name=None, workspace=None, scan_only=False) to upgrade PBIRLegacy → PBIR via REST.
  • Added polling helper logic to verify the report format switches to PBIR after updateDefinition.
  • Added scan-only path with an optional visual-count warning.

Reviewed changes

Copilot reviewed 1 out of 1 changed files in this pull request and generated 5 comments.

File Description
src/sempy_labs/report/_Fix_UpgradeToPbir.py Implements REST-based upgrade flow + polling verification for PBIR conversion.
src/sempy_labs/report/__init__.py Intended to expose the new fixer via the public labs.report namespace (currently missing export based on reviewed state).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +3
# Upgrade Report to PBIR Format
# Converts PBIRLegacy reports to PBIR format using the Fabric REST API
# (getDefinition → updateDefinition round-trip).
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module filename _Fix_UpgradeToPbir.py uses mixed/camel casing, while the rest of src/sempy_labs/report modules are consistently lowercase snake_case (e.g., _upgrade_to_pbir.py, _download_report.py). On case-sensitive filesystems this increases the risk of import mistakes and is inconsistent with the package’s conventions; consider renaming the file to a lowercase snake_case name (and updating any imports/exports accordingly).

Copilot uses AI. Check for mistakes.
Comment on lines +97 to +116
In scan mode the function only reports the current format.

Parameters
----------
report : str | uuid.UUID
Name or ID of the report.
page_name : str, default=None
Unused — accepted for interface consistency with other report fixers.
workspace : str | uuid.UUID, default=None
The Fabric workspace name or ID.
Defaults to None which resolves to the workspace of the attached lakehouse
or if no lakehouse attached, resolves to the workspace of the notebook.
scan_only : bool, default=False
If True, only reports the current format without upgrading.

Returns
-------
bool
True if the report is (or was upgraded to) PBIR format, False otherwise.
"""
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scan_only=True returns True for PBIRLegacy reports ("eligible for upgrade"), but the docstring’s Returns section says the boolean indicates whether the report is (or was upgraded to) PBIR.
This makes the return value ambiguous for callers; either adjust the return semantics (e.g., return False when PBIRLegacy in scan mode) or update the docstring to clearly state that True means "already PBIR or eligible" when scan_only is enabled.

Copilot uses AI. Check for mistakes.
Comment on lines +82 to +88
@log
def fix_upgrade_to_pbir(
report: str | UUID,
page_name: Optional[str] = None,
workspace: Optional[str | UUID] = None,
scan_only: bool = False,
) -> bool:
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description shows usage as labs.report.fix_upgrade_to_pbir(...), but this function is not imported/exported from sempy_labs.report.__init__ (currently only upgrade_to_pbir is exported). Without adding an import and updating __all__, users won’t be able to access it via the public labs.report namespace as documented.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +55
while time.time() - start_time < _POLL_TIME_LIMIT:
poll_count += 1
elapsed = int(time.time() - start_time)
print(
f"{icons.in_progress} Poll #{poll_count} — "
f"{elapsed}s / {_POLL_TIME_LIMIT}s elapsed..."
)

response = _base_api(request=url, client="fabric_sp")

for rpt in response.json().get("value", []):
if rpt.get("id") == report_id:
if rpt.get("format") == "PBIR":
verified_name = rpt.get("name")
break

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_check_upgrade_status polls the list reports endpoint and scans the full collection each time. There is an existing pattern in this repo to poll the single-report endpoint (GET /v1.0/myorg/groups/{workspaceId}/reports/{reportId} in _upgrade_to_pbir.check_upgrade_status), which avoids repeatedly transferring/iterating the entire reports list and reduces latency/load. Consider switching the polling to the single-report endpoint.

Copilot uses AI. Check for mistakes.
# Constants
# ---------------------------------------------------------------------------
_POLL_TIME_LIMIT = 60 # seconds to poll for server-side format conversion
_TIME_BETWEEN_REQUESTS = 3 # seconds between status checks
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The visual-count threshold 100 is a magic number and is duplicated in both scan and fix paths. Consider extracting it into a named constant (e.g., _VISUAL_LIMIT = 100) near the other module constants so the behavior is easier to discover/change and stays consistent.

Suggested change
_TIME_BETWEEN_REQUESTS = 3 # seconds between status checks
_TIME_BETWEEN_REQUESTS = 3 # seconds between status checks
_VISUAL_LIMIT = 100 # maximum number of visuals allowed before scan/fix gating

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants