While the Qlik platform has maintained and supported libraries developer libraries in JavaScript and .NET/C# for several years, they have more recently released a library for interacting with Qlik in Python. They call it the Platform SDK, which is also available as a TypeScript library.
The Python library is essentially a set of Python classes and methods that mirror the structures and functions of the Qlik QRS and Engine APIs, also providing some conveniences around authentication and WebSocket connections. The library is open for anyone to download and use thanks to its permissive MIT license.
The use cases for the Qlik Python SDK include being able to write automation scripts for repetitive admin tasks, load app and object data into a Pandas dataframe, and even creating reports built off of app or log data.
Installing the library is very simple — just make sure you are using at least Python 3.8:
python3 -m pip install --upgrade qlik-sdk
Let’s look at some examples of how we can use the library. Below, we import a few classes from the qlik_sdk
library and then create some variables to hold our Qlik Cloud tenant URL and API key. We’ll use the API key to authenticate with a bearer token but an OAuth2.0 implementation is also available. Learn how to generate an API key here. The tenant URL and API key are then used to create an Apps
object, which provides some high-level methods for interacting with app documents in Qlik Cloud.
from qlik_sdk import Apps, AuthType, Config
# connect to Qlik engine
= "https://your-tenant.us.qlikcloud.com/"
base_url = "xxxxxx"
api_key = Apps(Config(host=base_url, auth_type=AuthType.APIKey, api_key=api_key)) apps
Now that we’ve got our authentication situated, let’s add some code to interact with a Qlik app and its contents. First, let’s import a new class, NxPage
, which describes a hypercube page (more about Qlik hypercubes here). Then let’s create a new function, get_qlik_obj_data()
, to define the steps for getting data from a Qlik object, like a table or bar chart. In this function, we can take an app
parameter and an obj_id
parameter to open an WebSocket connection to the specified app, get the app layout, get the size of the object’s hypercube, and then fetch the data for that hypercube:
from qlik_sdk.apis.Qix import NxPage
= apps.get("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
app
def get_qlik_obj_data(app: NxApp, obj_id: str) -> list:
"""Get data from an object in a Qlik app."""
# opens a websocket connection against the Engine API and gets the app hypercube
with app.open():
= app.get_object(obj_id)
tbl_obj = tbl_obj.get_layout()
tbl_layout = tbl_layout.qHyperCube.qSize
tbl_size = tbl_obj.get_hyper_cube_data(
tbl_hc "/qHyperCubeDef",
=tbl_size.qcy, qWidth=tbl_size.qcx, qLeft=0, qTop=0)],
[NxPage(qHeight
)
return tbl_hc
= get_qlik_obj_data(app=app, obj_id="xxxxxx") obj_data
This code would end up returning a list of data pages, something like this:
[NxDataPage(qArea=Rect(qHeight=50, qLeft=0, qTop=0, qWidth=10), qIsReduced=None, qMatrix=[NxCellRows(), NxCellRows(), NxCellRows(), ...]
And if then then peek into one of the NxCellRows
contained in the qMatrix
property, we’d see an object like this:
NxCell(qAttrDims=None, qAttrExps=None, qElemNumber=29, qFrequency=None, qHighlightRanges=None, qInExtRow=None, qIsEmpty=None, qIsNull=None, qIsOtherCell=None, qIsTotalCell=None, qMiniChart=None, qNum=282, qState='O', qText='282')
The cell value is shown as 282 in the qText
property. We may note, though, that we can’t readily identify the field that this value represents.
Let’s add some code to make the resulting dataset include the fields for each cell value. We can do that by adding a get_ordered_cols_qlik_hc()
function to get the ordered list of columns in each of these NxCellRows
items.
This function will ultimately take a straight hypercube as an argument and do the following:
- Get the list of dimensions and measures and then combine them into one list.
- Reorder that list to match the correct column order as defined in the hypercube’s
qColumnOrder
property. - Return that ordered column list.
Then in our get_qlik_obj_data()
function, we use our new get_ordered_cols_qlik_hc()
function to get our columns. From there we iterate through each row of each data page in the hypercube and create a new dictionary object for each cell and then adding those dictionaries to a list for each row.
New and updated code shown in bold:
from qlik_sdk.apis.Qix import NxPage, HyperCube
def get_ordered_cols_qlik_hc(hc: HyperCube) -> list:
"""get ordered columns from Qlik hypercube."""
# get object columns
= [d.qFallbackTitle for d in hc.qDimensionInfo]
dim_names = [m.qFallbackTitle for m in hc.qMeasureInfo]
meas_names = dim_names.copy()
obj_cols
obj_cols.extend(meas_names)
# order column array to match hypercube column order
= []
new_cols = hc.qColumnOrder
new_col_order for c in new_col_order:
new_cols.append(obj_cols[c])
return new_cols
def get_qlik_obj_data(app: NxApp, obj_id: str) -> list:
""""""
# opens a websocket connection against the Engine API and gets the app hypercube
with app.open():
= app.get_object(obj_id)
tbl_obj = tbl_obj.get_layout()
tbl_layout = tbl_layout.qHyperCube.qSize
tbl_size = tbl_obj.get_hyper_cube_data(
tbl_hc "/qHyperCubeDef",
=tbl_size.qcy, qWidth=tbl_size.qcx, qLeft=0, qTop=0)],
[NxPage(qHeight
)
= get_ordered_cols_qlik_hc(tbl_layout.qHyperCube)
hc_cols
# traverse data pages and store dict for each row
= len(hc_cols)
hc_cols_count = []
tbl_data
for data_page in tbl_hc:
for rows in data_page.qMatrix:
= {hc_cols[i]: rows[i].qText for i in range(hc_cols_count)}
row
tbl_data.append(row)
return tbl_data
= get_qlik_obj_data(app=app, obj_id="xxxxxx") obj_data
This will get us the desired field: value
format that will allow us to better analyze the output, like so:
[ {'FID': '282', 'Summary Metric': '47', 'Name': 'Sweetwater', ...}, {'FID': '285', 'Summary Metric': '48', 'Name': 'Sweetwater', ...}, {'FID': '198', 'Summary Metric': '47', 'Name': 'Vision Drive', ...}, ]