qe-api-client 2.1.0__tar.gz → 2.3.0__tar.gz
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-2.1.0 → qe_api_client-2.3.0}/PKG-INFO +6 -3
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/README.md +5 -2
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_app_api.py +40 -58
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_field_api.py +32 -22
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_global_api.py +2 -1
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/engine.py +93 -43
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/structs.py +27 -12
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client.egg-info/PKG-INFO +6 -3
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client.egg-info/SOURCES.txt +0 -1
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/setup.py +1 -1
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/test/test_app_api.py +1 -1
- qe_api_client-2.3.0/test/test_field_api.py +52 -0
- qe_api_client-2.3.0/test/test_pyqlikengine.py +62 -0
- qe_api_client-2.1.0/qe_api_client/engine_helper.py +0 -67
- qe_api_client-2.1.0/test/test_field_api.py +0 -71
- qe_api_client-2.1.0/test/test_pyqlikengine.py +0 -74
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/LICENSE +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/__init__.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/__init__.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_dimension_api.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_measure_api.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_object_api.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_variable_api.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/engine_communicator.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client.egg-info/dependency_links.txt +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client.egg-info/requires.txt +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client.egg-info/top_level.txt +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/setup.cfg +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/test/test_global_api.py +0 -0
- {qe_api_client-2.1.0 → qe_api_client-2.3.0}/test/test_labs.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qe-api-client
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.3.0
|
4
4
|
Summary: Python wrapper around Qlik Engine JSON API
|
5
5
|
Home-page: https://github.com/lr-bicc/qe-api-client
|
6
6
|
Author: Rumen Vasilev
|
@@ -28,7 +28,7 @@ Forked from [jhettler/pyqlikengine](https://github.com/jhettler/pyqlikengine)
|
|
28
28
|
pip install qe-api-client
|
29
29
|
```
|
30
30
|
|
31
|
-
##
|
31
|
+
## Connecting to Qlik Sense Enterprise Server
|
32
32
|
You need to export the Qlik Sense certificates in PEM format from the Qlik Sense Enterprise server to a local folder in
|
33
33
|
order to authenticate on the server.
|
34
34
|
|
@@ -48,7 +48,7 @@ qixe = QixEngine(url=url, user_directory=user_directory, user_id=user_id, ca_cer
|
|
48
48
|
print(qixe.ega.get_doc_list())
|
49
49
|
```
|
50
50
|
|
51
|
-
##
|
51
|
+
## Connecting to Qlik Sense Desktop
|
52
52
|
You need to start your Qlik Sense Desktop client on your local PC.
|
53
53
|
|
54
54
|
```python
|
@@ -61,5 +61,8 @@ qixe = QixEngine(url=url)
|
|
61
61
|
print(qixe.ega.get_doc_list())
|
62
62
|
```
|
63
63
|
|
64
|
+
## Examples of usage
|
65
|
+
Please click on this [link](https://github.com/lr-bicc/qe-api-client/tree/master/examples) to find examples of usage of this client.
|
66
|
+
|
64
67
|
## API reference
|
65
68
|
Please click on this [link](https://lr-bicc.github.io/qe-api-client) for full API reference documentation .
|
@@ -13,7 +13,7 @@ Forked from [jhettler/pyqlikengine](https://github.com/jhettler/pyqlikengine)
|
|
13
13
|
pip install qe-api-client
|
14
14
|
```
|
15
15
|
|
16
|
-
##
|
16
|
+
## Connecting to Qlik Sense Enterprise Server
|
17
17
|
You need to export the Qlik Sense certificates in PEM format from the Qlik Sense Enterprise server to a local folder in
|
18
18
|
order to authenticate on the server.
|
19
19
|
|
@@ -33,7 +33,7 @@ qixe = QixEngine(url=url, user_directory=user_directory, user_id=user_id, ca_cer
|
|
33
33
|
print(qixe.ega.get_doc_list())
|
34
34
|
```
|
35
35
|
|
36
|
-
##
|
36
|
+
## Connecting to Qlik Sense Desktop
|
37
37
|
You need to start your Qlik Sense Desktop client on your local PC.
|
38
38
|
|
39
39
|
```python
|
@@ -46,5 +46,8 @@ qixe = QixEngine(url=url)
|
|
46
46
|
print(qixe.ega.get_doc_list())
|
47
47
|
```
|
48
48
|
|
49
|
+
## Examples of usage
|
50
|
+
Please click on this [link](https://github.com/lr-bicc/qe-api-client/tree/master/examples) to find examples of usage of this client.
|
51
|
+
|
49
52
|
## API reference
|
50
53
|
Please click on this [link](https://lr-bicc.github.io/qe-api-client) for full API reference documentation .
|
@@ -79,7 +79,7 @@ class EngineAppApi:
|
|
79
79
|
except KeyError:
|
80
80
|
return response['error']
|
81
81
|
|
82
|
-
def do_reload_ex(self, doc_handle, param_list=
|
82
|
+
def do_reload_ex(self, doc_handle, param_list={}):
|
83
83
|
"""
|
84
84
|
Triggers an extended reload of the app identified by the document handle.
|
85
85
|
|
@@ -91,10 +91,10 @@ class EngineAppApi:
|
|
91
91
|
dict: The result of the extended reload operation. In case of an error, returns the error information.
|
92
92
|
"""
|
93
93
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "DoReloadEx",
|
94
|
-
"params": param_list})
|
94
|
+
"params": {"qParams": param_list}})
|
95
95
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
96
96
|
try:
|
97
|
-
return response[
|
97
|
+
return response["result"]["qResult"]
|
98
98
|
except KeyError:
|
99
99
|
return response['error']
|
100
100
|
|
@@ -141,10 +141,10 @@ class EngineAppApi:
|
|
141
141
|
Parameters:
|
142
142
|
doc_handle (int): The handle identifying the app document.
|
143
143
|
field_name (str): The name of the field to retrieve.
|
144
|
-
state_name (str): The name of the state. Default is
|
144
|
+
state_name (str): The name of the alternate state. Default state is current selections.
|
145
145
|
|
146
146
|
Returns:
|
147
|
-
dict:
|
147
|
+
dict: Object interface.
|
148
148
|
"""
|
149
149
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "GetField",
|
150
150
|
"params": {"qFieldName": field_name, "qStateName": state_name}})
|
@@ -160,10 +160,7 @@ class EngineAppApi:
|
|
160
160
|
|
161
161
|
Parameters:
|
162
162
|
doc_handle (int): The handle identifying the app document.
|
163
|
-
|
164
|
-
q_type (str): The type of the new object. Default is "ListObject".
|
165
|
-
struct_name (str): The name of the structure defining the object. Default is "qListObjectDef".
|
166
|
-
ob_struct (dict): The structure defining the object.
|
163
|
+
prop (dict): Information about the object.
|
167
164
|
|
168
165
|
Returns:
|
169
166
|
dict: The created object (qReturn). In case of an error, returns the error information.
|
@@ -223,8 +220,16 @@ class EngineAppApi:
|
|
223
220
|
return response['error']
|
224
221
|
|
225
222
|
def clear_all(self, doc_handle, locked_also=False, alt_state=""):
|
223
|
+
"""
|
224
|
+
Clear selections in fields for current state. Locked fields are not cleared by default.
|
225
|
+
|
226
|
+
Parameters:
|
227
|
+
doc_handle (int): The handle identifying the app document.
|
228
|
+
locked_also (bool): When true, clears the selection for locked fields.
|
229
|
+
alt_state (str): Alternate state name. When set, applies to alternate state instead of current.
|
230
|
+
"""
|
226
231
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "ClearAll",
|
227
|
-
"params":
|
232
|
+
"params": {"qLockedAlso": locked_also, "qStateName": alt_state}})
|
228
233
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
229
234
|
try:
|
230
235
|
return response['result']
|
@@ -250,45 +255,24 @@ class EngineAppApi:
|
|
250
255
|
# can contain the same dimension.
|
251
256
|
# Parameters:
|
252
257
|
# qProp (MANDATORY: send dim_id, dim_title, dim_grouping, dim_field, dim_label, meta_def (optional) # NOQA
|
253
|
-
def
|
254
|
-
dim_grouping="N", dim_field='', dim_label='',
|
255
|
-
meta_def=""):
|
258
|
+
def create_dimension(self, doc_handle, prop):
|
256
259
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "CreateDimension",
|
257
|
-
"params":
|
258
|
-
"qInfo": {
|
259
|
-
"qId": dim_id,
|
260
|
-
"qType": "Dimension"
|
261
|
-
},
|
262
|
-
"qDim": {
|
263
|
-
"title": dim_title,
|
264
|
-
"qGrouping": dim_grouping,
|
265
|
-
"qFieldDefs": [
|
266
|
-
dim_field
|
267
|
-
],
|
268
|
-
"qFieldLabels": [
|
269
|
-
dim_label
|
270
|
-
]
|
271
|
-
},
|
272
|
-
"qMetaDef": {
|
273
|
-
"title": meta_def
|
274
|
-
}
|
275
|
-
}]
|
276
|
-
})
|
260
|
+
"params": {"qProp": prop}})
|
277
261
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
278
262
|
try:
|
279
|
-
return response[
|
263
|
+
return response["result"]["qReturn"]
|
280
264
|
except KeyError:
|
281
265
|
return response['error']
|
282
266
|
|
283
267
|
# DestroyDimension method: Removes a dimension
|
284
|
-
def
|
268
|
+
def destroy_dimension(self, doc_handle, dim_id):
|
285
269
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "DestroyDimension",
|
286
|
-
"params":
|
270
|
+
"params": {"qId": dim_id}})
|
287
271
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
288
272
|
try:
|
289
|
-
return response[
|
273
|
+
return response["result"]["qSuccess"]
|
290
274
|
except KeyError:
|
291
|
-
return response[
|
275
|
+
return response["error"]
|
292
276
|
|
293
277
|
# DestroyMeasure method: Removes a measure
|
294
278
|
def destroy_measure(self, doc_handle, measure_id):
|
@@ -347,25 +331,12 @@ class EngineAppApi:
|
|
347
331
|
# can contain the same dimension.
|
348
332
|
# Parameters:
|
349
333
|
# qProp (MANDATORY: send dim_id, dim_title, dim_grouping, dim_field, dim_label, meta_def (optional) # NOQA
|
350
|
-
def
|
351
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle,
|
352
|
-
"
|
353
|
-
"qInfo": {
|
354
|
-
"qId": measure_id,
|
355
|
-
"qType": "Measure"
|
356
|
-
},
|
357
|
-
"qMeasure": {
|
358
|
-
"qLabel": measure_title,
|
359
|
-
"qDef": measure_expr
|
360
|
-
},
|
361
|
-
"qMetaDef": {
|
362
|
-
"title": measure_title
|
363
|
-
}
|
364
|
-
}]
|
365
|
-
})
|
334
|
+
def create_measure(self, doc_handle, prop):
|
335
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "CreateMeasure",
|
336
|
+
"params": {"qProp": prop}})
|
366
337
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
367
338
|
try:
|
368
|
-
return response[
|
339
|
+
return response["result"]["qReturn"]
|
369
340
|
except KeyError:
|
370
341
|
return response['error']
|
371
342
|
|
@@ -464,8 +435,9 @@ class EngineAppApi:
|
|
464
435
|
|
465
436
|
# DoSave method: Saves an app - All objects and data in the data model are saved. # NOQA
|
466
437
|
# Desktop only - server auto saves
|
467
|
-
def do_save(self, doc_handle):
|
468
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "DoSave",
|
438
|
+
def do_save(self, doc_handle, file_name=""):
|
439
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "DoSave",
|
440
|
+
"params": {"qFileName": file_name}})
|
469
441
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
470
442
|
try:
|
471
443
|
return response['result']
|
@@ -695,7 +667,17 @@ class EngineAppApi:
|
|
695
667
|
|
696
668
|
# GetAllInfos method: Get the identifier and the type of any generic object in an app by using the GetAllInfos method. # NOQA
|
697
669
|
def get_lineage(self, doc_handle):
|
698
|
-
|
670
|
+
"""
|
671
|
+
Gets the lineage information of the app. The lineage information includes the LOAD and STORE statements from
|
672
|
+
the data load script associated with this app.
|
673
|
+
|
674
|
+
Parameters:
|
675
|
+
doc_handle (int): The handle identifying the app document.
|
676
|
+
|
677
|
+
Returns:
|
678
|
+
list: Information about the lineage of the data in the app.
|
679
|
+
"""
|
680
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": doc_handle, "method": "GetLineage", "params": {}})
|
699
681
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
700
682
|
try:
|
701
683
|
return response['result']['qLineage']
|
@@ -18,77 +18,87 @@ class EngineFieldApi:
|
|
18
18
|
"""
|
19
19
|
self.engine_socket = socket
|
20
20
|
|
21
|
-
def select(self, fld_handle, value):
|
21
|
+
def select(self, fld_handle, value, soft_lock = False, excluded_values_mode = 0):
|
22
22
|
"""
|
23
|
-
Selects
|
23
|
+
Selects field values matching a search string.
|
24
24
|
|
25
25
|
Args:
|
26
26
|
fld_handle (int): The handle of the field.
|
27
|
-
value (str):
|
27
|
+
value (str): String to search for. Can contain wild cards or numeric search criteria.
|
28
|
+
soft_lock (bool): Set to true to ignore locks; in that case, locked fields can be selected.
|
29
|
+
excluded_values_mode (int): Include excluded values in search.
|
28
30
|
|
29
31
|
Returns:
|
30
32
|
dict: The response from the engine, containing the result or an error message.
|
31
33
|
"""
|
32
34
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "Select",
|
33
|
-
"params":
|
35
|
+
"params": {"qMatch": value, "qSoftLock": soft_lock,
|
36
|
+
"qExcludedValuesMode": excluded_values_mode}})
|
34
37
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
35
38
|
try:
|
36
39
|
return response
|
37
40
|
except KeyError:
|
38
41
|
return response["error"]
|
39
42
|
|
40
|
-
def select_values(self, fld_handle, values=
|
43
|
+
def select_values(self, fld_handle, values, toggle_mode = False, soft_lock = False):
|
41
44
|
"""
|
42
45
|
Selects multiple values in a field.
|
43
46
|
|
44
47
|
Args:
|
45
48
|
fld_handle (int): The handle of the field.
|
46
|
-
values (list
|
49
|
+
values (list): A list of field values to select. Mandatory field.
|
50
|
+
toggle_mode (bool): The default value is false.
|
51
|
+
soft_lock (bool): Set to true to ignore locks; in that case, locked fields can be selected.
|
52
|
+
The default value is false.
|
47
53
|
|
48
54
|
Returns:
|
49
55
|
dict: The response from the engine, containing the result or an error message.
|
50
56
|
"""
|
51
|
-
if values is None:
|
52
|
-
values = []
|
53
57
|
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "SelectValues",
|
54
|
-
"params":
|
58
|
+
"params": {"qFieldValues": values, "qToggleMode": toggle_mode, "qSoftLock": soft_lock}})
|
55
59
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
56
60
|
try:
|
57
|
-
return response
|
61
|
+
return response["result"]["qReturn"]
|
58
62
|
except KeyError:
|
59
63
|
return response["error"]
|
60
64
|
|
61
|
-
def select_excluded(self, fld_handle):
|
65
|
+
def select_excluded(self, fld_handle, soft_lock=False):
|
62
66
|
"""
|
63
|
-
|
67
|
+
Inverts the current selections.
|
64
68
|
|
65
69
|
Args:
|
66
70
|
fld_handle (int): The handle of the field.
|
71
|
+
soft_lock (bool): Set to true to ignore locks; in that case, locked fields can be selected.
|
72
|
+
The default value is false.
|
67
73
|
|
68
74
|
Returns:
|
69
|
-
|
75
|
+
bool: true/false. The operation is successful if qReturn is set to true.
|
70
76
|
"""
|
71
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "SelectExcluded",
|
77
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "SelectExcluded",
|
78
|
+
"params": {"qSoftLock": soft_lock}})
|
72
79
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
73
80
|
try:
|
74
|
-
return response["result"]
|
81
|
+
return response["result"]["qReturn"]
|
75
82
|
except KeyError:
|
76
83
|
return response["error"]
|
77
84
|
|
78
|
-
def select_possible(self, fld_handle):
|
85
|
+
def select_possible(self, fld_handle, soft_lock=False):
|
79
86
|
"""
|
80
87
|
Selects all possible values in a field.
|
81
88
|
|
82
89
|
Args:
|
83
90
|
fld_handle (int): The handle of the field.
|
91
|
+
soft_lock (bool): Set to true to ignore locks; in that case, locked fields can be selected.
|
92
|
+
The default value is false.
|
84
93
|
|
85
94
|
Returns:
|
86
|
-
|
95
|
+
bool: true/false. The operation is successful if qReturn is set to true.
|
87
96
|
"""
|
88
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "SelectPossible",
|
97
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "SelectPossible",
|
98
|
+
"params": {"qSoftLock": soft_lock}})
|
89
99
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
90
100
|
try:
|
91
|
-
return response["result"]
|
101
|
+
return response["result"]["qReturn"]
|
92
102
|
except KeyError:
|
93
103
|
return response["error"]
|
94
104
|
|
@@ -102,7 +112,7 @@ class EngineFieldApi:
|
|
102
112
|
Returns:
|
103
113
|
dict: The response from the engine, containing the result or an error message.
|
104
114
|
"""
|
105
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "Clear", "params":
|
115
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "Clear", "params": {}})
|
106
116
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
107
117
|
try:
|
108
118
|
return response["result"]
|
@@ -119,9 +129,9 @@ class EngineFieldApi:
|
|
119
129
|
Returns:
|
120
130
|
int: The number of distinct values in the field, or an error message.
|
121
131
|
"""
|
122
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "GetCardinal", "params":
|
132
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle, "method": "GetCardinal", "params": {}})
|
123
133
|
response = json.loads(self.engine_socket.send_call(self.engine_socket, msg))
|
124
134
|
try:
|
125
|
-
return response["result"]
|
135
|
+
return response["result"]["qReturn"]
|
126
136
|
except KeyError:
|
127
137
|
return response["error"]
|
@@ -85,7 +85,8 @@ class EngineGlobalApi:
|
|
85
85
|
Returns:
|
86
86
|
dict: Information about the deletion result.
|
87
87
|
"""
|
88
|
-
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1, "method": "DeleteApp",
|
88
|
+
msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1, "method": "DeleteApp",
|
89
|
+
"params": {"qAppId": app_name}})
|
89
90
|
response = json.loads(
|
90
91
|
self.engine_socket.send_call(self.engine_socket, msg))
|
91
92
|
try:
|
@@ -12,6 +12,12 @@ import pandas as pd
|
|
12
12
|
|
13
13
|
|
14
14
|
class QixEngine:
|
15
|
+
"""
|
16
|
+
The class of the client to interact with the Qlik Sense Engine API.
|
17
|
+
|
18
|
+
Methods:
|
19
|
+
select_in_dimension(app_handle, dimension_name, list_of_values): Selects values in a given field.
|
20
|
+
"""
|
15
21
|
|
16
22
|
def __init__(self, url, user_directory=None, user_id=None, ca_certs=None, certfile=None, keyfile=None, app_id=None):
|
17
23
|
self.url = url
|
@@ -33,68 +39,112 @@ class QixEngine:
|
|
33
39
|
self.structs = structs
|
34
40
|
self.app_handle = ''
|
35
41
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
return app['qAppId']
|
40
|
-
except KeyError:
|
41
|
-
return app['message']
|
42
|
-
|
43
|
-
def load_script(self, script):
|
44
|
-
self.eaa.set_script(self.app_handle, script)
|
45
|
-
return self.eaa.do_reload_ex(self.app_handle)['qResult']['qSuccess']
|
46
|
-
|
47
|
-
def open_app(self, app_obj):
|
48
|
-
opened_app = self.ega.open_doc(app_obj)
|
49
|
-
self.app_handle = self.ega.get_handle(opened_app)
|
50
|
-
return opened_app['qGenericId']
|
51
|
-
|
52
|
-
def select_in_dimension(self, dimension_name, list_of_values):
|
53
|
-
lb_field = self.eaa.get_field(self.app_handle, dimension_name)
|
54
|
-
fld_handle = self.ega.get_handle(lb_field)
|
42
|
+
def select_in_dimension(self, app_handle, dimension_name, list_of_values):
|
43
|
+
lb_field = self.eaa.get_field(app_handle, dimension_name)
|
44
|
+
fld_handle = self.get_handle(lb_field)
|
55
45
|
values_to_select = []
|
56
46
|
for val in list_of_values:
|
57
|
-
|
58
|
-
values_to_select.append(
|
47
|
+
fld_value = self.structs.field_value(val)
|
48
|
+
values_to_select.append(fld_value)
|
59
49
|
return self.efa.select_values(fld_handle, values_to_select)
|
60
50
|
|
61
|
-
def select_excluded_in_dimension(self, dimension_name):
|
62
|
-
lb_field = self.eaa.get_field(
|
63
|
-
fld_handle = self.
|
51
|
+
def select_excluded_in_dimension(self, app_handle, dimension_name):
|
52
|
+
lb_field = self.eaa.get_field(app_handle, dimension_name)
|
53
|
+
fld_handle = self.get_handle(lb_field)
|
64
54
|
return self.efa.select_excluded(fld_handle)
|
65
55
|
|
66
|
-
def select_possible_in_dimension(self, dimension_name):
|
67
|
-
lb_field = self.eaa.get_field(
|
68
|
-
fld_handle = self.
|
56
|
+
def select_possible_in_dimension(self, app_handle, dimension_name):
|
57
|
+
lb_field = self.eaa.get_field(app_handle, dimension_name)
|
58
|
+
fld_handle = self.get_handle(lb_field)
|
69
59
|
return self.efa.select_possible(fld_handle)
|
70
60
|
|
71
61
|
# return a list of tuples where first value in tuple is the actual
|
72
62
|
# data value and the second tuple value is that
|
73
63
|
# values selection state
|
74
|
-
def get_list_object_data(self, dimension_name):
|
75
|
-
lb_field = self.eaa.get_field(
|
76
|
-
fld_handle = self.
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
64
|
+
def get_list_object_data(self, app_handle, dimension_name):
|
65
|
+
lb_field = self.eaa.get_field(app_handle, dimension_name)
|
66
|
+
fld_handle = self.get_handle(lb_field)
|
67
|
+
|
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))
|
70
|
+
lb_def = self.structs.list_object_def("$", "", nx_inline_dimension_def,
|
71
|
+
[nx_page])
|
72
|
+
|
73
|
+
# Create info structure
|
74
|
+
nx_info = self.structs.nx_info("ListObject", "SLB01")
|
75
|
+
|
76
|
+
# Create generic object properties structure
|
77
|
+
gen_obj_props = self.structs.generic_object_properties(nx_info, "qListObjectDef", lb_def)
|
78
|
+
listobj = self.eaa.create_session_object(app_handle, gen_obj_props) # NOQA
|
79
|
+
listobj_handle = self.get_handle(listobj)
|
82
80
|
val_list = self.egoa.get_layout(listobj_handle)["qListObject"]["qDataPages"][0]["qMatrix"] # NOQA
|
83
81
|
val_n_state_list = []
|
84
82
|
for val in val_list:
|
85
83
|
val_n_state_list.append((val[0]["qText"], val[0]["qState"]))
|
84
|
+
|
86
85
|
return val_n_state_list
|
87
86
|
|
88
|
-
def clear_selection_in_dimension(self, dimension_name):
|
89
|
-
lb_field = self.eaa.get_field(
|
90
|
-
fld_handle = self.
|
91
|
-
return self.efa.clear(fld_handle)
|
87
|
+
def clear_selection_in_dimension(self, app_handle, dimension_name):
|
88
|
+
lb_field = self.eaa.get_field(app_handle, dimension_name)
|
89
|
+
fld_handle = self.get_handle(lb_field)
|
90
|
+
return self.efa.clear(fld_handle)
|
91
|
+
|
92
|
+
def create_single_master_dimension(self, app_handle, dim_title, dim_def, dim_label):
|
93
|
+
"""
|
94
|
+
Creates a single master dimension.
|
95
|
+
|
96
|
+
Parameters:
|
97
|
+
app_handle (int): The handle of the app.
|
98
|
+
dim_title (str): The title of the dimension.
|
99
|
+
dim_def (str): The definition of the dimension.
|
100
|
+
dim_label (str): The label of the dimension.
|
101
|
+
|
102
|
+
Returns:
|
103
|
+
dict: The handle and Id of the dimension.
|
104
|
+
"""
|
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)
|
108
|
+
master_dim = self.eaa.create_dimension(app_handle, gen_dim_props)
|
109
|
+
return master_dim
|
92
110
|
|
93
|
-
def
|
94
|
-
|
111
|
+
def create_master_measure(self, app_handle, mes_title, mes_def, mes_label):
|
112
|
+
"""
|
113
|
+
Creates a master measure.
|
114
|
+
|
115
|
+
Parameters:
|
116
|
+
app_handle (int): The handle of the app.
|
117
|
+
mes_title (str): The title of the measure.
|
118
|
+
mes_def (str): The definition of the measure.
|
119
|
+
mes_label (str): The label of the measure.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
dict: The handle and Id of the measure.
|
123
|
+
"""
|
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)
|
127
|
+
master_mes = self.eaa.create_measure(app_handle, gen_mes_props)
|
128
|
+
return master_mes
|
129
|
+
|
130
|
+
def get_app_lineage_info(self, app_handle):
|
131
|
+
"""
|
132
|
+
Gets the lineage information of the app. The lineage information includes the LOAD and STORE statements from
|
133
|
+
the data load script associated with this app.
|
134
|
+
|
135
|
+
Parameters:
|
136
|
+
app_handle (int): The handle of the app.
|
137
|
+
|
138
|
+
Returns:
|
139
|
+
DataFrame: Information about the lineage of the data in the app.
|
140
|
+
"""
|
141
|
+
# Lineage-Daten aus der API holen
|
142
|
+
lineage_info = self.eaa.get_lineage(app_handle)
|
95
143
|
|
96
|
-
|
97
|
-
|
144
|
+
# Erstelle den DataFrame und fülle fehlende Werte mit ""
|
145
|
+
df_lineage_info = pd.DataFrame(lineage_info)
|
146
|
+
df_lineage_info = df_lineage_info[(df_lineage_info["qDiscriminator"].notna()) | (df_lineage_info["qStatement"].notna())].fillna("")
|
147
|
+
return df_lineage_info
|
98
148
|
|
99
149
|
def disconnect(self):
|
100
150
|
self.conn.close_qvengine_connection(self.conn)
|
@@ -1,15 +1,5 @@
|
|
1
|
-
def list_object_def(state_name="$", library_id="", field_defs=
|
2
|
-
|
3
|
-
if initial_data_fetch is None:
|
4
|
-
initial_data_fetch = []
|
5
|
-
if sort_criterias is None:
|
6
|
-
sort_criterias = []
|
7
|
-
if field_labels is None:
|
8
|
-
field_labels = []
|
9
|
-
if field_defs is None:
|
10
|
-
field_defs = []
|
11
|
-
return {"qStateName": state_name, "qLibraryId": library_id,
|
12
|
-
"qDef": {"qFieldDefs": field_defs, "qFieldLabels": field_labels, "qSortCriterias": sort_criterias},
|
1
|
+
def list_object_def(state_name="$", library_id="", field_defs=[], initial_data_fetch=[]):
|
2
|
+
return {"qStateName": state_name, "qLibraryId": library_id, "qDef": field_defs,
|
13
3
|
"qInitialDataFetch": initial_data_fetch}
|
14
4
|
|
15
5
|
def hypercube_def(state_name="$", nx_dims=[], nx_meas=[], nx_page=[], inter_column_sort=[0, 1, 2], suppress_zero=False,
|
@@ -56,3 +46,28 @@ def generic_object_properties(info, prop_name, prop_def, extends_id="", state_na
|
|
56
46
|
def sort_criteria(state=0, freq=0, numeric=0, ascii=0, load_order=1):
|
57
47
|
return {"qSortByState": state, "qSortByFrequency": freq, "qSortByNumeric": numeric, "qSortByAscii": ascii,
|
58
48
|
"qSortByLoadOrder": load_order, "qSortByExpression": 0, "qExpression": {"qv": ""}}
|
49
|
+
|
50
|
+
def field_value(text, is_numeric = False, number = 0):
|
51
|
+
return {"qText": text, "qIsNumeric": is_numeric, "qNumber": number}
|
52
|
+
|
53
|
+
def generic_dimension_properties(info, lb_dim_def, dim_title):
|
54
|
+
return {"qInfo": info, "qDim": lb_dim_def, "qMetaDef": {"title": dim_title}}
|
55
|
+
|
56
|
+
def nx_library_dimension_def(grouping="N", field_definitions=[], field_labels=[""], label_expression=""):
|
57
|
+
return {"qGrouping": grouping, "qFieldDefs": field_definitions, "qFieldLabels": field_labels,
|
58
|
+
"qLabelExpression": label_expression}
|
59
|
+
|
60
|
+
def nx_library_measure_def(label, mes_def, grouping="N", expressions=[], active_expression=0, label_expression="",
|
61
|
+
num_format={}):
|
62
|
+
return {"qLabel": label, "qDef": mes_def,"qGrouping": grouping, "qExpressions": expressions,
|
63
|
+
"qActiveExpression": active_expression, "qLabelExpression": label_expression, "qNumFormat": num_format}
|
64
|
+
|
65
|
+
def num_format(type="U", n_dec=10, use_thou=0, fmt="", dec="", thou=""):
|
66
|
+
return {"qType": type, "qnDec": n_dec, "qUseThou": use_thou, "qFmt": fmt, "qDec": dec, "qThou": thou}
|
67
|
+
|
68
|
+
def generic_measure_properties(info, lb_meas_def, meas_title):
|
69
|
+
return {"qInfo": info, "qMeasure": lb_meas_def, "qMetaDef": {"title": meas_title}}
|
70
|
+
|
71
|
+
def do_reload_ex_params(mode=0, partial=False, debug=False, reload_id="", skip_store=False, row_limit=0):
|
72
|
+
return {"qMode": mode, "qPartial": partial, "qDebug": debug, "qReloadId": reload_id, "qSkipStore": skip_store,
|
73
|
+
"qRowLimit": row_limit}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qe-api-client
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.3.0
|
4
4
|
Summary: Python wrapper around Qlik Engine JSON API
|
5
5
|
Home-page: https://github.com/lr-bicc/qe-api-client
|
6
6
|
Author: Rumen Vasilev
|
@@ -28,7 +28,7 @@ Forked from [jhettler/pyqlikengine](https://github.com/jhettler/pyqlikengine)
|
|
28
28
|
pip install qe-api-client
|
29
29
|
```
|
30
30
|
|
31
|
-
##
|
31
|
+
## Connecting to Qlik Sense Enterprise Server
|
32
32
|
You need to export the Qlik Sense certificates in PEM format from the Qlik Sense Enterprise server to a local folder in
|
33
33
|
order to authenticate on the server.
|
34
34
|
|
@@ -48,7 +48,7 @@ qixe = QixEngine(url=url, user_directory=user_directory, user_id=user_id, ca_cer
|
|
48
48
|
print(qixe.ega.get_doc_list())
|
49
49
|
```
|
50
50
|
|
51
|
-
##
|
51
|
+
## Connecting to Qlik Sense Desktop
|
52
52
|
You need to start your Qlik Sense Desktop client on your local PC.
|
53
53
|
|
54
54
|
```python
|
@@ -61,5 +61,8 @@ qixe = QixEngine(url=url)
|
|
61
61
|
print(qixe.ega.get_doc_list())
|
62
62
|
```
|
63
63
|
|
64
|
+
## Examples of usage
|
65
|
+
Please click on this [link](https://github.com/lr-bicc/qe-api-client/tree/master/examples) to find examples of usage of this client.
|
66
|
+
|
64
67
|
## API reference
|
65
68
|
Please click on this [link](https://lr-bicc.github.io/qe-api-client) for full API reference documentation .
|
@@ -70,7 +70,7 @@ class TestAppApi(unittest.TestCase):
|
|
70
70
|
first_element_number = hc_data["qDataPages"][0]["qMatrix"][0][0]["qElemNumber"] # NOQA
|
71
71
|
first_element_text = hc_data["qDataPages"][0]["qMatrix"][0][0]["qText"] # NOQA
|
72
72
|
self.assertTrue(first_element_number == 0,"Incorrect value in first element number")
|
73
|
-
self.assertTrue(first_element_text ==
|
73
|
+
self.assertTrue(first_element_text == "A","Incorrect value in first element text")
|
74
74
|
|
75
75
|
def tearDown(self):
|
76
76
|
self.qixe.ega.delete_app(self.app)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import unittest
|
2
|
+
from qe_api_client.engine import QixEngine
|
3
|
+
|
4
|
+
|
5
|
+
class TestFieldApi(unittest.TestCase):
|
6
|
+
|
7
|
+
def setUp(self):
|
8
|
+
url = 'ws://localhost:4848/app'
|
9
|
+
self.qixe = QixEngine(url)
|
10
|
+
self.app = self.qixe.ega.create_app("test_app")["qAppId"]
|
11
|
+
opened_app = self.qixe.ega.open_doc(self.app)
|
12
|
+
with open('./test_data/ctrl00_script.qvs') as f:
|
13
|
+
script = f.read()
|
14
|
+
self.app_handle = self.qixe.get_handle(opened_app)
|
15
|
+
self.qixe.eaa.set_script(self.app_handle, script)
|
16
|
+
self.qixe.eaa.do_reload_ex(self.app_handle)
|
17
|
+
|
18
|
+
nx_inline_dimension_def = self.qixe.structs.nx_inline_dimension_def(["Alpha"])
|
19
|
+
nx_page_initial = self.qixe.structs.nx_page(0, 0, 1, 26)
|
20
|
+
lb_def = self.qixe.structs.list_object_def("$", "", nx_inline_dimension_def,[nx_page_initial])
|
21
|
+
|
22
|
+
# Create info structure
|
23
|
+
nx_info = self.qixe.structs.nx_info("ListObject", "SLB01")
|
24
|
+
|
25
|
+
# Create generic object properties structure
|
26
|
+
gen_obj_props = self.qixe.structs.generic_object_properties(nx_info, "qListObjectDef", lb_def)
|
27
|
+
listobj = self.qixe.eaa.create_session_object(self.app_handle, gen_obj_props) # NOQA
|
28
|
+
|
29
|
+
self.lb_handle = self.qixe.get_handle(listobj)
|
30
|
+
self.qixe.egoa.get_layout(self.lb_handle)
|
31
|
+
self.lb_field = self.qixe.eaa.get_field(self.app_handle, "Alpha")
|
32
|
+
self.fld_handle = self.qixe.get_handle(self.lb_field)
|
33
|
+
|
34
|
+
def test_select_values(self):
|
35
|
+
values_to_select = [{'qText': 'A'}, {'qText': 'B'}, {'qText': 'C'}]
|
36
|
+
sel_res = self.qixe.efa.select_values(self.fld_handle, values_to_select)
|
37
|
+
self.assertTrue(sel_res is True,"Failed to perform selection")
|
38
|
+
val_mtrx = self.qixe.egoa.get_layout(self.lb_handle)["qListObject"]["qDataPages"][0]["qMatrix"] # NOQA
|
39
|
+
self.assertEqual(val_mtrx[0][0]["qState"],"S","Failed to select first value")
|
40
|
+
self.assertEqual(val_mtrx[4][0]["qState"],"X","Failed to exclude fifth value")
|
41
|
+
self.qixe.eaa.clear_all(self.app_handle)
|
42
|
+
val_mtrx = self.qixe.egoa.get_layout(self.lb_handle)["qListObject"]["qDataPages"][0]["qMatrix"] # NOQA
|
43
|
+
self.assertEqual(val_mtrx[0][0]["qState"],"O","Failed to clear selection")
|
44
|
+
self.assertEqual(val_mtrx[4][0]["qState"],"O","Failed to clear selection")
|
45
|
+
|
46
|
+
def tearDown(self):
|
47
|
+
self.qixe.ega.delete_app(self.app)
|
48
|
+
self.qixe.conn.close_qvengine_connection(self.qixe.conn)
|
49
|
+
|
50
|
+
|
51
|
+
if __name__ == '__main__':
|
52
|
+
unittest.main()
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import unittest
|
2
|
+
from qe_api_client.engine import QixEngine
|
3
|
+
|
4
|
+
|
5
|
+
class TestQixEngine(unittest.TestCase):
|
6
|
+
|
7
|
+
def setUp(self):
|
8
|
+
self.qixe = QixEngine('ws://localhost:4848/app')
|
9
|
+
self.app = self.qixe.ega.create_app("test_app")["qAppId"]
|
10
|
+
opened_app = self.qixe.ega.open_doc(self.app)
|
11
|
+
with open('./test_data/ctrl00_script.qvs') as f:
|
12
|
+
script = f.read()
|
13
|
+
self.app_handle = self.qixe.get_handle(opened_app)
|
14
|
+
self.qixe.eaa.set_script(self.app_handle, script)
|
15
|
+
self.assertTrue(self.qixe.eaa.do_reload_ex(self.app_handle)['qResult']['qSuccess'],'Failed to load script')
|
16
|
+
|
17
|
+
def test_select_clear_in_dimension(self):
|
18
|
+
select_result = self.qixe.select_in_dimension(self.app_handle, 'Alpha',['A', 'C', 'E'])
|
19
|
+
self.assertTrue(select_result, "Failed to select values")
|
20
|
+
self.assertTrue(self.qixe.clear_selection_in_dimension(self.app_handle, 'Alpha'),
|
21
|
+
'Failed to clear selection')
|
22
|
+
|
23
|
+
def test_select_clear_all_in_dimension(self):
|
24
|
+
select_result = self.qixe.select_in_dimension(self.app_handle, 'Alpha', ['A', 'C', 'E'])
|
25
|
+
self.assertTrue(select_result, "Failed to select values")
|
26
|
+
self.qixe.eaa.clear_all(self.app_handle)
|
27
|
+
|
28
|
+
def test_select_excluded(self):
|
29
|
+
self.qixe.select_in_dimension(self.app_handle, 'Alpha',['A', 'C', 'E'])
|
30
|
+
select_result = self.qixe.select_excluded_in_dimension(self.app_handle, 'Alpha')
|
31
|
+
self.assertTrue(select_result,'Failed to select excluded')
|
32
|
+
|
33
|
+
def test_select_possible(self):
|
34
|
+
select_result = self.qixe.select_possible_in_dimension(self.app_handle, 'Alpha')
|
35
|
+
self.assertTrue(select_result,'Failed to select possible')
|
36
|
+
|
37
|
+
def test_get_list_object_data(self):
|
38
|
+
self.assertTrue(len(self.qixe.get_list_object_data(self.app_handle, 'Alpha')) == 2,
|
39
|
+
'Failed to get value list')
|
40
|
+
|
41
|
+
def test_get_constructed_table_data(self):
|
42
|
+
dim_1 = self.qixe.create_single_master_dimension(self.app_handle, "Dim 1", "Dim1", "'Dimension 1'")
|
43
|
+
dim_2 = self.qixe.create_single_master_dimension(self.app_handle, "Dim 2", "Dim2", "'Dimension 2'")
|
44
|
+
dim_1_id = dim_1["qGenericId"]
|
45
|
+
dim_2_id = dim_2["qGenericId"]
|
46
|
+
|
47
|
+
list_of_dimensions = ["Dim3"]
|
48
|
+
list_of_master_dimensions = [dim_1_id, dim_2_id]
|
49
|
+
list_of_measures = ["Sum(Expression3)"]
|
50
|
+
list_of_master_measures = []
|
51
|
+
# list_of_master_measures = ["snmpR", "1ad7060c-56ec-46d1-b83a-ff1393e0b236"]
|
52
|
+
|
53
|
+
df = self.qixe.get_constructed_table_data(self.app_handle, list_of_dimensions, list_of_measures,
|
54
|
+
list_of_master_dimensions, list_of_master_measures)
|
55
|
+
print(df)
|
56
|
+
|
57
|
+
def tearDown(self):
|
58
|
+
self.assertTrue(self.qixe.ega.delete_app(self.app),'Failed to delete app')
|
59
|
+
self.qixe.conn.close_qvengine_connection(self.qixe.conn)
|
60
|
+
|
61
|
+
if __name__ == '__main__':
|
62
|
+
unittest.main()
|
@@ -1,67 +0,0 @@
|
|
1
|
-
import math
|
2
|
-
|
3
|
-
from qe_api_client.api_classes.engine_app_api import EngineAppApi
|
4
|
-
from qe_api_client.api_classes.engine_field_api import EngineFieldApi
|
5
|
-
from qe_api_client.api_classes.engine_generic_object_api import EngineGenericObjectApi
|
6
|
-
from qe_api_client.api_classes.engine_global_api import EngineGlobalApi
|
7
|
-
import qe_api_client.structs as structs
|
8
|
-
|
9
|
-
import pandas as pd
|
10
|
-
|
11
|
-
|
12
|
-
def getDataFrame(connection, appHandle, measures, dimensions, selections={}):
|
13
|
-
engineGlobalApi = EngineGlobalApi(connection)
|
14
|
-
# Define Dimensions of hypercube
|
15
|
-
hc_inline_dim = structs.nx_inline_dimension_def(dimensions)
|
16
|
-
|
17
|
-
# Set sorting of Dimension by Measure
|
18
|
-
hc_mes_sort = structs.sort_criteria()
|
19
|
-
|
20
|
-
# Define Measure of hypercube
|
21
|
-
hc_inline_mes = structs.nx_inline_measure_def(measures)
|
22
|
-
|
23
|
-
# Build hypercube from above definition
|
24
|
-
hc_dim = structs.nx_dimension(hc_inline_dim)
|
25
|
-
hc_mes = structs.nx_measure("", hc_inline_mes, hc_mes_sort)
|
26
|
-
|
27
|
-
width = len(measures) + len(dimensions)
|
28
|
-
height = int(math.floor(10000 / width))
|
29
|
-
nx_page = structs.nx_page(0, 0, width, height)
|
30
|
-
hc_def = structs.hypercube_def("$", [hc_dim], [hc_mes], [nx_page])
|
31
|
-
|
32
|
-
engineAppApi = EngineAppApi(connection)
|
33
|
-
hc_response = engineAppApi.create_object(appHandle, "CH01", "Chart", "qHyperCubeDef", hc_def) # NOQA
|
34
|
-
hc_handle = engineGlobalApi.get_handle(hc_response['qReturn'])
|
35
|
-
|
36
|
-
engineGenericObjectApi = EngineGenericObjectApi(connection)
|
37
|
-
|
38
|
-
engineFieldApi = EngineFieldApi(connection)
|
39
|
-
|
40
|
-
for field in selections.keys():
|
41
|
-
fieldHandle = engineGlobalApi.get_handle(engineAppApi.get_field(appHandle, field)) # NOQA
|
42
|
-
values = []
|
43
|
-
for selectedValue in selections[field]:
|
44
|
-
values.append({'qText': selectedValue})
|
45
|
-
|
46
|
-
engineFieldApi.select_values(fieldHandle, values)
|
47
|
-
|
48
|
-
i = 0
|
49
|
-
while i % height == 0:
|
50
|
-
nx_page = structs.nx_page(0, i, width, height)
|
51
|
-
hc_data = engineGenericObjectApi.get_hypercube_data(hc_handle, "/qHyperCubeDef", nx_page) # NOQA
|
52
|
-
elems = hc_data["qDataPages"][0]['qMatrix']
|
53
|
-
|
54
|
-
df = pd.DataFrame()
|
55
|
-
|
56
|
-
for elem in elems:
|
57
|
-
j = 0
|
58
|
-
for dim in dimensions:
|
59
|
-
df.set_value(i, dim, elem[j]["qText"])
|
60
|
-
j += 1
|
61
|
-
for meas in measures:
|
62
|
-
df.set_value(i, meas, elem[j]["qNum"])
|
63
|
-
j += 1
|
64
|
-
|
65
|
-
i += 1
|
66
|
-
|
67
|
-
return df
|
@@ -1,71 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
|
3
|
-
from qe_api_client.api_classes.engine_app_api import EngineAppApi
|
4
|
-
from qe_api_client.engine_communicator import EngineCommunicator
|
5
|
-
from qe_api_client.api_classes.engine_field_api import EngineFieldApi
|
6
|
-
from qe_api_client.api_classes.engine_global_api import EngineGlobalApi
|
7
|
-
import qe_api_client.structs as structs
|
8
|
-
|
9
|
-
from qe_api_client.api_classes.engine_generic_object_api import EngineGenericObjectApi
|
10
|
-
|
11
|
-
|
12
|
-
class TestFieldApi(unittest.TestCase):
|
13
|
-
|
14
|
-
def setUp(self):
|
15
|
-
url = 'ws://localhost:4848/app'
|
16
|
-
self.conn = EngineCommunicator(url)
|
17
|
-
self.ega = EngineGlobalApi(self.conn)
|
18
|
-
self.eaa = EngineAppApi(self.conn)
|
19
|
-
self.egoa = EngineGenericObjectApi(self.conn)
|
20
|
-
self.efa = EngineFieldApi(self.conn)
|
21
|
-
self.struct = structs
|
22
|
-
self.app = self.ega.create_app("TestApp")["qAppId"]
|
23
|
-
opened_app = self.ega.open_doc(self.app)
|
24
|
-
self.app_handle = self.ega.get_handle(opened_app)
|
25
|
-
with open('../test/test_data/ctrl00_script.qvs') as f:
|
26
|
-
script = f.read()
|
27
|
-
self.eaa.set_script(self.app_handle, script)
|
28
|
-
self.eaa.do_reload_ex(self.app_handle)
|
29
|
-
nx_page_initial = structs.nx_page(0, 0, 1, 26)
|
30
|
-
self.lb_def = structs.list_object_def("$", "",
|
31
|
-
["Alpha"],
|
32
|
-
None,
|
33
|
-
None,
|
34
|
-
[nx_page_initial])
|
35
|
-
self.lb_param = {"qInfo": {"qId": "SLB01", "qType": "ListObject"},
|
36
|
-
"qListObjectDef": self.lb_def}
|
37
|
-
self.lb_sobject = self.eaa.create_session_object(self.app_handle,
|
38
|
-
self.lb_param)
|
39
|
-
self.lb_handle = self.ega.get_handle(self.lb_sobject)
|
40
|
-
self.egoa.get_layout(self.lb_handle)
|
41
|
-
self.lb_field = self.eaa.get_field(self.app_handle, "Alpha")
|
42
|
-
self.fld_handle = self.ega.get_handle(self.lb_field)
|
43
|
-
|
44
|
-
def test_select_values(self):
|
45
|
-
values_to_select = [{'qText': 'A'}, {'qText': 'B'}, {'qText': 'C'}]
|
46
|
-
sel_res = self.efa.select_values(self.fld_handle, values_to_select)
|
47
|
-
self.assertTrue(sel_res["qReturn"] is True,
|
48
|
-
"Failed to perform selection")
|
49
|
-
val_mtrx = self.egoa.get_layout(self.lb_handle)["qListObject"]["qDataPages"][0]["qMatrix"] # NOQA
|
50
|
-
self.assertEqual(val_mtrx[0][0]["qState"],
|
51
|
-
"S",
|
52
|
-
"Failed to select first value")
|
53
|
-
self.assertEqual(val_mtrx[4][0]["qState"],
|
54
|
-
"X",
|
55
|
-
"Failed to exclude fifth value")
|
56
|
-
self.eaa.clear_all(self.app_handle)
|
57
|
-
val_mtrx = self.egoa.get_layout(self.lb_handle)["qListObject"]["qDataPages"][0]["qMatrix"] # NOQA
|
58
|
-
self.assertEqual(val_mtrx[0][0]["qState"],
|
59
|
-
"O",
|
60
|
-
"Failed to clear selection")
|
61
|
-
self.assertEqual(val_mtrx[4][0]["qState"],
|
62
|
-
"O",
|
63
|
-
"Failed to clear selection")
|
64
|
-
|
65
|
-
def tearDown(self):
|
66
|
-
self.ega.delete_app(self.app)
|
67
|
-
self.conn.close_qvengine_connection(self.conn)
|
68
|
-
|
69
|
-
|
70
|
-
if __name__ == '__main__':
|
71
|
-
unittest.main()
|
@@ -1,74 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
from qe_api_client.engine import QixEngine
|
3
|
-
|
4
|
-
|
5
|
-
class TestQixEngine(unittest.TestCase):
|
6
|
-
|
7
|
-
def setUp(self):
|
8
|
-
self.qixe = QixEngine('ws://localhost:4848/app')
|
9
|
-
app = self.qixe.create_app('test_app')
|
10
|
-
self.assertTrue(app.endswith('.qvf'), 'Failed to create app')
|
11
|
-
app_exists = self.qixe.create_app('test_app')
|
12
|
-
self.assertTrue(app_exists == "App already exists",
|
13
|
-
'Failed to handle existing app exception')
|
14
|
-
self.opened_app = self.qixe.open_app(app)
|
15
|
-
with open('./test_data/ctrl00_script.qvs') as f:
|
16
|
-
script = f.read()
|
17
|
-
self.assertTrue(self.qixe.load_script(script), 'Failed to load script')
|
18
|
-
|
19
|
-
def test_create_hypercube(self):
|
20
|
-
hc = self.qixe.create_hypercube(1, ['Dim1', 'Dim2'],
|
21
|
-
['=Sum(Expression1)',
|
22
|
-
'=Sum(Expression2)',
|
23
|
-
'=Sum(Expression3)'])
|
24
|
-
hc_cols = self.qixe.convert_hypercube_to_matrix(hc[0], hc[1])
|
25
|
-
self.assertTrue(len(hc_cols) == 5,
|
26
|
-
'Failed to return proper number of columns')
|
27
|
-
self.inline_table = self.qixe.convert_hypercube_to_inline_table(hc[0], 'MyTable') # NOQA
|
28
|
-
self.assertTrue(self.inline_table.startswith('MyTable'),
|
29
|
-
'Failed to create inline statement from hypercube')
|
30
|
-
self.mtrx = self.qixe.convert_hypercube_to_matrix(hc[0], hc[1])
|
31
|
-
self.assertTrue(len(self.mtrx) == 5,
|
32
|
-
'Failed to create matrix from hypercube')
|
33
|
-
|
34
|
-
def test_select_clear_in_dimension(self):
|
35
|
-
select_result = self.qixe.select_in_dimension('Alpha',
|
36
|
-
['A', 'C', 'E'])
|
37
|
-
self.assertTrue(select_result["change"] == [1, 2],
|
38
|
-
"Failed to select values")
|
39
|
-
self.assertTrue(select_result["result"]['qReturn'],
|
40
|
-
"Failed to select values")
|
41
|
-
self.assertTrue(self.qixe.clear_selection_in_dimension('Alpha'),
|
42
|
-
'Failed to clear selection')
|
43
|
-
|
44
|
-
def test_select_clear_all_in_dimension(self):
|
45
|
-
select_result = self.qixe.select_in_dimension('Alpha', ['A', 'C', 'E'])
|
46
|
-
self.assertTrue(select_result["change"] == [1, 2],
|
47
|
-
"Failed to select values")
|
48
|
-
self.assertTrue(select_result["result"]['qReturn'],
|
49
|
-
"Failed to select values")
|
50
|
-
self.qixe.clear_all_selections()
|
51
|
-
|
52
|
-
def test_select_excluded(self):
|
53
|
-
self.qixe.select_in_dimension('Alpha',
|
54
|
-
['A', 'C', 'E'])
|
55
|
-
select_result = self.qixe.select_excluded_in_dimension('Alpha')
|
56
|
-
self.assertTrue(select_result['qReturn'],
|
57
|
-
'Failed to select excluded')
|
58
|
-
|
59
|
-
def test_select_possible(self):
|
60
|
-
select_result = self.qixe.select_possible_in_dimension('Alpha')
|
61
|
-
self.assertTrue(select_result['qReturn'],
|
62
|
-
'Failed to select possible')
|
63
|
-
|
64
|
-
def test_get_list_object_data(self):
|
65
|
-
self.assertTrue(len(self.qixe.get_list_object_data('Alpha')) == 26,
|
66
|
-
'Failed to get value list')
|
67
|
-
|
68
|
-
def tearDown(self):
|
69
|
-
self.assertTrue(self.qixe.delete_app(self.opened_app),
|
70
|
-
'Failed to delete app')
|
71
|
-
|
72
|
-
|
73
|
-
if __name__ == '__main__':
|
74
|
-
unittest.main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_measure_api.py
RENAMED
File without changes
|
{qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_object_api.py
RENAMED
File without changes
|
{qe_api_client-2.1.0 → qe_api_client-2.3.0}/qe_api_client/api_classes/engine_generic_variable_api.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|