onetick.query-webapi 20250727.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,16 @@
1
+ # onetick.query-webapi
2
+
3
+ `onetick.query-webapi` is a Python package that provides APIs to construct OneTick's graph and query objects and then using execute them using only REST APIs. It is a lightweight, secure and easy to use package that comes with MIT license.
4
+
5
+ ## ✨ Features
6
+
7
+ - Provides classes to contruct OneTick graphs, save and query them
8
+ - Has secure oAuth2 authentication support
9
+ - Supports various return data types (pyarrow, numpy, pandas, polars)
10
+ - It is possible to execute real-time CEP queries
11
+ - Compatible with Python 3.8+
12
+
13
+ ## 🚀 Installation
14
+
15
+ ```bash
16
+ pip install onetick.query-webapi
@@ -0,0 +1,77 @@
1
+ import click
2
+ import requests as _requests
3
+ from . import eps_generator
4
+
5
+
6
+ def get_access_token(url, client_id, client_secret):
7
+ response = _requests.post(
8
+ url,
9
+ data={"grant_type": "client_credentials"},
10
+ auth=(client_id, client_secret),
11
+ )
12
+ if response.status_code == 200:
13
+ return response.json()["access_token"]
14
+ else:
15
+ raise Exception(f"Error retrieving access token: {response.status_code} - {response.text}")
16
+
17
+
18
+ CONTEXT_SETTINGS = dict(
19
+ help_option_names=['--help'],
20
+ terminal_width=97,
21
+ max_content_width=97,
22
+ color=True,
23
+ )
24
+ CMD_SETTINGS = dict(
25
+ ignore_unknown_options=True,
26
+ allow_extra_args=True,
27
+ )
28
+
29
+
30
+ @click.command(context_settings=CONTEXT_SETTINGS)
31
+ @click.option("-n", "--plugin_name", default=None, required=False, help="Plugin name")
32
+ @click.option("-o", "--output_dir", default=None, required=False, help="Directory path where to generate whl file")
33
+ @click.option("-a", "--http_address", required=True, help="Address of the onetick server")
34
+ @click.option("-u", "--http_username", default=None, required=False, help="Username for an http authentication if needed")
35
+ @click.option("-p", "--http_password", default=None, required=False, help="Password for an http authentication if needed")
36
+ @click.option("-i", "--client_id", default=None, required=False, help="Client id of a user")
37
+ @click.option("-s", "--client_secret", default=None, required=False, help="Client secret of a user")
38
+ @click.option("-ur", "--url", default=None, required=False, help="Identity provider url")
39
+ @click.option("-n", "--namespace", default=None, required=False, help="Namespace names of EPs to generate python code for")
40
+ @click.option("-d", "--generate_documentation", default=True, required=False, help="If thue then we also generate the documentation for EPs")
41
+ def console(plugin_name, output_dir, http_address, http_username, http_password, client_id, client_secret, url, namespace, generate_documentation):
42
+ if plugin_name:
43
+ if not output_dir:
44
+ raise Exception('output_dir must be specified, when plugin_name is specified')
45
+ if not namespace:
46
+ raise Exception('namespace must be specified, when plugin_name is specified')
47
+ else:
48
+ output_dir = None
49
+ namespace = None
50
+ if not http_address:
51
+ raise Exception('http_address not specified')
52
+
53
+ print("EPs generation started")
54
+ if plugin_name:
55
+ print(f"Creating a plugin for {namespace} namespace EPs. Plugin name is {plugin_name}")
56
+ else:
57
+ print("Regenerating all EPs")
58
+ if client_id and client_secret and url:
59
+ access_token = get_access_token(url, client_id, client_secret)
60
+ elif not client_id and not client_secret and not url:
61
+ access_token = None
62
+ else:
63
+ raise Exception('One of url, client_id, client_secret is not specified. '
64
+ 'These parameters must all be specified or none of them should be specified')
65
+ eps_generator.generate_plugin(plugin_name=plugin_name,
66
+ output_dir=output_dir,
67
+ http_address=http_address,
68
+ http_username=http_username,
69
+ http_password=http_password,
70
+ access_token=access_token,
71
+ generate_documentation=generate_documentation,
72
+ namespace=namespace)
73
+ print("Done")
74
+
75
+
76
+ if __name__ == '__main__':
77
+ console()
@@ -0,0 +1,428 @@
1
+ import onetick.query_webapi as otq
2
+ import os
3
+ import tempfile
4
+ from .utils import *
5
+ from . import plugin
6
+
7
+
8
+ def generate_ep_infos(eps_list_otq, eps_documentation_otq, http_address, generate_documentation,
9
+ http_username, http_password, access_token, namespace):
10
+ def is_number(s):
11
+ try:
12
+ int(s)
13
+ return True
14
+ except ValueError:
15
+ return False
16
+
17
+ def is_boolean_param(type_name, default_value, choices, param_name):
18
+ if param_name == "GO_BACK_TO_FIRST_TICK":
19
+ return False
20
+ if type_name.upper() == "BOOL" and (len(choices) == 2 or len(choices) == 0):
21
+ return True
22
+ is_boolean = (default_value and default_value.lower() in ['true', 'false']) or len(choices) > 0
23
+ if is_boolean:
24
+ for choice in choices:
25
+ if choice.lower() not in ['true', 'false']:
26
+ return False
27
+ return is_boolean
28
+
29
+ def is_integer_param(type_name, default_value, choices):
30
+ if type_name.upper() == "INTEGER" or type_name.upper() == "LONG":
31
+ return True
32
+ is_integer = default_value and is_number(default_value)
33
+ if is_integer:
34
+ for choice in choices:
35
+ if not is_number(choice):
36
+ return False
37
+ return is_integer
38
+
39
+ def is_enum_param(type_name, default_value, choices, param_name):
40
+ if type_name.upper() == "ENUM" and len(choices) > 1:
41
+ return True
42
+ if default_value and default_value not in choices:
43
+ return False
44
+ is_enum = len(choices) > 1 and not (is_boolean_param(type_name, default_value, choices, param_name) or
45
+ is_integer_param(type_name, default_value, choices))
46
+ return is_enum
47
+
48
+ def detect_param_type(type_name, default_value, choices, param_name):
49
+ choices = list(filter(None, choices))
50
+ if is_boolean_param(type_name, default_value, choices, param_name):
51
+ return ParamInfo.ParamType.PARAM_TYPE_BOOLEAN
52
+ if is_integer_param(type_name, default_value, choices):
53
+ return ParamInfo.ParamType.PARAM_TYPE_INTEGER
54
+ if is_enum_param(type_name, default_value, choices, param_name):
55
+ return ParamInfo.ParamType.PARAM_TYPE_ENUM
56
+ return ParamInfo.ParamType.PARAM_TYPE_STRING
57
+
58
+ def create_param_info(ep_name_param, param_name, value_type, default_value, choices):
59
+ special_ep_params = [("FIND_DB_SYMBOLS", "CEP_METHOD"),
60
+ ("OM/STRATEGY_DB_MANAGER", "PERMISSION")]
61
+ if (ep_name_param, param_name) in special_ep_params:
62
+ choices.insert(0, "EMPTY")
63
+ default_value = "EMPTY"
64
+ return ParamInfo(param_name,
65
+ detect_param_type(value_type, default_value, choices, param_name),
66
+ default_value,
67
+ choices)
68
+
69
+ data = otq.run(eps_list_otq, http_address, http_username=http_username, http_password=http_password,
70
+ access_token=access_token)["LOCAL::"]
71
+ ep_infos = dict()
72
+ cur_ep_info = EpInfo("", [])
73
+ for idx, ep_name in enumerate(data['MY_EVENT_PROCESSOR_NAME']):
74
+ ep_name = ep_name
75
+ if namespace and not ep_name.startswith(namespace):
76
+ continue
77
+ if ep_name == cur_ep_info.name:
78
+ if data['MY_PARAMETER_NAME'][idx]:
79
+ cur_ep_info.params.append(
80
+ create_param_info(ep_name,
81
+ data['MY_PARAMETER_NAME'][idx],
82
+ data['MY_TYPE_EXPR'][idx],
83
+ data['MY_PARAMETER_DEFAULT_VALUE'][idx],
84
+ data['MY_PARAMETER_CHOICES'][idx].split(',')))
85
+ else:
86
+ cur_ep_info = EpInfo(ep_name, [])
87
+ if data['MY_PARAMETER_NAME'][idx]:
88
+ cur_ep_info.params.append(
89
+ create_param_info(ep_name,
90
+ data['MY_PARAMETER_NAME'][idx],
91
+ data['MY_TYPE_EXPR'][idx],
92
+ data['MY_PARAMETER_DEFAULT_VALUE'][idx],
93
+ data['MY_PARAMETER_CHOICES'][idx].split(',')))
94
+ ep_infos[ep_name] = cur_ep_info
95
+
96
+ if generate_documentation:
97
+ data = otq.run(eps_documentation_otq, http_address, http_username=http_username, http_password=http_password,
98
+ access_token=access_token, compression="none")["LOCAL::"]
99
+ for idx, ep_name in enumerate(data['MY_EVENT_PROCESSOR_NAME']):
100
+ if ep_name not in ep_infos:
101
+ continue
102
+ ep_infos[ep_name].documentation = str(data['MY_DOCUMENTATION'][idx])
103
+ return ep_infos
104
+
105
+
106
+ def generate_ep_module(ep_infos, generate_documentation, plugin_name, output_dir):
107
+ temp_dir = ""
108
+ if plugin_name:
109
+ temp_dir = tempfile.mkdtemp()
110
+ plugin_dir = temp_dir + "/onetick/query_webapi/plugin/" + plugin_name
111
+ os.makedirs(plugin_dir + "/ep")
112
+ with open(plugin_dir + "/__init__.py", "w") as f:
113
+ f.write('from .ep import *\n')
114
+ else:
115
+ cur_dir = os.path.dirname(os.path.realpath(__file__))
116
+ plugin_dir = cur_dir + "/../query_webapi"
117
+
118
+ with open(plugin_dir + "/ep/__init__.py", "w") as f:
119
+ f.write('from .eps import *\n')
120
+
121
+ out = open(plugin_dir + "/ep/eps.py", "w")
122
+ if plugin_name:
123
+ print_line(out, 'import onetick.query_webapi.graph_components as _graph_components')
124
+ print_line(out, 'import onetick.query_webapi._internal_utils as _internal_utils')
125
+ print_line(out, 'import onetick.query_webapi.config as _config')
126
+ else:
127
+ print_line(out, 'from .. import graph_components as _graph_components')
128
+ print_line(out, 'from .. import _internal_utils')
129
+ print_line(out, 'from .. import config as _config')
130
+ print_line(out, 'from .. import utils as _utils')
131
+ print_line(out, '')
132
+ print_line(out, '')
133
+ for ep_name in ep_infos:
134
+ generate_ep_class(ep_infos[ep_name], out, generate_documentation)
135
+ out.close()
136
+
137
+ out = open(plugin_dir + "/_eps_factory.py", "w")
138
+ _indent = 0
139
+ if not plugin_name:
140
+ print_line(out, 'from . import eps_dict')
141
+ print_line(out, 'from . import ep')
142
+ print_line(out, 'from inspect import getframeinfo, currentframe')
143
+ print_line(out, "")
144
+ print_line(out, "")
145
+ print_line(out, "def create_ep(ep_name):")
146
+ for ep_name in ep_infos:
147
+ print_line(out, "if ep_name == '" + ep_name + "':", _indent + 1)
148
+ print_line(out, "return ep." + to_camel_case(ep_infos[ep_name].name) + "()", _indent + 2)
149
+ if not plugin_name:
150
+ print_line(out, "if ep_name in eps_dict:", _indent + 1)
151
+ print_line(out, "return eps_dict[ep_name]()", _indent + 2)
152
+ print_line(out, "")
153
+ print_line(out,
154
+ "raise Exception('wrong ep name: {}.'.format(ep_name), getframeinfo(currentframe()).filename, getframeinfo(currentframe()).lineno)",
155
+ _indent + 1)
156
+ out.close()
157
+ if plugin_name:
158
+ plugin.build(temp_dir, output_dir, plugin_name)
159
+
160
+
161
+ def generate_ep_class(ep_info: EpInfo, out, generate_documentation, _indent=0):
162
+ ep_class_name, have_postfix = get_ep_class_name(ep_info)
163
+ print_line(out, "class " + ep_class_name + "(_graph_components.EpBase):", _indent)
164
+ if generate_documentation:
165
+ print_line(out, "\"\"\"", _indent + 1)
166
+ print_line(out, html2text(ep_info.documentation), _indent + 2)
167
+ print_line(out, "\"\"\"", _indent + 1)
168
+ generate_available_parameters_aliases(ep_info.params, out, _indent + 1)
169
+ generate_enum_params_choices_wrapper_classes(ep_info.params, out, _indent + 1)
170
+ generate_ep_constructor(ep_info, out, _indent + 1)
171
+ generate_parameter_setters(ep_info.params, out, _indent + 1)
172
+ generate_ep_to_string(ep_info, out, _indent + 1)
173
+ generate_ep_destructor(out, _indent + 1)
174
+ if have_postfix:
175
+ print_line(out, "", _indent)
176
+ print_line(out, to_camel_case(ep_info.name) + " = " + ep_class_name, _indent)
177
+ print_line(out, "", _indent)
178
+
179
+ special_ep_aliases = dict(
180
+ [("NumTicks", "Count"), ("High", "Max"), ("Low", "Min"), ("Vwap", "WAvg"), ("Average", "Avg")]
181
+ )
182
+ if ep_class_name in special_ep_aliases:
183
+ print_line(out, "", _indent)
184
+ print_line(out, special_ep_aliases[ep_class_name] + " = " + ep_class_name, _indent)
185
+ print_line(out, "", _indent)
186
+ print_line(out, "")
187
+
188
+
189
+ def generate_available_parameters_aliases(ep_params, out, _indent):
190
+ print_line(out, "class Parameters:", _indent)
191
+ params_name_list = "["
192
+ params_name_list_with_private_members = "["
193
+ last_param_name = ""
194
+ if ep_params:
195
+ last_param_name = ep_params[-1].name
196
+ for ep_param in ep_params:
197
+ param_field_name = get_param_pythonic_name(ep_param.name)
198
+ param_server_name = ep_param.name
199
+
200
+ print_line(out, param_field_name + " = \"" + param_server_name + "\"", _indent + 1)
201
+ params_name_list += "\"" + param_field_name + "\""
202
+ params_name_list_with_private_members += "\"" + param_field_name + "\", "
203
+ params_name_list_with_private_members += "\"_default_" + param_field_name + "\""
204
+ if ep_param.name != last_param_name:
205
+ params_name_list += ", "
206
+ params_name_list_with_private_members += ", "
207
+
208
+ print_line(out, "stack_info = \"STACK_INFO\"", _indent + 1)
209
+ parameters_name_list_with_stack_info = params_name_list_with_private_members
210
+ if ep_params:
211
+ parameters_name_list_with_stack_info += ", "
212
+ parameters_name_list_with_stack_info += "\"stack_info\", \"_used_strings\"]"
213
+
214
+ # Construct list_parameters() method
215
+ params_name_list += ']'
216
+ print_line(out, "")
217
+ print_multi_line_string_with_indent(
218
+ out,
219
+ "@staticmethod\n" +
220
+ "def list_parameters():",
221
+ _indent + 1)
222
+ print_line(out, "list_val = " + params_name_list, _indent + 2)
223
+ print_multi_line_string_with_indent(
224
+ out,
225
+ "if _config.API_CONFIG[\'SHOW_STACK_INFO\'] == 1:\n" +
226
+ " list_val.append(\"stack_info\")\n" +
227
+ "return list_val",
228
+ _indent + 2)
229
+ print_line(out, "")
230
+ print_line(out, "__slots__ = " + parameters_name_list_with_stack_info, _indent)
231
+ print_line(out, "")
232
+
233
+
234
+ def generate_enum_params_choices_wrapper_classes(ep_params, out, _indent):
235
+ for ep_param in ep_params:
236
+ if ep_param.value_type == ParamInfo.ParamType.PARAM_TYPE_ENUM:
237
+ generate_enum_choices_wrapper_class(ep_param, out, _indent)
238
+
239
+
240
+ def generate_enum_choices_wrapper_class(ep_param: ParamInfo, out, _indent):
241
+ choices = ep_param.choices
242
+ param_wrapper_class_name = to_camel_case(ep_param.name)
243
+
244
+ print_line(out, "class " + param_wrapper_class_name + ":", _indent)
245
+ if len(ep_param.default_value) == 0:
246
+ print_line(out, "EMPTY = \"\"", _indent + 1)
247
+ for choice in choices:
248
+ if len(choice) == 0:
249
+ continue
250
+ choice_name = replace_special_chars_with_readable_words(choice).upper()
251
+ if choice_name == "EMPTY":
252
+ print_line(out, "EMPTY = \"\"", _indent + 1)
253
+ else:
254
+ print_line(out, choice_name + " = \"" + choice + "\"", _indent + 1)
255
+ print_line(out, "")
256
+
257
+
258
+ def generate_ep_constructor(ep_info: EpInfo, out, _indent):
259
+ is_in = False
260
+ is_out = False
261
+ class_name_line = "def __init__(self"
262
+ for ep_param in ep_info.params:
263
+ param_default = get_param_pythonic_default_value(ep_param)
264
+ param_name = get_param_pythonic_name(ep_param.name)
265
+ class_name_line += ", " + param_name + "=" + param_default
266
+ if param_name == "input_field_name":
267
+ is_in = True
268
+ if param_name == "output_field_name":
269
+ is_out = True
270
+ if is_in:
271
+ class_name_line += ", In = \"\""
272
+ if is_out:
273
+ class_name_line += ", Out = \"\""
274
+ class_name_line += "):"
275
+ print_line(out, class_name_line, _indent)
276
+
277
+ print_line(out, "_graph_components.EpBase.__init__(self, \"" + ep_info.name + "\")", _indent + 1)
278
+ for ep_param in ep_info.params:
279
+ ep_pythonic_param_name = get_param_pythonic_name(ep_param.name)
280
+ param_default = get_param_pythonic_default_value(ep_param, True)
281
+ print_multi_line_string_with_indent(
282
+ out,
283
+ "self._default_" + ep_pythonic_param_name + " = " + param_default + "\n" +
284
+ "self." + ep_pythonic_param_name + " = " + ep_pythonic_param_name,
285
+ _indent + 1)
286
+
287
+ if is_in:
288
+ print_multi_line_string_with_indent(
289
+ out,
290
+ "if In != \"\":\n" +
291
+ " self.input_field_name=In",
292
+ _indent + 1)
293
+ if is_out:
294
+ print_multi_line_string_with_indent(
295
+ out,
296
+ "if Out != \"\":\n" +
297
+ " self.output_field_name=Out",
298
+ _indent + 1)
299
+ print_multi_line_string_with_indent(
300
+ out,
301
+ "self._used_strings = {}\n" +
302
+ "for param_name in type(self).__dict__:\n" +
303
+ " param_val = getattr(self, param_name, '')\n" +
304
+ " if isinstance(param_val, str) and _internal_utils.get_reference_counted_prefix() in param_val and not (param_val in self._used_strings):\n" +
305
+ " _internal_utils.inc_ref_count(param_val)\n" +
306
+ " self._used_strings[param_val] = 1",
307
+ _indent + 1)
308
+ # Retrieve caller filename and line number in python
309
+ print_line(out, "import sys", _indent + 1)
310
+ print_line(out, "frame = sys._getframe(1)", _indent + 1)
311
+ print_line(out, "self.stack_info = frame.f_code.co_filename + \":\" + str(frame.f_lineno)", _indent + 1)
312
+ print_line(out, "")
313
+
314
+
315
+ def get_param_pythonic_default_value(ep_param: ParamInfo, prepend_class_name: bool = False):
316
+ param_default_value = ep_param.default_value
317
+ if ep_param.value_type == ParamInfo.ParamType.PARAM_TYPE_STRING:
318
+ return "\"" + escape_quotes(param_default_value) + "\""
319
+ elif ep_param.value_type == ParamInfo.ParamType.PARAM_TYPE_BOOLEAN:
320
+ if param_default_value.lower() == "true":
321
+ return "True"
322
+ else:
323
+ return "False"
324
+ elif ep_param.value_type == ParamInfo.ParamType.PARAM_TYPE_ENUM:
325
+ choices_wrapper_class_name = to_camel_case(ep_param.name)
326
+ choice_name = "EMPTY" if len(param_default_value) == 0 \
327
+ else replace_special_chars_with_readable_words(param_default_value).upper()
328
+ pref = "type(self)." if prepend_class_name else ""
329
+ return pref + choices_wrapper_class_name + "." + choice_name
330
+ if not param_default_value:
331
+ return "\"\""
332
+ return param_default_value
333
+
334
+
335
+ def generate_parameter_setters(ep_params, out, _indent):
336
+ for ep_param in ep_params:
337
+ param_name = get_param_pythonic_name(ep_param.name)
338
+ print_line(out, "def set_" + param_name + "(self, value):", _indent)
339
+ print_line(out, "self." + param_name + " = value", _indent + 1)
340
+ print_line(out, "return self", _indent + 1)
341
+ print_line(out, "")
342
+
343
+
344
+ def generate_ep_to_string(ep_info: EpInfo, out, _indent):
345
+ ep_name = ep_info.name
346
+ print_line(out, "@staticmethod", _indent)
347
+ print_line(out, "def _get_name():", _indent)
348
+ print_line(out, "return \"" + ep_name + "\"\n", _indent + 1)
349
+
350
+ print_line(out, "def _to_string(self, for_repr=False):", _indent)
351
+ print_line(out, "name = self._get_name()", _indent + 1)
352
+ print_line(out, "desc = name + \"(\"", _indent + 1)
353
+ print_line(out, "py_to_str = _utils.onetick_repr if for_repr else str", _indent + 1)
354
+
355
+ for param in ep_info.params:
356
+ pythonic_param_default = get_param_pythonic_default_value(param)
357
+ pythonic_param_name = get_param_pythonic_name(param.name)
358
+ pythonic_param_name_upper = pythonic_param_name.upper()
359
+
360
+ if pythonic_param_name_upper == "TICK_TYPE_FIELD" and ep_name == "FIND_DB_SYMBOLS":
361
+ pythonic_param_name_upper = "TICK_TYPE"
362
+ needed_self = ""
363
+ if param.value_type == ParamInfo.ParamType.PARAM_TYPE_ENUM:
364
+ needed_self = "self."
365
+
366
+ print_line(out, "if self." + pythonic_param_name + " != " + needed_self + pythonic_param_default + ": ",
367
+ _indent + 1)
368
+ print_line(out, "desc += \"" + pythonic_param_name_upper + "=\" + py_to_str(self." + pythonic_param_name +
369
+ ") + \",\"", _indent + 2)
370
+ print_line(out, "if _config.API_CONFIG[\'SHOW_STACK_INFO\'] == 1:", _indent + 1)
371
+ print_line(out, "desc += \"STACK_INFO=\" + py_to_str(self.stack_info) + \",\"", _indent + 2)
372
+ print_line(out, "desc = desc[:-1]", _indent + 1)
373
+ print_line(out, "if desc != name:", _indent + 1)
374
+ print_line(out, "desc += \")\"", _indent + 2)
375
+ print_line(out, "if for_repr:", _indent + 1)
376
+ print_line(out, "return desc + '()' if desc == name else desc", _indent + 2)
377
+ print_line(out, "desc += \"\\n\"", _indent + 1)
378
+ print_multi_line_string_with_indent(
379
+ out,
380
+ "if len(self._get_symbol_strings()) > 0:\n" +
381
+ " desc += \"SYMBOLS=[\" + \", \".join(self._get_symbol_strings()) + \"]\\n\"\n" +
382
+ "if len(self.tick_types_) > 0:\n" +
383
+ " desc += \"TICK_TYPES=[\" + \', \'.join(self.tick_types_) + \"]\\n\"\n" +
384
+ "if self.process_node_locally_:\n" +
385
+ " desc += \"PROCESS_NODE_LOCALLY=True\\n\"\n" +
386
+ "if self.node_name_ != \"\":\n" +
387
+ " desc += \"NODE_NAME=\" + self.node_name_ + \"\\n\"\n" +
388
+ "return desc",
389
+ _indent + 1)
390
+ print_multi_line_string_with_indent(
391
+ out,
392
+ "\n" +
393
+ "def __repr__(self):\n" +
394
+ " return self._to_string(for_repr=True)\n" +
395
+ "\n" +
396
+ "def __str__(self):\n" +
397
+ " return self._to_string()",
398
+ _indent)
399
+ print_line(out, "")
400
+
401
+
402
+ def generate_ep_destructor(out, _indent):
403
+ print_multi_line_string_with_indent(
404
+ out,
405
+ "def __del__(self):\n" +
406
+ " for param_name in getattr(self, '_used_strings', []):\n" +
407
+ " _internal_utils.dec_ref_count(param_name)\n" +
408
+ " if _internal_utils.get_ref_count(param_name) == 0:\n" +
409
+ " _internal_utils.remove_from_memory(param_name)",
410
+ _indent)
411
+ print_line(out, "")
412
+
413
+
414
+ def generate_plugin(plugin_name, output_dir, http_address, http_username=None, http_password=None, access_token=None,
415
+ generate_documentation=True, namespace=None):
416
+ cur_dir = os.path.dirname(os.path.realpath(__file__))
417
+ generate_ep_module(
418
+ generate_ep_infos(cur_dir + "/eps_list.otq",
419
+ cur_dir + "/eps_list_doc.otq",
420
+ http_address,
421
+ generate_documentation,
422
+ http_username,
423
+ http_password,
424
+ access_token,
425
+ namespace),
426
+ generate_documentation,
427
+ plugin_name,
428
+ output_dir)
@@ -0,0 +1,17 @@
1
+ [show_eps_list]
2
+ CPU_NUMBER = 1
3
+ NODE_4 = SHOW_EP_LIST(ALLOW_API_ONLY_EPS="TRUE")
4
+ NODE_8 = ADD_FIELDS(FIELDS="varstring MY_EVENT_PROCESSOR_NAME=EVENT_PROCESSOR_NAME,varstring MY_PARAMETER_NAME=PARAMETER_NAME,varstring MY_PARAMETER_DEFAULT_VALUE=PARAMETER_DEFAULT_VALUE,varstring MY_PARAMETER_CHOICES=PARAMETER_CHOICES,varstring MY_PARAMETER_DESCRIPTION=PARAMETER_DESCRIPTION,varstring MY_TYPE_EXPR=TYPE_EXPR")
5
+ NODE_8_SOURCE = NODE_4
6
+ ROOT = PASSTHROUGH(FIELDS="MY_EVENT_PROCESSOR_NAME,MY_PARAMETER_NAME,MY_PARAMETER_DEFAULT_VALUE,MY_PARAMETER_CHOICES,MY_PARAMETER_DESCRIPTION,MY_TYPE_EXPR")
7
+ ROOT_SOURCE = NODE_8
8
+ SECURITY = LOCAL:: 0
9
+ TYPE = GRAPH
10
+
11
+ [_meta]
12
+ ApplyTimesDaily = 0
13
+ end = 20170710125009000
14
+ file_version = 1.0
15
+ RunningQuery = 0
16
+ start = 20010710125008000
17
+ TZ = GMT
@@ -0,0 +1,19 @@
1
+
2
+ [show_eps_list]
3
+ CPU_NUMBER = 1
4
+ NODE_2 = ADD_FIELDS(FIELDS="varstring MY_EVENT_PROCESSOR_NAME=EVENT_PROCESSOR_NAME,varstring MY_DOCUMENTATION=DOCUMENTATION")
5
+ NODE_2_SOURCE = NODE_3
6
+ NODE_3 = SHOW_EP_LIST(LEVEL_OF_DETAIL=PER_EP,SHOW_DOCUMENTATION=TRUE,ALLOW_API_ONLY_EPS=TRUE)
7
+ NODE_3_TICK_TYPE = TRD
8
+ ROOT = PASSTHROUGH(FIELDS="MY_EVENT_PROCESSOR_NAME,MY_DOCUMENTATION")
9
+ ROOT_SOURCE = NODE_2
10
+ SECURITY = LOCAL:: 0
11
+ TYPE = GRAPH
12
+
13
+ [_meta]
14
+ ApplyTimesDaily = 0
15
+ end = 20170710125009000
16
+ file_version = 1.0
17
+ RunningQuery = 0
18
+ start = 20010710125008000
19
+ TZ = GMT
@@ -0,0 +1,74 @@
1
+ import sys
2
+ import os
3
+ import shutil
4
+ import glob
5
+ from subprocess import run
6
+
7
+
8
+ def build(temp_dir, output_dir, plugin_name, plugin_version="0.0.1"):
9
+ create_setup_file(temp_dir, plugin_name, plugin_version)
10
+ compile_plugin(temp_dir, output_dir)
11
+ print('Done.')
12
+
13
+
14
+ ##########################################################################
15
+
16
+ def create_setup_file(temp_dir, plugin_name, plugin_version):
17
+ setup_file_content = """
18
+ from setuptools import setup
19
+ from setuptools.dist import Distribution
20
+
21
+
22
+ PYTHON_VERSION = (3,8)
23
+ class BinaryDistribution(Distribution):
24
+ #Distribution which always forces a binary package with platform name
25
+ def has_ext_modules(foo):
26
+ return True
27
+
28
+
29
+ options = dict(
30
+ name='onetick.query_webapi.{plugin_name}',
31
+ packages=[
32
+ 'onetick.query_webapi.plugin.{plugin_name}',
33
+ 'onetick.query_webapi.plugin.{plugin_name}.ep'
34
+ ],
35
+
36
+ version='{version}',
37
+ description='OneTick client package',
38
+ long_description=__doc__,
39
+ author='OneTick',
40
+ author_email='support@onetick.com',
41
+ url='https://www.onetick.com',
42
+ license='commercial',
43
+
44
+ zip_safe=True,
45
+ include_package_data=True,
46
+
47
+ entry_points={{
48
+ 'onetick.query_webapi.plugin': 'onetick.query_webapi.{plugin_name} = onetick.query_webapi.plugin.{plugin_name}'
49
+ }},
50
+ install_requires=[
51
+ 'onetick.query_webapi',
52
+ ],
53
+ )
54
+
55
+ #########################
56
+ if __name__ == '__main__':
57
+ setup(**options)
58
+ """.format(plugin_name=plugin_name, version=plugin_version)
59
+
60
+ setup_file = temp_dir + '/setup.py'
61
+ f = open(setup_file, "x")
62
+ f.write(setup_file_content)
63
+ f.close()
64
+
65
+
66
+ def compile_plugin(temp_dir, output_dir):
67
+ print('create Wheel binary distribution...')
68
+
69
+ os.chdir(temp_dir)
70
+ cmd = f'{sys.executable} setup.py bdist_wheel'
71
+ run(cmd.split())
72
+ whl_file = temp_dir + '/dist/*.whl'
73
+ for file in glob.glob(whl_file):
74
+ shutil.copy(file, output_dir)