Skip to content

Examples

JChamboredon edited this page Sep 29, 2023 · 13 revisions

Interaction with Power BI service

Through the python-pbi package, you can interact with the Power BI service to download and upload reports, etc. This will require the Power BI Powershell.

Configuration

Add all the required configuration to create the Pbi object like so:

config = {
    'DOWNLOAD_FOLDER': './downloads/',
    'UPLOAD_FOLDER': './upload/'
}

Download a report

You can download a report from the Power BI service (providing you have installed the Power BI Powershell) like so:

from pbi.pbi import PowerBI
from tests.config import config

test_pbi = PowerBI(config)

report = test_pbi.download(
    'test_report',
    test_pbi.download_folder,
    workspace_id=<your_powerbi_workspace_id>
)

NB: Power BI service will ask you to authenticate and download all reports containing the string 'test_report'.

Upload a report

You can upload a report to the Power BI service (providing you have installed the Power BI Powershell) like so:

from pbi.pbi import PowerBI
from tests.config import config

test_pbi = PowerBI(config)

test_pbi.upload(
    test_pbi.upload_folder,
    workspace_id=<your_workspace_id>
)

NB: Power BI service will ask you to authenticate and upload all reports contained in the given folder to the Power BI workspace.

Handling the report in Python

The python-pbi package enables to create Python PbiReport objects to manipulate them.

Opening a report

Assume you have a Power BI report named test_report.pbix in the folder test_folder. You can bring this file to memory as a Python PbiReport object using the commands below:

from pbi.report import PbiReport

report = PbiReport(
    'test_folder',
    'test_report'
)

NB: At this stage, the Power BI report is accessible in memory. Please check the PbiReport section for a more detailed description.

Saving a report

Assume you have a PbiReport object in memory named report. After manipulating it, you can easily save it via the command below:

report.save()

NB: The save method also allows to change the dataset connection if needed.

Copying a report

You can easily copy a Power BI report to a new location by using the copy method. Note you will have to save the report to actually create the Power BI file in the desired location.

from pbi.report import PbiReport

report = PbiReport(
    'test_folder',
    'test_report'
)
new_report = report.copy(
    new_name='updated_test_report',
    new_folder='updated_report_name'
)
new_report.save()

Maintenance

Some Power BI implementation might make the report structure more complex than needed. Here are a couple of ways to simplify the reports automatically.

Tidying page IDs

As shown in the layout object, the pages of a report are stored as a list, along with some numbering (ordinal). You can reset the numbering using the following method:

report._update_section_id()

Tidying bookmarks

Bookmarks can also become a mess to maintain. Imagine you originally create quite a few bookmarks but eventually, as your report evolves, delete the associated visuals. It is not likely that you will remember which bookmarks used which visual, and eventually empty bookmarks will remain. The method below helps tidying empty bookmarks (using no visuals at all):

report.tidy_bookmarks()

Selecting pages

Assume your report has several pages, named 'Page 1', 'Page 2', 'Page 3', etc. You can easily remove pages from such a report, or select only some of the pages, by using the method below.

report.select_pages(
    [
        'Page 1',
        'Page 3'
    ]
)

NB: Selecting pages will tidy bookmarks by default.

Merging pages from different reports

Have you ever tried copying complex pages from one Power BI report to another? It is very tiresome, if at all possible, and still requires extensive effort to reproduce bookmarks, etc. Not anymore! With python-pbi, copying pages to another report also brings the bookmarks along, thanks to the merge method. See an example below, where we copy the last page of report0.pbix to report.pbix.

from pbi.report import PbiReport

# Creating objects
report0 = PbiReport(
    'temp_folder',
    'report0'
)
report = PbiReport(
    'temp_folder',
    'report'
)

# Filtering the interesting page(s)
report0 = report0.select_pages(['Last Page'])

# Merging both reports (includes bringing bookmarks!)
report.merge(report0)

NB: In the example above the file report0.pbix was not updated, as we did not apply the save method to report0.

NB: Merging reports does not currently support bringing along inserted images or custom visuals.

Manipulating the report layout

The overall structure of the report layout is explained in more details in the object section.

Copying visuals

To copy visuals (duplicating, or copying from one page to another, even from a different report), you will have to select the required visuals and ad them onto the appropriate page. Assuming you have a report with a 'Home Page' and a 'Page 1', below is an example copying a group of visuals (called header), as well as buttons:

# Selecting the pages
home_page = report.get_page('Home')
page1 = report.get_page('Page 1')

# Selecting the header group of visuals and adding it onto the other page
header = home_page.get_visual_group('Header')
added_header = page1.add_visuals(header)

# Selecting all visuals containing the string 'Button' and adding them onto the other page
buttons = home_page.get_visuals('Button')
added_buttons = page1.add_visuals(buttons)

Formatting

The objects exposed within the PbiReport allow to manipulate the visuals, filters, etc.

Replacing text

Sometimes, it can be useful to replace some text in the whole report. An example use case is when the data model has been updated, and some columns or some data values used in the Power BI filters have changed as a consequence. You can use the method below to replace all strings matching a certain value:

report.layout.replace(
    'old_name',
    'new_name'
)

NB: The method above is very brutal and will replace all matchings strings in the Power BI report when exported as a json string. It might break the structure of the Power BI file resulting in errors or corrupted files. Ensure you are using precise names and use with caution.

Hiding visuals and pages

To hide a visual or a page, you can use the hide method:

page_to_hide = report.get_page(<page_to_hide_name>)
page_to_hide.hide()

visual_to_hide = page.get_visuals(<visual_to_hide_name>)[0]
visual_to_hide.hide()

Updating font

The font is exposed inside the config object of a visual. You can for example use the command below to set the title font size:

title = home_page.get_visuals('Awesome title')[0]
title['config']['singleVisual']['objects']['general'][0]['properties']['paragraphs'][0]['textRuns'][0]['textStyle']['fontSize'] = '20pt'

Manipulating slicers

Power BI slicers (often shown as dropdowns) have several options that might become inconsistent within a report if developers are not given clear guidelines (whether to use CTRL for multiselect, add a search option, select all, etc.). Try some of the commands below.

report.update_multiselect()
report.add_search()

NB: The commands above will print the number of updates for each page in the report.

Updating the 'keep layer order' attribute

The 'keep layer order' attribute can be very annoying, as a report user can bring visuals to the front by clicking by mistake around the report, thus hiding other visuals. We can set this attribute to true automatically to prevent his behaviour by running the command below on the report itself:

report.update_keep_layer_oder()

NB: The command above will print the number of updates for each page in the report.

Disabling headers

Headers can also be very annoying for the report end users, especially when they appear for irrelevant visuals (shapes, etc.). We can deactivate headers by running the command below on the report itself:

report.disable_headers(
    types_to_filter=['shape', 'textbox']
)

NB: The command above will print the number of updates for each page in the report.

Manipulating report filters

Many Power BI objects can be associated with a filter (the report itself, a page, a slicer, a visual, etc.). These are implemented in python-pbi using the _PbiFilterObject class. For each of these, you can select a filter, update its value, etc.

slicer.update_filter(<slicer_filter_name>, <prefered_default_value>)
page.get_filter(<page_filter_name>)
report.add_filters(<list_of_awesome_filters>)

NB: This is still work in progress and not all filter features are currently covered.

Automatic deployment to production

Apart from saving valuable effort, automating download and upload can also allow for seamless deployment from development environment to test or production.

Quality and consistency

You can build your own CustomPbiReport class and incorporate inside the save method some of the examples above to ensure consistency of visuals and higher quality overall:

Changing the dataset

You can save a PowerBI report with a different dataset connection. This enables automatic deployment from a development environment to the production environment for example. See an example below:

from pbi.pbi import PowerBI
from pbi.report import PbiReport
from tests.config import config

test_pbi = PowerBI(config)

# Download the report from the development workspace into an arbitrary folder
test_pbi.download(
    'test_report',
    test_pbi.download_folder,
    workspace_id=<development_workspace_id>
)

# Brings the report to memory with python-pbi
dev_report = PbiReport(
    'temp_folder',
    'test_report'
)

# Copies the report to the upload location with the production name
prod_report = dev_report.copy(
    new_name='report',
    new_folder=test_pbi.upload_folder
)

# Changes the dataset from development to production dataset
prod_report.save(
    dataset_id_from=<development_dataset_id>,
    dataset_id_to=<production_dataset_id>,
)

# Uploads the contents of the folder to the production workspace
test_pbi.upload(
    test_pbi.upload_folder,
    workspace_id=<production_workspace_id>
)

NB: For downloading and uploading, the script above assumes you have installed the Power BI Powershell.

Protecting sensitive data

It is sometimes required not to expose sensitive data to lower environments (development, test), like URLs, etc. To update such data on-the-fly while deploying to production via the deployment script, you can add the few lines below:

dct = {
    'safe_name_1': 'sensitive_name_1',
    'safe_name_2': 'sensitive_name_2'
}
report.update_names(dct)

Replacing WIP visuals by some placeholder message

In case you want to deploy your report to production but some charts are still under development, you can replace them by a placeholder message inside the deployment script. Assuming a placeholder message is available in a Container object named placeholder_message, you can run the script below:

page = report.get_page(<page_name_with_the_WIP_visual>)
wip_visual = page.get_visuals(<visual_name_under_development>)
page.replace_visual_by_placeholder(
    wip_visual,
    placeholder_message
)

WIP mobile report

In case your report has been deployed to production as a desktop report, but you are still working on the mobile version, you can incorporate the following command in the deployment script to remove all the visuals from the mobile report (the mobile report will then show the Power BI default).

report.reset_mobile_screen()

In case some pages have their mobile report fully developed, you can also include only a list of pages in the command above:

report.reset_mobile_screen(pages=['WIP Page 1', 'WIP Page 3'])

You can even add a custom message to the mobile reports while they are being developed. The default message will come from a separate report, named custom_mobile_message in the example below.

from pbi.pbi import PbiReport

custom_message_report = PbiReport(
    'temp_folder',
    'custom_mobile_message'
)
report.reset_mobile_screen(
    default_message_report=custom_message_report
)