Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea
.env
test_clients.py
38 changes: 38 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
FROM postgres:12-alpine

#
# Docker image that adds multicorn & gooddata-fdw on top of official PostgreSQL image.
#
# Note: multicorn has some issues building against PostgreSQL 13 so going with v12 for now
#

#
# There is also some funny stuff in the multicorn make file. Documented here:
#
# see: https://github.com/Segfault-Inc/Multicorn/issues/183
# see: https://gist.github.com/felixge/49c37dffb49efc8bc0911b1113231de0#file-dockerfile
#
# The preflight-check is removed because of this.
#

RUN apk add --no-cache --update wget make musl-dev llvm11 gcc clang python3 python3-dev py3-setuptools py3-pip \
&& pip3 --no-color --no-cache-dir -qq install pgxnclient \
\
&& pgxnclient install foreign_table_exposer \
\
&& wget http://api.pgxn.org/dist/multicorn/1.4.0/multicorn-1.4.0.zip && unzip multicorn-1.4.0 && cd multicorn-1.4.0 \
&& echo "" > preflight-check.sh && PYTHON_OVERRIDE=python3 make && PYTHON_OVERRIDE=python3 make install

#
# Add all required gooddata-python packages into the image
#
ADD gooddata-afm-client /gd/gooddata-afm-client
ADD gooddata-metadata-client /gd/gooddata-metadata-client
ADD gooddata-sdk /gd/gooddata-sdk
ADD gooddata-fdw /gd/gooddata-fdw

RUN cd /gd/gooddata-afm-client && python3 setup.py install \
&& cd /gd/gooddata-metadata-client && python3 setup.py install \
&& cd /gd/gooddata-sdk && python3 setup.py install \
&& cd /gd/gooddata-fdw && python3 setup.py install \
&& echo "CREATE EXTENSION multicorn; CREATE EXTENSION foreign_table_exposer; " > /docker-entrypoint-initdb.d/create_extensions.sql
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,71 @@
# gooddata-python-sdk
GoodData.CN Python SDK
# GoodData.CN Python Foundations

This repository contains Python packages useful for integration with GoodData.CN:

- gooddata-afm-client, gooddata-metadata-client: low-level API clients generated from GD.CN Open API specifications
- gooddata-sdk: a Python SDK providing added value functions and convenience layers on top of the clients
- gooddata-fdw: a GD.CN Foreign Data Wrapper for PostgreSQL

## API Clients

These are generated using the openapi-generator. The generated clients are fairly convoluted and can be tricky
to use. They do work with some known issues and allow you to call any metadata or computation API in your GoodData.CN
installation.

### Known issues

The complexity of some of the GD.CN API schemas combined with the bugs in the generated code mean you may need to
disable return type checking and/or type checking when creating model objects.

Use the `_check_return_type=False` keyword parameter when calling generated API client methods to disable return
type checking. For example:

```python
import gooddata_metadata_client.apis as metadata_apis

api = metadata_apis.WorkspaceObjectControllerApi()
metrics = api.get_all_entities_metrics('workspace_id', size=500, _check_return_type=False)
```

Use the `_check_type=False` keyword parameter when creating objects from generated models. For example:

```python
import gooddata_afm_client.models as afm_models

afm_models.RelativeDateFilterBody(dataset=..., granularity=..., _from=..., to=..., _check_type=False)
```

## Python SDK

The Python SDK aims to provide cleaner APIs and convenience layers on top of the generated clients.

For instance behold how it is possible to read an Insight from GD.CN server, trigger its computation and then
read the data:

```python
import gooddata_sdk

sdk = gooddata_sdk.GoodDataSdk(HOST, TOKEN)

# reads insight from workspace
insight = sdk.insights.get_insight(workspace_id, insight_id)

# triggers computation for the insight. the result will be returned in a tabular form
table = sdk.tables.for_insight(workspace_id, insight)

# and this is how you can read data row-by-row and do something with it
for row in table.read_all():
print(row)
```

## GoodData.CN Foreign Data Wrapper for PostgreSQL

Foreign Data Wrapper (FDW) presents a way to map GoodData.CN semantic layer and/or insights stored in your GoodData.CN
into PostgreSQL as foreign tables that you can then query using SQL.

Check out the [gooddata-fdw package](./gooddata-fdw) documentation to learn more and get started.

## GoodData to pandas adapters

The [gooddata-pandas](./gooddata-pandas) is a thin layer that utilizes Python SDK and allows you to conveniently
create pandas series and data frames.
32 changes: 32 additions & 0 deletions generate_afm_client.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash

rm -rf gooddata_afm_client

#
# https://openapi-generator.tech/docs/generators/python/
# --additional-properties=packageName=gooddata_afm_client \
#

docker run --rm \
-v "${PWD}:/local" \
-u $(id -u ${USER}):$(id -g ${USER}) \
openapitools/openapi-generator-cli generate \
-g python \
--package-name gooddata_afm_client \
-i https://staging.anywhere.gooddata.com/api/schemas/afm \
-o /local/gooddata-afm-client

cd gooddata_afm_client
rm -rf .gitlab-ci.yml .travis.yml git_push.sh test
cd ..

#
# this here function in model_utils.py: convert_js_args_to_python_args
#
# gets messed up when our ObjectLinks are being parsed. that is because:
#
# - it uses _self as named parameter to a decorator function it creates; this function also has **kwargs
# - our ObjectLinks contain self (as in links.self); the generator for some of its internal workings also generates '_self' as key of some dict
# - the decorator function eventually gets called with this '_self' thing.. and things bomb because there are multiple values of a named argument
#
sed -i 's/_self/_self_loathing_/g' gooddata-afm-client/gooddata_afm_client/model_utils.py
30 changes: 30 additions & 0 deletions generate_metadata_client.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash

#
# https://openapi-generator.tech/docs/generators/python/
# --additional-properties=packageName=gooddata_afm_client \
#

docker run --rm \
-v "${PWD}:/local" \
-u $(id -u ${USER}):$(id -g ${USER}) \
openapitools/openapi-generator-cli generate \
-g python \
--additional-properties=packageName=gooddata_metadata_client \
-i https://staging.anywhere.gooddata.com/api/schemas/metadata \
-o /local/gooddata_metadata_client

cd gooddata-metadata-client
rm -rf .gitlab-ci.yml .travis.yml git_push.sh test
cd ..

#
# this here function in model_utils.py: convert_js_args_to_python_args
#
# gets messed up when our ObjectLinks are being parsed. that is because:
#
# - it uses _self as named parameter to a decorator function it creates; this function also has **kwargs
# - our ObjectLinks contain self (as in links.self); the generator for some of its internal workings also generates '_self' as key of some dict
# - the decorator function eventually gets called with this '_self' thing.. and things bomb because there are multiple values of a named argument
#
sed -i 's/_self/_self_loathing_/g' gooddata-metadata-client/gooddata_metadata_client/model_utils.py
66 changes: 66 additions & 0 deletions gooddata-afm-client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
venv/
.venv/
.python-version
.pytest_cache

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

#Ipython Notebook
.ipynb_checkpoints
23 changes: 23 additions & 0 deletions gooddata-afm-client/.openapi-generator-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Loading