qe-api-client 2.5.0__py3-none-any.whl → 2.7.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.
qe_api_client/engine.py CHANGED
@@ -1,3 +1,5 @@
1
+ import json
2
+
1
3
  import qe_api_client.api_classes.engine_app_api as engine_app_api
2
4
  import qe_api_client.engine_communicator as engine_communicator
3
5
  import qe_api_client.api_classes.engine_field_api as engine_field_api
@@ -93,8 +95,14 @@ class QixEngine:
93
95
  fld_handle = self.get_handle(lb_field)
94
96
  return self.efa.clear(fld_handle)
95
97
 
98
+
96
99
  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):
100
+ dim_desc: str = "", dim_tags: list = None, dim_color: str = None,
101
+ dim_color_index: int = -1, value_colors: list = None,
102
+ null_value_color: str = None, null_value_color_index: int = -1,
103
+ other_value_color: str = None, other_value_color_index: int = -1,
104
+ single_color: str = None, single_color_index: int = -1, palette: str = None
105
+ ):
98
106
  """
99
107
  Creates a single master dimension.
100
108
 
@@ -105,22 +113,105 @@ class QixEngine:
105
113
  dim_label (str, optional): The label of the dimension.
106
114
  dim_desc (str, optional): The description of the dimension.
107
115
  dim_tags (list, optional): The tags of the dimension.
116
+ dim_color (str, optional): The master dimension color.
117
+ dim_color_index (int, optional): The index of the master dimension color in the theme color picker.
118
+ value_colors (list, optional): The value colors of the master dimension.
119
+ null_value_color (str, optional): The NULL value color of the master dimension.
120
+ null_value_color_index (int, optional): The index of the NULL value color of the master dimension in the theme color picker.
121
+ other_value_color (str, optional): The OTHER value color of the master dimension.
122
+ other_value_color_index (int, optional): The index of the OTHER value color of the master dimension in the theme color picker.
123
+ single_color (str, optional): Single color of the values of the master dimension.
124
+ single_color_index (int, optional): The index of single color of the values of the master dimension in the theme color picker.
125
+ palette (str, optional): Choose a color palette, if there are more than one.
108
126
 
109
127
  Returns:
110
128
  dict: The handle and Id of the dimension.
111
129
  """
130
+ if value_colors is None:
131
+ value_colors = []
112
132
  if dim_tags is None:
113
133
  dim_tags = []
134
+
135
+ # Define of the single dimension properties
114
136
  nx_info = self.structs.nx_info(obj_type="dimension")
137
+ if dim_color is None:
138
+ coloring = self.structs.coloring()
139
+ else:
140
+ coloring = self.structs.coloring(base_color={"color": dim_color, "index": dim_color_index})
141
+
115
142
  nx_library_dimension_def = self.structs.nx_library_dimension_def(grouping="N", field_definitions=[dim_def],
116
143
  field_labels=[dim_title],
117
- label_expression=dim_label)
144
+ label_expression=dim_label, alias=dim_title,
145
+ title=dim_title, coloring=coloring)
118
146
  gen_dim_props = self.structs.generic_dimension_properties(nx_info=nx_info,
119
147
  nx_library_dimension_def=nx_library_dimension_def,
120
148
  title=dim_title, description=dim_desc, tags=dim_tags)
149
+
150
+ # Create the single dimension
121
151
  master_dim = self.eaa.create_dimension(app_handle, gen_dim_props)
152
+
153
+ # Get id and handle of the master dimension
154
+ master_dim_id = self.get_id(master_dim)
155
+ master_dim_handle = self.get_handle(master_dim)
156
+
157
+ # Update "colorMapRef" property with the master dimension id.
158
+ patch_value = json.dumps(master_dim_id)
159
+ patch_color_map_ref = self.structs.nx_patch(op="replace", path="/qDim/coloring/colorMapRef", value=patch_value)
160
+ self.egda.apply_patches(handle=master_dim_handle, patches=[patch_color_map_ref])
161
+
162
+ # Define the color properties
163
+ if null_value_color is None:
164
+ null_value = None
165
+ else:
166
+ null_value = {"color": null_value_color, "index": null_value_color_index}
167
+
168
+ if other_value_color is None:
169
+ other_value = None
170
+ else:
171
+ other_value = {"color": other_value_color, "index": other_value_color_index}
172
+
173
+ if single_color is None:
174
+ single = None
175
+ else:
176
+ single = {"color": single_color, "index": single_color_index}
177
+
178
+ colors = value_colors
179
+ color_map = self.structs.color_map(colors=colors, nul=null_value, oth=other_value, single=single, pal=palette)
180
+ color_map_props = self.structs.color_map_properties(dim_id=master_dim_id, _color_map=color_map)
181
+
182
+ # Create color map object, if colors are passed.
183
+ if value_colors or null_value_color is not None or other_value_color is not None or single_color is not None or palette is not None:
184
+ color_map_model = self.eaa.create_object(app_handle, color_map_props)
185
+ color_map_model_handle = self.get_handle(color_map_model)
186
+
187
+ # Set "autoFill" and "usePal" to "False", if a single color is passed.
188
+ if bool(single):
189
+ patch_value_use_pal_auto_fill = json.dumps(False)
190
+ patch_use_pal = self.structs.nx_patch(op="replace", path="/colorMap/usePal",
191
+ value=patch_value_use_pal_auto_fill)
192
+ self.egda.apply_patches(handle=color_map_model_handle, patches=[patch_use_pal])
193
+
194
+ patch_auto_fill = self.structs.nx_patch(op="replace", path="/colorMap/autoFill",
195
+ value=patch_value_use_pal_auto_fill)
196
+ self.egda.apply_patches(handle=color_map_model_handle, patches=[patch_auto_fill])
197
+
198
+ # Set "autoFill" to "False", if a color palette is passed.
199
+ if palette is not None:
200
+ patch_value_auto_fill = json.dumps(False)
201
+ patch_auto_fill = self.structs.nx_patch(op="replace", path="/colorMap/autoFill",
202
+ value=patch_value_auto_fill)
203
+ self.egda.apply_patches(handle=color_map_model_handle, patches=[patch_auto_fill])
204
+
205
+ # Update "hasValueColors" property, if value colors are passed.
206
+ if value_colors:
207
+ patch_value_has_value_colors = json.dumps(True)
208
+ patch_has_value_colors = self.structs.nx_patch(op="replace", path="/qDim/coloring/hasValueColors",
209
+ value=patch_value_has_value_colors)
210
+ self.egda.apply_patches(handle=master_dim_handle, patches=[patch_has_value_colors])
211
+
122
212
  return master_dim
123
213
 
214
+
124
215
  def create_master_measure(self, app_handle: int, mes_title: str, mes_def: str, mes_label: str = "",
125
216
  mes_desc: str = "", mes_tags: list = None):
126
217
  """
@@ -139,15 +230,215 @@ class QixEngine:
139
230
  """
140
231
  if mes_tags is None:
141
232
  mes_tags = []
233
+
234
+ # Define of the measure properties
142
235
  nx_info = self.structs.nx_info(obj_type="measure")
143
236
  nx_library_measure_def = self.structs.nx_library_measure_def(label=mes_title, mes_def=mes_def,
144
237
  label_expression=mes_label)
145
238
  gen_mes_props = self.structs.generic_measure_properties(nx_info=nx_info,
146
239
  nx_library_measure_def=nx_library_measure_def,
147
240
  title=mes_title, description=mes_desc, tags=mes_tags)
241
+
242
+ # Create the measure
148
243
  master_mes = self.eaa.create_measure(app_handle, gen_mes_props)
244
+
149
245
  return master_mes
150
246
 
247
+ def create_sheet(self, app_handle: int, sheet_title: str, sheet_desc: str = "", no_of_rows: int = 18):
248
+ """
249
+ Creates a sheet.
250
+
251
+ Parameters:
252
+ app_handle (int): The handle of the app.
253
+ sheet_title (str): The title of the sheet.
254
+ sheet_desc (str, optional): The description of the sheet.
255
+ no_of_rows (int, optional): TThe number of the sheet rows. Min. 8 rows and max. 42 rows.
256
+
257
+ Returns:
258
+ dict: The handle and Id of the sheet.
259
+ """
260
+ # Define of the sheet properties
261
+ nx_info = self.structs.nx_info(obj_type="sheet")
262
+ sheet_def = {"title": sheet_title, "description": sheet_desc}
263
+ sheet_props = self.structs.generic_object_properties(info=nx_info, prop_name="qMetaDef", prop_def=sheet_def)
264
+
265
+ # Add row and column attributes. The number of the row should be between 8 and 42.
266
+ if no_of_rows not in range(8, 43):
267
+ no_of_rows = 18
268
+ no_of_columns = no_of_rows * 2
269
+
270
+ # Derive the grid_resolution property
271
+ if no_of_rows == 12:
272
+ grid_resolution = "small"
273
+ elif no_of_rows == 15:
274
+ grid_resolution = "medium"
275
+ elif no_of_rows == 18:
276
+ grid_resolution = "large"
277
+ else:
278
+ grid_resolution = "customrows"
279
+
280
+ # Add new properties
281
+ sheet_props.update(
282
+ {
283
+ "thumbnail": {"qStaticContentUrlDef": {"qUrl": ""}}, "columns": no_of_columns, "rows": no_of_rows,
284
+ "customRowBase": no_of_rows, "gridResolution": grid_resolution, "layoutOptions": {"mobileLayout": "LIST"},
285
+ "qChildListDef": {"qData": {"title": "/title"}}
286
+ }
287
+ )
288
+
289
+ # Create the sheet
290
+ sheet = self.eaa.create_object(app_handle, sheet_props)
291
+
292
+ return sheet
293
+
294
+ def create_list_object(self, handle: int, dim_id: str = "", field_def: str = "", field_title: str = ""):
295
+ """
296
+ Creates a list object.
297
+
298
+ Parameters:
299
+ handle (int): The handle of the parent object.
300
+ dim_id (str, optional): The ID of the master dimension. Let this parameter empty, if you passed the "field_def".
301
+ field_def (str, optional): The definition of the field. Let this parameter empty, if you passed the "dim_id".
302
+ field_title (int, optional): The title of the field. Let this parameter empty, if you passed the "dim_id".
303
+
304
+ Returns:
305
+ dict: The handle and Id of the list object.
306
+ """
307
+ if field_def is None:
308
+ field_def = []
309
+
310
+ nx_info = self.structs.nx_info(obj_type="listbox")
311
+ sort_criterias = self.structs.sort_criteria()
312
+
313
+ nx_library_dimension_def = self.structs.nx_inline_dimension_def(grouping="N", field_definitions=[field_def],
314
+ field_labels=[field_def],
315
+ sort_criterias=[sort_criterias])
316
+ list_object_def = self.structs.list_object_def(library_id=dim_id, definition=nx_library_dimension_def)
317
+ list_object_props = self.structs.generic_object_properties(info=nx_info, prop_name="qListObjectDef",
318
+ prop_def=list_object_def)
319
+ list_object_props.update(
320
+ {"showTitles": True, "title": field_title, "subtitle": "", "footnote": "", "disableNavMenu": False,
321
+ "showDetails": True, "showDetailsExpression": False, "visualization": "listbox"})
322
+ list_object = self.egoa.create_child(handle=handle, prop=list_object_props)
323
+
324
+ return list_object
325
+
326
+ def create_filterpane_frame(self, handle: int, no_of_rows_sheet: int, col: int, row: int, colspan: int, rowspan: int):
327
+ """
328
+ Creates a filterpane frame.
329
+
330
+ Parameters:
331
+ handle (int): The handle of the parent object.
332
+ no_of_rows_sheet (int): The number of the sheet rows.
333
+ col (int): First column the filterpane visualisation starts.
334
+ row (int): First row the filterpane visualisation starts.
335
+ colspan (int): The width of the filterpane in columns.
336
+ rowspan (int): The height of the filterpane in rows.
337
+
338
+ Returns:
339
+ dict: The handle and Id of the filterpane frame.
340
+ """
341
+ nx_info = self.structs.nx_info(obj_type="filterpane")
342
+ filterpane_props = self.structs.generic_object_properties(info=nx_info, prop_name="qMetaDef")
343
+ filterpane_props.update({"qChildListDef": {"qData": {}}})
344
+ filterpane = self.egoa.create_child(handle=handle, prop=filterpane_props)
345
+
346
+ filterpane_id = self.get_id(filterpane)
347
+
348
+ no_of_cols_sheet = no_of_rows_sheet * 2
349
+ width = colspan / no_of_cols_sheet * 100
350
+ height = rowspan / no_of_rows_sheet * 100
351
+ y = row / no_of_rows_sheet * 100
352
+ x = col / no_of_cols_sheet * 100
353
+
354
+ if col >= 0 and colspan > 0 and no_of_cols_sheet >= col + colspan and row >= 0 and rowspan > 0 and no_of_rows_sheet >= row + rowspan:
355
+ filterpane_layout = self.structs.object_position_size(obj_id=filterpane_id, obj_type="filterpane",
356
+ col=col, row=row, colspan=colspan,
357
+ rowspan=rowspan, y=y, x=x, width=width,
358
+ height=height)
359
+
360
+ sheet_layout = self.egoa.get_layout(handle=handle)
361
+
362
+ if "cells" not in sheet_layout:
363
+ patch_value = str([filterpane_layout]).replace("'", "\"")
364
+ patch_cell = self.structs.nx_patch(op="add", path="/cells", value=patch_value)
365
+ else:
366
+ cells = sheet_layout["cells"]
367
+ cells.append(filterpane_layout)
368
+ patch_value = str(cells).replace("'", "\"")
369
+ patch_cell = self.structs.nx_patch(op="replace", path="/cells", value=patch_value)
370
+
371
+ self.egoa.apply_patches(handle=handle, patches=[patch_cell])
372
+ else:
373
+ print("The position of filterpane \"" + filterpane_id + "\" is out of range. This one will not be created.")
374
+
375
+ return filterpane
376
+
377
+
378
+ def create_chart(self, handle: int, obj_type: str, hypercube_def: dict, no_of_rows_sheet: int, col: int, row: int,
379
+ colspan: int, rowspan: int):
380
+ """
381
+ Creates a chart object.
382
+
383
+ Parameters:
384
+ handle (int): The handle of the parent object.
385
+ obj_type (str): The type of the chart.
386
+ hypercube_def (dict): Chart hypercube definition.
387
+ no_of_rows_sheet (int): The number of the sheet rows.
388
+ col (int): First column the chart visualisation starts.
389
+ row (int): First row the chart visualisation starts.
390
+ colspan (int): The width of the chart in columns.
391
+ rowspan (int): The height of the chart in rows.
392
+
393
+ Returns:
394
+ dict: The handle and Id of the filterpane frame.
395
+ """
396
+
397
+ nx_info = self.structs.nx_info(obj_type=obj_type)
398
+ if obj_type == "table":
399
+ chart_props = self.structs.table_properties(info=nx_info, hypercube_def=hypercube_def)
400
+ elif obj_type == "sn-table":
401
+ chart_props = self.structs.sn_table_properties(info=nx_info, hypercube_def=hypercube_def)
402
+ elif obj_type == "pivot-table":
403
+ chart_props = self.structs.pivot_table_properties(info=nx_info, hypercube_def=hypercube_def)
404
+ elif obj_type == "sn-pivot-table":
405
+ chart_props = self.structs.pivot_table_properties(info=nx_info, hypercube_def=hypercube_def)
406
+ else:
407
+ print("Not valid object type.")
408
+
409
+ chart = self.egoa.create_child(handle=handle, prop=chart_props)
410
+
411
+ chart_id = self.get_id(chart)
412
+
413
+ no_of_cols_sheet = no_of_rows_sheet * 2
414
+ width = colspan / no_of_cols_sheet * 100
415
+ height = rowspan / no_of_rows_sheet * 100
416
+ y = row / no_of_rows_sheet * 100
417
+ x = col / no_of_cols_sheet * 100
418
+
419
+ if col >= 0 and colspan > 0 and no_of_cols_sheet >= col + colspan and row >= 0 and rowspan > 0 and no_of_rows_sheet >= row + rowspan:
420
+ chart_layout = self.structs.object_position_size(obj_id=chart_id, obj_type=obj_type, col=col, row=row,
421
+ colspan=colspan, rowspan=rowspan, y=y, x=x, width=width,
422
+ height=height)
423
+
424
+ sheet_layout = self.egoa.get_layout(handle=handle)
425
+
426
+ if "cells" not in sheet_layout:
427
+ patch_value = str([chart_layout]).replace("'", "\"")
428
+ patch_cell = self.structs.nx_patch(op="add", path="/cells", value=patch_value)
429
+ else:
430
+ cells = sheet_layout["cells"]
431
+ cells.append(chart_layout)
432
+ patch_value = str(cells).replace("'", "\"")
433
+ patch_cell = self.structs.nx_patch(op="replace", path="/cells", value=patch_value)
434
+
435
+ self.egoa.apply_patches(handle=handle, patches=[patch_cell])
436
+ else:
437
+ print("The position of chart \"" + chart_id + "\" is out of range. This one will not be created.")
438
+
439
+ return chart
440
+
441
+
151
442
  def get_app_lineage_info(self, app_handle):
152
443
  """
153
444
  Gets the lineage information of the app. The lineage information includes the LOAD and STORE statements from
@@ -190,6 +481,26 @@ class QixEngine:
190
481
  except ValueError:
191
482
  return "Bad handle value in " + obj
192
483
 
484
+ @staticmethod
485
+ def get_id(obj):
486
+ """
487
+ Retrieves the id from a given object.
488
+
489
+ Parameters:
490
+ obj : dict
491
+ The object containing the handle.
492
+
493
+ Returns:
494
+ int: The handle value.
495
+
496
+ Raises:
497
+ ValueError: If the handle value is invalid.
498
+ """
499
+ try:
500
+ return obj["qGenericId"]
501
+ except ValueError:
502
+ return "Bad id value in " + obj
503
+
193
504
  def get_chart_data(self, app_handle, obj_id):
194
505
  """
195
506
  Retrieves the data from a given chart object.
@@ -355,7 +666,7 @@ class QixEngine:
355
666
  hc_mes.append(self.structs.nx_measure(library_id=measure))
356
667
 
357
668
  # Create hypercube structure
358
- hc_def = self.structs.hypercube_def(state_name="$", nx_dims=hc_dim, nx_meas=hc_mes)
669
+ hc_def = self.structs.hypercube_def(state_name="$", dimensions=hc_dim, measures=hc_mes)
359
670
 
360
671
  # Create info structure
361
672
  nx_info = self.structs.nx_info(obj_type="table")
@@ -542,39 +853,39 @@ class QixEngine:
542
853
  df_dimension_list.loc[len(df_dimension_list)] = dim_layout
543
854
 
544
855
  # Resolve the dictionary structure of attribute "qInfo"
545
- df_dimension_list_expanded = (df_dimension_list["qInfo"].apply(pd.Series).add_prefix("qInfo_"))
856
+ df_dimension_list_expanded = (df_dimension_list["qInfo"].dropna().apply(pd.Series).add_prefix("qInfo_"))
546
857
  df_dimension_list = df_dimension_list.drop(columns=["qInfo"]).join(df_dimension_list_expanded)
547
858
 
548
859
  # Resolve the dictionary structure of attribute "qMeta"
549
- df_dimension_list_expanded = (df_dimension_list["qMeta"].apply(pd.Series).add_prefix("qMeta_"))
860
+ df_dimension_list_expanded = (df_dimension_list["qMeta"].dropna().apply(pd.Series).add_prefix("qMeta_"))
550
861
  df_dimension_list = df_dimension_list.drop(columns=["qMeta"]).join(df_dimension_list_expanded)
551
862
 
552
863
  # Resolve the dictionary structure of attribute "qDim"
553
- df_dimension_list_expanded = (df_dimension_list["qDim"].apply(pd.Series).add_prefix("qDim_"))
864
+ df_dimension_list_expanded = (df_dimension_list["qDim"].dropna().apply(pd.Series).add_prefix("qDim_"))
554
865
  df_dimension_list = df_dimension_list.drop(columns=["qDim"]).join(df_dimension_list_expanded)
555
866
 
556
867
  # Resolve the dictionary structure of attribute "qDim_coloring"
557
868
  try:
558
869
  df_dimension_list_expanded = (
559
- df_dimension_list["qDim_coloring"].apply(pd.Series).add_prefix("qDim_coloring_"))
870
+ df_dimension_list["qDim_coloring"].dropna().apply(pd.Series).add_prefix("qDim_coloring_"))
560
871
  df_dimension_list = df_dimension_list.drop(columns=["qDim_coloring"]).join(df_dimension_list_expanded)
561
872
  except KeyError:
562
- df_dimension_list["qDim_coloring"] = ""
873
+ df_dimension_list["qDim_coloring"] = None
563
874
 
564
875
  # Resolve the dictionary structure of attribute "qDim_coloring_baseColor"
565
876
  try:
566
877
  df_dimension_list_expanded = (
567
- df_dimension_list["qDim_coloring_baseColor"].apply(pd.Series).add_prefix("qDim_coloring_baseColor_"))
878
+ df_dimension_list["qDim_coloring_baseColor"].dropna().apply(pd.Series).add_prefix("qDim_coloring_baseColor_"))
568
879
  df_dimension_list = df_dimension_list.drop(columns=["qDim_coloring_baseColor"]).join(
569
880
  df_dimension_list_expanded)
570
881
  except KeyError:
571
- df_dimension_list["qDim_coloring_baseColor"] = ""
882
+ df_dimension_list["qDim_coloring_baseColor"] = None
572
883
 
573
884
  # Resolve the list structure of attribute
574
885
  df_dimension_list = df_dimension_list.explode(['qDimInfos', 'qDim_qFieldDefs', 'qDim_qFieldLabels'])
575
886
 
576
887
  # Resolve the dictionary structure of attribute "qDimInfos"
577
- df_dimension_list_expanded = (df_dimension_list["qDimInfos"].apply(pd.Series).add_prefix("qDimInfos_"))
888
+ df_dimension_list_expanded = (df_dimension_list["qDimInfos"].dropna().apply(pd.Series).add_prefix("qDimInfos_"))
578
889
  index = df_dimension_list_expanded.index
579
890
  df_dimension_list_expanded = df_dimension_list_expanded[~index.duplicated(keep="first")]
580
891
  df_dimension_list = df_dimension_list.drop(columns=["qDimInfos"]).join(df_dimension_list_expanded)
@@ -627,11 +938,11 @@ class QixEngine:
627
938
  df_measure_list.loc[len(df_measure_list)] = measure_layout
628
939
 
629
940
  # Resolve the dictionary structure of attribute "qInfo"
630
- df_measure_list_expanded = (df_measure_list["qInfo"].apply(pd.Series).add_prefix("qInfo_"))
941
+ df_measure_list_expanded = (df_measure_list["qInfo"].dropna().apply(pd.Series).add_prefix("qInfo_"))
631
942
  df_measure_list = df_measure_list.drop(columns=["qInfo"]).join(df_measure_list_expanded)
632
943
 
633
944
  # Resolve the dictionary structure of attribute "qMeasure"
634
- df_measure_list_expanded = (df_measure_list["qMeasure"].apply(pd.Series).add_prefix("qMeasure_"))
945
+ df_measure_list_expanded = (df_measure_list["qMeasure"].dropna().apply(pd.Series).add_prefix("qMeasure_"))
635
946
  df_measure_list = df_measure_list.drop(columns=["qMeasure"]).join(df_measure_list_expanded)
636
947
 
637
948
  # Resolve the dictionary structure of attribute "qMeta"
@@ -640,29 +951,204 @@ class QixEngine:
640
951
 
641
952
  # Resolve the dictionary structure of attribute "qMeasure_qNumFormat"
642
953
  df_measure_list_expanded = (
643
- df_measure_list["qMeasure_qNumFormat"].apply(pd.Series).add_prefix("qMeasure_qNumFormat_"))
954
+ df_measure_list["qMeasure_qNumFormat"].dropna().apply(pd.Series).add_prefix("qMeasure_qNumFormat_"))
644
955
  df_measure_list = df_measure_list.drop(columns=["qMeasure_qNumFormat"]).join(df_measure_list_expanded)
645
956
 
646
957
  # Resolve the dictionary structure of attribute "qMeasure_coloring"
647
958
  try:
648
959
  df_measure_list_expanded = (
649
- df_measure_list["qMeasure_coloring"].apply(pd.Series).add_prefix("qMeasure_coloring_"))
960
+ df_measure_list["qMeasure_coloring"].dropna().apply(pd.Series).add_prefix("qMeasure_coloring_"))
650
961
  df_measure_list = df_measure_list.drop(columns=["qMeasure_coloring"]).join(df_measure_list_expanded)
651
962
  except KeyError:
652
- df_measure_list["qMeasure_coloring"] = ""
963
+ df_measure_list["qMeasure_coloring"] = None
653
964
 
654
965
  # Resolve the dictionary structure of attribute "qMeasure_coloring_baseColor"
655
966
  try:
656
- df_measure_list_expanded = (df_measure_list["qMeasure_coloring_baseColor"].apply(pd.Series).add_prefix(
967
+ df_measure_list_expanded = (df_measure_list["qMeasure_coloring_baseColor"].dropna().apply(pd.Series).add_prefix(
657
968
  "qMeasure_coloring_baseColor_"))
658
969
  df_measure_list = df_measure_list.drop(columns=["qMeasure_coloring_baseColor"]).join(
659
970
  df_measure_list_expanded)
660
971
  except KeyError:
661
- df_measure_list["qMeasure_coloring_baseColor"] = ""
972
+ df_measure_list["qMeasure_coloring_baseColor"] = None
662
973
 
663
974
  return df_measure_list
664
975
 
665
976
 
977
+ def get_app_sheets(self, app_handle):
978
+ """
979
+ Retrieves a list with all app sheets and their content containing metadata.
980
+
981
+ Parameters:
982
+ app_handle (int): The handle of the app.
983
+
984
+ Returns:
985
+ DataFrame: A table with all sheets and their content from an app.
986
+ """
987
+ # Define the parameters of the session object
988
+ nx_info = self.structs.nx_info(obj_type="SheetList")
989
+ sheet_list_def = self.structs.sheet_list_def()
990
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qAppObjectListDef",
991
+ prop_def=sheet_list_def)
992
+
993
+ # Create session object
994
+ session = self.eaa.create_session_object(app_handle, gen_obj_props)
995
+
996
+ # Get session handle
997
+ session_handle = self.get_handle(session)
998
+
999
+ # Get session object data
1000
+ session_layout = self.egoa.get_layout(session_handle)
1001
+
1002
+ # Get the sheet list as Dictionary structure
1003
+ sheet_list = session_layout["qAppObjectList"]["qItems"]
1004
+
1005
+ # Define the DataFrame structure
1006
+ df_sheet_list = pd.DataFrame(columns=['qInfo', 'qMeta', 'qSelectionInfo', 'rank', 'thumbnail', 'columns', 'rows', 'cells', 'qChildList', 'gridResolution', 'layoutOptions', 'gridMode', 'customRowBase'])
1007
+
1008
+ for sheet in sheet_list:
1009
+ # Get sheet ID
1010
+ sheet_id = sheet["qInfo"]["qId"]
1011
+ # Get sheet
1012
+ sheet_result = self.eaa.get_object(app_handle=app_handle, object_id=sheet_id)
1013
+ # Get sheet handle
1014
+ sheet_handle = self.get_handle(sheet_result)
1015
+ # Get session object data
1016
+ sheet_layout = self.egoa.get_layout(sheet_handle)
1017
+
1018
+ # Concatenate the measure metadata to the DataFrame structure
1019
+ df_sheet_list.loc[len(df_sheet_list)] = sheet_layout
1020
+
1021
+ # Resolve the dictionary structure of attribute "qInfo"
1022
+ df_sheet_list_expanded = (df_sheet_list["qInfo"].dropna().apply(pd.Series).add_prefix("qInfo_"))
1023
+ df_sheet_list = df_sheet_list.drop(columns=["qInfo"]).join(df_sheet_list_expanded)
1024
+
1025
+ # Resolve the dictionary structure of attribute "qMeta"
1026
+ df_sheet_list_expanded = (df_sheet_list["qMeta"].dropna().apply(pd.Series).add_prefix("qMeta_"))
1027
+ df_sheet_list = df_sheet_list.drop(columns=["qMeta"]).join(df_sheet_list_expanded)
1028
+
1029
+ # Resolve the dictionary structure of attribute "qSelectionInfo"
1030
+ df_sheet_list["qSelectionInfo"] = df_sheet_list["qSelectionInfo"].apply(
1031
+ lambda x: None if isinstance(x, dict) and len(x) == 0 else x
1032
+ )
1033
+ df_sheet_list_expanded = (df_sheet_list["qSelectionInfo"].dropna().apply(pd.Series).add_prefix("qSelectionInfo_"))
1034
+ df_sheet_list = df_sheet_list.drop(columns=["qSelectionInfo"]).join(df_sheet_list_expanded)
1035
+
1036
+ # Resolve the dictionary structure of attribute "thumbnail"
1037
+ df_sheet_list_expanded = (df_sheet_list["thumbnail"].dropna().apply(pd.Series).add_prefix("thumbnail_"))
1038
+ df_sheet_list = df_sheet_list.drop(columns=["thumbnail"]).join(df_sheet_list_expanded)
1039
+
1040
+ # Resolve the dictionary structure of attribute "thumbnail_qStaticContentUrl"
1041
+ df_sheet_list["thumbnail_qStaticContentUrl"] = df_sheet_list["thumbnail_qStaticContentUrl"].apply(
1042
+ lambda x: None if isinstance(x, dict) and len(x) == 0 else x
1043
+ )
1044
+ df_sheet_list_expanded = (df_sheet_list["thumbnail_qStaticContentUrl"].dropna().apply(pd.Series).add_prefix("thumbnail_qStaticContentUrl_"))
1045
+ df_sheet_list = df_sheet_list.drop(columns=["thumbnail_qStaticContentUrl"]).join(df_sheet_list_expanded)
1046
+
1047
+ # Resolve the dictionary structure of attribute "qChildList"
1048
+ df_sheet_list_expanded = (df_sheet_list["qChildList"].dropna().apply(pd.Series).add_prefix("qChildList_"))
1049
+ df_sheet_list = df_sheet_list.drop(columns=["qChildList"]).join(df_sheet_list_expanded)
1050
+
1051
+ # Resolve the dictionary structure of attribute "layoutOptions"
1052
+ df_sheet_list_expanded = (df_sheet_list["layoutOptions"].dropna().apply(pd.Series).add_prefix("layoutOptions_"))
1053
+ df_sheet_list = df_sheet_list.drop(columns=["layoutOptions"]).join(df_sheet_list_expanded)
1054
+
1055
+ # Resolve the list structure of attribute
1056
+ df_sheet_list = df_sheet_list.explode(['cells', 'qChildList_qItems'])
1057
+
1058
+ # Resolve the dictionary structure of attribute "cells"
1059
+ df_sheet_list_expanded = (df_sheet_list["cells"].dropna().apply(pd.Series).add_prefix("cells_"))
1060
+ index = df_sheet_list_expanded.index
1061
+ df_sheet_list_expanded = df_sheet_list_expanded[~index.duplicated(keep="first")]
1062
+ df_sheet_list = df_sheet_list.drop(columns=["cells"]).join(df_sheet_list_expanded)
1063
+
1064
+ # Resolve the dictionary structure of attribute "cells_bounds"
1065
+ df_sheet_list_expanded = (
1066
+ df_sheet_list["cells_bounds"].dropna().apply(pd.Series).add_prefix("cells_bounds_"))
1067
+ index = df_sheet_list_expanded.index
1068
+ df_sheet_list_expanded = df_sheet_list_expanded[~index.duplicated(keep="first")]
1069
+ df_sheet_list = df_sheet_list.drop(columns=["cells_bounds"]).join(df_sheet_list_expanded)
1070
+
1071
+ # Resolve the dictionary structure of attribute "qChildList_qItems"
1072
+ df_sheet_list_expanded = (
1073
+ df_sheet_list["qChildList_qItems"].dropna().apply(pd.Series).add_prefix("qChildList_qItems_"))
1074
+ index = df_sheet_list_expanded.index
1075
+ df_sheet_list_expanded = df_sheet_list_expanded[~index.duplicated(keep="first")]
1076
+ df_sheet_list = df_sheet_list.drop(columns=["qChildList_qItems"]).join(df_sheet_list_expanded)
1077
+
1078
+ # Resolve the dictionary structure of attribute "qChildList_qItems_qInfo"
1079
+ df_sheet_list_expanded = (
1080
+ df_sheet_list["qChildList_qItems_qInfo"].dropna().apply(pd.Series).add_prefix("qChildList_qItems_qInfo_"))
1081
+ index = df_sheet_list_expanded.index
1082
+ df_sheet_list_expanded = df_sheet_list_expanded[~index.duplicated(keep="first")]
1083
+ df_sheet_list = df_sheet_list.drop(columns=["qChildList_qItems_qInfo"]).join(df_sheet_list_expanded)
1084
+
1085
+ # Resolve the dictionary structure of attribute "qChildList_qItems_qMeta"
1086
+ df_sheet_list_expanded = (
1087
+ df_sheet_list["qChildList_qItems_qMeta"].dropna().apply(pd.Series).add_prefix("qChildList_qItems_qMeta_"))
1088
+ index = df_sheet_list_expanded.index
1089
+ df_sheet_list_expanded = df_sheet_list_expanded[~index.duplicated(keep="first")]
1090
+ df_sheet_list = df_sheet_list.drop(columns=["qChildList_qItems_qMeta"]).join(df_sheet_list_expanded)
1091
+
1092
+ # Resolve the dictionary structure of attribute "qChildList_qItems_qData"
1093
+ df_sheet_list_expanded = (
1094
+ df_sheet_list["qChildList_qItems_qData"].dropna().apply(pd.Series).add_prefix("qChildList_qItems_qData_"))
1095
+ index = df_sheet_list_expanded.index
1096
+ df_sheet_list_expanded = df_sheet_list_expanded[~index.duplicated(keep="first")]
1097
+ df_sheet_list = df_sheet_list.drop(columns=["qChildList_qItems_qData"]).join(df_sheet_list_expanded)
1098
+
1099
+ return df_sheet_list
1100
+
1101
+
1102
+ def get_app_variables(self, app_handle):
1103
+ """
1104
+ Retrieves a list with all app variables containing metadata.
1105
+
1106
+ Parameters:
1107
+ app_handle (int): The handle of the app.
1108
+
1109
+ Returns:
1110
+ DataFrame: A table with all variables from an app.
1111
+ """
1112
+ # Define the parameters of the session object
1113
+ nx_info = self.structs.nx_info(obj_type="VariableList")
1114
+ variable_list_def = self.structs.variable_list_def()
1115
+ gen_obj_props = self.structs.generic_object_properties(info=nx_info, prop_name="qVariableListDef",
1116
+ prop_def=variable_list_def)
1117
+
1118
+ # Create session object
1119
+ session = self.eaa.create_session_object(app_handle, gen_obj_props)
1120
+
1121
+ # Get session handle
1122
+ session_handle = self.get_handle(session)
1123
+
1124
+ # Get session object data
1125
+ session_layout = self.egoa.get_layout(session_handle)
1126
+
1127
+ # Get the variable list as Dictionary structure
1128
+ variable_list = session_layout["qVariableList"]["qItems"]
1129
+
1130
+ # Define the DataFrame structure
1131
+ df_variable_list = pd.DataFrame(columns=["qName", "qDefinition", "qMeta", "qInfo", "qData", "qIsScriptCreated", "qIsReserved"])
1132
+
1133
+ for variable in variable_list:
1134
+ # Concatenate the measure metadata to the DataFrame structure
1135
+ df_variable_list.loc[len(df_variable_list)] = variable
1136
+
1137
+ # Resolve the dictionary structure of attribute "qInfo"
1138
+ df_variable_list_expanded = (df_variable_list["qInfo"].dropna().apply(pd.Series).add_prefix("qInfo_"))
1139
+ df_variable_list = df_variable_list.drop(columns=["qInfo"]).join(df_variable_list_expanded)
1140
+
1141
+ # Resolve the dictionary structure of attribute "qMeta"
1142
+ df_variable_list_expanded = (df_variable_list["qMeta"].dropna().apply(pd.Series).add_prefix("qMeta_"))
1143
+ df_variable_list = df_variable_list.drop(columns=["qMeta"]).join(df_variable_list_expanded)
1144
+
1145
+ # Resolve the dictionary structure of attribute "qData"
1146
+ df_variable_list_expanded = (df_variable_list["qData"].dropna().apply(pd.Series).add_prefix("qData_"))
1147
+ df_variable_list = df_variable_list.drop(columns=["qData"]).join(df_variable_list_expanded)
1148
+
1149
+ return df_variable_list
1150
+
1151
+
666
1152
  def get_app_lineage(self, app_handle):
667
1153
  """
668
1154
  Retrieves a list with an app lineage data.