Add fix_upgrade_to_pbir: upgrade PBIRLegacy reports to PBIR format#1147
Add fix_upgrade_to_pbir: upgrade PBIRLegacy reports to PBIR format#1147KornAlexander wants to merge 1 commit intomicrosoft:mainfrom
Conversation
…a REST round-trip
There was a problem hiding this comment.
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.
| # Upgrade Report to PBIR Format | ||
| # Converts PBIRLegacy reports to PBIR format using the Fabric REST API | ||
| # (getDefinition → updateDefinition round-trip). |
There was a problem hiding this comment.
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).
| 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. | ||
| """ |
There was a problem hiding this comment.
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.
| @log | ||
| def fix_upgrade_to_pbir( | ||
| report: str | UUID, | ||
| page_name: Optional[str] = None, | ||
| workspace: Optional[str | UUID] = None, | ||
| scan_only: bool = False, | ||
| ) -> bool: |
There was a problem hiding this comment.
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.
| 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 | ||
|
|
There was a problem hiding this comment.
_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.
| # Constants | ||
| # --------------------------------------------------------------------------- | ||
| _POLL_TIME_LIMIT = 60 # seconds to poll for server-side format conversion | ||
| _TIME_BETWEEN_REQUESTS = 3 # seconds between status checks |
There was a problem hiding this comment.
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.
| _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 |
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
fix_upgrade_to_pbir(report, page_name=None, workspace=None, scan_only=False)Files
src/sempy_labs/report/_Fix_UpgradeToPbir.py(new file)src/sempy_labs/report/__init__.py(updated exports)Usage
Notes
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.
/)..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, andadmin/_tenant.py. These carry higher merge conflict risk and may need closer review or discussion.Dependencies & Review Order
sempy_labs.report.fix_piecharts(...)orsempy_labs.semantic_model.add_calculated_calendar(...).