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.
- qe_api_client/__init__.py +1 -0
- qe_api_client/engine.py +145 -0
- qe_api_client/engine_app_api.py +810 -0
- qe_api_client/engine_communicator.py +42 -0
- qe_api_client/engine_field_api.py +81 -0
- qe_api_client/engine_generic_object_api.py +101 -0
- qe_api_client/engine_global_api.py +376 -0
- qe_api_client/engine_helper.py +67 -0
- qe_api_client/structs.py +107 -0
- qe_api_client-1.0.0.dist-info/LICENSE +19 -0
- qe_api_client-1.0.0.dist-info/METADATA +45 -0
- qe_api_client-1.0.0.dist-info/RECORD +14 -0
- qe_api_client-1.0.0.dist-info/WHEEL +5 -0
- qe_api_client-1.0.0.dist-info/top_level.txt +1 -0
@@ -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
|