qe-api-client 2.7.0__py3-none-any.whl → 2.8.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.
@@ -208,3 +208,21 @@ class EngineGenericObjectApi:
208
208
  return response["result"]
209
209
  except KeyError:
210
210
  return response["error"]
211
+
212
+
213
+ def get_properties(self, handle: int):
214
+ """
215
+ Retrieves the properties of a specific generic object.
216
+
217
+ Parameters:
218
+ handle (int): The handle identifying the generic object.
219
+
220
+ Returns:
221
+ dict: The properties of the generic object (qLayout). In case of an error, returns the error information.
222
+ """
223
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle, "method": "GetProperties", "params": {}})
224
+ response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
225
+ try:
226
+ return response["result"]["qProp"]
227
+ except KeyError:
228
+ return response["error"]
qe_api_client/engine.py CHANGED
@@ -135,9 +135,9 @@ class QixEngine:
135
135
  # Define of the single dimension properties
136
136
  nx_info = self.structs.nx_info(obj_type="dimension")
137
137
  if dim_color is None:
138
- coloring = self.structs.coloring()
138
+ coloring = self.structs.dim_coloring()
139
139
  else:
140
- coloring = self.structs.coloring(base_color={"color": dim_color, "index": dim_color_index})
140
+ coloring = self.structs.dim_coloring(base_color={"color": dim_color, "index": dim_color_index})
141
141
 
142
142
  nx_library_dimension_def = self.structs.nx_library_dimension_def(grouping="N", field_definitions=[dim_def],
143
143
  field_labels=[dim_title],
@@ -213,7 +213,8 @@ class QixEngine:
213
213
 
214
214
 
215
215
  def create_master_measure(self, app_handle: int, mes_title: str, mes_def: str, mes_label: str = "",
216
- mes_desc: str = "", mes_tags: list = None):
216
+ mes_desc: str = "", mes_tags: list = None, mes_color: str = None,
217
+ mes_color_index: int = -1, gradient: dict = None):
217
218
  """
218
219
  Creates a master measure.
219
220
 
@@ -224,6 +225,8 @@ class QixEngine:
224
225
  mes_label (str, optional): The label of the measure.
225
226
  mes_desc (str, optional): The description of the measure.
226
227
  mes_tags (list, optional): The tags of the measure.
228
+ mes_color (str, optional): The color of the measure.
229
+ mes_color_index (int, optional): The index of the color of the measure.
227
230
 
228
231
  Returns:
229
232
  dict: The handle and Id of the measure.
@@ -233,8 +236,17 @@ class QixEngine:
233
236
 
234
237
  # Define of the measure properties
235
238
  nx_info = self.structs.nx_info(obj_type="measure")
239
+
240
+ if mes_color is None:
241
+ coloring = self.structs.mes_coloring()
242
+ else:
243
+ coloring = self.structs.mes_coloring(base_color={"color": mes_color, "index": mes_color_index})
244
+
245
+ if gradient is not None:
246
+ coloring.update({"gradient": gradient})
247
+
236
248
  nx_library_measure_def = self.structs.nx_library_measure_def(label=mes_title, mes_def=mes_def,
237
- label_expression=mes_label)
249
+ label_expression=mes_label, coloring=coloring)
238
250
  gen_mes_props = self.structs.generic_measure_properties(nx_info=nx_info,
239
251
  nx_library_measure_def=nx_library_measure_def,
240
252
  title=mes_title, description=mes_desc, tags=mes_tags)
@@ -526,14 +538,25 @@ class QixEngine:
526
538
  # Determine the number of the columns and the rows the table has and splits in certain circumstances the table
527
539
  # calls
528
540
  no_of_columns = obj_layout['qHyperCube']['qSize']['qcx']
541
+
542
+ if no_of_columns == 0:
543
+ return 'The chart either contains no columns or has a calculation condition!'
544
+
529
545
  width = no_of_columns
530
546
  no_of_rows = obj_layout['qHyperCube']['qSize']['qcy']
531
547
  height = int(math.floor(10000 / no_of_columns))
532
548
 
533
549
  # Extract the dimension and measure titles and concat them to column names.
534
- dimension_titles = [dim['qFallbackTitle'] for dim in obj_layout['qHyperCube']['qDimensionInfo']]
535
- measure_titles = [measure['qFallbackTitle'] for measure in obj_layout['qHyperCube']['qMeasureInfo']]
536
- column_names = dimension_titles + measure_titles
550
+ dimension_info = obj_layout['qHyperCube'].get('qDimensionInfo', [])
551
+ measure_info = obj_layout['qHyperCube'].get('qMeasureInfo', [])
552
+ column_info = dimension_info + measure_info
553
+
554
+ # Build the column mapping using qEffectiveInterColumnSortOrder
555
+ sort_order = sorted(obj_layout['qHyperCube']['qEffectiveInterColumnSortOrder'])
556
+ sort_order_positive = [x for x in sort_order if x >= 0]
557
+ column_names = []
558
+ for i in sort_order_positive:
559
+ column_names.append(column_info[i]["qFallbackTitle"])
537
560
 
538
561
  # if the type of the charts has a straight data structure
539
562
  if (obj_layout['qInfo']['qType'] in ['table', 'sn-table', 'piechart', 'scatterplot', 'combochart', 'barchart']
@@ -563,9 +586,10 @@ class QixEngine:
563
586
 
564
587
  # Supporting function to traverse all subnodes to get all dimensions
565
588
  def get_all_dimensions(node):
566
- dimensions = [node['qText']]
567
- # if 'qSubNodes' in node and node['qSubNodes']:
568
- if node['qSubNodes']:
589
+ label = node.get('qText', '') # Leerer String, falls nicht vorhanden
590
+ dimensions = [label]
591
+
592
+ if 'qSubNodes' in node and node['qSubNodes']:
569
593
  sub_dimensions = []
570
594
  for sub_node in node['qSubNodes']:
571
595
  sub_dimensions.extend([dimensions + d for d in get_all_dimensions(sub_node)])
@@ -573,13 +597,25 @@ class QixEngine:
573
597
  else:
574
598
  return [dimensions]
575
599
 
576
- # Gets the column headers for the pivot table
600
+ # Supporting function to get all column headers for the pivot table
601
+ def get_column_paths(node):
602
+ label = node.get('qText', '')
603
+ current_path = [label]
604
+
605
+ if 'qSubNodes' in node and node['qSubNodes']:
606
+ paths = []
607
+ for sub in node['qSubNodes']:
608
+ for path in get_column_paths(sub):
609
+ paths.append(current_path + path)
610
+ return paths
611
+ else:
612
+ return [current_path]
613
+
577
614
  col_headers = []
578
615
  nx_page_top = self.structs.nx_page(left=0, top=0, width=width, height=1)
579
- hc_top = self.egoa.get_hypercube_pivot_data(obj_handle, '/qHyperCubeDef', nx_page_top)[
580
- 'qDataPages'][0]['qTop']
616
+ hc_top = self.egoa.get_hypercube_pivot_data(obj_handle, '/qHyperCubeDef', nx_page_top)['qDataPages'][0]['qTop']
581
617
  for top_node in hc_top:
582
- col_headers.extend(get_all_dimensions(top_node))
618
+ col_headers.extend(get_column_paths(top_node))
583
619
 
584
620
  # Paging variables
585
621
  page = 0
@@ -610,6 +646,9 @@ class QixEngine:
610
646
 
611
647
  # Creates the Dataframe
612
648
  df = pd.DataFrame(data_values, index=row_index, columns=col_index)
649
+ index_levels = df.index.nlevels
650
+ df.index.names = column_names[:index_levels]
651
+ df = df.reset_index()
613
652
 
614
653
  # if the type of the charts has a stacked data structure
615
654
  elif obj_layout['qInfo']['qType'] in ['barchart'] and obj_layout['qHyperCube']['qStackedDataPages'] != []:
qe_api_client/structs.py CHANGED
@@ -277,14 +277,18 @@ def nx_library_dimension_def(grouping: str = "N", field_definitions: list = None
277
277
 
278
278
 
279
279
  def nx_library_measure_def(label: str, mes_def: str, grouping: str = "N", expressions: list = None,
280
- active_expression: int = 0, label_expression:str = "", num_format: dict = None):
280
+ active_expression: int = 0, label_expression:str = "", num_format: dict = None,
281
+ coloring: dict = None):
282
+ if coloring is None:
283
+ coloring = {}
281
284
  if num_format is None:
282
285
  num_format = {}
283
286
  if expressions is None:
284
287
  expressions = []
285
288
  return {
286
289
  "qLabel": label, "qDef": mes_def,"qGrouping": grouping, "qExpressions": expressions,
287
- "qActiveExpression": active_expression, "qLabelExpression": label_expression, "qNumFormat": num_format
290
+ "qActiveExpression": active_expression, "qLabelExpression": label_expression, "qNumFormat": num_format,
291
+ "coloring": coloring
288
292
  }
289
293
 
290
294
 
@@ -509,7 +513,7 @@ def color_map(colors: list = None, nul: dict = None, oth: dict = None, pal: str
509
513
  }
510
514
 
511
515
 
512
- def coloring(change_hash: str = None, color_map_ref: str = "", has_value_colors: bool = False, base_color: dict = None):
516
+ def dim_coloring(change_hash: str = None, color_map_ref: str = "", has_value_colors: bool = False, base_color: dict = None):
513
517
  if base_color is None:
514
518
  base_color = {"color": "none", "index": 0}
515
519
  return {
@@ -520,6 +524,15 @@ def coloring(change_hash: str = None, color_map_ref: str = "", has_value_colors:
520
524
  }
521
525
 
522
526
 
527
+ def mes_coloring(base_color: dict = None, _gradient: dict = None):
528
+ coloring = {}
529
+ if base_color is not None:
530
+ coloring.update({"baseColor": base_color})
531
+ if _gradient is not None:
532
+ coloring.update({"gradient": _gradient})
533
+ return coloring
534
+
535
+
523
536
  def color_map_properties(dim_id: str, prop_def:dict = None, extends_id: str = "", state_name: str = "",
524
537
  _color_map: dict = None):
525
538
 
@@ -539,3 +552,17 @@ def value_color(value: str, color: str, index: int = -1):
539
552
  "value": value,
540
553
  "baseColor": {"color": color, "index": index}
541
554
  }
555
+
556
+
557
+ def color(_color: str, index: int = -1):
558
+ return {"color": _color, "index": index}
559
+
560
+
561
+ def gradient(colors: list = None, break_types: list = None, limits: list = None, limit_type: str = "percent"):
562
+ if colors is None:
563
+ colors = [color(_color="#332288"), color(_color="#117733")]
564
+ if break_types is None:
565
+ break_types = [False]
566
+ if limits is None:
567
+ limits = [0.5]
568
+ return {"colors": colors, "breakTypes": break_types, "limits": limits, "limitType": limit_type}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qe-api-client
3
- Version: 2.7.0
3
+ Version: 2.8.0
4
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
@@ -11,8 +11,10 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.6
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: websocket-client>=0.47.0
14
+ Requires-Dist: websocket-client>=1.0.0
15
15
  Requires-Dist: pandas>=2.2.0
16
+ Requires-Dist: numpy>=2.0.0
17
+ Requires-Dist: uuid>=1.0
16
18
  Dynamic: author
17
19
  Dynamic: author-email
18
20
  Dynamic: classifier
@@ -1,17 +1,17 @@
1
1
  qe_api_client/__init__.py,sha256=bypB4CIjpHtf5Pu_NwtJajC69zqQD7qB9jo8cCX0B54,23
2
- qe_api_client/engine.py,sha256=4pll0uoFPph5WgRufpP4OsYlypWKQhMfJQAaaWPWWUU,56738
2
+ qe_api_client/engine.py,sha256=P98pUEbR86e-UDuI38lzIpRlpT1s93pAs5wNhJtxr5c,58380
3
3
  qe_api_client/engine_communicator.py,sha256=q6x7ix2Ev8yGmTTm7cf1vHcidOihKM0HjDXeJ-dZYjk,1133
4
- qe_api_client/structs.py,sha256=Gh7aGNLN58kYeBY-6Nb7yagQpHnd1f-IlfaE8aEF9ns,22621
4
+ qe_api_client/structs.py,sha256=HuXUCPpHWrQgqilplRID213VAfhO7sefh3FCWfTguvA,23515
5
5
  qe_api_client/api_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  qe_api_client/api_classes/engine_app_api.py,sha256=qobuSdLV5I-DOXto0Qi5ckMG3q5Dll0Lto3TyjZSbso,37493
7
7
  qe_api_client/api_classes/engine_field_api.py,sha256=zCLIR7rmxqwIrJYK_-uHVEhMvBcEP2qofuX8ZPygqCA,5479
8
8
  qe_api_client/api_classes/engine_generic_dimension_api.py,sha256=oSZoRT-j4hsCVnUm1OSg7XZPWXhUzFLY_53kM0KwPHs,2122
9
9
  qe_api_client/api_classes/engine_generic_measure_api.py,sha256=uj4i_ykX9F9Dtk78fOidMBhzSP8vEucEfrB6MrLwgPI,1340
10
- qe_api_client/api_classes/engine_generic_object_api.py,sha256=iasoNYSSsBTr_S3ExoorfCip9fhy7sCQ_J-ru2JYal8,10130
10
+ qe_api_client/api_classes/engine_generic_object_api.py,sha256=WTxRusRt2PGxmXsQQyGZ2M2JRyKTSSrV5TqpiykxDbA,10807
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.7.0.dist-info/licenses/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
14
- qe_api_client-2.7.0.dist-info/METADATA,sha256=5-VkSmGbK-92mrMlEqFgozK8FtbUfmpW1o5_zQZrLlA,2385
15
- qe_api_client-2.7.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
16
- qe_api_client-2.7.0.dist-info/top_level.txt,sha256=m_43YagP8UtZgJHmZEfu0vlBNwt36M01-Qby2jByMnk,14
17
- qe_api_client-2.7.0.dist-info/RECORD,,
13
+ qe_api_client-2.8.0.dist-info/licenses/LICENSE,sha256=2bm9uFabQZ3Ykb_SaSU_uUbAj2-htc6WJQmS_65qD00,1073
14
+ qe_api_client-2.8.0.dist-info/METADATA,sha256=94Fddh_umm8FPjkp7Scj3VGheOLvjGPEiyzx_V3UGjI,2437
15
+ qe_api_client-2.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
+ qe_api_client-2.8.0.dist-info/top_level.txt,sha256=m_43YagP8UtZgJHmZEfu0vlBNwt36M01-Qby2jByMnk,14
17
+ qe_api_client-2.8.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5