├── .github └── workflows │ └── pythonpublish.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── metabase ├── __init__.py └── metabase.py ├── setup.cfg └── setup.py /.github/workflows/pythonpublish.yml: -------------------------------------------------------------------------------- 1 | # This workflows 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 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v1 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install setuptools wheel twine 25 | - name: Build and publish 26 | env: 27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 29 | run: | 30 | python setup.py sdist bdist_wheel 31 | twine upload dist/* 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pot 3 | *.py[co] 4 | .tox/ 5 | __pycache__ 6 | MANIFEST 7 | dist/ 8 | docs/_build/ 9 | docs/locale/ 10 | node_modules/ 11 | tests/coverage_html/ 12 | tests/.coverage 13 | build/ 14 | tests/report/ 15 | venv/ 16 | assets/webpack_bundles 17 | .DS_Store 18 | *.tar* 19 | *.tgz 20 | db.sqlite3 21 | .env 22 | *.swp 23 | webpack-stats.json 24 | .idea 25 | .Python 26 | bin/ 27 | include/ 28 | lib/ 29 | pip-selfcheck.json 30 | test.py 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Derrick Hwechul Cho 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 | # metabase-py 2 | 3 | python wrapper for metabase api 4 | 5 | ## Installation 6 | 7 | ```bash 8 | pip install metabase 9 | ``` 10 | 11 | ## How to use 12 | 13 | ```python 14 | import pprint 15 | from metabase import Metabase 16 | 17 | metabase = Metabase(email="", password="") 18 | 19 | # get all cards 20 | pprint.pprint(metabase.get("/card/")) 21 | 22 | payload={ 23 | 'dataset_query': { 24 | 'database': 2, 25 | 'native': { 26 | 'query': "SELECT 1,2,3;" }, 27 | 'type': 'native' }, 28 | 'display': "area", 29 | 'name': 'test:1', 30 | 'visualization_settings': { 31 | 'graph.dimensions': ['a'], 32 | 'graph.metrics': ['b', 'c'], 33 | 'graph.show_goal': False, 34 | 'line.interpolate': 'linear', 35 | 'line.marker_enabled': True, 36 | 'line.missing': 'interpolate', 37 | 'stackable.stack_type': 'stacked', 38 | 'table.column_widths': [] }} 39 | 40 | pprint.pprint(metabase.post("/card/", json=payload)) 41 | pprint.pprint(metabase.get("/card/")) 42 | ``` 43 | 44 | ## Environments 45 | 46 | - `METABASE_ENDPOINT` 47 | - `METABASE_AUTH_EMAIL` 48 | - `METABASE_AUTH_PASSWORD` 49 | 50 | ## Methods 51 | 52 | - `get(, params=data)` 53 | - `post(, json=data)` 54 | - `head(, ...)` 55 | - `delete(, ...)` 56 | 57 | ## Features 58 | 59 | - can set `session key` as manually 60 | - `auth_callback` authentication callback (For custom storage) 61 | 62 | ## Notice 63 | 64 | This library wraps [requests](http://docs.python-requests.org/en/master/) 65 | 66 | ## Contributors 67 | 68 | see [here](https://github.com/STUnitas/metabase-py/graphs/contributors) 69 | -------------------------------------------------------------------------------- /metabase/__init__.py: -------------------------------------------------------------------------------- 1 | from .metabase import Metabase 2 | -------------------------------------------------------------------------------- /metabase/metabase.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import requests 4 | 5 | 6 | class Metabase(object): 7 | 8 | def __init__(self, *args, endpoint=None, email=None, 9 | password=None, session=None, **kwargs): 10 | self.endpoint = endpoint or os.getenv('METABASE_ENDPOINT') + '/api' 11 | self.email = email or os.getenv('METABASE_AUTH_EMAIL') 12 | self.password = password or os.getenv('METABASE_AUTH_PASSWORD') 13 | self.session = session or os.getenv('METABASE_SESSION') 14 | self.auth_callback = kwargs.pop('auth_callback', None) 15 | 16 | if self.session is None: 17 | self.auth() 18 | 19 | def session_header(self): 20 | return {'X-Metabase-Session': self.session} 21 | 22 | def get_session_headers(self, *args, **kwargs): 23 | res = requests.get(self.endpoint + '/user/current', 24 | headers=self.session_header()) 25 | if res.status_code == 401: 26 | self.auth() 27 | return self.session_header() 28 | 29 | def fetch_header(self, r): 30 | if r.status_code == 200 or r.status_code == 202: 31 | return True 32 | else: 33 | return False 34 | 35 | def fetch_body(self, r): 36 | if r.status_code == 200 or r.status_code == 202: 37 | return True, r.json() 38 | else: 39 | return False, None 40 | 41 | def _get_session_headers(self, kwargs): 42 | if not kwargs.pop('check_session', True): 43 | return self.get_session_header(**kwargs) 44 | return headers or {} 45 | 46 | def get(self, *args, headers=None, **kwargs): 47 | headers = self.get_session_headers(headers, kwargs) 48 | r = requests.get(self.endpoint + args[0], headers=headers, **kwargs) 49 | return self.fetch_body(r) 50 | 51 | def post(self, *args, headers=None, **kwargs): 52 | headers = self.get_session_headers(headers, kwargs) 53 | r = requests.post(self.endpoint + args[0], headers=headers, **kwargs) 54 | return self.fetch_body(r) 55 | 56 | def put(self, *args, headers=None, **kwargs): 57 | headers = self.get_session_headers(headers, kwargs) 58 | r = requests.put(self.endpoint + args[0], headers=headers, **kwargs) 59 | return self.fetch_header(r) 60 | 61 | def delete(self, *args, headers=None, **kwargs): 62 | headers = self.get_session_headers(headers, kwargs) 63 | r = requests.delete(self.endpoint + args[0], headers=headers, **kwargs) 64 | return self.fetch_header(r) 65 | 66 | def auth(self, **kwargs): 67 | payload = { 68 | 'username': self.email, 69 | 'password': self.password 70 | } 71 | 72 | res = requests.post(self.endpoint + '/session', json=payload) 73 | 74 | if res.status_code == 200: 75 | data = res.json() 76 | self.session = data['id'] 77 | else: 78 | raise Exception(res) 79 | 80 | if hasattr(self, 'auth_callback') and callable(self.auth_callback): 81 | self.auth_callback(self) 82 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | __version__ = "1.3.2" 4 | 5 | setup( 6 | name="metabase", 7 | version=__version__, 8 | description='python wrapper for metabase api', 9 | url="https://github.com/stunitas/metabase-py", 10 | license="MIT License", 11 | author="flrngel", 12 | author_email="flrngel@gmail.com", 13 | install_requires=["requests"], 14 | packages=find_packages()) 15 | --------------------------------------------------------------------------------