qe-api-client 2.4.0__py3-none-any.whl → 2.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -556,16 +556,6 @@ class EngineAppApi:
556
556
  except KeyError:
557
557
  return response['error']
558
558
 
559
- # GetDimension: Get the handle of a dimension by using the GetDimension method. # NOQA
560
- # Parameter: dimension id
561
- def get_dimension(self, doc_handle, dim_id):
562
- msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "GetDimension",
563
- "params": [dim_id]})
564
- response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
565
- try:
566
- return response['result']['qReturn']
567
- except KeyError:
568
- return response['error']
569
559
 
570
560
  # GetEmptyScript: Creates a script that contains one section. This section contains Set statements that give # NOQA
571
561
  # localized information from the regional settings of the computer.
@@ -18,18 +18,18 @@ class EngineGenericDimensionApi:
18
18
  """
19
19
  self.engine_socket = socket
20
20
 
21
- def get_dimension(self, handle, dimension_id):
21
+ def get_dimension(self, app_handle: int, dimension_id: str):
22
22
  """
23
23
  Retrieves the definition of a specific dimension from the Qlik Sense engine.
24
24
 
25
25
  Parameters:
26
- handle (int): The handle identifying the dimension object.
26
+ app_handle (int): The handle identifying the application.
27
27
  dimension_id (str): The unique identifier (qId) of the dimension to retrieve.
28
28
 
29
29
  Returns:
30
30
  dict: The definition of the requested dimension (qReturn). In case of an error, returns the error information.
31
31
  """
32
- msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle, "method": "GetDimension",
32
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": app_handle, "method": "GetDimension",
33
33
  "params": {"qId": dimension_id}})
34
34
  response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
35
35
  try:
@@ -18,18 +18,18 @@ class EngineGenericMeasureApi:
18
18
  """
19
19
  self.engine_socket = socket
20
20
 
21
- def get_measure(self, handle, measure_id):
21
+ def get_measure(self, app_handle: int, measure_id: str):
22
22
  """
23
23
  Retrieves the definition of a specific measure from the Qlik Sense engine.
24
24
 
25
25
  Parameters:
26
- handle (int): The handle identifying the measure object.
26
+ app_handle (int): The handle identifying the application.
27
27
  measure_id (str): The unique identifier (qId) of the measure to retrieve.
28
28
 
29
29
  Returns:
30
30
  dict: The definition of the requested measure (qReturn). In case of an error, returns the error information.
31
31
  """
32
- msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle, "method": "GetMeasure", "params": {"qId": measure_id}})
32
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": app_handle, "method": "GetMeasure", "params": {"qId": measure_id}})
33
33
  response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
34
34
  try:
35
35
  return response["result"]["qReturn"]
qe_api_client/engine.py CHANGED
@@ -9,6 +9,7 @@ import qe_api_client.api_classes.engine_generic_measure_api as engine_generic_me
9
9
  import qe_api_client.structs as structs
10
10
  import math
11
11
  import pandas as pd
12
+ import numpy as np
12
13
 
13
14
 
14
15
  class QixEngine:
@@ -39,42 +40,45 @@ class QixEngine:
39
40
  self.structs = structs
40
41
  self.app_handle = ''
41
42
 
42
- def select_in_dimension(self, app_handle, dimension_name, list_of_values):
43
- lb_field = self.eaa.get_field(app_handle, dimension_name)
43
+ def select_in_field(self, app_handle, field_name, list_of_values):
44
+ lb_field = self.eaa.get_field(app_handle, field_name)
44
45
  fld_handle = self.get_handle(lb_field)
45
- values_to_select = []
46
- for val in list_of_values:
47
- fld_value = self.structs.field_value(val)
48
- values_to_select.append(fld_value)
49
- return self.efa.select_values(fld_handle, values_to_select)
50
-
51
- def select_excluded_in_dimension(self, app_handle, dimension_name):
52
- lb_field = self.eaa.get_field(app_handle, dimension_name)
46
+ if fld_handle is None:
47
+ return "The field name " + field_name + " doesn't exist!"
48
+ else:
49
+ values_to_select = []
50
+ for val in list_of_values:
51
+ fld_value = self.structs.field_value(text=val)
52
+ values_to_select.append(fld_value)
53
+ return self.efa.select_values(fld_handle, values_to_select)
54
+
55
+ def select_excluded_in_field(self, app_handle, field_name):
56
+ lb_field = self.eaa.get_field(app_handle, field_name)
53
57
  fld_handle = self.get_handle(lb_field)
54
58
  return self.efa.select_excluded(fld_handle)
55
59
 
56
- def select_possible_in_dimension(self, app_handle, dimension_name):
57
- lb_field = self.eaa.get_field(app_handle, dimension_name)
60
+ def select_possible_in_field(self, app_handle, field_name):
61
+ lb_field = self.eaa.get_field(app_handle, field_name)
58
62
  fld_handle = self.get_handle(lb_field)
59
63
  return self.efa.select_possible(fld_handle)
60
64
 
61
65
  # return a list of tuples where first value in tuple is the actual
62
66
  # data value and the second tuple value is that
63
67
  # values selection state
64
- def get_list_object_data(self, app_handle, dimension_name):
65
- lb_field = self.eaa.get_field(app_handle, dimension_name)
68
+ def get_list_object_data(self, app_handle, field_name):
69
+ lb_field = self.eaa.get_field(app_handle, field_name)
66
70
  fld_handle = self.get_handle(lb_field)
67
71
 
68
- nx_inline_dimension_def = self.structs.nx_inline_dimension_def([dimension_name])
69
- nx_page = self.structs.nx_page(0, 0, self.efa.get_cardinal(fld_handle))
72
+ nx_inline_dimension_def = self.structs.nx_inline_dimension_def([field_name])
73
+ nx_page = self.structs.nx_page(left=0, top=0, width=self.efa.get_cardinal(fld_handle))
70
74
  lb_def = self.structs.list_object_def("$", "", nx_inline_dimension_def,
71
75
  [nx_page])
72
76
 
73
77
  # Create info structure
74
- nx_info = self.structs.nx_info("ListObject", "SLB01")
78
+ nx_info = self.structs.nx_info(obj_type="ListObject", obj_id="SLB01")
75
79
 
76
80
  # Create generic object properties structure
77
- gen_obj_props = self.structs.generic_object_properties(nx_info, "qListObjectDef", lb_def)
81
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qListObjectDef", prop_def=lb_def)
78
82
  listobj = self.eaa.create_session_object(app_handle, gen_obj_props) # NOQA
79
83
  listobj_handle = self.get_handle(listobj)
80
84
  val_list = self.egoa.get_layout(listobj_handle)["qListObject"]["qDataPages"][0]["qMatrix"] # NOQA
@@ -89,7 +93,8 @@ class QixEngine:
89
93
  fld_handle = self.get_handle(lb_field)
90
94
  return self.efa.clear(fld_handle)
91
95
 
92
- def create_single_master_dimension(self, app_handle, dim_title, dim_def, dim_label):
96
+ def create_single_master_dimension(self, app_handle: int, dim_title: str, dim_def: str, dim_label: str = "",
97
+ dim_desc: str = "", dim_tags: list = None):
93
98
  """
94
99
  Creates a single master dimension.
95
100
 
@@ -97,18 +102,27 @@ class QixEngine:
97
102
  app_handle (int): The handle of the app.
98
103
  dim_title (str): The title of the dimension.
99
104
  dim_def (str): The definition of the dimension.
100
- dim_label (str): The label of the dimension.
105
+ dim_label (str, optional): The label of the dimension.
106
+ dim_desc (str, optional): The description of the dimension.
107
+ dim_tags (list, optional): The tags of the dimension.
101
108
 
102
109
  Returns:
103
110
  dict: The handle and Id of the dimension.
104
111
  """
105
- nx_info = self.structs.nx_info("dimension")
106
- lb_dim_def = self.structs.nx_library_dimension_def("N",[dim_def],[""],dim_label)
107
- gen_dim_props = self.structs.generic_dimension_properties(nx_info, lb_dim_def, dim_title)
112
+ if dim_tags is None:
113
+ dim_tags = []
114
+ nx_info = self.structs.nx_info(obj_type="dimension")
115
+ nx_library_dimension_def = self.structs.nx_library_dimension_def(grouping="N", field_definitions=[dim_def],
116
+ field_labels=[dim_title],
117
+ label_expression=dim_label)
118
+ gen_dim_props = self.structs.generic_dimension_properties(nx_info=nx_info,
119
+ nx_library_dimension_def=nx_library_dimension_def,
120
+ title=dim_title, description=dim_desc, tags=dim_tags)
108
121
  master_dim = self.eaa.create_dimension(app_handle, gen_dim_props)
109
122
  return master_dim
110
123
 
111
- def create_master_measure(self, app_handle, mes_title, mes_def, mes_label):
124
+ def create_master_measure(self, app_handle: int, mes_title: str, mes_def: str, mes_label: str = "",
125
+ mes_desc: str = "", mes_tags: list = None):
112
126
  """
113
127
  Creates a master measure.
114
128
 
@@ -116,14 +130,21 @@ class QixEngine:
116
130
  app_handle (int): The handle of the app.
117
131
  mes_title (str): The title of the measure.
118
132
  mes_def (str): The definition of the measure.
119
- mes_label (str): The label of the measure.
133
+ mes_label (str, optional): The label of the measure.
134
+ mes_desc (str, optional): The description of the measure.
135
+ mes_tags (list, optional): The tags of the measure.
120
136
 
121
137
  Returns:
122
138
  dict: The handle and Id of the measure.
123
139
  """
124
- nx_info = self.structs.nx_info("measure")
125
- lb_mes_def = self.structs.nx_inline_measure_def(mes_def,mes_label)
126
- gen_mes_props = self.structs.generic_measure_properties(nx_info, lb_mes_def, mes_title)
140
+ if mes_tags is None:
141
+ mes_tags = []
142
+ nx_info = self.structs.nx_info(obj_type="measure")
143
+ nx_library_measure_def = self.structs.nx_library_measure_def(label=mes_title, mes_def=mes_def,
144
+ label_expression=mes_label)
145
+ gen_mes_props = self.structs.generic_measure_properties(nx_info=nx_info,
146
+ nx_library_measure_def=nx_library_measure_def,
147
+ title=mes_title, description=mes_desc, tags=mes_tags)
127
148
  master_mes = self.eaa.create_measure(app_handle, gen_mes_props)
128
149
  return master_mes
129
150
 
@@ -213,7 +234,7 @@ class QixEngine:
213
234
 
214
235
  # Retrieves the hypercube data in a loop (because of limitation from 10.000 cells per call)
215
236
  while no_of_rows > page * height:
216
- nx_page = self.structs.nx_page(0, page * height, width, height)
237
+ nx_page = self.structs.nx_page(left=0, top=page * height, width=width, height=height)
217
238
  hc_data = self.egoa.get_hypercube_data(obj_handle, '/qHyperCubeDef', nx_page)[
218
239
  'qDataPages'][0]['qMatrix']
219
240
  data_values.extend(hc_data)
@@ -243,7 +264,7 @@ class QixEngine:
243
264
 
244
265
  # Gets the column headers for the pivot table
245
266
  col_headers = []
246
- nx_page_top = self.structs.nx_page(0, 0, width, 1)
267
+ nx_page_top = self.structs.nx_page(left=0, top=0, width=width, height=1)
247
268
  hc_top = self.egoa.get_hypercube_pivot_data(obj_handle, '/qHyperCubeDef', nx_page_top)[
248
269
  'qDataPages'][0]['qTop']
249
270
  for top_node in hc_top:
@@ -256,7 +277,7 @@ class QixEngine:
256
277
 
257
278
  # Retrieves the hypercube data in a loop (bacause of limitation from 10.000 cells per call)
258
279
  while no_of_rows > page * height:
259
- nx_page = self.structs.nx_page(0, page * height, width, height)
280
+ nx_page = self.structs.nx_page(left=0, top=page * height, width=width, height=height)
260
281
 
261
282
  # Retrieves the row headers for the pivot table
262
283
  hc_left = self.egoa.get_hypercube_pivot_data(obj_handle, '/qHyperCubeDef', nx_page)[
@@ -282,7 +303,7 @@ class QixEngine:
282
303
  # if the type of the charts has a stacked data structure
283
304
  elif obj_layout['qInfo']['qType'] in ['barchart'] and obj_layout['qHyperCube']['qStackedDataPages'] != []:
284
305
  max_no_cells = no_of_columns * no_of_rows
285
- nx_page = self.structs.nx_page(0, 0, no_of_columns, no_of_rows)
306
+ nx_page = self.structs.nx_page(left=0, top=0, width=no_of_columns, height=no_of_rows)
286
307
  hc_data = self.egoa.get_hypercube_stack_data(obj_handle, '/qHyperCubeDef', nx_page, max_no_cells)[
287
308
  'qDataPages'][0]['qData'][0]['qSubNodes']
288
309
 
@@ -315,32 +336,32 @@ class QixEngine:
315
336
  list_of_master_measures (list): A list of master measures.
316
337
 
317
338
  Returns:
318
- DataFrame: A table of the chart content.
339
+ DataFrame: A table of the chart content.
319
340
  """
320
341
  # Create dimension property
321
342
  hc_dim = []
322
343
  for dimension in list_of_dimensions:
323
- hc_inline_dim_def = self.structs.nx_inline_dimension_def([dimension])
324
- hc_dim.append(self.structs.nx_dimension("", hc_inline_dim_def))
344
+ hc_inline_dim_def = self.structs.nx_inline_dimension_def(field_definitions=[dimension])
345
+ hc_dim.append(self.structs.nx_dimension(library_id="", dim_def=hc_inline_dim_def))
325
346
  for dimension in list_of_master_dimensions:
326
- hc_dim.append(self.structs.nx_dimension(dimension))
347
+ hc_dim.append(self.structs.nx_dimension(library_id=dimension))
327
348
 
328
349
  # Create measure property
329
350
  hc_mes = []
330
351
  for measure in list_of_measures:
331
- hc_inline_mes = self.structs.nx_inline_measure_def(measure)
332
- hc_mes.append(self.structs.nx_measure("", hc_inline_mes))
352
+ hc_inline_mes = self.structs.nx_inline_measure_def(definition=measure)
353
+ hc_mes.append(self.structs.nx_measure(library_id="", mes_def=hc_inline_mes))
333
354
  for measure in list_of_master_measures:
334
- hc_mes.append(self.structs.nx_measure(measure))
355
+ hc_mes.append(self.structs.nx_measure(library_id=measure))
335
356
 
336
357
  # Create hypercube structure
337
- hc_def = self.structs.hypercube_def("$", hc_dim, hc_mes)
358
+ hc_def = self.structs.hypercube_def(state_name="$", nx_dims=hc_dim, nx_meas=hc_mes)
338
359
 
339
360
  # Create info structure
340
- nx_info = self.structs.nx_info("table")
361
+ nx_info = self.structs.nx_info(obj_type="table")
341
362
 
342
363
  # Create generic object properties structure
343
- gen_obj_props = self.structs.generic_object_properties(nx_info, "qHyperCubeDef", hc_def)
364
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qHyperCubeDef", prop_def=hc_def)
344
365
 
345
366
  # Create session object
346
367
  hc_obj = self.eaa.create_session_object(app_handle, gen_obj_props)
@@ -368,7 +389,7 @@ class QixEngine:
368
389
 
369
390
  # Retrieves the hypercube data in a loop (because of limitation from 10.000 cells per call)
370
391
  while no_of_rows > page * height:
371
- nx_page = self.structs.nx_page(0, page * height, width, height)
392
+ nx_page = self.structs.nx_page(left=0, top=page * height, width=width, height=height)
372
393
  hc_data = self.egoa.get_hypercube_data(hc_obj_handle, '/qHyperCubeDef', nx_page)['qDataPages'][0]['qMatrix']
373
394
  data_values.extend(hc_data)
374
395
  page += 1
@@ -380,4 +401,286 @@ class QixEngine:
380
401
  df.columns = column_names
381
402
 
382
403
  # Returns the Dataframe
383
- return df
404
+ return df
405
+
406
+ def get_apps(self):
407
+ """
408
+ Retrieves a list with all apps on the server containing metadata.
409
+
410
+ Parameters:
411
+
412
+ Returns:
413
+ DataFrame: A table with all server apps.
414
+ """
415
+
416
+ # Get all apps from Qlik Server
417
+ doc_list = self.ega.get_doc_list()
418
+
419
+ # Convert into DataFrame structure
420
+ df_doc_list = pd.DataFrame(doc_list)
421
+
422
+ # Resolve the attribute "qMeta"
423
+ field_meta = df_doc_list['qMeta'].apply(pd.Series).reindex(columns=["createdDate", "modifiedDate", "published",
424
+ "publishTime", "privileges", "description",
425
+ "qStaticByteSize", "dynamicColor", "create",
426
+ "stream", "canCreateDataConnections"])
427
+
428
+ # Concat the resolved attribute and rename the new columns
429
+ df_doc_list_meta = pd.concat([df_doc_list.drop(['qMeta'], axis=1), field_meta], axis=1)
430
+ df_doc_list_meta = df_doc_list_meta.rename(columns={"createdDate": "qMeta_createdDate",
431
+ "modifiedDate": "qMeta_modifiedDate",
432
+ "published": "qMeta_published",
433
+ "publishTime": "qMeta_publishTime",
434
+ "privileges": "qMeta_privileges",
435
+ "description": "qMeta_description",
436
+ "qStaticByteSize": "qMeta_qStaticByteSize",
437
+ "dynamicColor": "qMeta_dynamicColor",
438
+ "create": "qMeta_create",
439
+ "stream": "qMeta_stream",
440
+ "canCreateDataConnections": "qMeta_canCreateDataConnections"})
441
+
442
+ # Resolve the attribute "stream"
443
+ field_meta_stream = df_doc_list_meta['qMeta_stream'].apply(pd.Series).reindex(columns=["id", "name"])
444
+
445
+ # Concat the resolved attribute and rename the new columns
446
+ df_doc_list_meta_stream = pd.concat([df_doc_list_meta.drop(['qMeta_stream'], axis=1), field_meta_stream],
447
+ axis=1)
448
+ df_doc_list_meta_stream = df_doc_list_meta_stream.rename(
449
+ columns={"id": "qMeta_stream_id", "name": "qMeta_stream_name"})
450
+
451
+ # Resolve the attribute "qThumbnail"
452
+ field_thumbnail = df_doc_list_meta_stream['qThumbnail'].apply(pd.Series).reindex(columns=["qUrl"])
453
+
454
+ ## Concat the resolved attribute and rename the new columns
455
+ df_doc_list_resolved = pd.concat([df_doc_list_meta_stream.drop(['qThumbnail'], axis=1), field_thumbnail],
456
+ axis=1)
457
+ df_doc_list_resolved = df_doc_list_resolved.rename(columns={"qUrl": "qThumbnail_qUrl"}).replace(np.nan,'')
458
+
459
+ return df_doc_list_resolved
460
+
461
+
462
+ def get_app_fields(self, app_handle):
463
+ """
464
+ Retrieves a list with all app fields containing meta data.
465
+
466
+ Parameters:
467
+ app_handle (int): The handle of the app.
468
+
469
+ Returns:
470
+ DataFrame: A table with all fields from an app.
471
+ """
472
+ # Define the parameters of the session object
473
+ nx_info = self.structs.nx_info(obj_type="FieldList")
474
+ field_list_def = self.structs.field_list_def()
475
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qFieldListDef",
476
+ prop_def=field_list_def)
477
+
478
+ # Create session object
479
+ session = self.eaa.create_session_object(app_handle, gen_obj_props)
480
+
481
+ # Get session handle
482
+ session_handle = self.get_handle(session)
483
+
484
+ # Get session object data
485
+ layout = self.egoa.get_layout(session_handle)
486
+
487
+ # Get the field list as Dictionary structure
488
+ fields_list = layout["qFieldList"]["qItems"]
489
+
490
+ # Define the DataFrame structure
491
+ df_fields_list = pd.DataFrame(columns=['qIsHidden', 'qIsSystem', 'qName', 'qCardinal', 'qTags', 'qSrcTables'])
492
+
493
+ for fields in fields_list:
494
+ # Concatenate the field list on the DataFrame structure
495
+ df_fields_list.loc[len(df_fields_list)] = fields
496
+
497
+ return df_fields_list
498
+
499
+
500
+ def get_app_dimensions(self, app_handle):
501
+ """
502
+ Retrieves a list with all app dimensions containing metadata.
503
+
504
+ Parameters:
505
+ app_handle (int): The handle of the app.
506
+
507
+ Returns:
508
+ DataFrame: A table with all dimensions from an app.
509
+ """
510
+ # Define the parameters of the session object
511
+ nx_info = self.structs.nx_info(obj_type="DimensionList")
512
+ dimension_list_def = self.structs.dimension_list_def()
513
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qDimensionListDef",
514
+ prop_def=dimension_list_def)
515
+
516
+ # Create session object
517
+ session = self.eaa.create_session_object(app_handle, gen_obj_props)
518
+
519
+ # Get session handle
520
+ session_handle = self.get_handle(session)
521
+
522
+ # Get session object data
523
+ session_layout = self.egoa.get_layout(session_handle)
524
+
525
+ # Get the dimension list as Dictionary structure
526
+ dimension_list = session_layout["qDimensionList"]["qItems"]
527
+
528
+ # Define the DataFrame structure
529
+ df_dimension_list = pd.DataFrame(columns=["qInfo", "qMeta", "qDim", "qDimInfos"])
530
+
531
+ for dimension in dimension_list:
532
+ # Get dimension ID
533
+ dim_id = dimension["qInfo"]["qId"]
534
+ # Get dimension
535
+ dim_result = self.egda.get_dimension(app_handle=app_handle, dimension_id=dim_id)
536
+ # Get dimension handle
537
+ dim_handle = self.get_handle(dim_result)
538
+ # Get dimension metadata
539
+ dim_layout = self.egoa.get_layout(dim_handle)
540
+
541
+ # Concatenate the dimension to the DataFrame structure
542
+ df_dimension_list.loc[len(df_dimension_list)] = dim_layout
543
+
544
+ # Resolve the dictionary structure of attribute "qInfo"
545
+ df_dimension_list_expanded = (df_dimension_list["qInfo"].apply(pd.Series).add_prefix("qInfo_"))
546
+ df_dimension_list = df_dimension_list.drop(columns=["qInfo"]).join(df_dimension_list_expanded)
547
+
548
+ # Resolve the dictionary structure of attribute "qMeta"
549
+ df_dimension_list_expanded = (df_dimension_list["qMeta"].apply(pd.Series).add_prefix("qMeta_"))
550
+ df_dimension_list = df_dimension_list.drop(columns=["qMeta"]).join(df_dimension_list_expanded)
551
+
552
+ # Resolve the dictionary structure of attribute "qDim"
553
+ df_dimension_list_expanded = (df_dimension_list["qDim"].apply(pd.Series).add_prefix("qDim_"))
554
+ df_dimension_list = df_dimension_list.drop(columns=["qDim"]).join(df_dimension_list_expanded)
555
+
556
+ # Resolve the dictionary structure of attribute "qDim_coloring"
557
+ try:
558
+ df_dimension_list_expanded = (
559
+ df_dimension_list["qDim_coloring"].apply(pd.Series).add_prefix("qDim_coloring_"))
560
+ df_dimension_list = df_dimension_list.drop(columns=["qDim_coloring"]).join(df_dimension_list_expanded)
561
+ except KeyError:
562
+ df_dimension_list["qDim_coloring"] = ""
563
+
564
+ # Resolve the dictionary structure of attribute "qDim_coloring_baseColor"
565
+ try:
566
+ df_dimension_list_expanded = (
567
+ df_dimension_list["qDim_coloring_baseColor"].apply(pd.Series).add_prefix("qDim_coloring_baseColor_"))
568
+ df_dimension_list = df_dimension_list.drop(columns=["qDim_coloring_baseColor"]).join(
569
+ df_dimension_list_expanded)
570
+ except KeyError:
571
+ df_dimension_list["qDim_coloring_baseColor"] = ""
572
+
573
+ # Resolve the list structure of attribute
574
+ df_dimension_list = df_dimension_list.explode(['qDimInfos', 'qDim_qFieldDefs', 'qDim_qFieldLabels'])
575
+
576
+ # Resolve the dictionary structure of attribute "qDimInfos"
577
+ df_dimension_list_expanded = (df_dimension_list["qDimInfos"].apply(pd.Series).add_prefix("qDimInfos_"))
578
+ index = df_dimension_list_expanded.index
579
+ df_dimension_list_expanded = df_dimension_list_expanded[~index.duplicated(keep="first")]
580
+ df_dimension_list = df_dimension_list.drop(columns=["qDimInfos"]).join(df_dimension_list_expanded)
581
+
582
+ return df_dimension_list
583
+
584
+
585
+ def get_app_measures(self, app_handle):
586
+ """
587
+ Retrieves a list with all app measures containing metadata.
588
+
589
+ Parameters:
590
+ app_handle (int): The handle of the app.
591
+
592
+ Returns:
593
+ DataFrame: A table with all measures from an app.
594
+ """
595
+ # Define the parameters of the session object
596
+ nx_info = self.structs.nx_info(obj_type="MeasureList")
597
+ measure_list_def = self.structs.measure_list_def()
598
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qMeasureListDef",
599
+ prop_def=measure_list_def)
600
+
601
+ # Create session object
602
+ session = self.eaa.create_session_object(app_handle, gen_obj_props)
603
+
604
+ # Get session handle
605
+ session_handle = self.get_handle(session)
606
+
607
+ # Get session object data
608
+ session_layout = self.egoa.get_layout(session_handle)
609
+
610
+ # Get the measure list as Dictionary structure
611
+ measure_list = session_layout["qMeasureList"]["qItems"]
612
+
613
+ # Define the DataFrame structure
614
+ df_measure_list = pd.DataFrame(columns=["qInfo", "qMeasure", "qMeta"])
615
+
616
+ for measure in measure_list:
617
+ # Get measure ID
618
+ measure_id = measure["qInfo"]["qId"]
619
+ # Get measure
620
+ measure_result = self.egma.get_measure(app_handle=app_handle, measure_id=measure_id)
621
+ # Get measure handle
622
+ measure_handle = self.get_handle(measure_result)
623
+ # Get session object data
624
+ measure_layout = self.egoa.get_layout(measure_handle)
625
+
626
+ # Concatenate the measure metadata to the DataFrame structure
627
+ df_measure_list.loc[len(df_measure_list)] = measure_layout
628
+
629
+ # Resolve the dictionary structure of attribute "qInfo"
630
+ df_measure_list_expanded = (df_measure_list["qInfo"].apply(pd.Series).add_prefix("qInfo_"))
631
+ df_measure_list = df_measure_list.drop(columns=["qInfo"]).join(df_measure_list_expanded)
632
+
633
+ # Resolve the dictionary structure of attribute "qMeasure"
634
+ df_measure_list_expanded = (df_measure_list["qMeasure"].apply(pd.Series).add_prefix("qMeasure_"))
635
+ df_measure_list = df_measure_list.drop(columns=["qMeasure"]).join(df_measure_list_expanded)
636
+
637
+ # Resolve the dictionary structure of attribute "qMeta"
638
+ df_measure_list_expanded = (df_measure_list["qMeta"].apply(pd.Series).add_prefix("qMeta_"))
639
+ df_measure_list = df_measure_list.drop(columns=["qMeta"]).join(df_measure_list_expanded)
640
+
641
+ # Resolve the dictionary structure of attribute "qMeasure_qNumFormat"
642
+ df_measure_list_expanded = (
643
+ df_measure_list["qMeasure_qNumFormat"].apply(pd.Series).add_prefix("qMeasure_qNumFormat_"))
644
+ df_measure_list = df_measure_list.drop(columns=["qMeasure_qNumFormat"]).join(df_measure_list_expanded)
645
+
646
+ # Resolve the dictionary structure of attribute "qMeasure_coloring"
647
+ try:
648
+ df_measure_list_expanded = (
649
+ df_measure_list["qMeasure_coloring"].apply(pd.Series).add_prefix("qMeasure_coloring_"))
650
+ df_measure_list = df_measure_list.drop(columns=["qMeasure_coloring"]).join(df_measure_list_expanded)
651
+ except KeyError:
652
+ df_measure_list["qMeasure_coloring"] = ""
653
+
654
+ # Resolve the dictionary structure of attribute "qMeasure_coloring_baseColor"
655
+ try:
656
+ df_measure_list_expanded = (df_measure_list["qMeasure_coloring_baseColor"].apply(pd.Series).add_prefix(
657
+ "qMeasure_coloring_baseColor_"))
658
+ df_measure_list = df_measure_list.drop(columns=["qMeasure_coloring_baseColor"]).join(
659
+ df_measure_list_expanded)
660
+ except KeyError:
661
+ df_measure_list["qMeasure_coloring_baseColor"] = ""
662
+
663
+ return df_measure_list
664
+
665
+
666
+ def get_app_lineage(self, app_handle):
667
+ """
668
+ Retrieves a list with an app lineage data.
669
+
670
+ Parameters:
671
+ app_handle (int): The handle of the app.
672
+
673
+ Returns:
674
+ DataFrame: A table with lineage data from an app.
675
+ """
676
+ # Get lineage data from an app
677
+ lineage_list = self.eaa.get_lineage(app_handle)
678
+
679
+ # Define the DataFrame structure
680
+ df_lineage_list = pd.DataFrame(columns=['qDiscriminator', 'qStatement'])
681
+
682
+ for lineage in lineage_list:
683
+ # Concatenate the lineage row on the DataFrame structure
684
+ df_lineage_list.loc[len(df_lineage_list)] = lineage
685
+
686
+ return df_lineage_list
qe_api_client/structs.py CHANGED
@@ -2,6 +2,7 @@ def list_object_def(state_name="$", library_id="", field_defs=[], initial_data_f
2
2
  return {"qStateName": state_name, "qLibraryId": library_id, "qDef": field_defs,
3
3
  "qInitialDataFetch": initial_data_fetch}
4
4
 
5
+
5
6
  def hypercube_def(state_name="$", nx_dims=[], nx_meas=[], nx_page=[], inter_column_sort=[0, 1, 2], suppress_zero=False,
6
7
  suppress_missing=False):
7
8
  return {"qStateName": state_name, "qDimensions": nx_dims, "qMeasures": nx_meas,
@@ -10,23 +11,27 @@ def hypercube_def(state_name="$", nx_dims=[], nx_meas=[], nx_page=[], inter_colu
10
11
  "qAlwaysFullyExpanded": False, "qMaxStackedCells": 5000, "qPopulateMissing": False,
11
12
  "qShowTotalsAbove": False, "qIndentMode": False, "qCalcCond": "", "qSortbyYValue": 0}
12
13
 
14
+
13
15
  def nx_inline_dimension_def(field_definitions=[], field_labels=[], sort_criterias=[], grouping='N'):
14
16
  return {"qGrouping": grouping, "qFieldDefs": field_definitions, "qFieldLabels": field_labels,
15
17
  "qSortCriterias": sort_criterias, "qReverseSort": False}
16
18
 
19
+
17
20
  def nx_inline_measure_def(definition, label="", description="", tags=[], grouping="N"):
18
21
  return {"qLabel": label, "qDescription": description, "qTags": tags, "qGrouping": grouping, "qDef": definition}
19
22
 
23
+
20
24
  def nx_page(left=0, top=0, width=2, height=2):
21
25
  return {"qLeft": left, "qTop": top, "qWidth": width, "qHeight": height}
22
26
 
27
+
23
28
  def nx_info(obj_type, obj_id=""):
24
29
  """
25
30
  Retrieves the data from a specific list object in a generic object.
26
31
 
27
32
  Parameters:
28
33
  obj_type (str): Type of the object. This parameter is mandatory.
29
- obj_id (str): Identifier of the object. If the chosen identifier is already in use, the engine automatically
34
+ obj_id (str, optional): Identifier of the object. If the chosen identifier is already in use, the engine automatically
30
35
  sets another one. If an identifier is not set, the engine automatically sets one. This parameter is optional.
31
36
 
32
37
  Returns:
@@ -34,45 +39,84 @@ def nx_info(obj_type, obj_id=""):
34
39
  """
35
40
  return {"qId": obj_id, "qType": obj_type}
36
41
 
42
+
37
43
  def nx_dimension(library_id="", dim_def={}, null_suppression=False):
38
44
  return {"qLibraryId": library_id, "qDef": dim_def, "qNullSuppression": null_suppression}
39
45
 
46
+
40
47
  def nx_measure(library_id="", mes_def={}, sort_by={}):
41
48
  return {"qLibraryId": library_id, "qDef": mes_def, "qSortBy": sort_by}
42
49
 
50
+
43
51
  def generic_object_properties(info, prop_name, prop_def, extends_id="", state_name="$"):
44
52
  return {"qInfo": info, "qExtendsId": extends_id, prop_name: prop_def, "qStateName": state_name}
45
53
 
54
+
46
55
  def sort_criteria(state=0, freq=0, numeric=0, ascii=0, load_order=1):
47
56
  return {"qSortByState": state, "qSortByFrequency": freq, "qSortByNumeric": numeric, "qSortByAscii": ascii,
48
57
  "qSortByLoadOrder": load_order, "qSortByExpression": 0, "qExpression": {"qv": ""}}
49
58
 
59
+
50
60
  def field_value(text, is_numeric = False, number = 0):
51
61
  return {"qText": text, "qIsNumeric": is_numeric, "qNumber": number}
52
62
 
53
- def generic_dimension_properties(info, lb_dim_def, dim_title):
54
- return {"qInfo": info, "qDim": lb_dim_def, "qMetaDef": {"title": dim_title}}
55
63
 
56
- def nx_library_dimension_def(grouping="N", field_definitions=[], field_labels=[""], label_expression=""):
64
+ def generic_dimension_properties(nx_info: dict, nx_library_dimension_def: dict, title: str, description: str = "",
65
+ tags: list = None):
66
+ if tags is None:
67
+ tags = []
68
+ return {"qInfo": nx_info, "qDim": nx_library_dimension_def, "qMetaDef": {"title": title, "description": description,
69
+ "tags": tags}}
70
+
71
+
72
+ def nx_library_dimension_def(grouping: str = "N", field_definitions: list = None, field_labels: list = None,
73
+ label_expression: str = ""):
74
+ if field_labels is None:
75
+ field_labels = []
76
+ if field_definitions is None:
77
+ field_definitions = []
57
78
  return {"qGrouping": grouping, "qFieldDefs": field_definitions, "qFieldLabels": field_labels,
58
79
  "qLabelExpression": label_expression}
59
80
 
60
- def nx_library_measure_def(label, mes_def, grouping="N", expressions=[], active_expression=0, label_expression="",
61
- num_format={}):
81
+
82
+ def nx_library_measure_def(label: str, mes_def: str, grouping: str = "N", expressions: list = None,
83
+ active_expression: int = 0, label_expression:str = "", num_format: dict = None):
84
+ if num_format is None:
85
+ num_format = {}
86
+ if expressions is None:
87
+ expressions = []
62
88
  return {"qLabel": label, "qDef": mes_def,"qGrouping": grouping, "qExpressions": expressions,
63
89
  "qActiveExpression": active_expression, "qLabelExpression": label_expression, "qNumFormat": num_format}
64
90
 
65
- def num_format(type="U", n_dec=10, use_thou=0, fmt="", dec="", thou=""):
91
+
92
+ def num_format(type: str = "U", n_dec: int = 10, use_thou:int = 0, fmt: str = "", dec: str = "", thou: str = ""):
66
93
  return {"qType": type, "qnDec": n_dec, "qUseThou": use_thou, "qFmt": fmt, "qDec": dec, "qThou": thou}
67
94
 
68
- def generic_measure_properties(info, lb_meas_def, meas_title):
69
- return {"qInfo": info, "qMeasure": lb_meas_def, "qMetaDef": {"title": meas_title}}
95
+
96
+ def generic_measure_properties(nx_info: dict, nx_library_measure_def: dict, title: str, description: str = "",
97
+ tags: list = None):
98
+ if tags is None:
99
+ tags = []
100
+ return {"qInfo": nx_info, "qMeasure": nx_library_measure_def, "qMetaDef": {"title": title,
101
+ "description": description,
102
+ "tags": tags}}
103
+
70
104
 
71
105
  def do_reload_ex_params(mode=0, partial=False, debug=False, reload_id="", skip_store=False, row_limit=0):
72
106
  return {"qMode": mode, "qPartial": partial, "qDebug": debug, "qReloadId": reload_id, "qSkipStore": skip_store,
73
107
  "qRowLimit": row_limit}
74
108
 
109
+
75
110
  def dimension_list_def():
76
- return {"qInfo": {"qType": "DimensionList"},
77
- "qDimensionListDef": {"qType": "dimension",
78
- "qData": {"title": "/title", "tags": "/tags", "grouping": "/qDim/qGrouping", "info": "/qDimInfos"}}}
111
+ return {"qType": "dimension",
112
+ "qData": {"title": "/title", "tags": "/tags", "grouping": "/qDim/qGrouping", "info": "/qDimInfos"}}
113
+
114
+
115
+ def measure_list_def():
116
+ return {"qType": "measure", "qData": {"title": "/title", "tags": "/tags"}}
117
+
118
+
119
+ def field_list_def(show_system: bool = True, show_hidden: bool = True, show_derived_fields: bool = True,
120
+ show_semantic: bool = True, show_src_tables: bool = True, show_implicit: bool = True):
121
+ return {"qShowSystem": show_system, "qShowHidden": show_hidden, "qShowDerivedFields": show_derived_fields,
122
+ "qShowSemantic": show_semantic, "qShowSrcTables": show_src_tables, "qShowImplicit": show_implicit}
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: qe-api-client
3
- Version: 2.4.0
4
- Summary: Python wrapper around Qlik Engine JSON API
3
+ Version: 2.5.0
4
+ Summary: Python client for the Qlik Engine JSON API
5
5
  Home-page: https://github.com/lr-bicc/qe-api-client
6
6
  Author: Rumen Vasilev
7
7
  Author-email: R.Vasilev@LRWorld.com
@@ -1,17 +1,17 @@
1
1
  qe_api_client/__init__.py,sha256=bypB4CIjpHtf5Pu_NwtJajC69zqQD7qB9jo8cCX0B54,23
2
- qe_api_client/engine.py,sha256=SCTjKlhtir2kOMNDnfwd1Cz-Su6xxDk79GBUtAMgSpU,16900
2
+ qe_api_client/engine.py,sha256=AGv3Ab5YE5-PpNdkQF6aCLYECKkgbiU96jqEcpb6VUE,32019
3
3
  qe_api_client/engine_communicator.py,sha256=q6x7ix2Ev8yGmTTm7cf1vHcidOihKM0HjDXeJ-dZYjk,1133
4
- qe_api_client/structs.py,sha256=eZw-M9QBhZe_lHxjMcWU5TJVi18G43FhCMMGzjdJxAk,4502
4
+ qe_api_client/structs.py,sha256=9_2LzC8Er_cFNmGPLRB_xuQ0v3AHY24XirGFVSBxkMo,5996
5
5
  qe_api_client/api_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- qe_api_client/api_classes/engine_app_api.py,sha256=H0CF-BwSUi1ZpZo7pyQg736jsdKm5biShVcELun9jwY,38021
6
+ qe_api_client/api_classes/engine_app_api.py,sha256=_wNFr3scbw0THoM_mMpSapKyiNEhjB4qYBDNgZLLoHg,37493
7
7
  qe_api_client/api_classes/engine_field_api.py,sha256=zCLIR7rmxqwIrJYK_-uHVEhMvBcEP2qofuX8ZPygqCA,5479
8
- qe_api_client/api_classes/engine_generic_dimension_api.py,sha256=1joTET6GWCTW-80wafrajLQuMyFwIPp0QKoILyLdP1U,1377
9
- qe_api_client/api_classes/engine_generic_measure_api.py,sha256=zbRYRA99LQS9SY3QVgoUABqgVDRPwBQ8o2ZbESVEsHE,1321
8
+ qe_api_client/api_classes/engine_generic_dimension_api.py,sha256=OdYnL54jTaNgfICDj5czJcFB1QZ4Y0s_YslqomQY26I,1394
9
+ qe_api_client/api_classes/engine_generic_measure_api.py,sha256=uj4i_ykX9F9Dtk78fOidMBhzSP8vEucEfrB6MrLwgPI,1340
10
10
  qe_api_client/api_classes/engine_generic_object_api.py,sha256=nqsEtvKkt5XkUEIVUoBtNVXtmUvuifxrgTcw2fDuaOE,8218
11
11
  qe_api_client/api_classes/engine_generic_variable_api.py,sha256=sWXZpE-GLfcMijmfORnDNrJ6lmXX3x5TRHlkEu_i0BQ,2027
12
12
  qe_api_client/api_classes/engine_global_api.py,sha256=G6QQHI36WOo7W25zg4Uz__gMSLC2ptNTvbBdElPzgZI,27535
13
- qe_api_client-2.4.0.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
14
- qe_api_client-2.4.0.dist-info/METADATA,sha256=uXwa8Jwcq9-w4r0o0CbET_lwWPM87WLY1PwxUkJYBNo,2363
15
- qe_api_client-2.4.0.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
16
- qe_api_client-2.4.0.dist-info/top_level.txt,sha256=m_43YagP8UtZgJHmZEfu0vlBNwt36M01-Qby2jByMnk,14
17
- qe_api_client-2.4.0.dist-info/RECORD,,
13
+ qe_api_client-2.5.0.dist-info/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
14
+ qe_api_client-2.5.0.dist-info/METADATA,sha256=TcvlAA9v6e69nWGG-dCXD9E0lxx_jrxrjBi7cVLKgmw,2363
15
+ qe_api_client-2.5.0.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
16
+ qe_api_client-2.5.0.dist-info/top_level.txt,sha256=m_43YagP8UtZgJHmZEfu0vlBNwt36M01-Qby2jByMnk,14
17
+ qe_api_client-2.5.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.1)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5