pbipy
is a Python Library for interacting with the Power BI Rest API. It aims to simplyify working with the Power BI Rest API and support programatic administration of Power BI in Python.
pbipy
supports operations for Apps, Dataflows, Datasets, Reports, and Workspaces (Groups), allowing users to perform actions on their PowerBI instance using Python.
pip install pbipy
Or to install the latest development code:
pip install git+https://github.com/andrewvillazon/pbipy
To use pbipy
you'll first need to acquire a bearer_token
.
How do I get a bearer_token
?
To acquire a bearer_token
you'll need to authenticate against your Registered Azure Power BI App. Registering is the first step in turning on the Power BI Rest API, so from here on it's assumed your Power BI Rest API is up and running.
To authenticate against the Registered App, Microsoft provides the MSAL
and azure-identity
python libraries. These libraries support different ways of acquiring a bearer_token
and which to use will depend on how your cloud/tenant is configured.
Because there are multiple ways to acquire the token, pbipy
leaves it up to do this in the way that suits, rather than directly handling authentication (of course, this might change in future).
This README
doesn't cover authentication in detail, however, these are some helpful resources that look at acquiring a bearer_token
in the context of Power BI:
- Power BI REST API with Python and MSAL. Part II.
- Power BI REST API with Python Part III, azure-identity
- Monitoring Power BI using REST APIs from Python
The example below uses the msal
library to to get a bearer_token.
import msal
# msal auth setup
def acquire_bearer_token(username, password, azure_tenant_id, client_id, scopes):
app = msal.PublicClientApplication(client_id, authority=azure_tenant_id)
result = app.acquire_token_by_username_password(username, password, scopes)
return result["access_token"]
bearer_token = acquire_bearer_token(
username="your-username",
password="your-password",
azure_tenant_id="https://login.microsoftonline.com/your-azure-tenant-id",
client_id="your-pbi-client-id",
scopes=["https://analysis.windows.net/powerbi/api/.default"],
)
The code that follows assumes you've authenticated and acquired your bearer_token
.
Start by creating the PowerBI()
client. Interactions with the Power BI Rest API go through this object.
from pbipy import PowerBI
pbi = PowerBI(bearer_token)
To interact with the API, simply call the relevant method from the client.
# Grab the datasets from a workspace
pbi.datasets(group="f089354e-8366-4e18-aea3-4cb4a3a50b48")
pbipy
converts API responses into regular Python objects, with snake case included! 🐍🐍
sales = pbi.dataset("cfafbeb1-8037-4d0c-896e-a46fb27ff229")
print(type(sales))
print(hasattr(sales, "configured_by"))
# <class 'pbipy.resources.Dataset'>
# True
Most methods take in an object id...
dataset = pbi.dataset(
id="cfafbeb1-8037-4d0c-896e-a46fb27ff229",
group="a2f89923-421a-464e-bf4c-25eab39bb09f"
)
... or just pass in the object itself.
group = pbi.group("a2f89923-421a-464e-bf4c-25eab39bb09f")
dataset = pbi.dataset(
"cfafbeb1-8037-4d0c-896e-a46fb27ff229"
,group=group
)
If you need to access the raw json representation, this is supported to.
sales = pbi.dataset("cfafbeb1-8037-4d0c-896e-a46fb27ff229")
print(sales.raw)
# {
# "id": "cfafbeb1-8037-4d0c-896e-a46fb27ff229",
# "name": "SalesMarketing",
# "addRowsAPIEnabled": False,
# "configuredBy": "john@contoso.com",
# ...
# }
Let's see how pbipy
works by performing some operations on a Dataset.
First, we initialize our client.
from pbipy import PowerBI
pbi = PowerBI(bearer_token)
Now that we've got a client, we can load a Dataset from the API. To load a Dataset, we call the dataset()
method with an id
and group
argument. In the Power BI Rest API, a Group and Workspace are synonymous and used interchangeably.
sales = pbi.dataset(
id="cfafbeb1-8037-4d0c-896e-a46fb27ff229",
group="f089354e-8366-4e18-aea3-4cb4a3a50b48",
)
print(sales)
# <Dataset id='cfafbeb1-8037-4d0c-896e-a46fb27ff229', name='SalesMarketing', ...>
Dataset not updating? Let's look at the Refresh History.
We call the refresh_history()
method on our Dataset. Easy.
refresh_history = sales.refresh_history()
for entry in refresh_history:
print(entry)
# {"refreshType":"ViaApi", "startTime":"2017-06-13T09:25:43.153Z", "status": "Completed" ...}
Need to kick off a refresh? That's easy too.
sales.refresh()
How about adding some user permissions to our Dataset? Just call the add_user()
method with the User's details and permissions.
# Give John 'Read' access on the dataset
sales.add_user("john@contoso.com", "User", "Read")
Lastly, if we're feeling adventurous, we can execute DAX against a Dataset and use the results in Python.
dxq_result = sales.execute_queries("EVALUATE VALUES(MyTable)")
print(dxq_result)
# {
# "results": [
# {
# "tables": [
# {
# "rows": [
# {
# "MyTable[Year]": 2010,
# "MyTable[Quarter]": "Q1"
# },
# ...
# }
pbypi
also supports Administrator Operations, specialized operations available to users with Power BI Admin rights. Let's see how we can use these.
First, we need to initialize our client. Then we call the admin
method and initialize an Admin
object.
from pbipy import PowerBI
pbi = PowerBI(bearer_token)
admin = pbi.admin()
Need to review some access on some reports? We can call the report_users
method.
users = admin.report_users("5b218778-e7a5-4d73-8187-f10824047715")
print(users[0])
# {"displayName": "John Nick", "emailAddress": "john@contoso.com", ...}
What about understanding User activity on your Power BI tenant?
from datetime import datetime
start_dtm = datetime(2019, 8, 31, 0, 0, 0)
end_dtm = datetime(2019, 8, 31, 23, 59, 59)
activity_events = admin.activity_events(start_dtm, end_dtm)
print(activity_events)
# [
# {
# "Id": "41ce06d1",
# "CreationTime": "2019-08-13T07:55:15",
# "Operation": "ViewReport",
# ...
# },
# {
# "Id": "c632aa64",
# "CreationTime": "2019-08-13T07:55:10",
# "Operation": "GetSnapshots",
# ...
# }
# ]
datasets = pbi.datasets(group="f089354e-8366-4e18-aea3-4cb4a3a50b48")
for dataset in datasets:
print(dataset)
# <Dataset id='cfafbeb1-8037-4d0c-896e-a46fb27ff229', ...>
# <Dataset id='f7fc6510-e151-42a3-850b-d0805a391db0', ...>
groups = pbi.groups()
for group in groups:
print(group)
# <Group id='a2f89923-421a-464e-bf4c-25eab39bb09f', name='contoso'>
# <Group id='3d9b93c6-7b6d-4801-a491-1738910904fd', name='marketing'>
group = pbi.create_group("contoso")
print(group)
# <Group id='a2f89923-421a-464e-bf4c-25eab39bb09f', name='contoso'>
group = pbi.group("a2f89923-421a-464e-bf4c-25eab39bb09f")
users = group.users()
for user in users:
print(user)
# {"identifier": "john@contoso.com", "groupUserAccessRight": "Admin", ... }
# {"identifier": "Adam@contoso.com", "groupUserAccessRight": "Member", ... }
pbipy
methods wrap around the Operations described in the Power BI Rest API Reference:
Power BI REST APIs for embedded analytics and automation - Power BI REST API
Most of the core operations on Datasets, Workspaces (Groups), Reports, Apps, and Dataflows are implemented. Given the many available endpoints, not everything is covered by pbipy
, so expect a few features to be missing.
If an operation is missing and you think it'd be useful, feel free to suggest it on the Issues tab.
PowerBI Component | Progress | Notes |
---|---|---|
Datasets | Done | |
Groups (Workspaces) | Done | |
Reports | Done | |
Apps | Done | |
Dataflows | Done | |
Admin Operations | Done | Implements operations related to Datasets, Groups, Reports, Apps, and Dataflows only. |
Dashboards | Todo | |
Everything else | Backlog |
Contributions such as bug reports, fixes, documentation or docstrings, enhancements, and ideas are welcome. pbipy
uses github to host code, track issues, record feature requests, and accept pull requests.
A contributing.md
is in the works, but in the meantime below is a general guide.
Pull requests are the best way to make a contribution to the code:
- Fork the repo and create your branch from master.
- If you've added code that should be tested, add tests.
- Add docstrings.
- Ensure the test suite passes.
- Format your code (
pbipy
uses black). - Issue that pull request!
Great Bug Reports tend to have:
- A quick summary and/or background
- Steps to reproduce. Be specific! Give sample code if you can.
- What you expected would happen
- What actually happens
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
The design of this library was heavily inspired by (basically copied) the pycontribs/jira library. It also borrows elements of cmberryay's pypowerbi wrapper.
Thank You to all the contributors to these libraries for the great examples of what an API Wrapper can be.