qe-api-client 1.0.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.
@@ -0,0 +1,42 @@
1
+ from websocket import create_connection
2
+ import ssl
3
+
4
+
5
+ class EngineCommunicator:
6
+
7
+ def __init__(self, url):
8
+ self.url = url
9
+ self.ws = create_connection(self.url)
10
+ # Holds session object. Required for Qlik Sense Sept. 2017 and later
11
+ self.session = self.ws.recv()
12
+
13
+ @staticmethod
14
+ def send_call(self, call_msg):
15
+ self.ws.send(call_msg)
16
+ return self.ws.recv()
17
+
18
+ @staticmethod
19
+ def close_qvengine_connection(self):
20
+ self.ws.close()
21
+
22
+
23
+ class SecureEngineCommunicator(EngineCommunicator):
24
+
25
+ def __init__(self, url, user_directory,
26
+ user_id, ca_certs, certfile,
27
+ keyfile, app_id=None
28
+ ):
29
+ self.url = "wss://" + url + ":4747/app/" + str(app_id)
30
+ certs = ({"ca_certs": ca_certs,
31
+ "certfile": certfile,
32
+ "keyfile": keyfile,
33
+ "cert_reqs": ssl.CERT_NONE,
34
+ "server_side": False
35
+ })
36
+
37
+ ssl.match_hostname = lambda cert, hostname: True
38
+ header = f'X-Qlik-User: UserDirectory={user_directory}; UserId={user_id}' # NOQA
39
+ self.ws = create_connection(
40
+ self.url, sslopt=certs,
41
+ cookie=None, header={header})
42
+ self.session = self.ws.recv()
@@ -0,0 +1,81 @@
1
+ import json
2
+
3
+
4
+ class EngineFieldApi:
5
+
6
+ def __init__(self, socket):
7
+ self.engine_socket = socket
8
+
9
+ def select(self, fld_handle, value):
10
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle,
11
+ "method": "Select",
12
+ "params": [value, False, 0]})
13
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
14
+ msg)
15
+ )
16
+ try:
17
+ return response
18
+ except KeyError:
19
+ return response["error"]
20
+
21
+ def select_values(self, fld_handle, values=None):
22
+ if values is None:
23
+ values = []
24
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle,
25
+ "method": "SelectValues",
26
+ "params": [values, False, False]})
27
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
28
+ msg)
29
+ )
30
+ try:
31
+ return response
32
+ except KeyError:
33
+ return response["error"]
34
+
35
+ def select_excluded(self, fld_handle):
36
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle,
37
+ "method": "SelectExcluded",
38
+ "params": []})
39
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
40
+ msg)
41
+ )
42
+ try:
43
+ return response["result"]
44
+ except KeyError:
45
+ return response["error"]
46
+
47
+ def select_possible(self, fld_handle):
48
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle,
49
+ "method": "SelectPossible",
50
+ "params": []})
51
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
52
+ msg)
53
+ )
54
+ try:
55
+ return response["result"]
56
+ except KeyError:
57
+ return response["error"]
58
+
59
+ def clear(self, fld_handle):
60
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle,
61
+ "method": "SelectExcluded",
62
+ "params": []})
63
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
64
+ msg)
65
+ )
66
+ try:
67
+ return response["result"]
68
+ except KeyError:
69
+ return response["error"]
70
+
71
+ def get_cardinal(self, fld_handle):
72
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": fld_handle,
73
+ "method": "GetCardinal",
74
+ "params": []})
75
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
76
+ msg)
77
+ )
78
+ try:
79
+ return response["result"]
80
+ except KeyError:
81
+ return response["error"]
@@ -0,0 +1,101 @@
1
+ import json
2
+
3
+
4
+ class EngineGenericObjectApi:
5
+
6
+ def __init__(self, socket):
7
+ self.engine_socket = socket
8
+
9
+ def get_layout(self, handle):
10
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle,
11
+ "method": "GetLayout", "params": []})
12
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
13
+ msg)
14
+ )
15
+ try:
16
+ return response["result"]
17
+ except KeyError:
18
+ return response["error"]
19
+
20
+ def get_full_property_tree(self, handle):
21
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle,
22
+ "method": "GetFullPropertyTree", "params": []})
23
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
24
+ msg)
25
+ )
26
+ try:
27
+ return response["result"]
28
+ except KeyError:
29
+ return response["error"]
30
+
31
+ def get_measure(self, handle, params):
32
+ msg = json.dumps(
33
+ {"jsonrpc": "2.0", "id": 0, "handle": handle,
34
+ "method": "GetMeasure", "params": params})
35
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
36
+ msg)
37
+ )
38
+ try:
39
+ return response["result"]
40
+ except KeyError:
41
+ return response["error"]
42
+
43
+ def get_dimension(self, handle, params):
44
+ msg = json.dumps(
45
+ {"jsonrpc": "2.0", "id": 0, "handle": handle,
46
+ "method": "GetDimension", "params": params})
47
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
48
+ msg)
49
+ )
50
+ try:
51
+ return response["result"]
52
+ except KeyError:
53
+ return response["error"]
54
+
55
+ def get_effective_properties(self, handle):
56
+ msg = json.dumps(
57
+ {"jsonrpc": "2.0", "id": 0, "handle": handle,
58
+ "method": "GetEffectiveProperties", "params": {}})
59
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
60
+ msg)
61
+ )
62
+ try:
63
+ return response["result"]
64
+ except KeyError:
65
+ return response["error"]
66
+
67
+ def get_hypercube_data(self, handle, path="/qHyperCubeDef", pages=[]):
68
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle,
69
+ "method": "GetHyperCubeData",
70
+ "params": [path, pages]})
71
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
72
+ msg)
73
+ )
74
+ try:
75
+ return response["result"]
76
+ except KeyError:
77
+ return response["error"]
78
+
79
+ def get_hypercube_pivot_data(self, handle, path="/qHyperCubeDef", pages=[]):
80
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle,
81
+ "method": "GetHyperCubePivotData",
82
+ "params": [path, pages]})
83
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
84
+ msg)
85
+ )
86
+ try:
87
+ return response["result"]
88
+ except KeyError:
89
+ return response["error"]
90
+
91
+ def get_list_object_data(self, handle, path="/qListObjectDef", pages=[]):
92
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": handle,
93
+ "method": "GetListObjectData",
94
+ "params": [path, pages]})
95
+ response = json.loads(self.engine_socket.send_call(self.engine_socket,
96
+ msg)
97
+ )
98
+ try:
99
+ return response["result"]
100
+ except KeyError:
101
+ return response["error"]
@@ -0,0 +1,376 @@
1
+ import json
2
+
3
+
4
+ class EngineGlobalApi:
5
+ def __init__(self, socket):
6
+ self.engine_socket = socket
7
+
8
+ # returns an array of doc objects.
9
+ # The doc object contains doc name, size, file time etc
10
+ def get_doc_list(self):
11
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -
12
+ 1, "method": "GetDocList", "params": []})
13
+ response = json.loads(
14
+ self.engine_socket.send_call(self.engine_socket, msg))
15
+ try:
16
+ return response['result']['qDocList']
17
+ except KeyError:
18
+ return response['error']
19
+
20
+ # returns the os name (always windowsNT). Obsolete?
21
+ def get_os_name(self):
22
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0,
23
+ "handle": -1, "method": "OSName", "params": []})
24
+ response = json.loads(
25
+ self.engine_socket.send_call(self.engine_socket, msg))
26
+ try:
27
+ return response['result']['qReturn']
28
+ except KeyError:
29
+ return response['error']
30
+
31
+ # returns the app id. If desktop is used the app id is the same
32
+ # as the full path to qvf if it's running against Enterprise,
33
+ # app id will be a guid
34
+ def create_app(self, app_name):
35
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
36
+ "method": "CreateApp", "params": [app_name]})
37
+ response = json.loads(
38
+ self.engine_socket.send_call(self.engine_socket, msg))
39
+ try:
40
+ return response['result']
41
+ except KeyError:
42
+ return response["error"]
43
+
44
+ # DeleteApp Method Deletes an app from the Qlik Sense repository or from the file system. Qlik Sense Enterprise: # NOQA
45
+ # In addition to being removed from the repository, the app is removed from the directory as well: # NOQA
46
+ # <installation_directory>\Qlik\Sense\Apps The default installation directory is ProgramData. Qlik Sense Desktop: # NOQA
47
+ # The app is deleted from the directory %userprofile%\Documents\Qlik\Sense\Apps. Parameters: qAppId.. Identifier # NOQA
48
+ # of the app to delete. In Qlik Sense Enterprise, the identifier of the app is a GUID in the Qlik Sense # NOQA
49
+ # repository. In Qlik Sense Desktop, the identifier of the app is the name of the app, as defined in the apps # NOQA
50
+ # folder %userprofile%\Documents\Qlik\Sense\Apps. This parameter is mandatory. # NOQA
51
+
52
+ def delete_app(self, app_name):
53
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
54
+ "method": "DeleteApp", "params": [app_name]})
55
+ response = json.loads(
56
+ self.engine_socket.send_call(self.engine_socket, msg))
57
+ try:
58
+ return response['result']
59
+ except KeyError:
60
+ return response["error"]
61
+
62
+ # opens an app and returns an object with handle, generic id and type
63
+ def open_doc(self, app_name, user_name='',
64
+ password='', serial='', no_data=False
65
+ ):
66
+ msg = json.dumps(
67
+ {"jsonrpc": "2.0", "id": 0, "handle": -1,
68
+ "method": "OpenDoc", "params": [app_name, user_name,
69
+ password, serial,
70
+ no_data]})
71
+ response = json.loads(
72
+ self.engine_socket.send_call(self.engine_socket, msg))
73
+ try:
74
+ return response['result']
75
+ except KeyError:
76
+ return response["error"]
77
+
78
+ # returns an object with handle, generic id and type for the active app
79
+ def get_active_doc(self):
80
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
81
+ "method": "GetActiveDoc", "params": []})
82
+ response = json.loads(
83
+ self.engine_socket.send_call(self.engine_socket, msg))
84
+ try:
85
+ return response['result']
86
+ except KeyError:
87
+ return response["error"]
88
+
89
+ @staticmethod
90
+ def get_handle(obj):
91
+ try:
92
+ return obj["qHandle"]
93
+ except ValueError:
94
+ return "Bad handle value in " + obj
95
+
96
+ # Abort All commands
97
+ def abort_all(self):
98
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0,
99
+ "handle": -1, "method": "AbortAll", "params": []})
100
+ response = json.loads(
101
+ self.engine_socket.send_call(self.engine_socket, msg))
102
+ try:
103
+ return response['result']
104
+ except KeyError:
105
+ return response["error"]
106
+
107
+ # Abort Specific Request
108
+ def abort_request(self, request_id):
109
+ msg = json.dumps(
110
+ {"jsonrpc": "2.0", "id": 0, "handle": -1,
111
+ "method": "AbortRequest", "params": {"qRequestId": request_id}})
112
+ response = json.loads(
113
+ self.engine_socket.send_call(self.engine_socket, msg))
114
+ try:
115
+ return response['result'] # ['qReturn']
116
+ except KeyError:
117
+ return response["error"]
118
+
119
+ # Configure Reload - This is done before doing a reload qCancelOnScriptError: If set to true, the script # NOQA
120
+ # execution is halted on error. Otherwise, the engine continues the script execution. This parameter is relevant # NOQA
121
+ # only if the variable ErrorMode is set to 1. qUseErrorData: If set to true, any script execution error is # NOQA
122
+ # returned in qErrorData by the GetProgress method. qInteractOnError: If set to true, the script execution is # NOQA
123
+ # halted on error and the engine is waiting for an interaction to be performed. If the result from the # NOQA
124
+ # interaction is 1 (qDef.qResult is 1), the engine continues the script execution otherwise the execution is # NOQA
125
+ # halted. This parameter is relevant only if the variable ErrorMode is set to 1 and the script is run in debug # NOQA
126
+ # mode (qDebug is set to true when calling the DoReload method).
127
+ def configure_reload(self, cancel_on_error=False,
128
+ use_error_data=True, interact_on_error=False):
129
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
130
+ "method": "ConfigureReload",
131
+ "params": {"qCancelOnScriptError": cancel_on_error,
132
+ "qUseErrorData": use_error_data,
133
+ "qInteractOnError": interact_on_error}})
134
+ response = json.loads(
135
+ self.engine_socket.send_call(self.engine_socket, msg))
136
+ try:
137
+ return response['result']
138
+ except KeyError:
139
+ return response["error"]
140
+
141
+ # Copy app - This is done before doing a reload qTargetAppId (MANDATORY): Identifier (GUID) of the app # NOQA
142
+ # entity in the Qlik Sense repository. The app entity must have been previously created by the repository (via # NOQA
143
+ # the REST API). qSrcAppId (MANDATORY): Identifier (GUID) of the source app in the Qlik Sense repository. Array # NOQA
144
+ # of QRS identifiers. The list of all the objects in the app to be copied must be given. This list must contain # NOQA
145
+ # the GUIDs of all these objects. If the list of the QRS identifiers is empty, the CopyApp method copies all # NOQA
146
+ # objects to the target app. Script-defined variables are automatically copied when copying an app. To be able to # NOQA
147
+ # copy variables not created via script, the GUID of each variable must be provided in the list of QRS # NOQA
148
+ # identifiers. To get the QRS identifiers of the objects in an app, you can use the QRS API. The GET method (from # NOQA
149
+ # the QRS API) returns the identifiers of the objects in the app. The following example returns the QRS # NOQA
150
+ # identifiers of all the objects in a specified app: GET /qrs/app/9c3f8634-6191-4a34-a114-a39102058d13 Where # NOQA
151
+ # 9c3f8634-6191-4a34-a114-a39102058d13 is the identifier of the app.
152
+
153
+ # BUG - Does not work in September 2017 release
154
+ def copy_app(self, target_app_id, src_app_id, qIds=[""]):
155
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
156
+ "method": "CopyApp",
157
+ "params": {"qTargetAppId": target_app_id,
158
+ "qSrcAppId": src_app_id,
159
+ "qIds": qIds}})
160
+ response = json.loads(
161
+ self.engine_socket.send_call(self.engine_socket, msg))
162
+ try:
163
+ return response['result']
164
+ except KeyError:
165
+ return response["error"]
166
+
167
+ # Creates an empty session app. The following applies: The name of a session app cannot be chosen. The engine # NOQA
168
+ # automatically assigns a unique identifier to the session app. A session app is not persisted and cannot be # NOQA
169
+ # saved. Everything created during a session app is non-persisted; for example: objects, data connections. # NOQA
170
+ def create_session_app(self):
171
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
172
+ "method": "CreateSessionApp", "params": {}})
173
+ response = json.loads(
174
+ self.engine_socket.send_call(self.engine_socket, msg))
175
+ try:
176
+ return response['result']
177
+ except KeyError:
178
+ return response["error"]
179
+
180
+ # Return the session App Id to use for subsequent calls
181
+ # The identifier of the session app is composed of the prefix SessionApp_ and of a GUID. # NOQA
182
+ # ['qReturn']
183
+
184
+ # Create an empty session app from an Existing App The objects in the source app are copied into the session app # NOQA
185
+ # but contain no data. The script of the session app can be edited and reloaded. The name of a session app cannot # NOQA
186
+ # be chosen. The engine automatically assigns a unique identifier to the session app. A session app is not # NOQA
187
+ # persisted and cannot be saved. Everything created during a session app is non-persisted; for example: objects, # NOQA
188
+ # data connections.
189
+ def create_session_app_from_app(self, src_app_id):
190
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
191
+ "method": "CreateSessionAppFromApp",
192
+ "params": {"qSrcAppId": src_app_id}})
193
+ response = json.loads(
194
+ self.engine_socket.send_call(self.engine_socket, msg))
195
+ try:
196
+ return response['result']
197
+ except KeyError:
198
+ return response["error"]
199
+
200
+ # ExportApp method: Exports an app from the Qlik Sense repository to the file system. !!! This operation is # NOQA
201
+ # possible only in Qlik Sense Enterprise. !!! Parameters: qTargetPath (MANDATORY) - Path and name of the target # NOQA
202
+ # app qSrcAppId (MANDATORY) - Identifier of the source app. The identifier is a GUID from the Qlik Sense # NOQA
203
+ # repository. qIds - Array of identifiers.. The list of all the objects in the app to be exported must be given. # NOQA
204
+ # This list must contain the GUIDs of all these objects.
205
+ def export_app(self, target_path, src_app_id, qIds=[""]):
206
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
207
+ "method": "ExportApp",
208
+ "params": {"qTargetPath": target_path,
209
+ "qSrcAppId": src_app_id,
210
+ "qIds": qIds}
211
+ })
212
+ response = json.loads(
213
+ self.engine_socket.send_call(self.engine_socket, msg))
214
+ try:
215
+ return response['result']
216
+ except KeyError:
217
+ return response["error"]
218
+
219
+ # ReplaceAppFromID method: Replaces an app with the objects from a source app. The list of objects in the app to # NOQA
220
+ # be replaced must be defined in qIds. !!! This operation is possible only in Qlik Sense Enterprise. !!! # NOQA
221
+ # Parameters: qTargetAppId (MANDATORY) - Identifier (GUID) of the target app. The target app is the app to be # NOQA
222
+ # replaced. qSrcAppId (MANDATORY) - Identifier of the source app. The identifier is a GUID from the Qlik Sense # NOQA
223
+ # repository. qIds - QRS identifiers (GUID) of the objects in the target app to be replaced. Only QRS-approved # NOQA
224
+ # GUIDs are applicable. An object that is QRS-approved, is for example an object that has been published (i.e not # NOQA
225
+ # private anymore). If an object is private, it should not be included in this list. If qIds is empty, # NOQA
226
+ # the engine automatically creates a list that contains all QRS-approved objects. If the array of identifiers # NOQA
227
+ # contains objects that are not present in the source app, the objects related to these identifiers are removed # NOQA
228
+ # from the target app.
229
+ def replace_app_from_id(self, target_path, src_app_id, qIds=[""]):
230
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
231
+ "method": "ReplaceAppFromID",
232
+ "params": {"qTargetAppId": target_path,
233
+ "qSrcAppId": src_app_id,
234
+ "qIds": qIds}
235
+ })
236
+ response = json.loads(
237
+ self.engine_socket.send_call(self.engine_socket, msg))
238
+ try:
239
+ return response['result']
240
+ except KeyError:
241
+ return response['error']
242
+
243
+ # GetAuthenticatedUser
244
+ # No parameters
245
+ def get_auth_user(self):
246
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
247
+ "method": "GetAuthenticatedUser", "params": {}})
248
+ response_json = json.loads(
249
+ self.engine_socket.send_call(self.engine_socket, msg))
250
+ try:
251
+ return response_json["result"]
252
+ except KeyError:
253
+ return response_json["error"]
254
+
255
+ # GetDatabasesFromConnectionString Lists the databases in a ODBC, OLEDB or CUSTOM data source (global level) # NOQA
256
+ # Parameters: qConnection (object - has several fields) qId: Identifier of the connection. Is generated by # NOQA
257
+ # the engine and is unique. qName (MANDATORY): Name of the connection. This parameter is mandatory and must # NOQA
258
+ # be set when creating or modifying a connection. qConnectionString (MANDATORY): One of: ODBC CONNECT TO [ # NOQA
259
+ # <provider name>], OLEDB CONNECT TO [<provider name>], CUSTOM CONNECT TO [<provider name>], "<local absolut # NOQA
260
+ # or relative path,UNC path >", "<URL>" Connection string. qType (MANDATORY): Type of the connection. One # NOQA
261
+ # of- ODBC, OLEDB, <Name of the custom connection file>, folder, internet. For ODBC, OLEDB and custom # NOQA
262
+ # connections, the engine checks that the connection type matches the connection string. The type is not cas # NOQA
263
+ # sensitive. qUserName: Name of the user who creates the connection. This parameter is optional; it is only # NOQA
264
+ # used for OLEDB, ODBC and CUSTOM connections. A call to GetConnection method does not return the user name. # NOQA
265
+ # qPassword: Password of the user who creates the connection. This parameter is optional; it is only used fo # NOQA
266
+ # OLEDB, ODBC and CUSTOM connections. A call to GetConnection method does not return the password. # NOQA
267
+ # qModifiedDate: Is generated by the engine. Creation date of the connection or last modification date of th # NOQA
268
+ # connection. qMeta: Information about the connection. qLogOn (SSO Passthrough or not): Select which user # NOQA
269
+ # credentials to use to connect to the source. LOG_ON_SERVICE_USER: Disables, LOG_ON_CURRENT_USER: Enabl # NOQA
270
+ def list_databases_from_odbc(self, connect_name,
271
+ connect_string, connect_type,
272
+ user_name, password, mod_date="",
273
+ meta="",
274
+ sso_passthrough="LOG_ON_SERVICE_USER"):
275
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
276
+ "method": "GetDatabasesFromConnectionString",
277
+ "params": [{"qId": "", "qName": connect_name,
278
+ "qConnectionString": connect_string,
279
+ "qType": connect_type,
280
+ "qUserName": user_name,
281
+ "qPassword": password,
282
+ "qModifiedDate": mod_date,
283
+ "qMeta": meta,
284
+ "qLogOn": sso_passthrough}]
285
+ })
286
+ response = json.loads(
287
+ self.engine_socket.send_call(self.engine_socket, msg))
288
+ try:
289
+ return response['result']
290
+ except KeyError:
291
+ return response['error']
292
+
293
+ # IsValidConnectionString method: Checks if a connection string is valid.
294
+ def is_valid_connect_string(self, connect_name,
295
+ connect_string, connect_type,
296
+ user_name, password, mod_date="",
297
+ meta="",
298
+ sso_passthrough="LOG_ON_SERVICE_USER"
299
+ ):
300
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
301
+ "method": "IsValidConnectionString", "params": [
302
+ {"qId": "", "qName": connect_name,
303
+ "qConnectionString": connect_string,
304
+ "qType": connect_type,
305
+ "qUserName": user_name,
306
+ "qPassword": password,
307
+ "qModifiedDate": mod_date,
308
+ "qMeta": meta,
309
+ "qLogOn": sso_passthrough}
310
+ ]
311
+ })
312
+ response = json.loads(
313
+ self.engine_socket.send_call(self.engine_socket, msg))
314
+ try:
315
+ return response['result'] # Returns an array of databases
316
+ except KeyError:
317
+ return response['error']
318
+
319
+ # GetOdbcDsns: List all the ODBC connectors installed on the Sense server machine in Windows # NOQA
320
+ def get_odbc_dsns(self):
321
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -
322
+ 1, "method": "GetOdbcDsns", "params": {}})
323
+ response = json.loads(
324
+ self.engine_socket.send_call(self.engine_socket, msg))
325
+ try:
326
+ return response['result']
327
+ except KeyError:
328
+ return response['error']
329
+
330
+ # GetOleDbProviders: Returns the list of the OLEDB providers installed on the system. # NOQA
331
+ def get_ole_dbs(self):
332
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
333
+ "method": "GetOleDbProviders", "params": {}})
334
+ response = json.loads(
335
+ self.engine_socket.send_call(self.engine_socket, msg))
336
+ try:
337
+ return response['result']
338
+ except KeyError:
339
+ return response['error']
340
+
341
+ # GetProgress: Gives information about the progress of the DoReload and DoSave calls. Parameters: qRequestId: # NOQA
342
+ # Identifier of the DoReload or DoSave request or 0. Complete information is returned if the identifier of the # NOQA
343
+ # request is given. If the identifier is 0, less information is given. Progress messages and error messages are # NOQA
344
+ # returned but information like when the request started and finished is not returned. # NOQA
345
+
346
+ def get_progress(self, request_id):
347
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -
348
+ 1, "method": "GetProgress", "params": {}})
349
+ response = json.loads(
350
+ self.engine_socket.send_call(self.engine_socket, msg))
351
+ try:
352
+ return response['result']
353
+ except KeyError:
354
+ return response['error']
355
+
356
+ # IsDesktopMode: Indicates whether the user is working
357
+ # in Qlik Sense Desktop.
358
+ # No parameters
359
+ def is_desktop_mode(self, request_id):
360
+ msg = json.dumps({"jsonrpc": "2.0", "id": 0, "handle": -1,
361
+ "method": "IsDesktopMode", "params": {}})
362
+ response = json.loads(
363
+ self.engine_socket.send_call(self.engine_socket, msg))
364
+ try:
365
+ return response['result']
366
+ except KeyError:
367
+ return response['error']
368
+
369
+ @staticmethod
370
+ def get_doc_handle(doc_object):
371
+ return doc_object['qHandle']
372
+
373
+ # ## NOT IMPLEMENTED, perceived out of use case scope: ## CreateDocEx, GetBaseBNFHash, GetBaseBNF, GetBNF, # NOQA
374
+ # GetCustomConnectors, GetDefaultAppFolder, GetFunctions, GetInteract, GetLogicalDriveStrings, # NOQA
375
+ # ## GetStreamList, GetSupportedCodePages, GetUniqueID, InteractDone, IsPersonalMode (deprecated), OSVersion, # NOQA
376
+ # ProductVersion (depr), QTProduct, QvVersion (depr), ## ReloadExtensionList, ReplaceAppFromID, # NOQA
@@ -0,0 +1,67 @@
1
+ import math
2
+
3
+ from qe_api_client.engine_app_api import EngineAppApi
4
+ from qe_api_client.engine_field_api import EngineFieldApi
5
+ from qe_api_client.engine_generic_object_api import EngineGenericObjectApi
6
+ from qe_api_client.engine_global_api import EngineGlobalApi
7
+ from qe_api_client.structs import 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.nx_sort_by()
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_hypercube_dimensions(hc_inline_dim)
25
+ hc_mes = Structs.nx_hypercube_measure(hc_mes_sort, hc_inline_mes)
26
+
27
+ width = len(measures) + len(dimensions)
28
+ height = int(math.floor(10000 / width))
29
+ nx_page = Structs.nx_page(0, 0, height, width)
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)
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(i, 0, height, width)
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