├── .github ├── FUNDING.yml └── workflows │ ├── python-package.yml │ └── python-publish.yml ├── .gitignore ├── .scripts └── make_venv.py ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.md ├── powerbi ├── apps.py ├── auth.py ├── available_features.py ├── capacities.py ├── client.py ├── dashboards.py ├── dataflow_storage_account.py ├── dataflows.py ├── datasets.py ├── enums.py ├── gateways.py ├── groups.py ├── import.py ├── imports.py ├── pipelines.py ├── push_datasets.py ├── reports.py ├── session.py ├── template_apps.py ├── users.py └── utils.py ├── requirements.txt ├── samples ├── use_available_features.py ├── use_capacities.py ├── use_client.py ├── use_dashboards_service.py ├── use_dataflow_storage.py ├── use_dataflows.py ├── use_datasets.py ├── use_groups_service.py ├── use_imports.py ├── use_pipelines.py ├── use_push_datasets.py ├── use_reports_service.py ├── use_template_apps_service.py ├── use_users_service.py └── use_utils.py ├── setup.py └── tests └── test_client.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [areed1192] 4 | patreon: sigmacoding 5 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 6 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | # Run only when manual 7 | on: 8 | workflow_dispatch 9 | 10 | # on: 11 | # push: 12 | # branches: [master] 13 | # pull_request: 14 | # branches: [master] 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-latest 19 | strategy: 20 | matrix: 21 | python-version: [3.6, 3.7, 3.8] 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | - name: Set up Python ${{ matrix.python-version }} 26 | uses: actions/setup-python@v2 27 | with: 28 | python-version: ${{ matrix.python-version }} 29 | 30 | - name: Install Dependencies from requirements.txt File. 31 | run: | 32 | python -m pip install --upgrade pip 33 | pip install flake8 pytest 34 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 35 | 36 | - name: Lint with flake8 37 | run: | 38 | # stop the build if there are Python syntax errors or undefined names 39 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 40 | 41 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 42 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 43 | 44 | - name: Test with Unittest. 45 | run: | 46 | # If we have a testing folder, then run with unittest. 47 | if [ -f tests/test_clients.py ]; then python -m unittest tests/test_client.py; fi 48 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | # Run only when manual 7 | on: 8 | workflow_dispatch 9 | 10 | # on: 11 | # release: 12 | # types: [created] 13 | 14 | jobs: 15 | deploy: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Set up Python 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: "3.7" 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install setuptools wheel twine 28 | - name: Publish to TestPyPI 29 | env: 30 | TWINE_USERNAME: "__token__" 31 | TWINE_PASSWORD: ${{ secrets.test_pypi_token }} 32 | run: | 33 | python setup.py sdist bdist_wheel 34 | twine upload --repository testpypi --verbose dist/* 35 | - name: Publish to PyPI 36 | env: 37 | TWINE_USERNAME: "__token__" 38 | TWINE_PASSWORD: ${{ secrets.pypi_token }} 39 | run: | 40 | python setup.py sdist bdist_wheel 41 | twine upload --verbose dist/* 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # Alex Folder. 132 | config/ 133 | logs/ 134 | .github/ 135 | *power_bi_state.jsonc 136 | power_bi_state.jsonc 137 | 138 | .powerbi_venv/ 139 | .eastridge/ -------------------------------------------------------------------------------- /.scripts/make_venv.py: -------------------------------------------------------------------------------- 1 | """Create a virtual environment in the current directory.""" 2 | 3 | import venv 4 | 5 | venv.EnvBuilder( 6 | with_pip=True, 7 | system_site_packages=False, 8 | clear=True, 9 | symlinks=False, 10 | upgrade=True, 11 | upgrade_deps=True 12 | ).create(".powerbi_venv") 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Python: Run Power BI Client", 6 | "type": "debugpy", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/samples/use_reports_service.py", 9 | "console": "integratedTerminal" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"], 3 | "python.testing.pytestEnabled": false, 4 | "python.testing.unittestEnabled": true 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 Alex Reed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial Power Bi Python API 2 | 3 | ## Table of Contents 4 | 5 | - [Overview](#overview) 6 | - [Resources](#resources) 7 | - [Setup](#setup) 8 | - [Usage](#usage) 9 | - [Support These Projects](#support-these-projects) 10 | 11 | ## Overview 12 | 13 | Version: **0.1.2** 14 | 15 | Power BI is a business analytics service by Microsoft. It aims to provide interactive 16 | visualizations and business intelligence capabilities with an interface simple enough 17 | for end users to create their own reports and dashboards. It is part of the Microsoft 18 | Power Platform. This library allows you to use the Power BI Rest API from python. Along 19 | with providing the different endpoints, it will also handle the authentication process 20 | for you. 21 | 22 | ## Resources 23 | 24 | - [Power BI App Registration Portal](https://dev.powerbi.com/Apps) 25 | - [Power BI Rest API Documentation](https://docs.microsoft.com/en-us/rest/api/power-bi/) 26 | 27 | ## Setup 28 | 29 | **Setup - Requirements Install:** 30 | 31 | For this particular project, you only need to install the dependencies, to use the project. The dependencies 32 | are listed in the `requirements.txt` file and can be installed by running the following command: 33 | 34 | ```console 35 | pip install -r requirements.txt 36 | ``` 37 | 38 | After running that command, the dependencies should be installed. 39 | 40 | **Setup - Local Install:** 41 | 42 | If you are planning to make modifications to this project or you would like to access it 43 | before it has been indexed on `PyPi`. I would recommend you either install this project 44 | in `editable` mode or do a `local install`. For those of you, who want to make modifications 45 | to this project. I would recommend you install the library in `editable` mode. 46 | 47 | If you want to install the library in `editable` mode, make sure to run the `setup.py` 48 | file, so you can install any dependencies you may need. To run the `setup.py` file, 49 | run the following command in your terminal. 50 | 51 | ```console 52 | pip install -e . 53 | ``` 54 | 55 | If you don't plan to make any modifications to the project but still want to use it across 56 | your different projects, then do a local install. 57 | 58 | ```console 59 | pip install . 60 | ``` 61 | 62 | This will install all the dependencies listed in the `setup.py` file. Once done 63 | you can use the library wherever you want. 64 | 65 | **Setup - PyPi Install:** 66 | 67 | To **install** the library, run the following command from the terminal. 68 | 69 | ```console 70 | pip install python-power-bi 71 | ``` 72 | 73 | **Setup - PyPi Upgrade:** 74 | 75 | To **upgrade** the library, run the following command from the terminal. 76 | 77 | ```console 78 | pip install --upgrade python-power-bi 79 | ``` 80 | 81 | ## Usage 82 | 83 | Here is a simple example of using the `powerbi` library. 84 | 85 | ```python 86 | from pprint import pprint 87 | from configparser import ConfigParser 88 | from powerbi.client import PowerBiClient 89 | 90 | # Initialize the Parser. 91 | config = ConfigParser() 92 | 93 | # Read the file. 94 | config.read('config/config.ini') 95 | 96 | # Get the specified credentials. 97 | client_id = config.get('power_bi_api', 'client_id') 98 | redirect_uri = config.get('power_bi_api', 'redirect_uri') 99 | client_secret = config.get('power_bi_api', 'client_secret') 100 | 101 | # Initialize the Client. 102 | power_bi_client = PowerBiClient( 103 | client_id=client_id, 104 | client_secret=client_secret, 105 | scope=['https://analysis.windows.net/powerbi/api/.default'], 106 | redirect_uri=redirect_uri, 107 | credentials='config/power_bi_state.jsonc' 108 | ) 109 | 110 | # Initialize the `Dashboards` service. 111 | dashboard_service = power_bi_client.dashboards() 112 | 113 | # Add a dashboard to our Workspace. 114 | dashboard_service.add_dashboard(name='my_new_dashboard') 115 | 116 | # Get all the dashboards in our Org. 117 | pprint(dashboard_service.get_dashboards()) 118 | ``` 119 | 120 | ## Support These Projects 121 | 122 | **Patreon:** 123 | Help support this project and future projects by donating to my [Patreon Page](https://www.patreon.com/sigmacoding). I'm 124 | always looking to add more content for individuals like yourself, unfortuantely some of the APIs I would require me to 125 | pay monthly fees. 126 | 127 | **YouTube:** 128 | If you'd like to watch more of my content, feel free to visit my YouTube channel [Sigma Coding](https://www.youtube.com/c/SigmaCoding). 129 | 130 | **Questions:** 131 | If you have questions please feel free to reach out to me at [coding.sigma@gmail.com](mailto:coding.sigma@gmail.com?subject=[GitHub]%20Fred%20Library) 132 | -------------------------------------------------------------------------------- /powerbi/apps.py: -------------------------------------------------------------------------------- 1 | """"Module for the `Apps` service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class Apps: 8 | """Class for the `Apps` service.""" 9 | 10 | def __init__(self, session: object) -> None: 11 | """Initializes the `Apps` service. 12 | 13 | ### Parameters 14 | ---- 15 | session : object 16 | An authenticated session for our Microsoft PowerBi Client. 17 | 18 | ### Usage 19 | ---- 20 | >>> apps_service = power_bi_client.apps() 21 | """ 22 | 23 | # Set the session. 24 | self.power_bi_session: PowerBiSession = session 25 | 26 | # Set the endpoint. 27 | self.endpoint = "myorg/apps" 28 | 29 | def get_app(self, app_id: str) -> Dict: 30 | """Returns the specified installed app. 31 | 32 | ### Returns 33 | ------- 34 | Dict 35 | A collection of `App` resources. 36 | 37 | ### Usage 38 | ---- 39 | >>> apps_service = power_bi_client.apps() 40 | >>> apps_service.get_app(app_id='c0g14be3-38d3-49hc-ef1d-b4f57c9c9058') 41 | """ 42 | 43 | content = self.power_bi_session.make_request( 44 | method="get", endpoint=f"myorg/apps/{app_id}" 45 | ) 46 | 47 | return content 48 | 49 | def get_apps(self) -> Dict: 50 | """Returns a list of installed apps. 51 | 52 | ### Returns 53 | ------- 54 | Dict 55 | A collection of `Apps` resources. 56 | 57 | ### Usage 58 | ---- 59 | >>> apps_service = power_bi_client.apps() 60 | >>> apps_service.get_apps() 61 | """ 62 | 63 | content = self.power_bi_session.make_request( 64 | method="get", endpoint=self.endpoint 65 | ) 66 | 67 | return content 68 | 69 | def get_dashboard(self, app_id: str, dashboard_id: str) -> Dict: 70 | """Returns the specified dashboard from the specified app. 71 | 72 | ### Returns 73 | ------- 74 | Dict 75 | A collection of `Dashboard` resources. 76 | 77 | ### Usage 78 | ---- 79 | >>> apps_service = power_bi_client.apps() 80 | >>> apps_service.get_dashboard( 81 | app_id='c0g14be3-38d3-49hc-ef1d-b4f57c9c9058', 82 | dashboard_id='088bbddg-a162-4a31-98f8-1aea79df954a' 83 | ) 84 | """ 85 | 86 | content = self.power_bi_session.make_request( 87 | method="get", endpoint=f"myorg/apps/{app_id}/dashboards/{dashboard_id}" 88 | ) 89 | 90 | return content 91 | 92 | def get_dashboards(self, app_id: str) -> Dict: 93 | """Returns a list of dashboards from the specified app. 94 | 95 | ### Returns 96 | ------- 97 | Dict 98 | A collection of `Dashboards` resources. 99 | 100 | ### Usage 101 | ---- 102 | >>> apps_service = power_bi_client.apps() 103 | >>> apps_service.get_dashboards( 104 | app_id='f089354e-8366-4e18-aea3-4cb4a3a50b48' 105 | ) 106 | """ 107 | 108 | content = self.power_bi_session.make_request( 109 | method="get", endpoint=f"myorg/apps/{app_id}/dashboards" 110 | ) 111 | 112 | return content 113 | 114 | def get_report(self, app_id: str, report_id: str) -> Dict: 115 | """Returns the specified report from the specified app. 116 | 117 | ### Returns 118 | ------- 119 | Dict 120 | A collection of `Report` resources. 121 | 122 | ### Usage 123 | ---- 124 | >>> apps_service = power_bi_client.apps() 125 | >>> apps_service.get_report( 126 | app_id='f089354e-8366-4e18-aea3-4cb4a3a50b48', 127 | report_id='088bbddg-a162-4a31-98f8-1aea79df954a' 128 | ) 129 | """ 130 | 131 | content = self.power_bi_session.make_request( 132 | method="get", endpoint=f"myorg/apps/{app_id}/reports/{report_id}" 133 | ) 134 | 135 | return content 136 | 137 | def get_reports(self, app_id: str) -> Dict: 138 | """Returns a list of reports from the specified app. 139 | 140 | ### Returns 141 | ------- 142 | Dict 143 | A collection of `Reports` resources. 144 | 145 | ### Usage 146 | ---- 147 | >>> apps_service = power_bi_client.apps() 148 | >>> apps_service.get_reports( 149 | app_id='f089354e-8366-4e18-aea3-4cb4a3a50b48' 150 | ) 151 | """ 152 | 153 | content = self.power_bi_session.make_request( 154 | method="get", endpoint=f"myorg/apps/{app_id}/reports" 155 | ) 156 | 157 | return content 158 | 159 | def get_tile(self, app_id: str, dashboard_id: str, tile_id: str) -> Dict: 160 | """Returns the specified tile within the specified dashboard from the specified app. 161 | 162 | Supported tiles include datasets and live tiles that contain an entire report page. 163 | 164 | ### Returns 165 | ------- 166 | Dict 167 | A collection of `Tile` resources. 168 | 169 | ### Usage 170 | ---- 171 | >>> apps_service = power_bi_client.apps() 172 | >>> apps_service.get_tile( 173 | app_id='f089354e-8366-4e18-aea3-4cb4a3a50b48', 174 | dashboard_id='5b218778-e7a5-4d73-8187-f10824047715', 175 | tile_id='312fbfe9-2eda-44e0-9ed0-ab5dc571bb4b' 176 | ) 177 | """ 178 | 179 | content = self.power_bi_session.make_request( 180 | method="get", 181 | endpoint=f"myorg/apps/{app_id}/dashboards/{dashboard_id}/tiles/{tile_id}", 182 | ) 183 | 184 | return content 185 | 186 | def get_tiles(self, app_id: str, dashboard_id: str) -> Dict: 187 | """Returns a list of reports from the specified app. 188 | 189 | ### Returns 190 | ------- 191 | Dict 192 | A collection of `Tiles` resources. 193 | 194 | ### Usage 195 | ---- 196 | >>> apps_service = power_bi_client.apps() 197 | >>> apps_service.get_tiles( 198 | app_id='f089354e-8366-4e18-aea3-4cb4a3a50b48', 199 | dashboard_id='5b218778-e7a5-4d73-8187-f10824047715' 200 | ) 201 | """ 202 | 203 | content = self.power_bi_session.make_request( 204 | method="get", 205 | endpoint=f"myorg/apps/{app_id}/dashboards/{dashboard_id}/tiles", 206 | ) 207 | 208 | return content 209 | -------------------------------------------------------------------------------- /powerbi/auth.py: -------------------------------------------------------------------------------- 1 | """Module for handling authentication with the Microsoft Power Bi API.""" 2 | 3 | from typing import List 4 | from typing import Dict 5 | 6 | import json 7 | import time 8 | import urllib 9 | import random 10 | import string 11 | import pathlib 12 | 13 | import msal 14 | 15 | from powerbi.session import PowerBiSession 16 | 17 | 18 | class PowerBiAuth: 19 | """Handles all the authentication for the Microsoft Power Bi API.""" 20 | 21 | AUTHORITY_URL = "https://login.microsoftonline.com/" 22 | AUTH_ENDPOINT = "/oauth2/v2.0/authorize?" 23 | TOKEN_ENDPOINT = "/oauth2/v2.0/token" 24 | 25 | def __init__( 26 | self, 27 | client_id: str, 28 | client_secret: str, 29 | redirect_uri: str, 30 | scope: List[str], 31 | account_type: str = "common", 32 | credentials: str = None, 33 | ): 34 | """Initializes the `PowerBiAuth` Client. 35 | 36 | ### Parameters 37 | ---- 38 | client_id : str 39 | The application Client ID assigned when 40 | creating a new Microsoft App. 41 | 42 | client_secret : str 43 | The application Client Secret assigned when 44 | creating a new Microsoft App. 45 | 46 | redirect_uri : str 47 | The application Redirect URI assigned when 48 | creating a new Microsoft App. 49 | 50 | scope : List[str] 51 | The list of scopes you want the application 52 | to have access to. 53 | 54 | account_type : str (optional, Default='common') 55 | The account type you're application wants to 56 | authenticate as. 57 | 58 | credentials : str (optional, Default=None) 59 | The file path to your local credential file. 60 | """ 61 | 62 | # printing lowercase 63 | letters = string.ascii_lowercase 64 | 65 | self.credentials = credentials 66 | self.token_dict = None 67 | 68 | self.client_id = client_id 69 | self.client_secret = client_secret 70 | self.api_version = "v1.0" 71 | self.account_type = account_type 72 | self.redirect_uri = redirect_uri 73 | 74 | self.scope = scope 75 | self.state = "".join(random.choice(letters) for i in range(10)) 76 | 77 | self.access_token = None 78 | self.refresh_token = None 79 | self.graph_session = None 80 | self.id_token = None 81 | 82 | self._redirect_code = None 83 | self._power_bi_session: PowerBiSession = None 84 | 85 | self.graph_url = self.AUTHORITY_URL + self.account_type + self.AUTH_ENDPOINT 86 | 87 | # Initialize the Credential App. 88 | self.client_app = msal.ConfidentialClientApplication( 89 | client_id=self.client_id, 90 | authority=self.AUTHORITY_URL + self.account_type, 91 | client_credential=self.client_secret, 92 | ) 93 | 94 | def _state(self, action: str, token_dict: dict = None) -> bool: 95 | """Sets the session state for the Client Library. 96 | 97 | ### Parameters 98 | ---- 99 | action : str 100 | Defines what action to take when determining the state. Either 101 | `load` or `save`. 102 | 103 | token_dict : dict, optional 104 | If the state is defined as `save` then pass through the 105 | token dictionary you want to save, by default None. 106 | 107 | ### Returns 108 | ---- 109 | bool : 110 | If the state action was successful, then returns `True` 111 | otherwise it returns `False`. 112 | """ 113 | 114 | # Determine if the Credentials file exists. 115 | does_exists = pathlib.Path(self.credentials).exists() 116 | 117 | # If it exists and we are loading it then proceed. 118 | if does_exists and action == "load": 119 | 120 | # Load the file. 121 | with open(file=self.credentials, mode="r", encoding="utf-8") as state_file: 122 | credentials = json.load(fp=state_file) 123 | 124 | # Grab the Token if it exists. 125 | if "refresh_token" in credentials: 126 | 127 | self.refresh_token = credentials["refresh_token"] 128 | self.access_token = credentials["access_token"] 129 | self.id_token = credentials["id_token"] 130 | self.token_dict = credentials 131 | 132 | return True 133 | 134 | else: 135 | return False 136 | 137 | # If we are saving the state then open the file and dump the dictionary. 138 | elif action == "save": 139 | 140 | token_dict["expires_in"] = time.time() + int(token_dict["expires_in"]) 141 | token_dict["ext_expires_in"] = time.time() + int( 142 | token_dict["ext_expires_in"] 143 | ) 144 | 145 | self.refresh_token = token_dict["refresh_token"] 146 | self.access_token = token_dict["access_token"] 147 | self.id_token = token_dict["id_token"] 148 | self.token_dict = token_dict 149 | 150 | with open(file=self.credentials, mode="w+", encoding="utf-8") as state_file: 151 | json.dump(obj=token_dict, fp=state_file, indent=2) 152 | 153 | def _token_seconds(self, token_type: str = "access_token") -> int: 154 | """Determines time till expiration for a token. 155 | 156 | Return the number of seconds until the current access token or refresh token 157 | will expire. The default value is access token because this is the most commonly used 158 | token during requests. 159 | 160 | ### Parameters 161 | ---- 162 | token_type : str (optional, Default='access_token') 163 | The type of token you would like to determine lifespan for. 164 | Possible values are ['access_token', 'refresh_token']. 165 | 166 | ### Returns 167 | ---- 168 | int : 169 | The number of seconds till expiration. 170 | """ 171 | 172 | # if needed check the access token. 173 | if token_type == "access_token": 174 | 175 | # if the time to expiration is less than or equal to 0, return 0. 176 | if not self.access_token or ( 177 | time.time() + 60 >= self.token_dict["expires_in"] 178 | ): 179 | return 0 180 | 181 | # else return the number of seconds until expiration. 182 | token_exp = int(self.token_dict["expires_in"] - time.time() - 60) 183 | 184 | # if needed check the refresh token. 185 | elif token_type == "refresh_token": 186 | 187 | # if the time to expiration is less than or equal to 0, return 0. 188 | if not self.refresh_token or ( 189 | time.time() + 60 >= self.token_dict["ext_expires_in"] 190 | ): 191 | return 0 192 | 193 | # else return the number of seconds until expiration. 194 | token_exp = int(self.token_dict["ext_expires_in"] - time.time() - 60) 195 | 196 | else: 197 | raise ValueError("Invalid Token Type Provided.") 198 | 199 | return token_exp 200 | 201 | def _token_validation(self, nseconds: int = 60): 202 | """Checks if a token is valid. 203 | 204 | Verify the current access token is valid for at least N seconds, and 205 | if not then attempt to refresh it. Can be used to assure a valid token 206 | before making a call to the TD Ameritrade API. 207 | 208 | ### Parameters 209 | ---- 210 | nseconds {int} -- The minimum number of seconds the token has to be 211 | valid for before attempting to get a refresh token. (default: {5}) 212 | """ 213 | 214 | if self._token_seconds(token_type="access_token") < nseconds: 215 | self.grab_refresh_token() 216 | 217 | def _silent_sso(self) -> bool: 218 | """Attempts a Silent Authentication using the Access Token and Refresh Token. 219 | 220 | ### Returns 221 | ---- 222 | bool : 223 | `True` if it was successful and `False` if it failed. 224 | """ 225 | 226 | # if the current access token is not expired then we are still authenticated. 227 | if self._token_seconds(token_type="access_token") > 0: 228 | return True 229 | 230 | # if the current access token is expired then try and refresh access token. 231 | elif self.refresh_token and self.grab_refresh_token(): 232 | return True 233 | 234 | # More than likely a first time login, so can't do silent authenticaiton. 235 | return False 236 | 237 | def login(self) -> None: 238 | """Logs the user into the session.""" 239 | 240 | # Load the State. 241 | self._state(action="load") 242 | 243 | # Try a Silent SSO First. 244 | if self._silent_sso(): 245 | 246 | # Set the Session. 247 | self.graph_session = PowerBiSession(client=self) 248 | 249 | return True 250 | 251 | else: 252 | 253 | # Build the URL. 254 | url = self.authorization_url() 255 | 256 | # aks the user to go to the URL provided, they will be 257 | # prompted to authenticate themsevles. 258 | print(f"Please go to URL provided authorize your account: {url}") 259 | 260 | # ask the user to take the final URL after authentication 261 | # and paste here so we can parse. 262 | my_response = input("Paste the full URL redirect here: ") 263 | 264 | # store the redirect URL 265 | self._redirect_code = my_response 266 | 267 | # this will complete the final part of the authentication process. 268 | self.grab_access_token() 269 | 270 | # Set the session. 271 | self._power_bi_session = PowerBiSession(client=self) 272 | 273 | def authorization_url(self) -> str: 274 | """Builds the authorization URL used to get an Authorization Code. 275 | 276 | ### Returns 277 | ---- 278 | str : 279 | The full authorization url. 280 | """ 281 | 282 | auth_url = { 283 | "response_type": "code", 284 | "client_id": self.client_id, 285 | "redirect_uri": self.redirect_uri, 286 | "resource": "https://analysis.windows.net/powerbi/api", 287 | } 288 | 289 | # Build the Auth URL. 290 | auth_url = self.client_app.get_authorization_request_url( 291 | scopes=self.scope, state=self.state, redirect_uri=self.redirect_uri 292 | ) 293 | 294 | return auth_url 295 | 296 | def grab_access_token(self) -> Dict: 297 | """Exchanges a code for an Access Token. 298 | 299 | ### Returns 300 | ---- 301 | Dict : 302 | A dictionary containing a new access token and refresh token. 303 | """ 304 | 305 | # Parse the Code. 306 | query_dict = urllib.parse.parse_qs(self._redirect_code) 307 | 308 | # Grab the Code. 309 | code = query_dict[self.redirect_uri + "?code"] 310 | 311 | # Grab the Token. 312 | token_dict = self.client_app.acquire_token_by_authorization_code( 313 | code=code, scopes=self.scope, redirect_uri=self.redirect_uri 314 | ) 315 | 316 | # Save the token dict. 317 | self._state(action="save", token_dict=token_dict) 318 | 319 | return token_dict 320 | 321 | def grab_refresh_token(self) -> Dict: 322 | """Grabs a new access token using a refresh token. 323 | 324 | ### Returns 325 | ---- 326 | Dict : 327 | A token dictionary with a new access token. 328 | """ 329 | 330 | # Grab a new token using our refresh token. 331 | token_dict = self.client_app.acquire_token_by_refresh_token( 332 | refresh_token=self.refresh_token, scopes=self.scope 333 | ) 334 | 335 | if "error" in token_dict: 336 | print(token_dict) 337 | raise PermissionError( 338 | "Permissions not authorized, delete json file and run again." 339 | ) 340 | 341 | # Save the Token. 342 | self._state(action="save", token_dict=token_dict) 343 | 344 | return token_dict 345 | 346 | @property 347 | def power_bi_session(self) -> PowerBiSession: 348 | """Returns the current Power Bi""" 349 | return self._power_bi_session 350 | -------------------------------------------------------------------------------- /powerbi/available_features.py: -------------------------------------------------------------------------------- 1 | """Module for the `AvailableFeatures` service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class AvailableFeatures: 8 | 9 | """Class for the `AvailableFeatures` service.""" 10 | 11 | def __init__(self, session: object) -> None: 12 | """Initializes the `AvailableFeatures` service. 13 | 14 | ### Parameters 15 | ---- 16 | session : object 17 | An authenticated session for our Microsoft PowerBi Client. 18 | 19 | ### Usage 20 | ---- 21 | >>> available_features_service = power_bi_client.available_features() 22 | """ 23 | 24 | # Set the session. 25 | self.power_bi_session: PowerBiSession = session 26 | 27 | def get_available_features(self) -> Dict: 28 | """Returns a list of available features for the user. 29 | 30 | ### Returns 31 | ---- 32 | Dict 33 | A collection of `AvailableFeature` resources. 34 | 35 | ### Usage 36 | ---- 37 | >>> available_features_service = power_bi_client.available_features() 38 | >>> available_features_service.get_available_features() 39 | """ 40 | 41 | # Make the request. 42 | content = self.power_bi_session.make_request( 43 | method="get", endpoint="myorg/availableFeatures" 44 | ) 45 | 46 | return content 47 | 48 | def get_available_feature_by_name(self, feature_name: str) -> Dict: 49 | """Returns the specified available feature for user by name. 50 | 51 | ### Parameters 52 | ---- 53 | str : 54 | The feature name. 55 | 56 | ### Returns 57 | ---- 58 | Dict 59 | A `AvailableFeature` resource. 60 | 61 | ### Usage 62 | ---- 63 | >>> available_features_service = power_bi_client.available_features() 64 | >>> available_features_service.get_available_featureby_name( 65 | feature_name='embedTrial' 66 | ) 67 | """ 68 | 69 | # Make the request. 70 | content = self.power_bi_session.make_request( 71 | method="get", 72 | endpoint="myorg/availableFeatures(featureName='" + feature_name + "')", 73 | ) 74 | 75 | return content 76 | -------------------------------------------------------------------------------- /powerbi/capacities.py: -------------------------------------------------------------------------------- 1 | """"Module for the PowerBi `Capacities` service.""" 2 | 3 | from enum import Enum 4 | from typing import Dict 5 | from powerbi.session import PowerBiSession 6 | 7 | 8 | class Capacities: 9 | """Class for the `Capacities` service.""" 10 | 11 | def __init__(self, session: object) -> None: 12 | """Initializes the `Capacities` service. 13 | 14 | ### Parameters 15 | ---- 16 | session : object 17 | An authenticated session for our Microsoft PowerBi Client. 18 | 19 | ### Usage 20 | ---- 21 | >>> capacities_service = power_bi_client.capacities() 22 | """ 23 | 24 | # Set the session. 25 | self.power_bi_session: PowerBiSession = session 26 | 27 | def get_capacities(self) -> Dict: 28 | """Returns a list of capacities the user has access to. 29 | 30 | ### Returns 31 | ---- 32 | Dict 33 | A collection of `Capacities` resources. 34 | 35 | ### Usage 36 | ---- 37 | >>> capacities_service = power_bi_client.capacities() 38 | >>> capacities_service.get_capacities() 39 | """ 40 | 41 | # Make the request. 42 | content = self.power_bi_session.make_request( 43 | method="get", endpoint="myorg/capacities" 44 | ) 45 | 46 | return content 47 | 48 | def get_workloads(self, capacity_id: str) -> Dict: 49 | """Returns the current state of the specified capacity workloads, if a 50 | workload is enabled also returns the maximum memory percentage that 51 | the workload can consume. 52 | 53 | ### Parameters 54 | ---- 55 | capacity_id: str 56 | The capacity Id. 57 | 58 | ### Returns 59 | ---- 60 | Dict 61 | A collection of `Workload` resources. 62 | 63 | ### Usage 64 | ---- 65 | >>> capacities_service = power_bi_client.capacities() 66 | >>> capacities_service.get_workloads( 67 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413' 68 | ) 69 | """ 70 | 71 | # Make the request. 72 | content = self.power_bi_session.make_request( 73 | method="get", endpoint=f"myorg/capacities/{capacity_id}/Workloads" 74 | ) 75 | 76 | return content 77 | 78 | def get_workload(self, capacity_id: str, workload_name: str) -> Dict: 79 | """Returns the current state of the specified capacity workloads, if a 80 | workload is enabled also returns the maximum memory percentage that 81 | the workload can consume. 82 | 83 | ### Parameters 84 | ---- 85 | capacity_id: str 86 | The capacity Id. 87 | 88 | workload_name: str 89 | The name of the workload. 90 | 91 | ### Returns 92 | ---- 93 | Dict 94 | A collection of `Workload` resources. 95 | 96 | ### Usage 97 | ---- 98 | >>> capacities_service = power_bi_client.capacities() 99 | >>> capacities_service.get_workload( 100 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413', 101 | workload_name='my-workload' 102 | ) 103 | """ 104 | 105 | # Make the request. 106 | content = self.power_bi_session.make_request( 107 | method="get", 108 | endpoint=f"myorg/capacities/{capacity_id}/Workloads/{workload_name}", 109 | ) 110 | 111 | return content 112 | 113 | def get_refreshables( 114 | self, top: int = 10, expand: str = None, filter: str = None, skip: int = None 115 | ) -> Dict: 116 | """Returns a list of refreshables for all capacities of which the user has access to. 117 | 118 | ### Parameters 119 | ---- 120 | top: int (optional, Default=10) 121 | Returns only the first n results. 122 | 123 | expand: str (optional, Default=None) 124 | Expands related entities inline, receives a comma-separated list of 125 | data types. Supported: capacities and groups. 126 | 127 | filter: str (optional, Default=None) 128 | Filters the results based on a boolean condition. 129 | 130 | skip: int (optional, Default=None) 131 | Skips the first n results. Use with top to fetch results 132 | beyond the first 1000. 133 | 134 | ### Returns 135 | ---- 136 | Dict 137 | A collection of `Refreshable` resources. 138 | 139 | ### Usage 140 | ---- 141 | >>> capacities_service = power_bi_client.capacities() 142 | >>> capacities_service.get_refreshables( 143 | top=10 144 | ) 145 | """ 146 | 147 | params = {"$expand": expand, "$filter": filter, "$top": top, "$skip": skip} 148 | 149 | # Make the request. 150 | content = self.power_bi_session.make_request( 151 | method="get", endpoint="myorg/capacities/refreshables", params=params 152 | ) 153 | 154 | return content 155 | 156 | def get_refreshables_for_capacity( 157 | self, 158 | capacity_id: str, 159 | top: int = 10, 160 | expand: str = None, 161 | filter: str = None, 162 | skip: int = None, 163 | ) -> Dict: 164 | """Returns a list of refreshables for the specified capacity the user has access to. 165 | 166 | ### Parameters 167 | ---- 168 | capacity_id: str 169 | The capacity id. 170 | 171 | top: int (optional, Default=10) 172 | Returns only the first n results. 173 | 174 | expand: str (optional, Default=None) 175 | Expands related entities inline, receives a comma-separated list of 176 | data types. Supported: capacities and groups. 177 | 178 | filter: str (optional, Default=None) 179 | Filters the results based on a boolean condition. 180 | 181 | skip: int (optional, Default=None) 182 | Skips the first n results. Use with top to fetch results 183 | beyond the first 1000. 184 | 185 | ### Returns 186 | ---- 187 | Dict 188 | A collection of `Refreshable` resources. 189 | 190 | ### Usage 191 | ---- 192 | >>> capacities_service = power_bi_client.capacities() 193 | >>> capacities_service.get_refreshables_for_capacity( 194 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413', 195 | top=10 196 | ) 197 | """ 198 | 199 | params = {"$expand": expand, "$filter": filter, "$top": top, "$skip": skip} 200 | 201 | # Make the request. 202 | content = self.power_bi_session.make_request( 203 | method="get", 204 | endpoint=f"myorg/capacities/{capacity_id}/refreshables", 205 | params=params, 206 | ) 207 | 208 | return content 209 | 210 | def get_refreshable_for_capacity( 211 | self, 212 | capacity_id: str, 213 | refreshable_id: str, 214 | expand: str = None, 215 | ) -> Dict: 216 | """Returns the specified refreshable for the specified capacity 217 | that the user has access to. 218 | 219 | ### Parameters 220 | ---- 221 | capacity_id: str 222 | The capacity id. 223 | 224 | refreshable_id: str 225 | The refreshable id. 226 | 227 | expand: str (optional, Default=None) 228 | Expands related entities inline, receives a comma-separated 229 | list of data types. Supported: `capacities` and `groups`. 230 | 231 | ### Returns 232 | ---- 233 | Dict 234 | A collection of `Refreshable` resources. 235 | 236 | ### Usage 237 | ---- 238 | >>> capacities_service = power_bi_client.capacities() 239 | >>> capacities_service.get_refreshable_for_capacity( 240 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413', 241 | refreshable_id='my-refreshable', 242 | expand='capacities' 243 | ) 244 | """ 245 | 246 | if expand is None: 247 | params = {} 248 | else: 249 | params = {"$expand": expand} 250 | 251 | # Make the request. 252 | content = self.power_bi_session.make_request( 253 | method="get", 254 | endpoint=f"myorg/capacities/{capacity_id}/refreshables/{refreshable_id}", 255 | params=params, 256 | ) 257 | 258 | return content 259 | 260 | def groups_assign_my_workspace_to_capacity( 261 | self, 262 | capacity_id: str, 263 | ) -> None: 264 | """Assigns My workspace to the specified capacity. 265 | 266 | ### Parameters 267 | ---- 268 | capacity_id: str 269 | The capacity id. 270 | 271 | ### Usage 272 | ---- 273 | >>> capacities_service = power_bi_client.capacities() 274 | >>> capacities_service.groups_assign_my_workspace_to_capacity( 275 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413' 276 | ) 277 | """ 278 | 279 | body = {"capacityId": capacity_id} 280 | 281 | # Make the request. 282 | content = self.power_bi_session.make_request( 283 | method="post", endpoint="/myorg/AssignToCapacity", json_payload=body 284 | ) 285 | 286 | return content 287 | 288 | def groups_assign_to_capacity( 289 | self, 290 | group_id: str, 291 | capacity_id: str, 292 | ) -> None: 293 | """Assigns the specified workspace to the specified capacity. 294 | 295 | ### Parameters 296 | ---- 297 | group_id: str 298 | The workspace id. 299 | 300 | capacity_id: str 301 | The capacity id. 302 | 303 | ### Usage 304 | ---- 305 | >>> capacities_service = power_bi_client.capacities() 306 | >>> capacities_service.groups_assign_to_capacity( 307 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 308 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413' 309 | ) 310 | """ 311 | 312 | body = {"capacityId": capacity_id} 313 | 314 | # Make the request. 315 | content = self.power_bi_session.make_request( 316 | method="post", 317 | endpoint=f"/myorg/groups/{group_id}/AssignToCapacity", 318 | json_payload=body, 319 | ) 320 | 321 | return content 322 | 323 | def groups_capacity_assignment_status(self, group_id: str) -> dict: 324 | """Gets the status of the assignment-to-capacity operation for the 325 | specified workspace. 326 | 327 | ### Parameters 328 | ---- 329 | group_id: str 330 | The workspace id. 331 | 332 | ### Returns 333 | ---- 334 | dict 335 | A collection of `CapacityAssignmentStatus` 336 | resources. 337 | 338 | ### Usage 339 | ---- 340 | >>> capacities_service = power_bi_client.capacities() 341 | >>> capacities_service.groups_capacity_assignment_status( 342 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 343 | ) 344 | """ 345 | 346 | # Make the request. 347 | content = self.power_bi_session.make_request( 348 | method="get", 349 | endpoint=f"/myorg/groups/{group_id}/CapacityAssignmentStatus", 350 | ) 351 | 352 | return content 353 | 354 | def groups_capacity_assignment_status_my_workspace(self) -> dict: 355 | """Gets the status of the My workspace assignment-to-capacity 356 | operation. 357 | 358 | ### Returns 359 | ---- 360 | dict 361 | A collection of `CapacityAssignmentStatus` 362 | resources. 363 | 364 | ### Usage 365 | ---- 366 | >>> capacities_service = power_bi_client.capacities() 367 | >>> capacities_service.groups_capacity_assignment_status_my_workspace() 368 | """ 369 | 370 | # Make the request. 371 | content = self.power_bi_session.make_request( 372 | method="get", 373 | endpoint="/myorg/CapacityAssignmentStatus", 374 | ) 375 | 376 | return content 377 | 378 | def patch_workload( 379 | self, 380 | capacity_id: str, 381 | workload_name: str, 382 | state: str | Enum, 383 | max_memory_percentage_set_by_user: int = None, 384 | ) -> None: 385 | """Changes the state of a specific workload to Enabled or Disabled. 386 | When enabling a workload, specify the percentage of maximum 387 | memory that the workload can consume. 388 | 389 | ### Parameters 390 | ---- 391 | capacity_id: str 392 | The capacity Id. 393 | 394 | workload_name: str 395 | The name of the workload. 396 | 397 | state: str | Enum 398 | The state of the workload. Can be either 399 | `Enabled` or `Disabled`. 400 | 401 | max_memory_percentage_set_by_user: int (optional, Default=None) 402 | The percentage of maximum memory that the 403 | workload can consume. 404 | 405 | ### Usage 406 | ---- 407 | >>> capacities_service = power_bi_client.capacities() 408 | >>> capacities_service.patch_workload( 409 | capacity_id='890D018E-4B64-4BB1-97E5-BD5490373413', 410 | workload_name='my-workload', 411 | state='Enabled', 412 | max_memory_percentage_set_by_user=50 413 | ) 414 | """ 415 | 416 | # Make sure percentage is between 0 and 100. 417 | if max_memory_percentage_set_by_user is not None: 418 | if ( 419 | max_memory_percentage_set_by_user < 0 420 | or max_memory_percentage_set_by_user > 100 421 | ): 422 | raise ValueError( 423 | "max_memory_percentage_set_by_user must be between 0 and 100." 424 | ) 425 | 426 | # Check if enum is passed. 427 | if isinstance(state, Enum): 428 | state = state.value 429 | 430 | body = { 431 | "state": state, 432 | "maxMemoryPercentageSetByUser": max_memory_percentage_set_by_user, 433 | } 434 | 435 | # Make the request. 436 | content = self.power_bi_session.make_request( 437 | method="patch", 438 | endpoint=f"/myorg/capacities/{capacity_id}/Workloads/{workload_name}", 439 | json_payload=body, 440 | ) 441 | 442 | return content 443 | -------------------------------------------------------------------------------- /powerbi/client.py: -------------------------------------------------------------------------------- 1 | """Module for the `PowerBiClient` class.""" 2 | 3 | from typing import List 4 | 5 | from powerbi.session import PowerBiSession 6 | from powerbi.auth import PowerBiAuth 7 | from powerbi.dashboards import Dashboards 8 | from powerbi.groups import Groups 9 | from powerbi.users import Users 10 | from powerbi.template_apps import TemplateApps 11 | from powerbi.dataflow_storage_account import DataflowStorageAccount 12 | from powerbi.push_datasets import PushDatasets 13 | from powerbi.dataflows import Dataflows 14 | from powerbi.datasets import Datasets 15 | from powerbi.imports import Imports 16 | from powerbi.reports import Reports 17 | from powerbi.available_features import AvailableFeatures 18 | from powerbi.capacities import Capacities 19 | from powerbi.pipelines import Pipelines 20 | from powerbi.apps import Apps 21 | from powerbi.gateways import Gateways 22 | 23 | 24 | class PowerBiClient: 25 | """ 26 | ### Overview 27 | ---- 28 | Is the main entry point to the other Power BI 29 | REST Services. 30 | """ 31 | 32 | def __init__( 33 | self, 34 | client_id: str, 35 | client_secret: str, 36 | redirect_uri: str, 37 | scope: List[str], 38 | account_type: str = "common", 39 | credentials: str = None, 40 | ): 41 | """Initializes the Graph Client. 42 | 43 | ### Parameters 44 | ---- 45 | client_id : str 46 | The application Client ID assigned when 47 | creating a new Microsoft App. 48 | 49 | client_secret : str 50 | The application Client Secret assigned when 51 | creating a new Microsoft App. 52 | 53 | redirect_uri : str 54 | The application Redirect URI assigned when 55 | creating a new Microsoft App. 56 | 57 | scope : List[str] 58 | The list of scopes you want the application 59 | to have access to. 60 | 61 | account_type : str (optional, Default='common') 62 | The account type you're application wants to 63 | authenticate as. 64 | 65 | credentials : str (optional, Default=None) 66 | The file path to your local credential file. 67 | 68 | ### Usage 69 | ---- 70 | >>> power_bi_client = PowerBiClient( 71 | client_id=client_id, 72 | client_secret=client_secret, 73 | scope=['https://analysis.windows.net/powerbi/api/.default'], 74 | redirect_uri=redirect_uri, 75 | credentials='config/power_bi_state.jsonc' 76 | ) 77 | """ 78 | 79 | self.credentials = credentials 80 | self.client_id = client_id 81 | self.client_secret = client_secret 82 | self.account_type = account_type 83 | self.redirect_uri = redirect_uri 84 | self.scope = scope 85 | 86 | self.power_bi_auth_client = PowerBiAuth( 87 | client_id=self.client_id, 88 | client_secret=self.client_secret, 89 | redirect_uri=self.redirect_uri, 90 | scope=self.scope, 91 | account_type=self.account_type, 92 | credentials=self.credentials, 93 | ) 94 | 95 | self.power_bi_auth_client.login() 96 | 97 | self.power_bi_session = PowerBiSession(client=self.power_bi_auth_client) 98 | 99 | def apps(self) -> Apps: 100 | """Used to access the `Apps` Services and metadata. 101 | 102 | ### Returns 103 | --- 104 | Apps : 105 | The `Apps` services Object. 106 | 107 | ### Usage 108 | ---- 109 | >>> power_bi_client = PowerBiClient( 110 | client_id=client_id, 111 | client_secret=client_secret, 112 | scope=['https://analysis.windows.net/powerbi/api/.default'], 113 | redirect_uri=redirect_uri, 114 | credentials='config/power_bi_state.jsonc' 115 | ) 116 | >>> apps_service = power_bi_client.apps() 117 | """ 118 | 119 | return Apps(session=self.power_bi_session) 120 | 121 | def dashboards(self) -> Dashboards: 122 | """Used to access the `Dashboards` Services and metadata. 123 | 124 | ### Returns 125 | --- 126 | Dashboards : 127 | The `Dashboards` services Object. 128 | 129 | ### Usage 130 | ---- 131 | >>> power_bi_client = PowerBiClient( 132 | client_id=client_id, 133 | client_secret=client_secret, 134 | scope=['https://analysis.windows.net/powerbi/api/.default'], 135 | redirect_uri=redirect_uri, 136 | credentials='config/power_bi_state.jsonc' 137 | ) 138 | >>> dashboard_service = power_bi_client.dashboards() 139 | """ 140 | 141 | return Dashboards(session=self.power_bi_session) 142 | 143 | def groups(self) -> Groups: 144 | """Used to access the `Groups` Services and metadata. 145 | 146 | ### Returns 147 | --- 148 | Groups : 149 | The `Groups` services Object. 150 | 151 | ### Usage 152 | ---- 153 | >>> power_bi_client = PowerBiClient( 154 | client_id=client_id, 155 | client_secret=client_secret, 156 | scope=['https://analysis.windows.net/powerbi/api/.default'], 157 | redirect_uri=redirect_uri, 158 | credentials='config/power_bi_state.jsonc' 159 | ) 160 | >>> groups_service = power_bi_client.groups() 161 | """ 162 | 163 | return Groups(session=self.power_bi_session) 164 | 165 | def users(self) -> Users: 166 | """Used to access the `Users` Services and metadata. 167 | 168 | ### Returns 169 | --- 170 | Users : 171 | The `Users` services Object. 172 | 173 | ### Usage 174 | ---- 175 | >>> power_bi_client = PowerBiClient( 176 | client_id=client_id, 177 | client_secret=client_secret, 178 | scope=['https://analysis.windows.net/powerbi/api/.default'], 179 | redirect_uri=redirect_uri, 180 | credentials='config/power_bi_state.jsonc' 181 | ) 182 | >>> users_service = power_bi_client.users() 183 | """ 184 | 185 | return Users(session=self.power_bi_session) 186 | 187 | def template_apps(self) -> TemplateApps: 188 | """Used to access the `TemplateApps` Services and metadata. 189 | 190 | ### Returns 191 | --- 192 | TemplateApps : 193 | The `TemplateApps` services Object. 194 | 195 | ### Usage 196 | ---- 197 | >>> power_bi_client = PowerBiClient( 198 | client_id=client_id, 199 | client_secret=client_secret, 200 | scope=['https://analysis.windows.net/powerbi/api/.default'], 201 | redirect_uri=redirect_uri, 202 | credentials='config/power_bi_state.jsonc' 203 | ) 204 | >>> template_apps_service = power_bi_client.template_apps() 205 | """ 206 | 207 | return TemplateApps(session=self.power_bi_session) 208 | 209 | def dataflow_storage_account(self) -> DataflowStorageAccount: 210 | """Used to access the `DataflowStorageAccount` Services and metadata. 211 | 212 | ### Returns 213 | --- 214 | DataflowStorageAccount : 215 | The `DataflowStorageAccount` services Object. 216 | 217 | ### Usage 218 | ---- 219 | >>> power_bi_client = PowerBiClient( 220 | client_id=client_id, 221 | client_secret=client_secret, 222 | scope=['https://analysis.windows.net/powerbi/api/.default'], 223 | redirect_uri=redirect_uri, 224 | credentials='config/power_bi_state.jsonc' 225 | ) 226 | >>> dataflow_storage_service = power_bi_client.dataflow_storage_accounts() 227 | """ 228 | 229 | return DataflowStorageAccount(session=self.power_bi_session) 230 | 231 | def push_datasets(self) -> PushDatasets: 232 | """Used to access the `PushDatasets` Services and metadata. 233 | 234 | ### Returns 235 | --- 236 | PushDatasets : 237 | The `PushDatasets` services Object. 238 | 239 | ### Usage 240 | ---- 241 | >>> power_bi_client = PowerBiClient( 242 | client_id=client_id, 243 | client_secret=client_secret, 244 | scope=['https://analysis.windows.net/powerbi/api/.default'], 245 | redirect_uri=redirect_uri, 246 | credentials='config/power_bi_state.jsonc' 247 | ) 248 | >>> push_datasets_service = power_bi_client.push_datasets() 249 | """ 250 | 251 | return PushDatasets(session=self.power_bi_session) 252 | 253 | def imports(self) -> Imports: 254 | """Used to access the `Imports` Services and metadata. 255 | 256 | ### Returns 257 | --- 258 | Imports: 259 | The `Imports` services Object. 260 | 261 | ### Usage 262 | ---- 263 | >>> power_bi_client = PowerBiClient( 264 | client_id=client_id, 265 | client_secret=client_secret, 266 | scope=['https://analysis.windows.net/powerbi/api/.default'], 267 | redirect_uri=redirect_uri, 268 | credentials='config/power_bi_state.jsonc' 269 | ) 270 | >>> imports_service = power_bi_client.imports() 271 | """ 272 | 273 | return Imports(session=self.power_bi_session) 274 | 275 | def reports(self) -> Reports: 276 | """Used to access the `Reports` Services and metadata. 277 | 278 | ### Returns 279 | --- 280 | Reports: 281 | The `Reports` services Object. 282 | 283 | ### Usage 284 | ---- 285 | >>> power_bi_client = PowerBiClient( 286 | client_id=client_id, 287 | client_secret=client_secret, 288 | scope=['https://analysis.windows.net/powerbi/api/.default'], 289 | redirect_uri=redirect_uri, 290 | credentials='config/power_bi_state.jsonc' 291 | ) 292 | >>> reports_service = power_bi_client.reports() 293 | """ 294 | 295 | return Reports(session=self.power_bi_session) 296 | 297 | def available_features(self) -> AvailableFeatures: 298 | """Used to access the `AvailableFeatures` Services and metadata. 299 | 300 | ### Returns 301 | --- 302 | AvailableFeatures: 303 | The `AvailableFeatures` services Object. 304 | 305 | ### Usage 306 | ---- 307 | >>> power_bi_client = PowerBiClient( 308 | client_id=client_id, 309 | client_secret=client_secret, 310 | scope=['https://analysis.windows.net/powerbi/api/.default'], 311 | redirect_uri=redirect_uri, 312 | credentials='config/power_bi_state.jsonc' 313 | ) 314 | >>> available_features_service = power_bi_client.available_features() 315 | """ 316 | 317 | return AvailableFeatures(session=self.power_bi_session) 318 | 319 | def capactities(self) -> Capacities: 320 | """Used to access the `Capacities` Services and metadata. 321 | 322 | ### Returns 323 | --- 324 | Capacities: 325 | The `Capacities` services Object. 326 | 327 | ### Usage 328 | ---- 329 | >>> power_bi_client = PowerBiClient( 330 | client_id=client_id, 331 | client_secret=client_secret, 332 | scope=['https://analysis.windows.net/powerbi/api/.default'], 333 | redirect_uri=redirect_uri, 334 | credentials='config/power_bi_state.jsonc' 335 | ) 336 | >>> capacities_service = power_bi_client.capactities() 337 | """ 338 | 339 | return Capacities(session=self.power_bi_session) 340 | 341 | def pipelines(self) -> Pipelines: 342 | """Used to access the `Pipelines` Services and metadata. 343 | 344 | ### Returns 345 | --- 346 | Pipelines: 347 | The `Pipelines` services Object. 348 | 349 | ### Usage 350 | ---- 351 | >>> power_bi_client = PowerBiClient( 352 | client_id=client_id, 353 | client_secret=client_secret, 354 | scope=['https://analysis.windows.net/powerbi/api/.default'], 355 | redirect_uri=redirect_uri, 356 | credentials='config/power_bi_state.jsonc' 357 | ) 358 | >>> pipelines_service = power_bi_client.pipelines() 359 | """ 360 | 361 | return Pipelines(session=self.power_bi_session) 362 | 363 | def dataflows(self) -> Dataflows: 364 | """Used to access the `Dataflows` Services and metadata. 365 | 366 | ### Returns 367 | --- 368 | Dataflows: 369 | The `Dataflows` services Object. 370 | 371 | ### Usage 372 | ---- 373 | >>> power_bi_client = PowerBiClient( 374 | client_id=client_id, 375 | client_secret=client_secret, 376 | scope=['https://analysis.windows.net/powerbi/api/.default'], 377 | redirect_uri=redirect_uri, 378 | credentials='config/power_bi_state.jsonc' 379 | ) 380 | >>> dataflows_service = power_bi_client.dataflows() 381 | """ 382 | 383 | return Dataflows(session=self.power_bi_session) 384 | 385 | def datasets(self) -> Datasets: 386 | """Used to access the `Datasets` Services and metadata. 387 | 388 | ### Returns 389 | --- 390 | Datasets: 391 | The `Datasets` services Object. 392 | 393 | ### Usage 394 | ---- 395 | >>> power_bi_client = PowerBiClient( 396 | client_id=client_id, 397 | client_secret=client_secret, 398 | scope=['https://analysis.windows.net/powerbi/api/.default'], 399 | redirect_uri=redirect_uri, 400 | credentials='config/power_bi_state.jsonc' 401 | ) 402 | >>> datasets_service = power_bi_client.datasets() 403 | """ 404 | 405 | return Datasets(session=self.power_bi_session) 406 | 407 | def gateways(self) -> Gateways: 408 | """Used to access the `Gateways` Services and metadata. 409 | 410 | ### Returns 411 | --- 412 | Gateways: 413 | The `Gateways` services Object. 414 | 415 | ### Usage 416 | ---- 417 | >>> power_bi_client = PowerBiClient( 418 | client_id=client_id, 419 | client_secret=client_secret, 420 | scope=['https://analysis.windows.net/powerbi/api/.default'], 421 | redirect_uri=redirect_uri, 422 | credentials='config/power_bi_state.jsonc' 423 | ) 424 | >>> gateways_service = power_bi_client.gateways() 425 | """ 426 | 427 | return Gateways(session=self.power_bi_session) 428 | -------------------------------------------------------------------------------- /powerbi/dashboards.py: -------------------------------------------------------------------------------- 1 | """Module for the `Dashboards` service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class Dashboards: 8 | """Class for the `Dashboards` service.""" 9 | 10 | def __init__(self, session: object) -> None: 11 | """Initializes the `Dashboards` service. 12 | 13 | ### Parameters 14 | ---- 15 | session : object 16 | An authenticated session for our Microsoft PowerBi Client. 17 | 18 | ### Usage 19 | ---- 20 | >>> dashboard_service = power_bi_client.dashboards() 21 | """ 22 | 23 | # Set the session. 24 | self.power_bi_session: PowerBiSession = session 25 | 26 | # Set the endpoint. 27 | self.endpoint = "myorg/dashboards" 28 | self.group_endpoint = "myorg/groups/{group_id}/dashboards" 29 | 30 | def add_dashboard(self, name: str) -> Dict: 31 | """Creates a new empty dashboard on `My Workspace`. 32 | 33 | ### Parameters 34 | ---- 35 | name : str 36 | The name of the new dashboard. 37 | 38 | ### Returns 39 | ---- 40 | Dict 41 | A `Dashboard` resource. 42 | 43 | ### Usage 44 | ---- 45 | >>> dashboard_service = power_bi_client.dashboards() 46 | >>> dashboard_service.add_dashboard(name='my_new_dashboard') 47 | """ 48 | 49 | # Define the payload. 50 | payload = {"name": name} 51 | 52 | # Make the request. 53 | content = self.power_bi_session.make_request( 54 | method="post", endpoint=self.endpoint, json_payload=payload 55 | ) 56 | 57 | return content 58 | 59 | def add_dashboard_in_group(self, name: str, group_id: str) -> Dict: 60 | """Creates a new empty dashboard on the specified workspace. 61 | 62 | ### Parameters 63 | ---- 64 | name : str 65 | The name of the new dashboard. 66 | 67 | group_id : str 68 | The workspace id. 69 | 70 | ### Returns 71 | ---- 72 | Dict 73 | A `Dashboard` resource. 74 | 75 | ### Usage 76 | ---- 77 | >>> dashboard_service = power_bi_client.dashboards() 78 | >>> dashboard_service.add_dashboard_in_group( 79 | name='my_new_dashboard', 80 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78' 81 | ) 82 | """ 83 | 84 | # Define the payload. 85 | payload = {"name": name} 86 | 87 | # Make the request. 88 | content = self.power_bi_session.make_request( 89 | method="post", 90 | endpoint=f"myorg/groups/{group_id}/dashboards", 91 | json_payload=payload, 92 | ) 93 | 94 | return content 95 | 96 | def get_dashboards(self) -> Dict: 97 | """Returns a list of dashboards from `My Workspace`. 98 | 99 | ### Returns 100 | ------- 101 | Dict 102 | A collection of `Dashboard` resources. 103 | 104 | ### Usage 105 | ---- 106 | >>> dashboard_service = power_bi_client.dashboards() 107 | >>> dashboard_service.get_dashboards() 108 | """ 109 | 110 | content = self.power_bi_session.make_request( 111 | method="get", endpoint=self.endpoint 112 | ) 113 | 114 | return content 115 | 116 | def get_dashboard(self, dashboard_id: str) -> Dict: 117 | """Returns the specified dashboard from "My Workspace". 118 | 119 | ### Parameters 120 | ---- 121 | dashboard_id : str 122 | The ID of the dashboard you want to query. 123 | 124 | ### Returns 125 | ------- 126 | Dict 127 | A `Dashboard` resources. 128 | 129 | ### Usage 130 | ---- 131 | >>> dashboard_service = power_bi_client.dashboards() 132 | >>> dashboard_service.get_dashboard( 133 | dashboard_id='bf2c7d16-ec7b-40a2-ab56-f8797fdc5fb8' 134 | ) 135 | """ 136 | 137 | content = self.power_bi_session.make_request( 138 | method="get", endpoint=f"myorg/dashboards/{dashboard_id}" 139 | ) 140 | 141 | return content 142 | 143 | def get_group_dashboards(self, group_id: str) -> Dict: 144 | """Returns a list of dashboards from the specified workspace. 145 | 146 | ### Parameters 147 | ---- 148 | group_id : str 149 | The workspace id. 150 | 151 | ### Returns 152 | ------- 153 | Dict 154 | A collection of `Dashboard` resources. 155 | 156 | ### Usage 157 | ---- 158 | >>> dashboard_service = power_bi_client.dashboards() 159 | >>> dashboard_service.get_group_dashboards( 160 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78' 161 | ) 162 | """ 163 | 164 | content = self.power_bi_session.make_request( 165 | method="get", endpoint=self.group_endpoint.format(group_id=group_id) 166 | ) 167 | 168 | return content 169 | 170 | def get_group_dashboard(self, group_id: str, dashboard_id: str) -> Dict: 171 | """Returns the specified dashboard from the specified workspace. 172 | 173 | ### Parameters 174 | ---- 175 | group_id : str 176 | The workspace id. 177 | 178 | dashboard_id : str 179 | The ID of the dashboard you want to query. 180 | 181 | ### Returns 182 | ------- 183 | Dict 184 | A collection of `Dashboard` resources. 185 | 186 | ### Usage 187 | ---- 188 | >>> dashboard_service = power_bi_client.dashboards() 189 | >>> dashboard_service.get_group_dashboard( 190 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 191 | dashboard_id='1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358' 192 | ) 193 | """ 194 | 195 | content = self.power_bi_session.make_request( 196 | method="get", endpoint=f"myorg/groups/{group_id}/dashboards/{dashboard_id}" 197 | ) 198 | 199 | return content 200 | 201 | def get_tiles(self, dashboard_id: str) -> Dict: 202 | """Returns a list of tiles within the specified dashboard from "My Workspace". 203 | 204 | ### Overview 205 | ---- 206 | Note: All tile types are supported except for "model tiles", which include 207 | datasets and live tiles that contain an entire report page. 208 | 209 | ### Parameters 210 | ---- 211 | dashboard_id : str 212 | The ID of the dashboard you want to query. 213 | 214 | ### Returns 215 | ------- 216 | Dict 217 | A collection of `Tile` resources. 218 | 219 | ### Usage 220 | ---- 221 | >>> dashboard_service = power_bi_client.dashboards() 222 | >>> dashboard_service.get_tiles( 223 | dashboard_id='bf2c7d16-ec7b-40a2-ab56-f8797fdc5fb8' 224 | ) 225 | """ 226 | 227 | content = self.power_bi_session.make_request( 228 | method="get", endpoint=f"myorg/dashboards/{dashboard_id}/tiles" 229 | ) 230 | 231 | return content 232 | 233 | def get_group_tiles(self, group_id: str, dashboard_id: str) -> Dict: 234 | """Returns a list of tiles within the specified dashboard from the specified workspace. 235 | 236 | ### Overview 237 | ---- 238 | Note: All tile types are supported except for "model tiles", which include 239 | datasets and live tiles that contain an entire report page. 240 | 241 | ### Parameters 242 | ---- 243 | group_id : str 244 | The workspace id. 245 | 246 | dashboard_id : str 247 | The ID of the dashboard you want to query. 248 | 249 | ### Returns 250 | ------- 251 | Dict 252 | A collection of `Tile` resources. 253 | 254 | ### Usage 255 | ---- 256 | >>> dashboard_service = power_bi_client.dashboards() 257 | >>> dashboard_service.get_group_tiles( 258 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 259 | dashboard_id='bf2c7d16-ec7b-40a2-ab56-f8797fdc5fb8' 260 | ) 261 | """ 262 | 263 | content = self.power_bi_session.make_request( 264 | method="get", 265 | endpoint=f"myorg/groups/{group_id}/dashboards/{dashboard_id}/tiles", 266 | ) 267 | 268 | return content 269 | 270 | def get_tile(self, dashboard_id: str, tile_id: str) -> Dict: 271 | """Returns the specified tile within the specified dashboard from "My Workspace". 272 | 273 | ### Overview 274 | ---- 275 | Note: All tile types are supported except for "model tiles", which include 276 | datasets and live tiles that contain an entire report page. 277 | 278 | ### Parameters 279 | ---- 280 | dashboard_id : str 281 | The ID of the dashboard you want to query. 282 | 283 | tile_id: str 284 | The tile id you want to query. 285 | 286 | ### Returns 287 | ------- 288 | Dict 289 | A `Tile` resources. 290 | 291 | ### Usage 292 | ---- 293 | >>> dashboard_service = power_bi_client.dashboards() 294 | >>> dashboard_service.get_tile( 295 | dashboard_id='bf2c7d16-ec7b-40a2-ab56-f8797fdc5fb8', 296 | tile_id='093bfb85-828e-4705-bcf8-0126dd2d5d70' 297 | ) 298 | """ 299 | 300 | content = self.power_bi_session.make_request( 301 | method="get", endpoint=f"myorg/dashboards/{dashboard_id}/tiles/{tile_id}" 302 | ) 303 | 304 | return content 305 | 306 | def get_group_tile(self, group_id: str, dashboard_id: str, tile_id: str) -> Dict: 307 | """Returns the specified tile within the specified dashboard from the specified workspace. 308 | 309 | ### Overview 310 | ---- 311 | Note: All tile types are supported except for "model tiles", which include 312 | datasets and live tiles that contain an entire report page. 313 | 314 | ### Parameters 315 | ---- 316 | group_id : str 317 | The workspace id. 318 | 319 | dashboard_id : str 320 | The ID of the dashboard you want to query. 321 | 322 | tile_id: str 323 | The tile id you want to query. 324 | 325 | ### Returns 326 | ------- 327 | Dict 328 | A `Tile` resource. 329 | 330 | ### Usage 331 | ---- 332 | >>> dashboard_service = power_bi_client.dashboards() 333 | >>> dashboard_service.get_group_tile( 334 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 335 | dashboard_id='1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358', 336 | tile_id='093bfb85-828e-4705-bcf8-0126dd2d5d70' 337 | ) 338 | """ 339 | 340 | content = self.power_bi_session.make_request( 341 | method="get", 342 | endpoint=f"myorg/groups/{group_id}/dashboards/{dashboard_id}/tiles/{tile_id}", 343 | ) 344 | 345 | return content 346 | 347 | def clone_tile( 348 | self, 349 | dashboard_id: str, 350 | tile_id: str, 351 | target_dashboard_id: str, 352 | position_conflict_action: str = "tail", 353 | target_model_id: str = None, 354 | target_report_id: str = None, 355 | target_workspace_id: str = None, 356 | ) -> Dict: 357 | """Clones the specified tile from "My Workspace". 358 | 359 | ### Overview 360 | ---- 361 | If target report id and target dataset are not specified, the following can occur: 362 | When a tile clone is performed within the same workspace, the report and dataset 363 | links will be cloned from the source tile. When cloning a tile within a different 364 | workspace, report and dataset links will be rested, and the tile will be broken. 365 | 366 | ### Parameters 367 | ---- 368 | dashboard_id : str 369 | The ID of the dashboard you want to query. 370 | 371 | tile_id: str 372 | The tile id you want to query. 373 | 374 | target_dashboard_id : str 375 | The target dashboard id. 376 | 377 | position_conflict_action : str (optional, Default='tail') 378 | Optional parameter for specifying the action in case of 379 | position conflict. 380 | 381 | target_model_id : str (optional, Default=None) 382 | When cloning a tile linked to a dataset, pass the target 383 | model id to rebind the new tile to a different dataset. 384 | 385 | target_report_id : str (optional, Default=None) 386 | When cloning a tile linked to a report, pass the target 387 | report id to rebind the new tile to a different report. 388 | 389 | target_workspace_id : str (optional, Default=None) 390 | Specifices the target workspace id. Empty Guid 391 | (00000000-0000-0000-0000-000000000000) indicates 'My Workspace'. 392 | If not provided, tile will be cloned within the same workspace 393 | as the source tile. 394 | 395 | ### Returns 396 | ------- 397 | Dict 398 | A `Tile` resource. 399 | 400 | ### Usage 401 | ---- 402 | >>> dashboard_service = power_bi_client.dashboards() 403 | >>> dashboard_service.clone_tile( 404 | dashboard_id='1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358', 405 | tile_id='093bfb85-828e-4705-bcf8-0126dd2d5d70', 406 | target_dashboard_id='86cb0a0e-612d-4822-9a29-d83478e21199' 407 | ) 408 | """ 409 | 410 | payload = { 411 | "targetDashboardId": target_dashboard_id, 412 | "positionConflictAction": position_conflict_action, 413 | "targetModelId": target_model_id, 414 | "targetReportId": target_report_id, 415 | "targetWorkspaceId": target_workspace_id, 416 | } 417 | 418 | content = self.power_bi_session.make_request( 419 | method="post", 420 | endpoint=f"myorg/dashboards/{dashboard_id}/tiles/{tile_id}/Clone", 421 | json_payload=payload, 422 | ) 423 | 424 | return content 425 | 426 | def clone_group_tile( 427 | self, 428 | group_id: str, 429 | dashboard_id: str, 430 | tile_id: str, 431 | target_dashboard_id: str, 432 | position_conflict_action: str = "tail", 433 | target_model_id: str = None, 434 | target_report_id: str = None, 435 | target_workspace_id: str = None, 436 | ) -> Dict: 437 | """Clones the specified tile from the specified workspace. 438 | 439 | ### Overview 440 | ---- 441 | If target report id and target dataset are not specified, the following can occur: 442 | When a tile clone is performed within the same workspace, the report and dataset 443 | links will be cloned from the source tile. When cloning a tile within a different 444 | workspace, report and dataset links will be rested, and the tile will be broken. 445 | 446 | ### Parameters 447 | ---- 448 | group_id : str 449 | The workspace ID. 450 | 451 | dashboard_id : str 452 | The ID of the dashboard you want to query. 453 | 454 | tile_id: str 455 | The tile id you want to query. 456 | 457 | target_dashboard_id : str 458 | The target dashboard id. 459 | 460 | position_conflict_action : str (optional, Default='tail') 461 | Optional parameter for specifying the action in case of 462 | position conflict. 463 | 464 | target_model_id : str (optional, Default=None) 465 | When cloning a tile linked to a dataset, pass the target 466 | model id to rebind the new tile to a different dataset. 467 | 468 | target_report_id : str (optional, Default=None) 469 | When cloning a tile linked to a report, pass the target 470 | report id to rebind the new tile to a different report. 471 | 472 | target_workspace_id : str (optional, Default=None) 473 | Specifices the target workspace id. Empty Guid 474 | (00000000-0000-0000-0000-000000000000) indicates 'My Workspace'. 475 | If not provided, tile will be cloned within the same workspace 476 | as the source tile. 477 | 478 | ### Returns 479 | ------- 480 | Dict 481 | A `Tile` resource. 482 | 483 | ### Usage 484 | ---- 485 | >>> dashboard_service = power_bi_client.dashboards() 486 | >>> dashboard_service.clone_tile( 487 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 488 | dashboard_id='1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358', 489 | tile_id='093bfb85-828e-4705-bcf8-0126dd2d5d70', 490 | target_dashboard_id='86cb0a0e-612d-4822-9a29-d83478e21199' 491 | ) 492 | """ 493 | 494 | payload = { 495 | "targetDashboardId": target_dashboard_id, 496 | "positionConflictAction": position_conflict_action, 497 | "targetModelId": target_model_id, 498 | "targetReportId": target_report_id, 499 | "targetWorkspaceId": target_workspace_id, 500 | } 501 | 502 | content = self.power_bi_session.make_request( 503 | method="post", 504 | endpoint=f"myorg/groups/{group_id}/dashboards/{dashboard_id}/tiles/{tile_id}/Clone", 505 | json_payload=payload, 506 | ) 507 | 508 | return content 509 | -------------------------------------------------------------------------------- /powerbi/dataflow_storage_account.py: -------------------------------------------------------------------------------- 1 | """Module for the `DataflowStorageAccount` service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class DataflowStorageAccount: 8 | """Class for the `DataflowStorageAccount` service.""" 9 | 10 | def __init__(self, session: object) -> None: 11 | """Initializes the `DataflowStorageAccount` service. 12 | 13 | ### Parameters 14 | ---- 15 | session : object 16 | An authenticated session for our Microsoft PowerBi Client. 17 | 18 | ### Usage 19 | ---- 20 | >>> dataflow_storage_service = power_bi_client.dataflow_storage_account() 21 | """ 22 | 23 | # Set the session. 24 | self.power_bi_session: PowerBiSession = session 25 | 26 | # Set the endpoint. 27 | self.endpoint = "myorg/dataflowStorageAccounts" 28 | 29 | def get_dataflow_storage_accounts(self) -> Dict: 30 | """Returns a list of dataflow storage accounts the user 31 | has access to. 32 | 33 | ### Returns 34 | ---- 35 | Dict 36 | A collection of `DataflowStorageAccount` resources. 37 | 38 | ### Usage 39 | ---- 40 | >>> dataflow_storage_service = power_bi_client.dataflow_storage_account() 41 | >>> dataflow_storage_service.get_dataflow_storage_accounts() 42 | """ 43 | 44 | content = self.power_bi_session.make_request( 45 | method="get", endpoint="myorg/dataflowStorageAccounts" 46 | ) 47 | 48 | return content 49 | 50 | def assign_to_dataflow_storage_account( 51 | self, group_id: str, dataflow_storage_id: str 52 | ) -> Dict: 53 | """Assigns the specified workspace to the specified dataflow storage 54 | account. 55 | 56 | ### Parameters 57 | ---- 58 | group_id : str 59 | The workspace id. 60 | 61 | dataflow_storage_id : str 62 | The Power BI dataflow storage account id. To unassign 63 | the specified workspace from a Power BI dataflow storage 64 | account, an empty GUID (00000000-0000-0000-0000-000000000000) 65 | should be provided as dataflowStorageId. 66 | 67 | ### Returns 68 | ---- 69 | Dict 70 | A collection of `DataflowStorageAccount` resources. 71 | 72 | ### Usage 73 | ---- 74 | >>> dataflow_storage_service = power_bi_client.dataflow_storage_account() 75 | >>> dataflow_storage_service.assign_to_dataflow_storage_account( 76 | group_id='', 77 | dataflow_storage_id='' 78 | ) 79 | """ 80 | 81 | payload = {"dataflowStorageId": dataflow_storage_id} 82 | 83 | content = self.power_bi_session.make_request( 84 | method="post", 85 | endpoint=f"myorg/groups/{group_id}/AssignToDataflowStorage", 86 | json_payload=payload, 87 | ) 88 | 89 | return content 90 | -------------------------------------------------------------------------------- /powerbi/dataflows.py: -------------------------------------------------------------------------------- 1 | """Module for the `Dataflows` service.""" 2 | 3 | from enum import Enum 4 | 5 | from powerbi.session import PowerBiSession 6 | 7 | 8 | class Dataflows: 9 | """Class for the `Dataflows` service.""" 10 | 11 | def __init__(self, session: object) -> None: 12 | """Initializes the `Dataflows` service. 13 | 14 | ### Parameters 15 | ---- 16 | session : object 17 | An authenticated session for our Microsoft PowerBi Client. 18 | 19 | ### Usage 20 | ---- 21 | >>> groups_service = power_bi_client.dataflow() 22 | """ 23 | 24 | # Set the session. 25 | self.power_bi_session: PowerBiSession = session 26 | 27 | def get_dataflows(self, group_id: str) -> dict: 28 | """Returns a list of all dataflows from the 29 | specified workspace. 30 | 31 | ### Parameters 32 | ---- 33 | group_id : str 34 | The Workspace ID. 35 | 36 | ### Returns 37 | ------- 38 | Dict 39 | A collection of `Dataflow` resources. 40 | 41 | ### Usage 42 | ---- 43 | >>> dataflows_service = power_bi_client.dataflows() 44 | >>> dataflows_service.get_dataflows( 45 | group_id='' 46 | ) 47 | """ 48 | 49 | content = self.power_bi_session.make_request( 50 | method="get", endpoint=f"myorg/groups/{group_id}/dataflows" 51 | ) 52 | 53 | return content 54 | 55 | def get_dataflow(self, group_id: str, dataflow_id: str) -> dict: 56 | """Exports the specified dataflow definition to a JSON file. 57 | 58 | ### Parameters 59 | ---- 60 | group_id : str 61 | The Workspace ID. 62 | 63 | dataflow_id : str 64 | The dataflow ID. 65 | 66 | ### Returns 67 | ------- 68 | Dict 69 | A collection of `Dataflow` resources. 70 | 71 | ### Usage 72 | ---- 73 | >>> dataflows_service = power_bi_client.dataflows() 74 | >>> dataflows_service.get_dataflow( 75 | group_id='' 76 | dataflow_id='' 77 | ) 78 | """ 79 | 80 | content = self.power_bi_session.make_request( 81 | method="get", endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}" 82 | ) 83 | 84 | return content 85 | 86 | def get_dataflow_transactions(self, group_id: str, dataflow_id: str) -> dict: 87 | """Returns a list of transactions for the specified dataflow. 88 | 89 | ### Parameters 90 | ---- 91 | group_id : str 92 | The Workspace ID. 93 | 94 | dataflow_id : str 95 | The dataflow ID. 96 | 97 | ### Returns 98 | ------- 99 | Dict 100 | A collection of `DataflowTransactions` resources. 101 | 102 | ### Usage 103 | ---- 104 | >>> dataflows_service = power_bi_client.dataflows() 105 | >>> dataflows_service.get_dataflow_transactions( 106 | group_id='' 107 | dataflow_id='' 108 | ) 109 | """ 110 | 111 | content = self.power_bi_session.make_request( 112 | method="get", 113 | endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}/transactions", 114 | ) 115 | 116 | return content 117 | 118 | def get_dataflow_datasources(self, group_id: str, dataflow_id: str) -> dict: 119 | """Returns a list of data sources for the specified dataflow. 120 | 121 | ### Parameters 122 | ---- 123 | group_id : str 124 | The Workspace ID. 125 | 126 | dataflow_id : str 127 | The dataflow ID. 128 | 129 | ### Returns 130 | ------- 131 | Dict 132 | A collection of `Datasource` resources. 133 | 134 | ### Usage 135 | ---- 136 | >>> dataflows_service = power_bi_client.dataflows() 137 | >>> dataflows_service.get_dataflow_datasources( 138 | group_id='' 139 | dataflow_id='' 140 | ) 141 | """ 142 | 143 | content = self.power_bi_session.make_request( 144 | method="get", 145 | endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}/datasources", 146 | ) 147 | 148 | return content 149 | 150 | def delete_dataflow(self, group_id: str, dataflow_id: str) -> None: 151 | """Deletes a dataflow from Power BI data prep storage, including 152 | its definition file and model. 153 | 154 | ### Parameters 155 | ---- 156 | group_id : str 157 | The Workspace ID. 158 | 159 | dataflow_id : str 160 | The dataflow ID. 161 | 162 | ### Usage 163 | ---- 164 | >>> dataflows_service = power_bi_client.dataflows() 165 | >>> dataflows_service.delete_dataflow( 166 | group_id='' 167 | dataflow_id='' 168 | ) 169 | """ 170 | 171 | content = self.power_bi_session.make_request( 172 | method="delete", endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}" 173 | ) 174 | 175 | return content 176 | 177 | def update_refresh_schedule( 178 | self, group_id: str, dataflow_id: str, refresh_schedule: dict 179 | ) -> None: 180 | """Creates or updates the refresh schedule for a specified dataflow. 181 | 182 | ### Parameters 183 | ---- 184 | group_id : str 185 | The group ID. 186 | 187 | dataflow_id : str 188 | The dataflow ID. 189 | 190 | refresh_schedule : dict 191 | The refresh schedule. 192 | 193 | ### Returns 194 | ------- 195 | None 196 | 197 | ### Usage 198 | ---- 199 | >>> dataflows_service = power_bi_client.dataflows() 200 | >>> dataflows_service.get_dataflows( 201 | group_id='', 202 | dataflow_id='', 203 | refresh_schedule={} 204 | ) 205 | """ 206 | 207 | content = self.power_bi_session.make_request( 208 | method="patch", 209 | json_payload=refresh_schedule, 210 | endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}/refreshSchedule", 211 | ) 212 | 213 | return content 214 | 215 | def get_upstream_dataflows_in_group(self, group_id: str, dataflow_id: str) -> dict: 216 | """Returns a list of upstream dataflows in the specified workspace. 217 | 218 | ### Parameters 219 | ---- 220 | group_id : str 221 | The Workspace ID. 222 | 223 | dataflow_id : str 224 | The dataflow ID. 225 | 226 | ### Returns 227 | ------- 228 | dict 229 | A collection of `DependentDataflows` resources. 230 | 231 | ### Usage 232 | ---- 233 | >>> dataflows_service = power_bi_client.dataflows() 234 | >>> dataflows_service.get_upstream_dataflows_in_group( 235 | group_id='' 236 | dataflow_id='' 237 | ) 238 | """ 239 | 240 | content = self.power_bi_session.make_request( 241 | method="get", 242 | endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}/upstreamDataflows", 243 | ) 244 | 245 | return content 246 | 247 | def refresh_dataflow( 248 | self, 249 | group_id: str, 250 | dataflow_id: str, 251 | notify_option: str | Enum, 252 | process_type: str = None, 253 | ) -> None: 254 | """Triggers a refresh for the specified dataflow. 255 | 256 | ### Parameters 257 | ---- 258 | group_id : str 259 | The Workspace ID. 260 | 261 | dataflow_id : str 262 | The dataflow ID. 263 | 264 | notify_option : str | Enum 265 | Mail notification options. 266 | 267 | process_type : str 268 | Type of refresh process to use. 269 | 270 | ### Returns 271 | ------- 272 | dict 273 | A `DataflowTransactionStatus` resource. 274 | 275 | ### Usage 276 | ---- 277 | >>> dataflows_service = power_bi_client.dataflows() 278 | >>> dataflows_service.refresh_dataflow( 279 | group_id='' 280 | dataflow_id='', 281 | notify_option='MailOnFailure' 282 | ) 283 | """ 284 | 285 | if process_type: 286 | params = {"processType": process_type} 287 | else: 288 | params = {} 289 | 290 | # Check if the notify option is an enum. 291 | if isinstance(notify_option, Enum): 292 | notify_option = notify_option.value 293 | 294 | body = {"notifyOption": notify_option} 295 | 296 | content = self.power_bi_session.make_request( 297 | method="post", 298 | endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}/refreshes", 299 | params=params, 300 | json_payload=body, 301 | ) 302 | 303 | return content 304 | 305 | def cancel_dataflow_transaction(self, group_id: str, transaction_id: str) -> None: 306 | """Attempts to cancel the specified transactions. 307 | 308 | ### Parameters 309 | ---- 310 | group_id : str 311 | The Workspace ID. 312 | 313 | transaction_id : str 314 | The transaction ID. 315 | 316 | ### Returns 317 | ------- 318 | dict 319 | A `DataflowTransactionStatus` resource. 320 | 321 | ### Usage 322 | ---- 323 | >>> dataflows_service = power_bi_client.dataflows() 324 | >>> dataflows_service.cancel_dataflow_transaction( 325 | group_id='' 326 | transaction_id='' 327 | ) 328 | """ 329 | 330 | content = self.power_bi_session.make_request( 331 | method="post", 332 | endpoint=f"myorg/groups/{group_id}/dataflowTransactions/{transaction_id}/cancel", 333 | ) 334 | 335 | return content 336 | 337 | def update_dataflow( 338 | self, 339 | group_id: str, 340 | dataflow_id: str, 341 | allow_native_queries: bool = None, 342 | compute_engine_behavior: str | Enum = None, 343 | description: str = None, 344 | name: str = None, 345 | ) -> None: 346 | """Updates dataflow properties, capabilities and settings. 347 | 348 | ### Parameters 349 | ---- 350 | group_id : str 351 | The Workspace ID. 352 | 353 | dataflow_id : str 354 | The dataflow ID. 355 | 356 | allow_native_queries : bool 357 | Whether to allow native queries. 358 | 359 | compute_engine_behavior : str | Enum 360 | The behavior of the compute engine. 361 | 362 | description : str 363 | The new description for the dataflow. 364 | 365 | name : str 366 | The new name for the dataflow. 367 | 368 | ### Usage 369 | ---- 370 | >>> dataflows_service = power_bi_client.dataflows() 371 | >>> dataflows_service.update_dataflow( 372 | group_id='' 373 | dataflow_id='', 374 | allow_native_queries=True, 375 | compute_engine_behavior='computeOptimized', 376 | description='', 377 | name='' 378 | ) 379 | """ 380 | 381 | if compute_engine_behavior and isinstance(compute_engine_behavior, Enum): 382 | compute_engine_behavior = compute_engine_behavior.value 383 | 384 | body = { 385 | "allowNativeQueries": allow_native_queries, 386 | "computeEngineBehavior": compute_engine_behavior, 387 | "description": description, 388 | "name": name, 389 | } 390 | 391 | content = self.power_bi_session.make_request( 392 | method="patch", 393 | json_payload=body, 394 | endpoint=f"myorg/groups/{group_id}/dataflows/{dataflow_id}", 395 | ) 396 | 397 | return content 398 | -------------------------------------------------------------------------------- /powerbi/datasets.py: -------------------------------------------------------------------------------- 1 | """Module for the Power BI `Datasets` service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class Datasets: 8 | """Class for the `Datasets` service.""" 9 | 10 | def __init__(self, session: object) -> None: 11 | """Initializes the `Datasets` service. 12 | 13 | ### Parameters 14 | ---- 15 | session : object 16 | An authenticated session for our Microsoft PowerBi Client. 17 | 18 | ### Usage 19 | ---- 20 | >>> datasets_service = power_bi_client.datasets() 21 | """ 22 | 23 | # Set the session. 24 | self.power_bi_session: PowerBiSession = session 25 | 26 | # Set the endpoint. 27 | self.endpoint = "myorg/groups/{group_id}/datasets" 28 | 29 | def get_datasets_in_group(self, group_id: str) -> Dict: 30 | """Returns a list of datasets in a group. 31 | 32 | ### Returns 33 | ------- 34 | Dict 35 | A collection of `Dataset` resources. 36 | 37 | ### Usage 38 | ---- 39 | >>> datasets_service = power_bi_client.datasets() 40 | >>> datasets_service.get_datasets_in_group(group_id='') 41 | """ 42 | 43 | content = self.power_bi_session.make_request( 44 | method="get", endpoint=f"myorg/groups/{group_id}/datasets" 45 | ) 46 | 47 | return content 48 | 49 | def update_refresh_schedule_in_group( 50 | self, group_id: str, dataset_id: str, refresh_schedule: dict 51 | ) -> None: 52 | """Creates or updates the refresh schedule for a specified dataset. 53 | 54 | ### Parameters 55 | ---- 56 | group_id : str 57 | The group ID. 58 | 59 | dataset_id : str 60 | The dataset ID. 61 | 62 | refresh_schedule : dict 63 | The refresh schedule. 64 | 65 | ### Returns 66 | ------- 67 | None 68 | 69 | ### Usage 70 | ---- 71 | >>> dataset_service = power_bi_client.datasets() 72 | >>> dataset_service.get_dataflows( 73 | group_id='', 74 | dataset_id='', 75 | refresh_schedule={} 76 | ) 77 | """ 78 | 79 | content = self.power_bi_session.make_request( 80 | method="patch", 81 | json_payload=refresh_schedule, 82 | endpoint=f"myorg/groups/{group_id}/datasets/{ 83 | dataset_id}/refreshSchedule", 84 | ) 85 | 86 | return content 87 | 88 | def bind_to_gateway( 89 | self, 90 | dataset_id: str, 91 | gateway_object_id: str, 92 | datasource_object_ids: list = None, 93 | ) -> None: 94 | """Binds a dataset to a specified gateway. 95 | 96 | ### Parameters 97 | ---- 98 | dataset_id : str 99 | The ID of the dataset to bind. 100 | 101 | gateway_object_id : str 102 | The ID of the gateway to bind the dataset to. When using a gateway cluster, 103 | this refers to the primary gateway. 104 | 105 | datasource_object_ids : list, (optional, default=None) 106 | A list of unique identifiers for the data sources in the gateway. 107 | 108 | ### Returns 109 | ------- 110 | None 111 | 112 | ### Usage 113 | ---- 114 | >>> dataset_service = power_bi_client.datasets() 115 | >>> dataset_service.bind_to_gateway( 116 | dataset_id='cfafbeb1-8037-4d0c-896e-a46fb27ff229', 117 | gateway_object_id='1f69e798-5852-4fdd-ab01-33bb14b6e934', 118 | datasource_object_ids=[ 119 | 'dc2f2dac-e5e2-4c37-af76-2a0bc10f16cb', 120 | '3bfe5d33-ab7d-4d24-b0b5-e2bb8eb01cf5' 121 | ] 122 | ) 123 | """ 124 | 125 | # Prepare the payload. 126 | payload = {"gatewayObjectId": gateway_object_id} 127 | 128 | # Add datasource IDs if provided. 129 | if datasource_object_ids: 130 | payload["datasourceObjectIds"] = datasource_object_ids 131 | 132 | # Make the API call. 133 | response = self.power_bi_session.make_request( 134 | method="post", 135 | json_payload=payload, 136 | endpoint=f"myorg/datasets/{dataset_id}/Default.BindToGateway", 137 | ) 138 | 139 | return response 140 | 141 | def bind_to_gateway_in_group( 142 | self, 143 | group_id: str, 144 | dataset_id: str, 145 | gateway_object_id: str, 146 | datasource_object_ids: list = None, 147 | ) -> None: 148 | """Binds a dataset in a specified workspace to a specified gateway. 149 | 150 | ### Parameters 151 | ---- 152 | group_id : str 153 | The ID of the workspace containing the dataset. 154 | 155 | dataset_id : str 156 | The ID of the dataset to bind. 157 | 158 | gateway_object_id : str 159 | The ID of the gateway to bind the dataset to. When using a gateway cluster, 160 | this refers to the primary gateway. 161 | 162 | datasource_object_ids : list, optional 163 | A list of unique identifiers for the data sources in the gateway. 164 | 165 | ### Returns 166 | ------- 167 | None 168 | 169 | ### Usage 170 | ---- 171 | >>> dataset_service = power_bi_client.datasets() 172 | >>> dataset_service.bind_to_gateway_in_group( 173 | group_id='f089354e-8366-4e18-aea3-4cb4a3a50b48', 174 | dataset_id='cfafbeb1-8037-4d0c-896e-a46fb27ff229', 175 | gateway_object_id='1f69e798-5852-4fdd-ab01-33bb14b6e934', 176 | datasource_object_ids=[ 177 | 'dc2f2dac-e5e2-4c37-af76-2a0bc10f16cb', 178 | '3bfe5d33-ab7d-4d24-b0b5-e2bb8eb01cf5' 179 | ] 180 | ) 181 | """ 182 | 183 | # Prepare the payload. 184 | payload = {"gatewayObjectId": gateway_object_id} 185 | 186 | # Add datasource IDs if provided. 187 | if datasource_object_ids: 188 | payload["datasourceObjectIds"] = datasource_object_ids 189 | 190 | # Make the API call. 191 | response = self.power_bi_session.make_request( 192 | method="post", 193 | json_payload=payload, 194 | endpoint=f"myorg/groups/{group_id}/datasets/{ 195 | dataset_id}/Default.BindToGateway", 196 | ) 197 | 198 | return response 199 | 200 | def cancel_refresh(self, dataset_id: str, refresh_id: str) -> None: 201 | """Cancels the specified refresh operation for the specified dataset. 202 | 203 | ### Parameters 204 | ---- 205 | dataset_id : str 206 | The ID of the dataset. 207 | 208 | refresh_id : str 209 | The ID of the refresh operation to cancel. 210 | 211 | ### Returns 212 | ------- 213 | None 214 | 215 | ### Usage 216 | ---- 217 | >>> dataset_service = power_bi_client.datasets() 218 | >>> dataset_service.cancel_refresh( 219 | dataset_id='f7fc6510-e151-42a3-850b-d0805a391db0', 220 | refresh_id='87f31ef7-1e3a-4006-9b0b-191693e79e9e' 221 | ) 222 | """ 223 | 224 | # Make the API call. 225 | response = self.power_bi_session.make_request( 226 | method="delete", 227 | endpoint=f"myorg/datasets/{dataset_id}/refreshes/{refresh_id}", 228 | ) 229 | 230 | return response 231 | 232 | def cancel_refresh_in_group( 233 | self, group_id: str, dataset_id: str, refresh_id: str 234 | ) -> None: 235 | """Cancels the specified refresh operation for the specified dataset in a workspace. 236 | 237 | ### Parameters 238 | ---- 239 | group_id : str 240 | The ID of the workspace containing the dataset. 241 | 242 | dataset_id : str 243 | The ID of the dataset. 244 | 245 | refresh_id : str 246 | The ID of the refresh operation to cancel. 247 | 248 | ### Returns 249 | ------- 250 | None 251 | 252 | ### Usage 253 | ---- 254 | >>> dataset_service = power_bi_client.datasets() 255 | >>> dataset_service.cancel_refresh_in_group( 256 | group_id='fdb91b8f-0a9b-44c1-b6c0-0cb185c6ebfb', 257 | dataset_id='f7fc6510-e151-42a3-850b-d0805a391db0', 258 | refresh_id='87f31ef7-1e3a-4006-9b0b-191693e79e9e' 259 | ) 260 | """ 261 | 262 | # Make the API call. 263 | response = self.power_bi_session.make_request( 264 | method="delete", 265 | endpoint=f"myorg/groups/{group_id}/datasets/{dataset_id}/refreshes/{refresh_id}", 266 | ) 267 | 268 | return response 269 | 270 | def delete_dataset(self, dataset_id: str) -> None: 271 | """Deletes the specified dataset from My workspace. 272 | 273 | ### Parameters 274 | ---- 275 | dataset_id : str 276 | The ID of the dataset to delete. 277 | 278 | ### Returns 279 | ------- 280 | None 281 | 282 | ### Usage 283 | ---- 284 | >>> dataset_service = power_bi_client.datasets() 285 | >>> dataset_service.delete_dataset( 286 | dataset_id='cfafbeb1-8037-4d0c-896e-a46fb27ff229' 287 | ) 288 | """ 289 | 290 | # Make the API call. 291 | response = self.power_bi_session.make_request( 292 | method="delete", endpoint=f"myorg/datasets/{dataset_id}" 293 | ) 294 | 295 | return response 296 | 297 | def delete_dataset_in_group(self, group_id: str, dataset_id: str) -> None: 298 | """Deletes the specified dataset from the specified workspace. 299 | 300 | ### Parameters 301 | ---- 302 | group_id : str 303 | The ID of the workspace containing the dataset. 304 | 305 | dataset_id : str 306 | The ID of the dataset to delete. 307 | 308 | ### Returns 309 | ------- 310 | None 311 | 312 | ### Usage 313 | ---- 314 | >>> dataset_service = power_bi_client.datasets() 315 | >>> dataset_service.delete_dataset_in_group( 316 | group_id='f089354e-8366-4e18-aea3-4cb4a3a50b48', 317 | dataset_id='cfafbeb1-8037-4d0c-896e-a46fb27ff229' 318 | ) 319 | """ 320 | 321 | # Make the API call. 322 | response = self.power_bi_session.make_request( 323 | method="delete", endpoint=f"myorg/groups/{group_id}/datasets/{dataset_id}" 324 | ) 325 | 326 | return response 327 | -------------------------------------------------------------------------------- /powerbi/enums.py: -------------------------------------------------------------------------------- 1 | """Power BI Python SDK Enums""" 2 | 3 | from enum import Enum 4 | 5 | 6 | class ColumnDataTypes(Enum): 7 | """Represents all the data types you can use 8 | when creating a new column in a `PowerBiTable`. 9 | 10 | ### Usage: 11 | ---- 12 | >>> from powerbi.enums import ColumnDataTypes 13 | >>> ColumnDataTypes.INT64.value 14 | """ 15 | 16 | INT64 = "Int64" 17 | DOUBLE = "Double" 18 | BOOLEAN = "bool" 19 | DATETIME = "DateTime" 20 | STRING = "string" 21 | DECIMAL = "Decimal" 22 | 23 | 24 | class ColumnAggregationMethods(Enum): 25 | """Represents all the aggregation methods you can 26 | use when creating aggregating a new column in a 27 | `PowerBiTable`. 28 | 29 | ### Usage: 30 | ---- 31 | >>> from powerbi.enums import ColumnAggregationMethods 32 | >>> ColumnAggregationMethods.COUNT.value 33 | """ 34 | 35 | DEFAULT = "default" 36 | NULL = "none" 37 | SUM = "sum" 38 | MIN = "min" 39 | MAX = "max" 40 | COUNT = "count" 41 | AVERAGE = "average" 42 | DISTINCT_COUNT = "distinctCount" 43 | 44 | 45 | class DatasetModes(Enum): 46 | """Represents all the dataset modes you can 47 | use when creating a new `PowerBiDataset` 48 | 49 | ### Usage: 50 | ---- 51 | >>> from powerbi.enums import DatasetModes 52 | >>> DatasetModes.AS_AZURE.value 53 | """ 54 | 55 | AS_AZURE = "AsAzure" 56 | AS_ON_PREM = "AsOnPrem" 57 | PUSH = "Push" 58 | PUSH_STREAMING = "PushStreaming" 59 | STREAMING = "Streaming" 60 | 61 | 62 | class DataSourceType(Enum): 63 | """Represents all the datasource type you can 64 | use when creating a new `PowerBiDataset` 65 | 66 | ### Usage: 67 | ---- 68 | >>> from powerbi.enums import DataSourceType 69 | >>> DataSourceType.SQL.value 70 | """ 71 | 72 | ANALYSIS_SERVICES = "AnalysisServices" 73 | SQL = "Sql" 74 | FILE = "File" 75 | ODATA = "OData" 76 | ORACLE = "Oracle" 77 | SAP_HANA = "SAPHana" 78 | SHAREPOINT_LIST = "SharePointList" 79 | 80 | 81 | class GroupUserAccessRights(Enum): 82 | """Represents all the GroupUserAccessRights type you can 83 | use when creating a new `PowerBiGroupUser`. 84 | 85 | For more info, go to: 86 | https://docs.microsoft.com/en-us/rest/api/power-bi/groups/addgroupuser#groupuseraccessright 87 | 88 | ### Usage: 89 | ---- 90 | >>> from powerbi.enums import GroupUserAccessRights 91 | >>> GroupUserAccessRights.ADMIN.value 92 | """ 93 | 94 | ADMIN = "Admin" 95 | CONTRIBUTOR = "Contributor" 96 | MEMBER = "Member" 97 | REMOVE = None 98 | VIEWER = "Viewer" 99 | 100 | 101 | class PrincipalType(Enum): 102 | """Represents all the PrincipalTypes you can 103 | use when creating a new `PowerBiGroupUser`. 104 | 105 | For more info, go to: 106 | https://docs.microsoft.com/en-us/rest/api/power-bi/groups/addgroupuser#principaltype 107 | 108 | ### Usage: 109 | ---- 110 | >>> from powerbi.enums import PrincipalType 111 | >>> PrincipalType.APP.value 112 | """ 113 | 114 | APP = "App" 115 | GROUP = "Group" 116 | USER = "User" 117 | NONE = "None" 118 | 119 | 120 | class ImportConflictHandlerMode(Enum): 121 | """Represents all the ImportConflictHandlerMode you can 122 | use when creating a new `PowerBiImport`. 123 | 124 | ### Usage: 125 | ---- 126 | >>> from powerbi.enums import ImportConflictHandlerMode 127 | >>> ImportConflictHandlerMode.ABORT.value 128 | """ 129 | 130 | ABORT = "Abort" 131 | CREATE_OR_OVERWRITE = "CreateOrOverwrite" 132 | GENERATE_UNIQUE_NAME = "GenerateUniqueName" 133 | IGNORE = "Ignore" 134 | OVERWRITE = "Overwrite" 135 | 136 | 137 | class ExportFileFormats(Enum): 138 | """Represents all the File Formats you can 139 | export a `PowerBiReport` to. 140 | 141 | ### Usage: 142 | ---- 143 | >>> from powerbi.enums import ExportFileFormats 144 | >>> ExportFileFormats.PDF.value 145 | """ 146 | 147 | ACCESSIBLE_PDF = "ACCESSIBLEPDF" 148 | CSV = "CSV" 149 | DOCX = "DOCX" 150 | IMAGE = "IMAGE" 151 | MHTML = "MHTML" 152 | PDF = "PDF" 153 | PNG = "PNG" 154 | PPTX = "PPTX" 155 | XLSX = "XLSX" 156 | XML = "XML" 157 | 158 | 159 | class GatewayDataSourceAccessRights(Enum): 160 | """Represents all the Gateway Data Source Access Rights you can 161 | use when creating a new `PowerBiGatewayDataSourceUser`. 162 | 163 | ### Usage: 164 | ---- 165 | >>> from powerbi.enums import GatewayDataSourceAccessRights 166 | >>> GatewayDataSourceAccessRights.READ.value 167 | """ 168 | 169 | READ = "Read" 170 | READ_OVERRIDE_EFFECTIVE_IDENTITY = "ReadOverrideEffectiveIdentity" 171 | NONE = None 172 | 173 | 174 | class GatewayPrincipalType(Enum): 175 | """Represents all the Gateway Principal Types you can 176 | use when creating a new `PowerBiGatewayDataSourceUser`. 177 | 178 | ### Usage: 179 | ---- 180 | >>> from powerbi.enums import GatewayPrincipalType 181 | >>> GatewayPrincipalType.APP.value 182 | """ 183 | 184 | APP = "App" 185 | GROUP = "Group" 186 | NONE = "None" 187 | USER = "User" 188 | 189 | 190 | class GatewayServicePrincipalProfile(Enum): 191 | """Represents all the Gateway ServicePrincipalProfile you can 192 | use when creating a new `PowerBiGatewayDataSourceUser`. 193 | 194 | ### Usage: 195 | ---- 196 | >>> from powerbi.enums import GatewayServicePrincipalProfile 197 | >>> GatewayServicePrincipalProfile.DISPLAY_NAME.value 198 | """ 199 | 200 | DISPLAY_NAME = "displayName" 201 | ID = "id" 202 | 203 | 204 | class CredentialTypes(Enum): 205 | """Represents all the Credential Types you can 206 | use when creating a new `PowerBiGatewayDataSource`. 207 | 208 | ### Usage: 209 | ---- 210 | >>> from powerbi.enums import CredentialTypes 211 | >>> CredentialTypes.BASIC.value 212 | """ 213 | 214 | ANONYMOUS = "Anonymous" 215 | BASIC = "Basic" 216 | KEY = "Key" 217 | OAUTH2 = "OAuth2" 218 | SAS = "SAS" 219 | WINDOWS = "Windows" 220 | 221 | 222 | class EncryptedConnections(Enum): 223 | """Represents all the Encrypted Connections you can 224 | use when creating a new `PowerBiGatewayDataSource`. 225 | 226 | ### Overview: 227 | ---- 228 | Whether to encrypt the data source connection. The API 229 | call will fail if you select encryption and Power BI 230 | is unable to establish an encrypted connection with 231 | the data source. 232 | 233 | ### Usage: 234 | ---- 235 | >>> from powerbi.enums import EncryptedConnections 236 | >>> EncryptedConnections.ENCRYPTED.value 237 | """ 238 | 239 | ENCRYPTED = "Encrypted" 240 | NOT_ENCRYPTED = "NotEncrypted" 241 | 242 | 243 | class EncryptionAlgorithm(Enum): 244 | """Represents all the Encryption Algorithm you can 245 | use when creating a new `PowerBiGatewayDataSource`. 246 | 247 | ### Usage: 248 | ---- 249 | >>> from powerbi.enums import EncryptionAlgorithm 250 | >>> EncryptionAlgorithm.RSA_OAEP.value 251 | """ 252 | 253 | NONE = "None" 254 | RSA_OAEP = "RSA-OAEP" 255 | 256 | 257 | class PrivacyLevels(Enum): 258 | """Represents all the Privacy Levels you can 259 | use when creating a new `PowerBiGatewayDataSource`. 260 | 261 | ### Usage: 262 | ---- 263 | >>> from powerbi.enums import PrivacyLevels 264 | >>> PrivacyLevels.PUBLIC.value 265 | """ 266 | 267 | PUBLIC = "Public" 268 | ORGANIZATIONAL = "Organizational" 269 | PRIVATE = "Private" 270 | NONE = "None" 271 | 272 | 273 | class WorkloadStates(Enum): 274 | """Represents all the Workload States you can 275 | use when patching a workload in a capacity. 276 | 277 | ### Usage: 278 | ---- 279 | >>> from powerbi.enums import WorkloadStates 280 | >>> WorkloadStates.ENABLED.value 281 | """ 282 | 283 | ENABLED = "Enabled" 284 | DISABLED = "Disabled" 285 | UNSUPPORTED = "Unsupported" 286 | 287 | 288 | class NotifyOption(Enum): 289 | """Represents all the Mail notification options you 290 | can use when refreshing a Dataflow. 291 | 292 | ### Usage: 293 | ---- 294 | >>> from powerbi.enums import WorkloadStates 295 | >>> NotifyOption.MAIL_ON_COMPLETION.value 296 | """ 297 | 298 | MAIL_ON_COMPLETION = "MailOnCompletion" 299 | MAIL_ON_FAILURE = "MailOnFailure" 300 | NO_NOTIFICATION = "NoNotification" 301 | 302 | 303 | class ComputeEngineBehavior(Enum): 304 | """Represents all the Compute Engine Behavior you 305 | can use when creating a new `PowerBiDataflow`. 306 | 307 | ### Usage: 308 | ---- 309 | >>> from powerbi.enums import computeEngineBehavior 310 | >>> computeEngineBehavior.COMPUTE_OPTIMIZED.value 311 | """ 312 | 313 | COMPUTE_OPTIMIZED = "computeOptimized" 314 | COMPUTE_ON = "computeOn" 315 | COMPUTE_DISABLED = "computeDisabled" 316 | -------------------------------------------------------------------------------- /powerbi/gateways.py: -------------------------------------------------------------------------------- 1 | """Module for the `Gateways` service.""" 2 | 3 | from enum import Enum 4 | 5 | from powerbi.session import PowerBiSession 6 | from powerbi.utils import CredentialDetails 7 | 8 | 9 | class Gateways: 10 | """The `Gateways` service allows you to manage Gateways 11 | in Microsoft PowerBi.""" 12 | 13 | def __init__(self, session: object) -> None: 14 | """Initializes the `Gateways` service. 15 | 16 | ### Parameters 17 | ---- 18 | session : object 19 | An authenticated session for our Microsoft PowerBi Client. 20 | 21 | ### Usage 22 | ---- 23 | >>> gateways_service = power_bi_client.gateways() 24 | """ 25 | 26 | # Set the session. 27 | self.power_bi_session: PowerBiSession = session 28 | 29 | def add_datasource_user( 30 | self, 31 | gateway_id: str, 32 | datasource_id: str, 33 | data_source_access_right: str | Enum, 34 | display_name: str = None, 35 | email_address: str = None, 36 | identifier: str = None, 37 | principal_type: str | Enum = None, 38 | profile: str | Enum = None, 39 | ) -> None: 40 | """Grants or updates the permissions required to use the 41 | specified data source for the specified user. 42 | 43 | ### Parameters 44 | ---- 45 | gateway_id : str 46 | The gateway ID. When using a gateway cluster, the gateway ID refers to 47 | the primary (first) gateway in the cluster. In such cases, gateway ID 48 | is similar to gateway cluster ID. 49 | 50 | datasource_id : str 51 | The data source ID. 52 | 53 | data_source_access_right : str | Enum 54 | The access right (permission level) that a user has on the data source. 55 | 56 | display_name : str, optional 57 | The display name of the principal. 58 | 59 | email_address : str, optional 60 | The email address of the user. 61 | 62 | identifier : str, optional 63 | The object ID of the principal. 64 | 65 | principal_type : str | Enum, optional 66 | The principal type. 67 | 68 | profile : str | Enum, optional 69 | A Power BI service principal profile. Only 70 | relevant for Power BI Embedded multi-tenancy 71 | solution. 72 | 73 | ### Usage 74 | ---- 75 | >>> gateways_service = power_bi_client.gateways() 76 | >>> gateways_service.add_datasource_user( 77 | gateway_id="12345678-1234-1234-1234-123456789012", 78 | datasource_id="12345678-1234-1234-1234-123456789012", 79 | data_source_access_right="Read", 80 | ) 81 | """ 82 | 83 | if not isinstance(data_source_access_right, str): 84 | data_source_access_right = data_source_access_right.value 85 | 86 | if not isinstance(principal_type, str): 87 | principal_type = principal_type.value 88 | 89 | if not isinstance(profile, str): 90 | profile = profile.value 91 | 92 | # Define the payload. 93 | payload = { 94 | "datasourceAccessRight": data_source_access_right, 95 | "displayName": display_name, 96 | "emailAddress": email_address, 97 | "identifier": identifier, 98 | "principalType": principal_type, 99 | "profile": profile, 100 | } 101 | 102 | # Define the endpoint. 103 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}/users" 104 | 105 | # Make the request. 106 | content = self.power_bi_session.make_request( 107 | method="post", endpoint=endpoint, json_payload=payload 108 | ) 109 | 110 | return content 111 | 112 | def create_datasource( 113 | self, 114 | gateway_id: str, 115 | connection_details: str, 116 | credential_details: dict | CredentialDetails, 117 | data_source_name: str, 118 | data_source_type: str | Enum, 119 | ) -> dict: 120 | """Creates a new data source on the specified on-premises gateway. 121 | 122 | ### Parameters 123 | ---- 124 | gateway_id : str 125 | The gateway ID. When using a gateway cluster, the gateway ID refers to 126 | the primary (first) gateway in the cluster. In such cases, gateway ID 127 | is similar to gateway cluster ID. 128 | 129 | connection_details : str 130 | The connection details of the data source. 131 | 132 | credential_details : dict | CredentialDetails 133 | The credential details of the data source. 134 | 135 | data_source_name : str 136 | The data source name. 137 | 138 | data_source_type : str | Enum 139 | The data source type. 140 | 141 | ### Usage 142 | ---- 143 | >>> gateways_service = power_bi_client.gateways() 144 | >>> gateways_service.create_datasource( 145 | gateway_id="12345678-1234-1234-1234-123456789012", 146 | connection_details="{\"server\":\"MyServer\",\"database\":\"MyDatabase\"}", 147 | data_source_name="Sample Datasource", 148 | data_source_type="SQL", 149 | credential_details={ 150 | "credentialType": "Windows", 151 | "credentials": "AB....EF==", 152 | "encryptedConnection": "Encrypted", 153 | "encryptionAlgorithm": "RSA-OAEP", 154 | "privacyLevel": "None" 155 | } 156 | ) 157 | """ 158 | 159 | if not isinstance(data_source_type, str): 160 | data_source_type = data_source_type.value 161 | 162 | if not isinstance(credential_details, dict): 163 | credential_details = credential_details.to_dict() 164 | 165 | # Define the payload. 166 | payload = { 167 | "dataSourceType": data_source_type, 168 | "connectionDetails": connection_details, 169 | "credentialDetails": credential_details, 170 | "datasourceName": data_source_name, 171 | } 172 | 173 | # Define the endpoint. 174 | endpoint = f"myorg/gateways/{gateway_id}/datasources" 175 | 176 | # Make the request. 177 | content = self.power_bi_session.make_request( 178 | method="post", endpoint=endpoint, json_payload=payload 179 | ) 180 | 181 | return content 182 | 183 | def delete_datasource(self, gateway_id: str, datasource_id: str) -> None: 184 | """Deletes a data source from the specified on-premises gateway. 185 | 186 | ### Parameters 187 | ---- 188 | gateway_id : str 189 | The gateway ID. When using a gateway cluster, the gateway ID refers to 190 | the primary (first) gateway in the cluster. In such cases, gateway ID 191 | is similar to gateway cluster ID. 192 | 193 | datasource_id : str 194 | The data source ID. 195 | 196 | ### Usage 197 | ---- 198 | >>> gateways_service = power_bi_client.gateways() 199 | >>> gateways_service.delete_datasource( 200 | gateway_id="12345678-1234-1234-1234-123456789012", 201 | datasource_id="12345678-1234-1234-1234-123456789012" 202 | ) 203 | """ 204 | 205 | # Define the endpoint. 206 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}" 207 | 208 | # Make the request. 209 | content = self.power_bi_session.make_request(method="delete", endpoint=endpoint) 210 | 211 | return content 212 | 213 | def delete_datasource_user( 214 | self, 215 | gateway_id: str, 216 | datasource_id: str, 217 | email_address: str, 218 | profile_id: str = None, 219 | ) -> None: 220 | """Removes the specified user from the specified data source. 221 | 222 | ### Parameters 223 | ---- 224 | gateway_id : str 225 | The gateway ID. When using a gateway cluster, the gateway ID refers to 226 | the primary (first) gateway in the cluster. In such cases, gateway ID 227 | is similar to gateway cluster ID. 228 | 229 | datasource_id : str 230 | The data source ID. 231 | 232 | email_address : str 233 | The email address of the user. 234 | 235 | profile_id : str, optional 236 | The service principal profile ID to delete. 237 | 238 | ### Usage 239 | ---- 240 | >>> gateways_service = power_bi_client.gateways() 241 | >>> gateways_service.delete_datasource_user( 242 | gateway_id="12345678-1234-1234-1234-123456789012", 243 | datasource_id="12345678-1234-1234-1234-123456789012", 244 | email_address="jon.doe@email.com" 245 | ) 246 | """ 247 | 248 | # Define the endpoint. 249 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}/users/{email_address}" 250 | 251 | # Define the parameters. 252 | if profile_id is not None: 253 | params = {"profileId": profile_id} 254 | else: 255 | params = None 256 | 257 | # Make the request. 258 | content = self.power_bi_session.make_request( 259 | method="delete", endpoint=endpoint, params=params 260 | ) 261 | 262 | return content 263 | 264 | def get_datasource(self, gateway_id: str, datasource_id: str) -> dict: 265 | """Returns the specified data source from the specified gateway. 266 | 267 | ### Parameters 268 | ---- 269 | gateway_id : str 270 | The gateway ID. When using a gateway cluster, the gateway ID refers to 271 | the primary (first) gateway in the cluster. In such cases, gateway ID 272 | is similar to gateway cluster ID. 273 | 274 | datasource_id : str 275 | The data source ID. 276 | 277 | ### Usage 278 | ---- 279 | >>> gateways_service = power_bi_client.gateways() 280 | >>> gateways_service.get_datasource( 281 | gateway_id="12345678-1234-1234-1234-123456789012", 282 | datasource_id="12345678-1234-1234-1234-123456789012" 283 | ) 284 | """ 285 | 286 | # Define the endpoint. 287 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}" 288 | 289 | # Make the request. 290 | content = self.power_bi_session.make_request(method="get", endpoint=endpoint) 291 | 292 | return content 293 | 294 | def get_datasource_status(self, gateway_id: str, datasource_id: str) -> dict: 295 | """Checks the connectivity status of the specified data source from 296 | the specified gateway. 297 | 298 | ### Parameters 299 | ---- 300 | gateway_id : str 301 | The gateway ID. When using a gateway cluster, the gateway ID refers to 302 | the primary (first) gateway in the cluster. In such cases, gateway ID 303 | is similar to gateway cluster ID. 304 | 305 | datasource_id : str 306 | The data source ID. 307 | 308 | ### Usage 309 | ---- 310 | >>> gateways_service = power_bi_client.gateways() 311 | >>> gateways_service.get_datasource_status( 312 | gateway_id="12345678-1234-1234-1234-123456789012", 313 | datasource_id="12345678-1234-1234-1234-123456789012" 314 | ) 315 | """ 316 | 317 | # Define the endpoint. 318 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}/status" 319 | 320 | # Make the request. 321 | content = self.power_bi_session.make_request(method="get", endpoint=endpoint) 322 | 323 | return content 324 | 325 | def get_datasource_users(self, gateway_id: str, datasource_id: str) -> dict: 326 | """Returns a list of users who have access to the specified data source. 327 | 328 | ### Parameters 329 | ---- 330 | gateway_id : str 331 | The gateway ID. When using a gateway cluster, the gateway ID refers to 332 | the primary (first) gateway in the cluster. In such cases, gateway ID 333 | is similar to gateway cluster ID. 334 | 335 | datasource_id : str 336 | The data source ID. 337 | 338 | ### Usage 339 | ---- 340 | >>> gateways_service = power_bi_client.gateways() 341 | >>> gateways_service.get_datasource_users( 342 | gateway_id="12345678-1234-1234-1234-123456789012", 343 | datasource_id="12345678-1234-1234-1234-123456789012" 344 | ) 345 | """ 346 | 347 | # Define the endpoint. 348 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}/users" 349 | 350 | # Make the request. 351 | content = self.power_bi_session.make_request(method="get", endpoint=endpoint) 352 | 353 | return content 354 | 355 | def get_datasources(self, gateway_id: str) -> dict: 356 | """Returns a list of data sources from the specified gateway. 357 | 358 | ### Parameters 359 | ---- 360 | gateway_id : str 361 | The gateway ID. When using a gateway cluster, the gateway ID refers to 362 | the primary (first) gateway in the cluster. In such cases, gateway ID 363 | is similar to gateway cluster ID. 364 | 365 | ### Usage 366 | ---- 367 | >>> gateways_service = power_bi_client.gateways() 368 | >>> gateways_service.get_datasources( 369 | gateway_id="12345678-1234-1234-1234-123456789012" 370 | ) 371 | """ 372 | 373 | # Define the endpoint. 374 | endpoint = f"myorg/gateways/{gateway_id}/datasources" 375 | 376 | # Make the request. 377 | content = self.power_bi_session.make_request(method="get", endpoint=endpoint) 378 | 379 | return content 380 | 381 | def get_gateways(self) -> dict: 382 | """Returns a list of gateways for which the user is an admin. 383 | 384 | ### Usage 385 | ---- 386 | >>> gateways_service = power_bi_client.gateways() 387 | >>> gateways_service.get_gateways() 388 | """ 389 | 390 | # Define the endpoint. 391 | endpoint = "myorg/gateways" 392 | 393 | # Make the request. 394 | content = self.power_bi_session.make_request(method="get", endpoint=endpoint) 395 | 396 | return content 397 | 398 | def get_gateway(self, gateway_id: str) -> dict: 399 | """Returns the specified gateway. 400 | 401 | ### Parameters 402 | ---- 403 | gateway_id : str 404 | The gateway ID. When using a gateway cluster, the gateway ID refers to 405 | the primary (first) gateway in the cluster. In such cases, gateway ID 406 | is similar to gateway cluster ID. 407 | 408 | ### Usage 409 | ---- 410 | >>> gateways_service = power_bi_client.gateways() 411 | >>> gateways_service.get_gateway( 412 | gateway_id="12345678-1234-1234-1234-123456789012" 413 | ) 414 | """ 415 | 416 | # Define the endpoint. 417 | endpoint = f"myorg/gateways/{gateway_id}" 418 | 419 | # Make the request. 420 | content = self.power_bi_session.make_request(method="get", endpoint=endpoint) 421 | 422 | return content 423 | 424 | def update_datasource( 425 | self, 426 | gateway_id: str, 427 | datasource_id: str, 428 | credential_details: dict | CredentialDetails = None, 429 | ) -> dict: 430 | """Updates the credentials of the specified data source from the 431 | specified gateway. 432 | 433 | ### Parameters 434 | ---- 435 | gateway_id : str 436 | The gateway ID. When using a gateway cluster, the gateway ID refers to 437 | the primary (first) gateway in the cluster. In such cases, gateway ID 438 | is similar to gateway cluster ID. 439 | 440 | datasource_id : str 441 | The data source ID. 442 | 443 | credential_details : dict | CredentialDetails 444 | The credential details of the data source. 445 | 446 | ### Usage 447 | ---- 448 | >>> gateways_service = power_bi_client.gateways() 449 | >>> gateways_service.update_datasource( 450 | gateway_id="12345678-1234-1234-1234-123456789012", 451 | datasource_id="12345678-1234-1234-1234-123456789012", 452 | credential_details={ 453 | "credentialType": "Windows", 454 | "credentials": "AB....EF==", 455 | "encryptedConnection": "Encrypted", 456 | "encryptionAlgorithm": "RSA-OAEP", 457 | "privacyLevel": "None" 458 | } 459 | ) 460 | """ 461 | 462 | if not isinstance(credential_details, dict): 463 | credential_details = credential_details.to_dict() 464 | 465 | # Define the payload. 466 | payload = { 467 | "credentialDetails": credential_details, 468 | } 469 | 470 | # Define the endpoint. 471 | endpoint = f"myorg/gateways/{gateway_id}/datasources/{datasource_id}" 472 | 473 | # Make the request. 474 | content = self.power_bi_session.make_request( 475 | method="patch", endpoint=endpoint, json_payload=payload 476 | ) 477 | 478 | return content 479 | -------------------------------------------------------------------------------- /powerbi/groups.py: -------------------------------------------------------------------------------- 1 | """Module for the PowerBi `Groups` service.""" 2 | 3 | from enum import Enum 4 | from typing import Union 5 | from typing import Dict 6 | from powerbi.session import PowerBiSession 7 | 8 | 9 | class Groups: 10 | """Class for the `Groups` service.""" 11 | 12 | def __init__(self, session: object) -> None: 13 | """Initializes the `Groups` service. 14 | 15 | ### Parameters 16 | ---- 17 | session : object 18 | An authenticated session for our Microsoft PowerBi Client. 19 | 20 | ### Usage 21 | ---- 22 | >>> groups_service = power_bi_client.groups() 23 | """ 24 | 25 | # Set the session. 26 | self.power_bi_session: PowerBiSession = session 27 | 28 | # Set the endpoint. 29 | self.endpoint = "myorg/groups" 30 | 31 | def get_groups(self) -> Dict: 32 | """Returns a list of workspaces the user has access to. 33 | 34 | ### Returns 35 | ------- 36 | Dict 37 | A collection of `Group` resources. 38 | 39 | ### Usage 40 | ---- 41 | >>> groups_service = power_bi_client.groups() 42 | >>> groups_service.get_groups() 43 | """ 44 | 45 | content = self.power_bi_session.make_request( 46 | method="get", endpoint=self.endpoint 47 | ) 48 | 49 | return content 50 | 51 | def get_group_users(self, group_id: str) -> Dict: 52 | """Returns a list of users that have access to the specified workspace. 53 | 54 | ### Parameters 55 | ---- 56 | group_id : str 57 | The workspace ID. 58 | 59 | ### Returns 60 | ---- 61 | Dict 62 | A collection of `GroupUsers` resources. 63 | 64 | ### Usage 65 | ---- 66 | >>> groups_service = power_bi_client.groups() 67 | >>> groups_service.get_group_users( 68 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78' 69 | ) 70 | """ 71 | 72 | content = self.power_bi_session.make_request( 73 | method="get", endpoint=f"myorg/groups/{group_id}/users" 74 | ) 75 | 76 | return content 77 | 78 | def create_group(self, name: str, workspace_v2: bool = None) -> Dict: 79 | """Creates new workspace. 80 | 81 | ### Parameters 82 | ---- 83 | name : str 84 | The name of the workspace. 85 | 86 | workspace_v2 : bool (optional, Default=None) 87 | Preview feature: Create a workspace V2. The only 88 | supported value is true. 89 | 90 | ### Returns 91 | ---- 92 | Dict 93 | A `Group` resource. 94 | 95 | ### Usage 96 | ---- 97 | >>> groups_service = power_bi_client.groups() 98 | >>> groups_service.create_group( 99 | name='my-new-workspace', 100 | workspace_v2=True 101 | ) 102 | """ 103 | 104 | params = {"name": name} 105 | 106 | content = self.power_bi_session.make_request( 107 | method="post", 108 | endpoint=f"myorg/groups?workspaceV2={workspace_v2}", 109 | json_payload=params, 110 | ) 111 | 112 | return content 113 | 114 | def delete_group(self, group_id: str) -> None: 115 | """Deletes the specified workspace. 116 | 117 | ### Parameters 118 | ---- 119 | group_id : str 120 | The workspace ID. 121 | 122 | ### Usage 123 | ---- 124 | >>> groups_service = power_bi_client.groups() 125 | >>> groups_service.delete_group( 126 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78' 127 | ) 128 | """ 129 | 130 | content = self.power_bi_session.make_request( 131 | method="delete", endpoint=f"myorg/groups/{group_id}" 132 | ) 133 | 134 | return content 135 | 136 | def add_group_user( 137 | self, 138 | group_id: str, 139 | group_user_access_rights: Union[str, Enum], 140 | display_name: str = None, 141 | email_address: str = None, 142 | identifier: str = None, 143 | principal_type: Union[str, Enum] = None, 144 | ) -> None: 145 | """Grants the specified user permissions to the specified workspace. 146 | 147 | ### Parameters 148 | ---- 149 | group_id : str 150 | The workspace ID. 151 | 152 | group_user_access_rights : Union[str, Enum] 153 | Access rights user has for the workspace. 154 | 155 | display_name : str (optional, Default=None) 156 | Display name of the principal. 157 | 158 | email_address : str (optional, Default=None) 159 | Email address of the user. 160 | 161 | identifier : str (optional, Default=None) 162 | Object ID of the principal 163 | 164 | principal_type : str (optional, Default=None) 165 | The principal type. 166 | 167 | ### Usage 168 | ---- 169 | >>> groups_service = power_bi_client.groups() 170 | >>> groups_service.add_group_user( 171 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 172 | group_user_access_right='Admin', 173 | email_address='john@contoso.com' 174 | ) 175 | """ 176 | 177 | if isinstance(group_user_access_rights, Enum): 178 | group_user_access_rights = group_user_access_rights.value 179 | 180 | if isinstance(principal_type, Enum): 181 | principal_type = principal_type.value 182 | 183 | params = {} 184 | params["groupUserAccessRight"] = group_user_access_rights 185 | params["displayName"] = display_name 186 | params["emailAddress"] = email_address 187 | params["identifier"] = identifier 188 | params["principalType"] = principal_type 189 | 190 | content = self.power_bi_session.make_request( 191 | method="post", 192 | endpoint=f"myorg/groups/{group_id}/users", 193 | json_payload=params, 194 | ) 195 | 196 | return content 197 | 198 | def delete_group_user(self, group_id: str, email_address: str) -> None: 199 | """Deletes the specified user permissions from the specified workspace. 200 | 201 | ### Parameters 202 | ---- 203 | group_id : str 204 | The workspace ID. 205 | 206 | email_address : str 207 | Email address of the user. 208 | 209 | ### Usage 210 | ---- 211 | >>> groups_service = power_bi_client.groups() 212 | >>> groups_service.delete_group_user( 213 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 214 | email_address='john@contoso.com' 215 | ) 216 | """ 217 | 218 | content = self.power_bi_session.make_request( 219 | method="delete", endpoint=f"myorg/groups/{group_id}/users/{email_address}" 220 | ) 221 | 222 | return content 223 | 224 | def update_group_user( 225 | self, 226 | group_id: str, 227 | group_user_access_rights: Union[str, Enum], 228 | display_name: str = None, 229 | email_address: str = None, 230 | identifier: str = None, 231 | principal_type: Union[str, Enum] = None, 232 | ) -> None: 233 | """Update the specified user permissions to the specified workspace. 234 | 235 | ### Parameters 236 | ---- 237 | group_id : str 238 | The workspace ID. 239 | 240 | group_user_access_rights : Union[str, Enum] 241 | Access rights user has for the workspace. 242 | 243 | display_name : str (optional, Default=None) 244 | Display name of the principal. 245 | 246 | email_address : str (optional, Default=None) 247 | Email address of the user. 248 | 249 | identifier : str (optional, Default=None) 250 | Object ID of the principal 251 | 252 | principal_type : str (optional, Default=None) 253 | The principal type. 254 | 255 | ### Usage 256 | ---- 257 | >>> groups_service = power_bi_client.groups() 258 | >>> groups_service.update_group_user( 259 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 260 | group_user_access_right='Admin', 261 | email_address='john@contoso.com' 262 | ) 263 | """ 264 | 265 | if isinstance(group_user_access_rights, Enum): 266 | group_user_access_rights = group_user_access_rights.value 267 | 268 | if isinstance(principal_type, Enum): 269 | principal_type = principal_type.value 270 | 271 | params = {} 272 | params["groupUserAccessRight"] = group_user_access_rights 273 | params["displayName"] = display_name 274 | params["emailAddress"] = email_address 275 | params["identifier"] = identifier 276 | params["principalType"] = principal_type 277 | 278 | content = self.power_bi_session.make_request( 279 | method="post", 280 | endpoint=f"myorg/groups/{group_id}/users", 281 | json_payload=params, 282 | ) 283 | 284 | return content 285 | -------------------------------------------------------------------------------- /powerbi/import.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class ImportBuilder(): 4 | 5 | def __init__(self, file_type: str) -> None: 6 | 7 | self.allowed_file_types = [ 8 | 'xlsx', 9 | 'json', 10 | 'pbix', 11 | 'rdl', 12 | 'onedrive' 13 | ] 14 | 15 | if file_type not in self.allowed_file_types: 16 | raise ValueError( 17 | "File type not supported, please provide file types that are supported." 18 | ) 19 | 20 | _content_header = f""" 21 | Content-Disposition: form-data; filename="{0}" 22 | Content-Type: {0} 23 | """ 24 | 25 | def set_file_type(self) -> None: 26 | pass 27 | 28 | def set_file_path(self) -> None: 29 | pass 30 | 31 | def load_and_encode(self, file_path: str) -> None: 32 | pass 33 | 34 | def connection_details(self, connection_type: str = None, file_path: str = None, file_url: str = None) -> None: 35 | pass 36 | 37 | def _construct_headers(self) -> None: 38 | pass 39 | 40 | def _validate_file_extension(self) -> None: 41 | pass 42 | -------------------------------------------------------------------------------- /powerbi/imports.py: -------------------------------------------------------------------------------- 1 | """Module for the `Imports` service.""" 2 | 3 | from enum import Enum 4 | from typing import Union 5 | from typing import Dict 6 | from powerbi.session import PowerBiSession 7 | 8 | 9 | class Imports: 10 | """Class for the `Imports` service.""" 11 | 12 | def __init__(self, session: object) -> None: 13 | """Initializes the `Imports` service. 14 | 15 | ### Parameters 16 | ---- 17 | session : object 18 | An authenticated session for our Microsoft PowerBi Client. 19 | 20 | ### Usage 21 | ---- 22 | >>> imports_service = power_bi_client.imports() 23 | """ 24 | 25 | # Set the session. 26 | self.power_bi_session: PowerBiSession = session 27 | 28 | def create_temporary_upload_location(self) -> Dict: 29 | """Creates a temporary blob storage to be used to import large .pbix 30 | files larger than 1 GB and up to 10 GB. 31 | 32 | ### Overview 33 | ---- 34 | To import large .pbix files, create a temporary upload location and 35 | upload the .pbix file using the shared access signature (SAS) url from 36 | the response, and then call Post Import and specify 'fileUrl' to be the 37 | SAS url in the Request Body 38 | 39 | ### Returns 40 | ---- 41 | A `TemporaryUploadLocation` resource. 42 | 43 | ### Usage 44 | ---- 45 | >>> imports_service = power_bi_client.imports() 46 | >>> imports_service.create_temporary_upload_location() 47 | """ 48 | 49 | content = self.power_bi_session.make_request( 50 | method="post", endpoint="myorg/imports/createTemporaryUploadLocation" 51 | ) 52 | 53 | return content 54 | 55 | def create_group_temporary_upload_location(self, group_id: str) -> Dict: 56 | """Creates a temporary blob storage to be used to import large .pbix 57 | files larger than 1 GB and up to 10 GB. 58 | 59 | ### Overview 60 | ---- 61 | To import large .pbix files, create a temporary upload location and 62 | upload the .pbix file using the shared access signature (SAS) url from 63 | the response, and then call Post Import and specify 'fileUrl' to be the 64 | SAS url in the Request Body 65 | 66 | ### Parameters 67 | ---- 68 | group_id : str 69 | The Workspace ID. 70 | 71 | ### Returns 72 | ---- 73 | A `TemporaryUploadLocation` resource. 74 | 75 | ### Usage 76 | ---- 77 | >>> imports_service = power_bi_client.imports() 78 | >>> imports_service.create_group_temporary_upload_location( 79 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78' 80 | ) 81 | """ 82 | 83 | content = self.power_bi_session.make_request( 84 | method="post", 85 | endpoint=f"/myorg/groups/{group_id}/imports/createTemporaryUploadLocation", 86 | ) 87 | 88 | return content 89 | 90 | def get_imports(self) -> Dict: 91 | """Returns a list of imports from "My Workspace". 92 | 93 | ### Returns 94 | ---- 95 | A collection `Import` resource. 96 | 97 | ### Usage 98 | ---- 99 | >>> imports_service = power_bi_client.imports() 100 | >>> imports_service.get_imports() 101 | """ 102 | 103 | content = self.power_bi_session.make_request( 104 | method="get", endpoint="/myorg/imports" 105 | ) 106 | 107 | return content 108 | 109 | def get_group_imports(self, group_id: str) -> Dict: 110 | """Returns a list of imports from the specified workspace. 111 | 112 | ### parameters 113 | ---- 114 | group_id : str 115 | The workspace ID. 116 | 117 | ### Returns 118 | ---- 119 | A collection `Import` resource. 120 | 121 | ### Usage 122 | ---- 123 | >>> imports_service = power_bi_client.imports() 124 | >>> imports_service.get_group_imports( 125 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78' 126 | ) 127 | """ 128 | 129 | content = self.power_bi_session.make_request( 130 | method="get", endpoint=f"/myorg/groups/{group_id}/imports" 131 | ) 132 | 133 | return content 134 | 135 | def get_import(self, import_id: str) -> Dict: 136 | """Returns the specified import from "My Workspace". 137 | 138 | ### Parameters 139 | ---- 140 | import_id : str 141 | The import ID you want to query. 142 | 143 | ### Returns 144 | ---- 145 | A `Import` resource. 146 | 147 | ### Usage 148 | ---- 149 | >>> imports_service = power_bi_client.imports() 150 | >>> imports_service.get_import( 151 | import_id='e40f7c73-84d1-4cf5-a696-5850a5ec8ad3' 152 | ) 153 | """ 154 | 155 | content = self.power_bi_session.make_request( 156 | method="get", endpoint=f"/myorg/imports/{import_id}" 157 | ) 158 | 159 | return content 160 | 161 | def get_group_import(self, group_id: str, import_id: str) -> Dict: 162 | """Returns the specified import from the specified workspace. 163 | 164 | ### Parameters 165 | ---- 166 | group_id : str 167 | The workspace ID. 168 | 169 | import_id : str 170 | The import ID you want to query. 171 | 172 | ### Returns 173 | ---- 174 | A `Import` resource. 175 | 176 | ### Usage 177 | ---- 178 | >>> imports_service = power_bi_client.imports() 179 | >>> imports_service.get_group_import( 180 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 181 | import_id='e40f7c73-84d1-4cf5-a696-5850a5ec8ad3' 182 | ) 183 | """ 184 | 185 | content = self.power_bi_session.make_request( 186 | method="get", endpoint=f"/myorg/groups/{group_id}/imports/{import_id}" 187 | ) 188 | 189 | return content 190 | 191 | def post_import( 192 | self, 193 | dataset_display_name: str, 194 | name_conflict: Union[str, Enum] = "Ignore", 195 | skip_report: bool = None, 196 | ) -> Dict: 197 | """Creates new content on "My Workspace" from PBIX (Power BI Desktop), 198 | JSON, XLSX (Excel), RDL or file path in OneDrive for Business. 199 | 200 | ### Parameters 201 | ---- 202 | dataset_display_name : str 203 | The display name of the dataset, should include file extension. 204 | Not supported when importing from OneDrive for Business. 205 | 206 | name_conflict : Union[str, Enum] (optional, Default='Ignore') 207 | Determines what to do if a dataset with the same name already 208 | exists. Only `Abort` and `Overwrite` are supported with Rdl files. 209 | 210 | skip_report : bool (optional, Default=None) 211 | Determines whether to skip report import, if specified value must 212 | be `True`. Only supported for PBIX files. 213 | 214 | ### Returns 215 | ---- 216 | A `Import` resource. 217 | 218 | ### Usage 219 | ---- 220 | >>> imports_service = power_bi_client.imports() 221 | >>> imports_service.get_group_import( 222 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 223 | import_id='e40f7c73-84d1-4cf5-a696-5850a5ec8ad3' 224 | ) 225 | """ 226 | 227 | content_types = {"file": "multipart/form-data", "xlsx": "application/json"} 228 | 229 | if isinstance(name_conflict, Enum): 230 | name_conflict = name_conflict.value 231 | 232 | params = { 233 | "datasetDisplayName": dataset_display_name, 234 | "nameConflict": name_conflict, 235 | "skipReport": skip_report, 236 | } 237 | 238 | request = self.power_bi_session.build_custom_request() 239 | request.headers["Content-Type"] = content_types["file"] 240 | request.data = "" 241 | 242 | content = self.power_bi_session.make_request( 243 | method="get", endpoint="/myorg/imports", params=params 244 | ) 245 | 246 | return content 247 | -------------------------------------------------------------------------------- /powerbi/pipelines.py: -------------------------------------------------------------------------------- 1 | """Microsoft PowerBi `Pipeline` Service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class Pipelines: 8 | """Class for the `Pipelines` service.""" 9 | 10 | def __init__(self, session: object) -> None: 11 | """Initializes the `Pipelines` service. 12 | 13 | ### Parameters 14 | ---- 15 | session : object 16 | An authenticated session for our Microsoft PowerBi Client. 17 | 18 | ### Usage 19 | ---- 20 | >>> pipeline_service = power_bi_client.pipelines() 21 | """ 22 | 23 | # Set the session. 24 | self.power_bi_session: PowerBiSession = session 25 | 26 | def get_pipelines(self) -> Dict: 27 | """Returns a list of deployment `pipelines` the user has access to. 28 | 29 | ### Returns 30 | ---- 31 | Dict 32 | A collection of `DeploymentPipeline` resources. 33 | 34 | ### Usage 35 | ---- 36 | >>> pipeline_service = power_bi_client.pipelines() 37 | >>> pipeline_service.get_pipelines() 38 | """ 39 | 40 | content = self.power_bi_session.make_request( 41 | method="get", 42 | endpoint="myorg/pipelines", 43 | ) 44 | 45 | return content 46 | 47 | def get_pipeline(self, pipeline_id: str, expand_stages: bool = True) -> Dict: 48 | """Returns the specified deployment pipeline. 49 | 50 | ### Parameters 51 | ---- 52 | pipeline_id : str 53 | The pipeline ID. 54 | 55 | expand_stages : bool (optional, Default=True) 56 | Expands related entities inline, receives a comma-separated list 57 | of data types. 58 | 59 | ### Returns 60 | ---- 61 | Dict 62 | A `DeploymentPipeline` resource. 63 | 64 | ### Usage 65 | ---- 66 | >>> pipeline_service = power_bi_client.pipelines() 67 | >>> pipeline_service.get_pipeline( 68 | pipeline_id='a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357' 69 | ) 70 | """ 71 | 72 | if expand_stages: 73 | url = f"myorg/pipelines/{pipeline_id}?$expand=stages" 74 | else: 75 | url = (f"myorg/pipelines/{pipeline_id}",) 76 | 77 | content = self.power_bi_session.make_request( 78 | method="get", 79 | endpoint=url, 80 | ) 81 | 82 | return content 83 | 84 | def get_pipeline_operations(self, pipeline_id: str) -> Dict: 85 | """Returns a list of up to 20 last deploy operations performed on 86 | the specified deployment pipeline. 87 | 88 | ### Parameters 89 | ---- 90 | pipeline_id : str 91 | The pipeline ID. 92 | 93 | ### Returns 94 | ---- 95 | Dict 96 | A collection of `PipelineOperation` resources. 97 | 98 | ### Usage 99 | ---- 100 | >>> pipeline_service = power_bi_client.pipelines() 101 | >>> pipeline_service.get_pipeline_operations( 102 | pipeline_id='a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357' 103 | ) 104 | """ 105 | 106 | content = self.power_bi_session.make_request( 107 | method="get", 108 | endpoint=f"myorg/pipelines/{pipeline_id}/operations", 109 | ) 110 | 111 | return content 112 | 113 | def get_pipeline_operation(self, pipeline_id: str, operation_id: str) -> Dict: 114 | """Returns the details of the specified deploy operation performed 115 | on the specified deployment pipeline including the executionPlan. 116 | Use to track the status of the deploy operation. 117 | 118 | ### Parameters 119 | ---- 120 | pipeline_id : str 121 | The pipeline ID. 122 | 123 | operation_id : str 124 | The operation ID. 125 | 126 | ### Returns 127 | ---- 128 | Dict 129 | A collection of `PipelineOperation` resources. 130 | 131 | ### Usage 132 | ---- 133 | >>> pipeline_service = power_bi_client.pipelines() 134 | >>> pipeline_service.get_pipeline_operation( 135 | pipeline_id='a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357', 136 | operation_id='' 137 | ) 138 | """ 139 | 140 | content = self.power_bi_session.make_request( 141 | method="get", 142 | endpoint=f"myorg/pipelines/{pipeline_id}/operations/{operation_id}", 143 | ) 144 | 145 | return content 146 | 147 | def get_pipeline_stage_artifacts(self, pipeline_id: str, stage_order: int) -> Dict: 148 | """Returns the supported items from the workspace assigned to the specified 149 | deployment pipeline stage. 150 | 151 | ### Parameters 152 | ---- 153 | pipeline_id : str 154 | The pipeline ID. 155 | 156 | stage_order : int 157 | The deployment pipeline stage order. Development (0), 158 | Test (1), Production (2). 159 | 160 | ### Returns 161 | ---- 162 | Dict 163 | A collection of `PipelineOperation` resources. 164 | 165 | ### Usage 166 | ---- 167 | >>> pipeline_service = power_bi_client.pipelines() 168 | >>> pipeline_service.get_pipeline_stage_artifacts( 169 | pipeline_id='a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357', 170 | stage_order=1 171 | ) 172 | """ 173 | 174 | content = self.power_bi_session.make_request( 175 | method="get", 176 | endpoint=f"myorg/pipelines/{pipeline_id}/stages/{stage_order}/artifacts", 177 | ) 178 | 179 | return content 180 | -------------------------------------------------------------------------------- /powerbi/push_datasets.py: -------------------------------------------------------------------------------- 1 | """Microsoft PowerBi `PushDatasets` Service.""" 2 | 3 | import json 4 | 5 | from typing import Dict 6 | from typing import Union 7 | from powerbi.utils import Dataset 8 | from powerbi.utils import Table 9 | from powerbi.utils import PowerBiEncoder 10 | from powerbi.session import PowerBiSession 11 | 12 | 13 | class PushDatasets: 14 | 15 | """Microsoft PowerBi `PushDatasets` Service.""" 16 | 17 | def __init__(self, session: object) -> None: 18 | """Initializes the `PushDatasets` service. 19 | 20 | ### Parameters 21 | ---- 22 | session : object 23 | An authenticated session for our Microsoft PowerBi Client. 24 | 25 | ### Usage 26 | ---- 27 | >>> push_datasets_service = power_bi_client.push_datasets() 28 | """ 29 | 30 | # Set the session. 31 | self.power_bi_session: PowerBiSession = session 32 | 33 | def get_tables(self, dataset_id: str) -> Dict: 34 | """Returns a list of tables tables within the specified dataset from 35 | "My Workspace". 36 | 37 | ### Parameters 38 | ---- 39 | dataset_id : str 40 | The dataset ID you want to query. 41 | 42 | ### Returns 43 | ---- 44 | Dict 45 | A collection of `Tables` resources. 46 | 47 | ### Usage 48 | ---- 49 | >>> push_datasets_service = power_bi_client.push_datasets() 50 | >>> push_datasets_service.get_tables( 51 | dataset_id='8c2765d5-96f7-4f79-a5b4-3a07e367ad8e' 52 | ) 53 | """ 54 | 55 | content = self.power_bi_session.make_request( 56 | method="get", 57 | endpoint=f"myorg/datasets/{dataset_id}/tables", 58 | ) 59 | 60 | return content 61 | 62 | def get_group_tables(self, group_id: str, dataset_id: str) -> Dict: 63 | """Returns a list of tables tables within the specified dataset from 64 | the specified workspace. 65 | 66 | ### Parameters 67 | ---- 68 | group_id : str 69 | The workspace id. 70 | 71 | dataset_id : str 72 | The dataset ID you want to query. 73 | 74 | ### Returns 75 | ---- 76 | Dict 77 | A collection of `Tables` resources. 78 | 79 | ### Usage 80 | ---- 81 | >>> push_datasets_service = power_bi_client.push_datasets() 82 | >>> push_datasets_service.get_group_tables( 83 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 84 | dataset_id='8c2765d5-96f7-4f79-a5b4-3a07e367ad8e' 85 | ) 86 | """ 87 | 88 | content = self.power_bi_session.make_request( 89 | method="get", 90 | endpoint=f"myorg/groups/{group_id}/datasets/{dataset_id}/tables", 91 | ) 92 | 93 | return content 94 | 95 | def post_dataset( 96 | self, dataset: Union[dict, Dataset], default_retention_policy: str = None 97 | ) -> Dict: 98 | """Creates a new dataset on "My Workspace". 99 | 100 | ### Parameters 101 | ---- 102 | dataset : Union[dict, Dataset] 103 | The dataset you want to post. 104 | 105 | default_retention_policy : str (optional, Default=None) 106 | The default retention policy. 107 | 108 | ### Returns 109 | ---- 110 | Dict 111 | A datset resource with the id. 112 | 113 | ### Usage 114 | ---- 115 | >>> push_datasets_service = power_bi_client.push_datasets() 116 | >>> push_datasets_service.post_dataset( 117 | dataset={}, 118 | default_retention_policy='basicFIFO' 119 | ) 120 | """ 121 | 122 | if isinstance(dataset, Dataset): 123 | 124 | dataset = json.dumps( 125 | obj=dataset._prep_for_post(), indent=4, cls=PowerBiEncoder 126 | ) 127 | 128 | content = self.power_bi_session.make_request( 129 | method="post", 130 | endpoint=f"myorg/datasets?defaultRetentionPolicy={default_retention_policy}", 131 | data=dataset, 132 | ) 133 | 134 | return content 135 | 136 | def post_group_dataset( 137 | self, 138 | group_id: str, 139 | dataset: Union[dict, Dataset], 140 | default_retention_policy: str = None, 141 | ) -> Dict: 142 | """Creates a new dataset in the specified workspace. 143 | 144 | ### Parameters 145 | ---- 146 | group_id : str 147 | The workspace ID. 148 | 149 | dataset : Union[dict, Dataset] 150 | The dataset you want to post. 151 | 152 | default_retention_policy : str (optional, Default=None) 153 | The default retention policy. 154 | 155 | ### Returns 156 | ---- 157 | Dict 158 | A datset resource with the id. 159 | 160 | ### Usage 161 | ---- 162 | >>> push_datasets_service = power_bi_client.push_datasets() 163 | >>> push_datasets_service.post_group_dataset( 164 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 165 | dataset={}, 166 | default_retention_policy='basicFIFO' 167 | ) 168 | """ 169 | 170 | if isinstance(dataset, Dataset): 171 | 172 | dataset = json.dumps( 173 | obj=dataset._prep_for_post(), indent=4, cls=PowerBiEncoder 174 | ) 175 | 176 | content = self.power_bi_session.make_request( 177 | method="post", 178 | endpoint=f"myorg/groups/{group_id}/datasets?defaultRetentionPolicy={default_retention_policy}", 179 | data=dataset, 180 | ) 181 | 182 | return content 183 | 184 | def post_dataset_rows(self, dataset_id: str, table_name: str, rows: list) -> None: 185 | """Adds new data rows to the specified table within the specified 186 | dataset from "My Workspace". 187 | 188 | ### Parameters 189 | ---- 190 | dataset_id : str 191 | The dataset id 192 | 193 | table_name: str 194 | The dataset table name you want to post rows 195 | to. 196 | 197 | rows : list 198 | An array of data rows pushed to a dataset table. 199 | 200 | ### Usage 201 | ---- 202 | >>> push_datasets_service = power_bi_client.push_datasets() 203 | >>> push_datasets_service.post_dataset_rows( 204 | dataset_id='8ea21119-fb8f-4592-b2b8-141b824a2b7e', 205 | table_name='sales_table', 206 | rows=[ 207 | { 208 | 'partner_name': 'Alex Reed', 209 | 'partner_sales': 1000.30 210 | }, 211 | { 212 | 'partner_name': 'John Reed', 213 | 'partner_sales': 2000.30 214 | }, 215 | { 216 | 'partner_name': 'James Reed', 217 | 'partner_sales': 5000.30 218 | } 219 | ] 220 | ) 221 | """ 222 | 223 | content = self.power_bi_session.make_request( 224 | method="post", 225 | endpoint=f"myorg/datasets/{dataset_id}/tables/{table_name}/rows", 226 | json_payload=rows, 227 | ) 228 | 229 | return content 230 | 231 | def post_group_dataset_rows( 232 | self, group_id: str, dataset_id: str, table_name: str, rows: list 233 | ) -> None: 234 | """Adds new data rows to the specified table, within the specified dataset, 235 | from the specified workspace. 236 | 237 | ### Parameters 238 | ---- 239 | group_id : str 240 | The workspace id. 241 | 242 | dataset_id : str 243 | The dataset id 244 | 245 | table_name: str 246 | The dataset table name you want to post rows 247 | to. 248 | 249 | rows : list 250 | An array of data rows pushed to a dataset table. 251 | 252 | ### Usage 253 | ---- 254 | >>> push_datasets_service = power_bi_client.push_datasets() 255 | >>> push_datasets_service.post_group_dataset_rows( 256 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 257 | dataset_id='8ea21119-fb8f-4592-b2b8-141b824a2b7e', 258 | table_name='sales_table', 259 | rows=[ 260 | { 261 | 'partner_name': 'Alex Reed', 262 | 'partner_sales': 1000.30 263 | }, 264 | { 265 | 'partner_name': 'John Reed', 266 | 'partner_sales': 2000.30 267 | }, 268 | { 269 | 'partner_name': 'James Reed', 270 | 'partner_sales': 5000.30 271 | } 272 | ] 273 | ) 274 | """ 275 | 276 | content = self.power_bi_session.make_request( 277 | method="post", 278 | endpoint=f"myorg/groups/{group_id}/datasets/{dataset_id}/tables/{table_name}/rows", 279 | json_payload=rows, 280 | ) 281 | 282 | return content 283 | 284 | def put_dataset( 285 | self, dataset_id: str, table_name: str, table: Union[Table, dict] 286 | ) -> Dict: 287 | """Updates the metadata and schema for the specified table within the 288 | specified dataset from "My Workspace". 289 | 290 | ### Parameters 291 | ---- 292 | dataset_id : str 293 | The dataset ID. 294 | 295 | table_name : str 296 | The name of the table you want to update. 297 | 298 | table : Union[Table, dict] 299 | The table information you want updated, can 300 | be a `Table` object. 301 | 302 | ### Returns 303 | ---- 304 | Dict 305 | A `Table` object. 306 | 307 | ### Usage 308 | ---- 309 | >>> push_datasets_service = power_bi_client.push_datasets() 310 | >>> push_datasets_service.put_dataset( 311 | dataset_id='8ea21119-fb8f-4592-b2b8-141b824a2b7e', 312 | table_name='sales_table', 313 | table=new_table_sales 314 | ) 315 | """ 316 | 317 | if isinstance(table, Table): 318 | 319 | del table["rows"] 320 | 321 | table = json.dumps(obj=table, indent=4, cls=PowerBiEncoder) 322 | 323 | content = self.power_bi_session.make_request( 324 | method="put", 325 | endpoint=f"myorg/datasets/{dataset_id}/tables/{table_name}", 326 | data=table, 327 | ) 328 | 329 | return content 330 | 331 | def put_group_dataset( 332 | self, group_id: str, dataset_id: str, table_name: str, table: Union[Table, dict] 333 | ) -> Dict: 334 | """Updates the metadata and schema for the specified table within the 335 | specified dataset from the specified workspace. 336 | 337 | ### Parameters 338 | ---- 339 | group_id : str 340 | The workspace ID. 341 | 342 | dataset_id : str 343 | The dataset ID. 344 | 345 | table_name : str 346 | The name of the table you want to update. 347 | 348 | table : Union[Table, dict] 349 | The table information you want updated, can 350 | be a `Table` object. 351 | 352 | ### Returns 353 | ---- 354 | Dict 355 | A `Table` object. 356 | 357 | ### Usage 358 | ---- 359 | >>> push_datasets_service = power_bi_client.push_datasets() 360 | >>> push_datasets_service.put_group_dataset( 361 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 362 | dataset_id='8ea21119-fb8f-4592-b2b8-141b824a2b7e', 363 | table_name='sales_table', 364 | table=new_table_sales 365 | ) 366 | """ 367 | 368 | if isinstance(table, Table): 369 | 370 | del table["rows"] 371 | 372 | table = json.dumps(obj=table, indent=4, cls=PowerBiEncoder) 373 | 374 | content = self.power_bi_session.make_request( 375 | method="put", 376 | endpoint=f"myorg/groups/{group_id}/datasets/{dataset_id}/tables/{table_name}", 377 | data=table, 378 | ) 379 | 380 | return content 381 | 382 | def delete_dataset_rows(self, dataset_id: str, table_name: str) -> None: 383 | """Delets All rows from the specified table within the specified 384 | dataset from "My Workspace". 385 | 386 | ### Parameters 387 | ---- 388 | dataset_id : str 389 | The dataset id 390 | 391 | table_name: str 392 | The dataset table name you want to post rows 393 | to. 394 | 395 | ### Usage 396 | ---- 397 | >>> push_datasets_service = power_bi_client.push_datasets() 398 | >>> push_datasets_service.post_dataset_rows( 399 | dataset_id='8ea21119-fb8f-4592-b2b8-141b824a2b7e', 400 | table_name='sales_table' 401 | ) 402 | """ 403 | 404 | content = self.power_bi_session.make_request( 405 | method="delete", 406 | endpoint=f"myorg/datasets/{dataset_id}/tables/{table_name}/rows", 407 | ) 408 | 409 | return content 410 | 411 | def delete_group_dataset_rows( 412 | self, group_id: str, dataset_id: str, table_name: str 413 | ) -> None: 414 | """Deletes all the data rows from the specified table, within the specified dataset, 415 | from the specified workspace. 416 | 417 | ### Parameters 418 | ---- 419 | group_id : str 420 | The workspace id. 421 | 422 | dataset_id : str 423 | The dataset id 424 | 425 | table_name: str 426 | The dataset table name you want to post rows 427 | to.. 428 | 429 | ### Usage 430 | ---- 431 | >>> push_datasets_service = power_bi_client.push_datasets() 432 | >>> push_datasets_service.post_group_dataset_rows( 433 | group_id='f78705a2-bead-4a5c-ba57-166794b05c78', 434 | dataset_id='8ea21119-fb8f-4592-b2b8-141b824a2b7e', 435 | table_name='sales_table' 436 | ) 437 | """ 438 | 439 | content = self.power_bi_session.make_request( 440 | method="delete", 441 | endpoint=f"myorg/groups/{group_id}/datasets/{dataset_id}/tables/{table_name}/rows", 442 | ) 443 | 444 | return content 445 | -------------------------------------------------------------------------------- /powerbi/session.py: -------------------------------------------------------------------------------- 1 | """Handles all the requests made to the Microsoft Power Bi API.""" 2 | 3 | import sys 4 | import json 5 | import logging 6 | import pathlib 7 | 8 | from typing import Dict 9 | 10 | import requests 11 | 12 | 13 | class PowerBiSession: 14 | """Serves as the Session for the Current Microsoft 15 | Power Bi API.""" 16 | 17 | def __init__(self, client: object) -> None: 18 | """Initializes the `PowerBiSession` client. 19 | 20 | ### Overview: 21 | ---- 22 | The `PowerBiSession` object handles all the requests made 23 | for the different endpoints on the Microsoft Power Bi API. 24 | 25 | ### Arguments: 26 | ---- 27 | client (str): The Microsoft Power BI API Python Client. 28 | 29 | ### Usage: 30 | ---- 31 | >>> power_bi_session = PowerBiSession() 32 | """ 33 | 34 | from powerbi.client import ( # pylint: disable=import-outside-toplevel 35 | PowerBiClient, 36 | ) 37 | 38 | # We can also add custom formatting to our log messages. 39 | log_format = "%(asctime)-15s|%(filename)s|%(message)s" 40 | 41 | self.client: PowerBiClient = client 42 | self.resource_url = "https://api.powerbi.com/" 43 | self.version = "v1.0/" 44 | 45 | if not pathlib.Path("logs").exists(): 46 | pathlib.Path("logs").mkdir() 47 | pathlib.Path("logs/log_file_custom.log").touch() 48 | if sys.version_info[1] == 8: 49 | logging.basicConfig( 50 | filename="logs/log_file_custom.log", 51 | level=logging.INFO, 52 | format=log_format, 53 | ) 54 | else: 55 | logging.basicConfig( 56 | filename="logs/log_file_custom.log", 57 | level=logging.INFO, 58 | encoding="utf-8", 59 | format=log_format, 60 | ) 61 | 62 | def build_headers(self) -> Dict: 63 | """Used to build the headers needed to make the request. 64 | 65 | ### Parameters 66 | ---- 67 | mode: str, optional 68 | The content mode the headers is being built for, by default `json`. 69 | 70 | ### Returns 71 | ---- 72 | Dict: 73 | A dictionary containing all the components. 74 | """ 75 | 76 | # Fake the headers. 77 | headers = { 78 | "Authorization": f"Bearer {self.client.access_token}", 79 | "Content-Type": "application/json", 80 | } 81 | 82 | return headers 83 | 84 | def build_url(self, endpoint: str) -> str: 85 | """Build the URL used the make string. 86 | 87 | ### Parameters 88 | ---- 89 | endpoint : str 90 | The endpoint used to make the full URL. 91 | 92 | ### Returns 93 | ---- 94 | str: 95 | The full URL with the endpoint needed. 96 | """ 97 | 98 | url = self.resource_url + self.version + endpoint 99 | 100 | return url 101 | 102 | def make_request( 103 | self, 104 | method: str, 105 | endpoint: str, 106 | params: dict = None, 107 | data: dict = None, 108 | json_payload: dict = None, 109 | ) -> Dict: 110 | """Handles all the requests in the library. 111 | 112 | ### Overview: 113 | --- 114 | A central function used to handle all the requests made in the library, 115 | this function handles building the URL, defining Content-Type, passing 116 | through payloads, and handling any errors that may arise during the 117 | request. 118 | 119 | ### Arguments: 120 | ---- 121 | method : str 122 | The Request method, can be one of the following: 123 | ['get','post','put','delete','patch'] 124 | 125 | endpoint : str 126 | The API URL endpoint, example is 'quotes' 127 | 128 | mode : str 129 | The content-type mode, can be one of the 130 | following: ['form','json'] 131 | 132 | params : dict 133 | The URL params for the request. 134 | 135 | data : dict 136 | A data payload for a request. 137 | 138 | json_payload : dict 139 | A json data payload for a request 140 | 141 | ### Returns: 142 | ---- 143 | A Dictionary object containing the 144 | JSON values. 145 | """ 146 | 147 | # Build the URL. 148 | url = self.build_url(endpoint=endpoint) 149 | 150 | # Define the headers. 151 | headers = self.build_headers() 152 | 153 | logging.info("URL: %s", url) 154 | 155 | # Define a new session. 156 | request_session = requests.Session() 157 | request_session.verify = True 158 | 159 | # Define a new request. 160 | request_request = requests.Request( 161 | method=method.upper(), 162 | headers=headers, 163 | url=url, 164 | params=params, 165 | data=data, 166 | json=json_payload, 167 | ).prepare() 168 | 169 | # Send the request. 170 | response: requests.Response = request_session.send(request=request_request) 171 | 172 | # Close the session. 173 | request_session.close() 174 | 175 | # If it's okay and no details. 176 | if ( 177 | response.ok 178 | and len(response.content) > 0 179 | and response.headers["Content-Type"] != "application/zip" 180 | ): 181 | 182 | return response.json() 183 | 184 | elif ( 185 | response.ok 186 | and len(response.content) > 0 187 | and response.headers["Content-Type"] == "application/zip" 188 | ): 189 | 190 | return response.content 191 | 192 | elif len(response.content) > 0 and response.ok: 193 | return { 194 | "message": "response successful", 195 | "status_code": response.status_code, 196 | } 197 | elif not response.ok: 198 | 199 | if len(response.content) == 0: 200 | response_data = "" 201 | else: 202 | response_data = response.json() 203 | 204 | response.request.headers["Authorization"] = "Bearer XXXXXXX" 205 | 206 | # Define the error dict. 207 | error_dict = { 208 | "error_code": response.status_code, 209 | "response_url": response.url, 210 | "response_body": response_data, 211 | "response_request": dict(response.request.headers), 212 | "response_method": response.request.method, 213 | } 214 | 215 | # Log the error. 216 | logging.error(msg=json.dumps(obj=error_dict, indent=4)) 217 | 218 | raise requests.HTTPError() 219 | -------------------------------------------------------------------------------- /powerbi/template_apps.py: -------------------------------------------------------------------------------- 1 | """Module for `TemplateApps` service.""" 2 | 3 | from typing import Dict 4 | from powerbi.session import PowerBiSession 5 | 6 | 7 | class TemplateApps: 8 | """Class for `TemplateApps` service.""" 9 | 10 | def __init__(self, session: object) -> None: 11 | """Initializes the `TemplateApps` service. 12 | 13 | ### Parameters 14 | ---- 15 | session : object 16 | An authenticated session for our Microsoft PowerBi Client. 17 | 18 | ### Usage 19 | ---- 20 | >>> template_apps_service = power_bi_client.template_apps() 21 | """ 22 | 23 | # Set the session. 24 | self.power_bi_session: PowerBiSession = session 25 | 26 | # Set the endpoint. 27 | self.endpoint = "myorg/CreateTemplateAppInstallTicket" 28 | 29 | def create_install_ticket( 30 | self, app_id: str, owner_tenant_id: str, package_key: str, config: Dict 31 | ) -> Dict: 32 | """Generates an installation ticket for Template Apps automated install flow. 33 | 34 | ### Overview 35 | ---- 36 | This API is only available when using service principal for authentication, 37 | see Service Principal with Power BI document along with considerations and 38 | limitations section. 39 | 40 | ### Parameters 41 | ---- 42 | app_id : str 43 | Unique application Id. 44 | 45 | owner_tenant_id : str 46 | Application owner's tenant object Id. 47 | 48 | package_key : str 49 | Application version secure key. 50 | 51 | config : Dict 52 | Automated install configuration. 53 | 54 | ### Returns 55 | ---- 56 | Dict 57 | A `InstallTicket` resource. 58 | 59 | ### Usage 60 | ---- 61 | >>> template_apps_service = power_bi_client.template_apps() 62 | >>> template_apps_service.create_install_ticket( 63 | app_id='91ce06d1-d81b-4ea0-bc6d-2ce3dd2f8e87', 64 | owner_tenant_id='d43e3248-3d83-44aa-a94d-c836bd7f9b79', 65 | package_key='g632bb64...OfsoqT56xEM=', 66 | config={ 67 | 'configuration': { 68 | 'param1': 'value1', 69 | 'param2': 'value2' 70 | } 71 | } 72 | ) 73 | """ 74 | 75 | payload = { 76 | "appId": app_id, 77 | "packageKey": package_key, 78 | "ownerTenantId": owner_tenant_id, 79 | "config": config, 80 | } 81 | 82 | content = self.power_bi_session.make_request( 83 | method="post", endpoint=self.endpoint, json_payload=payload 84 | ) 85 | 86 | return content 87 | -------------------------------------------------------------------------------- /powerbi/users.py: -------------------------------------------------------------------------------- 1 | """Module for the `Users` service.""" 2 | 3 | from powerbi.session import PowerBiSession 4 | 5 | 6 | class Users: 7 | """Class for the `Users` service.""" 8 | 9 | def __init__(self, session: object) -> None: 10 | """Initializes the `Users` service. 11 | 12 | ### Parameters 13 | ---- 14 | session : object 15 | An authenticated session for our Microsoft PowerBi Client. 16 | 17 | ### Usage 18 | ---- 19 | >>> users_service = power_bi_client.users() 20 | """ 21 | 22 | # Set the session. 23 | self.power_bi_session: PowerBiSession = session 24 | 25 | # Set the endpoint. 26 | self.endpoint = "myorg/RefreshUserPermissions" 27 | 28 | def refresh_user_permissions(self) -> None: 29 | """Refreshes user permissions in Power BI. 30 | 31 | ### Overview 32 | ---- 33 | When a user is granted permissions to a workspace, app, or 34 | artifact, it might not be immediately available through API 35 | calls. This operation refreshes user permissions and makes 36 | sure the user permissions are fully updated. Make the refresh 37 | user permissions call, before any other API calls. It takes 38 | about two minutes for the permissions to get refreshed. 39 | Before calling other APIs, wait for two minutes. 40 | 41 | ### Usage 42 | ---- 43 | >>> users_service = power_bi_client.users() 44 | >>> users_service.refresh_user_permissions() 45 | """ 46 | 47 | content = self.power_bi_session.make_request( 48 | method="post", endpoint=self.endpoint 49 | ) 50 | 51 | return content 52 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | msal>=1.31.1 2 | requests>=2.32.3 3 | setuptools>=75.8.0 4 | -------------------------------------------------------------------------------- /samples/use_available_features.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `AvailableFeatures` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `AvailableFeatures` service. 28 | available_features_service = power_bi_client.available_features() 29 | 30 | # List all Available Features 31 | pprint(available_features_service.get_available_features()) 32 | 33 | # List all Available Features 34 | pprint( 35 | available_features_service.get_available_feature_by_name(feature_name="embedTrial") 36 | ) 37 | -------------------------------------------------------------------------------- /samples/use_capacities.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Capacities` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `Capacities` service. 28 | capacities_service = power_bi_client.capactities() 29 | 30 | # Get a list of the User's available capacities. 31 | pprint(capacities_service.get_capacities()) 32 | 33 | # Get a list of the User's available capacities. 34 | pprint( 35 | capacities_service.get_workloads(capacity_id="890D018E-4B64-4BB1-97E5-BD5490373413") 36 | ) 37 | 38 | # Grab a specific workload from a capacity. 39 | pprint( 40 | capacities_service.get_workload( 41 | capacity_id="890D018E-4B64-4BB1-97E5-BD5490373413", workload_name="my-workload" 42 | ) 43 | ) 44 | 45 | # Grab a specific workload from a capacity. 46 | pprint(capacities_service.get_refreshables()) 47 | 48 | # Get refreshables for a specific capacity. 49 | pprint( 50 | capacities_service.get_refreshables_for_capacity( 51 | capacity_id="890D018E-4B64-4BB1-97E5-BD5490373413".lower(), top=10 52 | ) 53 | ) 54 | -------------------------------------------------------------------------------- /samples/use_client.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `PowerBiClient` class.""" 2 | 3 | from configparser import ConfigParser 4 | from powerbi.client import PowerBiClient 5 | 6 | # Initialize the Parser. 7 | config = ConfigParser() 8 | 9 | # Read the file. 10 | config.read("config/config.ini") 11 | 12 | # Get the specified credentials. 13 | client_id = config.get("power_bi_api", "client_id") 14 | redirect_uri = config.get("power_bi_api", "redirect_uri") 15 | client_secret = config.get("power_bi_api", "client_secret") 16 | 17 | # Initialize the Client. 18 | power_bi_client = PowerBiClient( 19 | client_id=client_id, 20 | client_secret=client_secret, 21 | scope=["https://analysis.windows.net/powerbi/api/.default"], 22 | redirect_uri=redirect_uri, 23 | credentials="config/power_bi_state.jsonc", 24 | ) 25 | 26 | # Initialize the `Dashboards` service. 27 | dashboard_service = power_bi_client.dashboards() 28 | -------------------------------------------------------------------------------- /samples/use_dashboards_service.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Dashboards` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `Dashboards` service. 28 | dashboard_service = power_bi_client.dashboards() 29 | 30 | # Add a dashboard to our Workspace. 31 | dashboard_service.add_dashboard(name="tradingRobot") 32 | 33 | # Get all the dashboards in our Org. 34 | pprint(dashboard_service.get_dashboards()) 35 | 36 | # Grab all the dashboards for a specific workspace. 37 | pprint( 38 | dashboard_service.get_dashboard(dashboard_id="bf2c7d16-ec7b-40a2-ab56-f8797fdc5fb8") 39 | ) 40 | 41 | # Add a dashboard to a specific workspace. 42 | pprint( 43 | dashboard_service.add_dashboard_in_group( 44 | name="my_new_dashboard", group_id="f78705a2-bead-4a5c-ba57-166794b05c78" 45 | ) 46 | ) 47 | 48 | # Grab all the dashboards for a specific workspace. 49 | pprint( 50 | dashboard_service.get_group_dashboards( 51 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78" 52 | ) 53 | ) 54 | 55 | # Grab a specific dashboard from a specific workspace. 56 | pprint( 57 | dashboard_service.get_group_dashboard( 58 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 59 | dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358", 60 | ) 61 | ) 62 | 63 | # Grab all the tiles from a dashboard. 64 | pprint(dashboard_service.get_tiles(dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358")) 65 | 66 | # Grab all the tiles from a specific dashboard from a specific workspace. 67 | pprint( 68 | dashboard_service.get_group_tiles( 69 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 70 | dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358", 71 | ) 72 | ) 73 | 74 | # Grab a specific tile from a specific dashboard. 75 | pprint( 76 | dashboard_service.get_tile( 77 | dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358", 78 | tile_id="093bfb85-828e-4705-bcf8-0126dd2d5d70", 79 | ) 80 | ) 81 | 82 | # Grab a specific tile from a specific workspace and a specific workspace.. 83 | pprint( 84 | dashboard_service.get_group_tile( 85 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 86 | dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358", 87 | tile_id="093bfb85-828e-4705-bcf8-0126dd2d5d70", 88 | ) 89 | ) 90 | 91 | # Clone a specific tile. 92 | pprint( 93 | dashboard_service.clone_tile( 94 | dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358", 95 | tile_id="093bfb85-828e-4705-bcf8-0126dd2d5d70", 96 | target_dashboard_id="86cb0a0e-612d-4822-9a29-d83478e21199", 97 | ) 98 | ) 99 | 100 | # Clone a specific tile from a specific workspace. 101 | pprint( 102 | dashboard_service.clone_group_tile( 103 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 104 | dashboard_id="1a0a15d9-67d1-4e97-b7bd-4f0ed4ec8358", 105 | tile_id="093bfb85-828e-4705-bcf8-0126dd2d5d70", 106 | target_dashboard_id="86cb0a0e-612d-4822-9a29-d83478e21199", 107 | ) 108 | ) 109 | -------------------------------------------------------------------------------- /samples/use_dataflow_storage.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `DataflowStorageAccount` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `DataflowStorageAccount` service. 28 | dataflow_storage_service = power_bi_client.dataflow_storage_account() 29 | 30 | # Refresh Users Permissions. 31 | pprint(dataflow_storage_service.get_dataflow_storage_accounts()) 32 | -------------------------------------------------------------------------------- /samples/use_dataflows.py: -------------------------------------------------------------------------------- 1 | """Used to demonstrate the usage of the `Dataflows` service.""" 2 | 3 | from configparser import ConfigParser 4 | from powerbi.client import PowerBiClient 5 | 6 | # Initialize the Parser. 7 | config = ConfigParser() 8 | 9 | # Read the file. 10 | config.read("config/config.ini") 11 | 12 | # Get the specified credentials. 13 | client_id = config.get("power_bi_api", "client_id") 14 | redirect_uri = config.get("power_bi_api", "redirect_uri") 15 | client_secret = config.get("power_bi_api", "client_secret") 16 | 17 | # Initialize the Client. 18 | power_bi_client = PowerBiClient( 19 | client_id=client_id, 20 | client_secret=client_secret, 21 | # You need to make sure you request this permission, but you can't have it 22 | # with the `.default` scope. 23 | scope=["https://analysis.windows.net/powerbi/api/Pipeline.ReadWrite.All"], 24 | redirect_uri=redirect_uri, 25 | credentials="config/power_bi_state.jsonc", 26 | ) 27 | 28 | # Initialize the `Dataflows` service. 29 | dataflows_service = power_bi_client.dataflows() 30 | -------------------------------------------------------------------------------- /samples/use_datasets.py: -------------------------------------------------------------------------------- 1 | """Used to demonstrate the usage of the `Datasets` service.""" 2 | 3 | # from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | # You need to make sure you request this permission, but you can't have it 23 | # with the `.default` scope. 24 | scope=["https://analysis.windows.net/powerbi/api/Pipeline.ReadWrite.All"], 25 | redirect_uri=redirect_uri, 26 | credentials="config/power_bi_state.jsonc", 27 | ) 28 | 29 | # Initialize the `Datasets` service. 30 | datasets_service = power_bi_client.datasets() 31 | -------------------------------------------------------------------------------- /samples/use_groups_service.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Groups` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `Groups` service. 28 | groups_service = power_bi_client.groups() 29 | 30 | # Grab all the Groups. 31 | all_groups = groups_service.get_groups() 32 | 33 | # List all the groups. 34 | pprint(groups_service.get_groups()) 35 | 36 | # Loop through the Groups. 37 | for group in all_groups["value"]: 38 | 39 | group_id = group.get("id", None) 40 | group_name = group.get("name", None) 41 | 42 | # Print the Group ID and Name. 43 | print(f"Group ID: {group_id}") 44 | print(f"Group Name: {group_name}") 45 | print("*" * 50) 46 | -------------------------------------------------------------------------------- /samples/use_imports.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Imports` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `Imports` service. 28 | imports_service = power_bi_client.imports() 29 | 30 | # Create a temporary upload location. 31 | pprint(imports_service.create_temporary_upload_location()) 32 | 33 | # Get all the Imports from my workspace. 34 | pprint(imports_service.get_imports()) 35 | 36 | # Query a specific Import from my workspace. 37 | pprint(imports_service.get_import(import_id="e40f7c73-84d1-4cf5-a696-5850a5ec8ad3")) 38 | -------------------------------------------------------------------------------- /samples/use_pipelines.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Pipelines` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | # You need to make sure you request this permission, but you can't have it 23 | # with the `.default` scope. 24 | scope=["https://analysis.windows.net/powerbi/api/Pipeline.ReadWrite.All"], 25 | redirect_uri=redirect_uri, 26 | credentials="config/power_bi_state.jsonc", 27 | ) 28 | 29 | # Initialize the `Pipelines` service. 30 | pipeline_service = power_bi_client.pipelines() 31 | 32 | # Get all the Pipelines a User has access to. 33 | pprint(pipeline_service.get_pipelines()) 34 | 35 | # Grab a specific pipeline. 36 | pprint( 37 | pipeline_service.get_pipeline( 38 | pipeline_id="a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357", expand_stages=True 39 | ) 40 | ) 41 | 42 | # Grab a specific pipeline's operations. 43 | pprint( 44 | pipeline_service.get_pipeline_operations( 45 | pipeline_id="a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357" 46 | ) 47 | ) 48 | 49 | # Get the Stage Artifacts for the Development Pipeline (1) 50 | pprint( 51 | pipeline_service.get_pipeline_stage_artifacts( 52 | pipeline_id="a6ffe4a2-0b24-4b87-a83c-dc8e7f7a3357", stage_order=0 53 | ) 54 | ) 55 | -------------------------------------------------------------------------------- /samples/use_push_datasets.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `PushDatasets` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | 6 | from powerbi.utils import Table 7 | from powerbi.utils import Column 8 | from powerbi.utils import Dataset 9 | from powerbi.enums import ColumnDataTypes 10 | from powerbi.client import PowerBiClient 11 | 12 | # Initialize the Parser. 13 | config = ConfigParser() 14 | 15 | # Read the file. 16 | config.read("config/config.ini") 17 | 18 | # Get the specified credentials. 19 | client_id = config.get("power_bi_api", "client_id") 20 | redirect_uri = config.get("power_bi_api", "redirect_uri") 21 | client_secret = config.get("power_bi_api", "client_secret") 22 | 23 | # Initialize the Client. 24 | power_bi_client = PowerBiClient( 25 | client_id=client_id, 26 | client_secret=client_secret, 27 | scope=["https://analysis.windows.net/powerbi/api/.default"], 28 | redirect_uri=redirect_uri, 29 | credentials="config/power_bi_state.jsonc", 30 | ) 31 | 32 | # Initialize the `PushDatasets` service. 33 | push_datasets_service = power_bi_client.push_datasets() 34 | 35 | # Grab the tables from a Dataset. 36 | pprint( 37 | push_datasets_service.get_tables(dataset_id="8ea21119-fb8f-4592-b2b8-141b824a2b7e") 38 | ) 39 | 40 | # Grab the tables from a Dataset. 41 | pprint( 42 | push_datasets_service.get_group_tables( 43 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 44 | dataset_id="8ea21119-fb8f-4592-b2b8-141b824a2b7e", 45 | ) 46 | ) 47 | 48 | # Create a new Table Object. 49 | table_sales = Table(name="sales_table") 50 | 51 | # Create a new column for our partner name. 52 | name_column = Column(name="partner_name", data_type=ColumnDataTypes.STRING) 53 | 54 | # Also create a new one for our sales numbers. 55 | sales_column = Column(name="partner_sales", data_type=ColumnDataTypes.DECIMAL) 56 | 57 | # Add the columns to the table. 58 | table_sales.add_column(column=name_column) 59 | table_sales.add_column(column=sales_column) 60 | 61 | # Define a new dataset. 62 | new_dataset = Dataset(name="sales_dataset", tables=[]) 63 | new_dataset.default_mode = "Push" 64 | 65 | # Add the Sales table to it. 66 | new_dataset.add_table(table=table_sales) 67 | 68 | pprint(push_datasets_service.post_dataset(dataset=new_dataset)) 69 | 70 | # Define some fake data. 71 | new_rows = [ 72 | {"partner_name": "Alex Reed", "partner_sales": 1000.30}, 73 | {"partner_name": "John Reed", "partner_sales": 2000.30}, 74 | {"partner_name": "James Reed", "partner_sales": 5000.30}, 75 | ] 76 | 77 | push_datasets_service.post_dataset_rows( 78 | dataset_id="8ea21119-fb8f-4592-b2b8-141b824a2b7e", 79 | table_name="sales_table", 80 | rows=new_rows, 81 | ) 82 | 83 | 84 | # Let's update the table by creating a new table object. 85 | new_table_sales = Table(name="sales_table") 86 | 87 | # Keep the Name Column. 88 | name_column = Column(name="partner_name", data_type=ColumnDataTypes.STRING) 89 | 90 | # Keep the Sales Column. 91 | sales_column = Column(name="partner_sales", data_type=ColumnDataTypes.DECIMAL) 92 | 93 | # Add a new column for the location. 94 | location_column = Column(name="partner_location", data_type=ColumnDataTypes.STRING) 95 | location_column.data_category = "Location" 96 | 97 | new_table_sales.add_column(column=name_column) 98 | new_table_sales.add_column(column=sales_column) 99 | new_table_sales.add_column(column=location_column) 100 | 101 | new_rows = [ 102 | { 103 | "partner_name": "Alex Reed", 104 | "partner_sales": 1000.30, 105 | "partner_location": "Great Falls, VA", 106 | }, 107 | { 108 | "partner_name": "John Reed", 109 | "partner_sales": 2000.30, 110 | "partner_location": "Houston, TX", 111 | }, 112 | { 113 | "partner_name": "James Reed", 114 | "partner_sales": 5000.30, 115 | "partner_location": "San Diego, CA", 116 | }, 117 | ] 118 | 119 | # Update the table. 120 | pprint( 121 | push_datasets_service.put_dataset( 122 | dataset_id="8ea21119-fb8f-4592-b2b8-141b824a2b7e", 123 | table_name="sales_table", 124 | table=new_table_sales, 125 | ) 126 | ) 127 | 128 | # Add the new rows. 129 | push_datasets_service.post_dataset_rows( 130 | dataset_id="8ea21119-fb8f-4592-b2b8-141b824a2b7e", 131 | table_name="sales_table", 132 | rows=new_rows, 133 | ) 134 | -------------------------------------------------------------------------------- /samples/use_reports_service.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Reports` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | from powerbi.enums import ExportFileFormats 7 | 8 | # Initialize the Parser. 9 | config = ConfigParser() 10 | 11 | # Read the file. 12 | config.read("config/config.ini") 13 | 14 | # Get the specified credentials. 15 | client_id = config.get("power_bi_api", "client_id") 16 | redirect_uri = config.get("power_bi_api", "redirect_uri") 17 | client_secret = config.get("power_bi_api", "client_secret") 18 | 19 | # Initialize the Client. 20 | power_bi_client = PowerBiClient( 21 | client_id=client_id, 22 | client_secret=client_secret, 23 | scope=["https://analysis.windows.net/powerbi/api/.default"], 24 | redirect_uri=redirect_uri, 25 | credentials="config/power_bi_state.jsonc", 26 | ) 27 | 28 | # Initialize the `Reports` service. 29 | reports_service = power_bi_client.reports() 30 | 31 | # Grab all the reports in our workspace. 32 | pprint(reports_service.get_reports()) 33 | 34 | # Grab all the reports from a specific workspace. 35 | pprint( 36 | reports_service.get_group_reports(group_id="f78705a2-bead-4a5c-ba57-166794b05c78") 37 | ) 38 | 39 | # Grab a specific report from our workspace. 40 | pprint(reports_service.get_report(report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082")) 41 | 42 | # Grab a specific report from a specific workspace. 43 | pprint( 44 | reports_service.get_group_report( 45 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 46 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", 47 | ) 48 | ) 49 | 50 | # Grab the pages from a specific report. 51 | pprint(reports_service.get_pages(report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082")) 52 | 53 | # Grab the pages from a specific report in a specific workspace. 54 | pprint( 55 | reports_service.get_group_pages( 56 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 57 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", 58 | ) 59 | ) 60 | 61 | # Grab a specific page from a specific report. 62 | pprint( 63 | reports_service.get_page( 64 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", page_name="ReportSection" 65 | ) 66 | ) 67 | 68 | # Grab a specific page from a specific report in a specific workspace. 69 | pprint( 70 | reports_service.get_group_page( 71 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 72 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", 73 | page_name="ReportSection", 74 | ) 75 | ) 76 | 77 | # Clone a specific report. 78 | pprint( 79 | reports_service.clone_report( 80 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", name="MyNewReport" 81 | ) 82 | ) 83 | 84 | # Clone the same report but this time from a specific workspace. 85 | pprint( 86 | reports_service.clone_group_report( 87 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 88 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", 89 | name="MyOtherNewReport", 90 | ) 91 | ) 92 | 93 | 94 | # Delete a specific report. 95 | pprint(reports_service.delete_report(report_id="c19c7599-7f92-4d11-b384-c9ae33368304")) 96 | 97 | # Delete a specific report from a specific workspace. 98 | pprint( 99 | reports_service.delete_group_report( 100 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 101 | report_id="f0ca06d0-4a40-4329-823d-6184d9a3f468", 102 | ) 103 | ) 104 | 105 | # Export a report from "My Workspace". 106 | my_report_content = reports_service.export_report( 107 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082" 108 | ) 109 | 110 | with open(file="my_report_export.pbix", mode="wb+") as power_bi_file: 111 | power_bi_file.write(my_report_content) 112 | 113 | 114 | # Export a report from a specific workspace. 115 | my_report_content = reports_service.export_group_report( 116 | group_id="f78705a2-bead-4a5c-ba57-166794b05c78", 117 | report_id="cec3fab1-2fc2-424e-8d36-d6180ef05082", 118 | ) 119 | 120 | 121 | with open(file="my_group_report_export.pbix", mode="wb+") as power_bi_file: 122 | power_bi_file.write(my_report_content) 123 | 124 | pprint( 125 | reports_service.get_datasources(report_id="cd5fd3b0-e806-4e38-a02b-ff13ef594c09") 126 | ) 127 | 128 | 129 | my_report_content = reports_service.export_to_file( 130 | report_id="cd5fd3b0-e806-4e38-a02b-ff13ef594c09", file_format=ExportFileFormats.PDF 131 | ) 132 | 133 | pprint(my_report_content) 134 | 135 | with open(file="my_group_report_export.pdf", mode="wb+") as power_bi_file: 136 | power_bi_file.write(my_report_content) 137 | -------------------------------------------------------------------------------- /samples/use_template_apps_service.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `TemplateApps` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `TemplateApps` service. 28 | template_apps_service = power_bi_client.template_apps() 29 | 30 | # Create an Install Ticket. 31 | pprint( 32 | template_apps_service.create_install_ticket( 33 | app_id="91ce06d1-d81b-4ea0-bc6d-2ce3dd2f8e87", 34 | owner_tenant_id="d43e3248-3d83-44aa-a94d-c836bd7f9b79", 35 | package_key="g632bb64...OfsoqT56xEM=", 36 | config={"configuration": {"param1": "value1", "param2": "value2"}}, 37 | ) 38 | ) 39 | -------------------------------------------------------------------------------- /samples/use_users_service.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `Users` service.""" 2 | 3 | from pprint import pprint 4 | from configparser import ConfigParser 5 | from powerbi.client import PowerBiClient 6 | 7 | # Initialize the Parser. 8 | config = ConfigParser() 9 | 10 | # Read the file. 11 | config.read("config/config.ini") 12 | 13 | # Get the specified credentials. 14 | client_id = config.get("power_bi_api", "client_id") 15 | redirect_uri = config.get("power_bi_api", "redirect_uri") 16 | client_secret = config.get("power_bi_api", "client_secret") 17 | 18 | # Initialize the Client. 19 | power_bi_client = PowerBiClient( 20 | client_id=client_id, 21 | client_secret=client_secret, 22 | scope=["https://analysis.windows.net/powerbi/api/.default"], 23 | redirect_uri=redirect_uri, 24 | credentials="config/power_bi_state.jsonc", 25 | ) 26 | 27 | # Initialize the `Users` service. 28 | users_service = power_bi_client.users() 29 | 30 | # Refresh Users Permissions. 31 | pprint(users_service.refresh_user_permissions()) 32 | -------------------------------------------------------------------------------- /samples/use_utils.py: -------------------------------------------------------------------------------- 1 | """Demonstrates how to use the `powerbi.utils` module.""" 2 | 3 | from powerbi.utils import Table 4 | from powerbi.utils import Column 5 | from powerbi.utils import Dataset 6 | from powerbi.enums import ColumnDataTypes 7 | 8 | # Create a new Table Object. 9 | table_sales = Table(name="sales_table") 10 | 11 | # Create a new column for our partner name. 12 | name_column = Column(name="partner_name", data_type=ColumnDataTypes.STRING) 13 | 14 | # Also create a new one for our sales numbers. 15 | sales_column = Column(name="partner_sales", data_type=ColumnDataTypes.DECIMAL) 16 | 17 | # Add the columns to the table. 18 | table_sales.add_column(column=name_column) 19 | table_sales.add_column(column=sales_column) 20 | 21 | # Define a new dataset. 22 | new_dataset = Dataset(name="sales_dataset", tables=[]) 23 | 24 | # Add the Sales table to it. 25 | new_dataset.add_table(table=table_sales) 26 | 27 | # Print the new dataset. 28 | print(new_dataset) 29 | print(new_dataset.to_dict()) 30 | print(table_sales.to_dict()) 31 | print(name_column.to_dict()) 32 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Setup file for the power-bi-python-api library.""" 2 | 3 | from setuptools import setup 4 | from setuptools import find_namespace_packages 5 | 6 | # Open the README file. 7 | with open(file="README.md", mode="r", encoding="utf-8") as fh: 8 | long_description = fh.read() 9 | 10 | setup( 11 | name="python-power-bi", 12 | 13 | # Define Author Info. 14 | author="Alex Reed", 15 | author_email="coding.sigma@gmail.com", 16 | 17 | # Define Version Info. 18 | version="0.1.2", 19 | 20 | # Define descriptions. 21 | description="The Unofficial Python API wrapper for the Microsoft Power BI REST API.", 22 | long_description=long_description, 23 | long_description_content_type="text/markdown", 24 | 25 | # Define repo location. 26 | url="https://github.com/areed1192/power-bi-python-api.git", 27 | 28 | # Define dependencies. 29 | install_requires=["msal>=1.31.1", "requests>=2.32.3"], 30 | 31 | # Specify folder content. 32 | packages=find_namespace_packages(include=["powerbi"]), 33 | 34 | # Define the python version. 35 | python_requires=">3.7" 36 | ) 37 | -------------------------------------------------------------------------------- /tests/test_client.py: -------------------------------------------------------------------------------- 1 | """Unit test for the `PowerBiClient` object.""" 2 | 3 | import unittest 4 | 5 | from unittest import TestCase 6 | from configparser import ConfigParser 7 | 8 | from powerbi.client import PowerBiClient 9 | from powerbi.auth import PowerBiAuth 10 | from powerbi.session import PowerBiSession 11 | from powerbi.dashboards import Dashboards 12 | from powerbi.groups import Groups 13 | from powerbi.template_apps import TemplateApps 14 | from powerbi.users import Users 15 | from powerbi.dataflow_storage_account import DataflowStorageAccount 16 | from powerbi.push_datasets import PushDatasets 17 | from powerbi.available_features import AvailableFeatures 18 | from powerbi.capacities import Capacities 19 | from powerbi.reports import Reports 20 | from powerbi.pipelines import Pipelines 21 | from powerbi.apps import Apps 22 | 23 | 24 | class TestPowerBiSession(TestCase): 25 | """Will perform a unit test for the `PowerBiClient` object.""" 26 | 27 | def setUp(self) -> None: 28 | """Set up the `PowerBiClient` object.""" 29 | 30 | # Initialize the Parser. 31 | config = ConfigParser() 32 | 33 | # Read the file. 34 | config.read("config/config.ini") 35 | 36 | # Get the specified credentials. 37 | client_id = config.get("power_bi_api", "client_id") 38 | redirect_uri = config.get("power_bi_api", "redirect_uri") 39 | client_secret = config.get("power_bi_api", "client_secret") 40 | 41 | # Initialize the Client. 42 | self.power_bi_client = PowerBiClient( 43 | client_id=client_id, 44 | client_secret=client_secret, 45 | scope=["https://analysis.windows.net/powerbi/api/.default"], 46 | redirect_uri=redirect_uri, 47 | credentials="config/power_bi_state.jsonc", 48 | ) 49 | 50 | def test_creates_instance_of_client(self): 51 | """Create an instance and make sure it's a `PowerBiClient` object""" 52 | 53 | self.assertIsInstance(self.power_bi_client, PowerBiClient) 54 | 55 | def test_creates_instance_of_session(self): 56 | """Create an instance and make sure it's a `PowerBiSession` object""" 57 | 58 | self.assertIsInstance(self.power_bi_client.power_bi_session, PowerBiSession) 59 | 60 | def test_creates_instance_of_auth(self): 61 | """Create an instance and make sure it's a `PowerBiAuth` object""" 62 | 63 | self.assertIsInstance(self.power_bi_client.power_bi_auth_client, PowerBiAuth) 64 | 65 | def test_creates_instance_of_apps(self): 66 | """Create an instance and make sure it's a `Apps` object""" 67 | 68 | self.assertIsInstance(self.power_bi_client.apps(), Apps) 69 | 70 | def test_creates_instance_of_dashboards(self): 71 | """Create an instance and make sure it's a `Dashboards` object""" 72 | 73 | self.assertIsInstance(self.power_bi_client.dashboards(), Dashboards) 74 | 75 | def test_creates_instance_of_groups(self): 76 | """Create an instance and make sure it's a `Groups` object""" 77 | 78 | self.assertIsInstance(self.power_bi_client.groups(), Groups) 79 | 80 | def test_creates_instance_of_users(self): 81 | """Create an instance and make sure it's a `Users` object""" 82 | 83 | self.assertIsInstance(self.power_bi_client.users(), Users) 84 | 85 | def test_creates_instance_of_template_apps(self): 86 | """Create an instance and make sure it's a `TemplateApps` object""" 87 | 88 | self.assertIsInstance(self.power_bi_client.template_apps(), TemplateApps) 89 | 90 | def test_creates_instance_of_dataflow_storage_account(self): 91 | """Create an instance and make sure it's a `DataflowStorageAccount` object""" 92 | 93 | self.assertIsInstance( 94 | self.power_bi_client.dataflow_storage_account(), DataflowStorageAccount 95 | ) 96 | 97 | def test_creates_instance_of_push_datasets(self): 98 | """Create an instance and make sure it's a `PushDatasets` object""" 99 | 100 | self.assertIsInstance(self.power_bi_client.push_datasets(), PushDatasets) 101 | 102 | def test_creates_instance_of_available_features(self): 103 | """Create an instance and make sure it's a `AvailableFeatures` object""" 104 | 105 | self.assertIsInstance( 106 | self.power_bi_client.available_features(), AvailableFeatures 107 | ) 108 | 109 | def test_creates_instance_of_capacities(self): 110 | """Create an instance and make sure it's a `Capacities` object""" 111 | 112 | self.assertIsInstance(self.power_bi_client.capactities(), Capacities) 113 | 114 | def test_creates_instance_of_reports(self): 115 | """Create an instance and make sure it's a `Capacities` object""" 116 | 117 | self.assertIsInstance(self.power_bi_client.reports(), Reports) 118 | 119 | def test_creates_instance_of_pipelines(self): 120 | """Create an instance and make sure it's a `Pipelines` object""" 121 | 122 | self.assertIsInstance(self.power_bi_client.pipelines(), Pipelines) 123 | 124 | def tearDown(self) -> None: 125 | """Teardown the `PowerBiClient` object.""" 126 | 127 | del self.power_bi_client 128 | 129 | 130 | if __name__ == "__main__": 131 | unittest.main() 132 | --------------------------------------------------------------------------------