onetick-py 1.177.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.
- locator_parser/__init__.py +0 -0
- locator_parser/acl.py +73 -0
- locator_parser/actions.py +262 -0
- locator_parser/common.py +368 -0
- locator_parser/io.py +43 -0
- locator_parser/locator.py +150 -0
- onetick/__init__.py +101 -0
- onetick/doc_utilities/__init__.py +3 -0
- onetick/doc_utilities/napoleon.py +40 -0
- onetick/doc_utilities/ot_doctest.py +140 -0
- onetick/doc_utilities/snippets.py +279 -0
- onetick/lib/__init__.py +4 -0
- onetick/lib/instance.py +141 -0
- onetick/py/__init__.py +293 -0
- onetick/py/_stack_info.py +89 -0
- onetick/py/_version.py +2 -0
- onetick/py/aggregations/__init__.py +11 -0
- onetick/py/aggregations/_base.py +648 -0
- onetick/py/aggregations/_docs.py +948 -0
- onetick/py/aggregations/compute.py +286 -0
- onetick/py/aggregations/functions.py +2216 -0
- onetick/py/aggregations/generic.py +104 -0
- onetick/py/aggregations/high_low.py +80 -0
- onetick/py/aggregations/num_distinct.py +83 -0
- onetick/py/aggregations/order_book.py +501 -0
- onetick/py/aggregations/other.py +1014 -0
- onetick/py/backports.py +26 -0
- onetick/py/cache.py +374 -0
- onetick/py/callback/__init__.py +5 -0
- onetick/py/callback/callback.py +276 -0
- onetick/py/callback/callbacks.py +131 -0
- onetick/py/compatibility.py +798 -0
- onetick/py/configuration.py +771 -0
- onetick/py/core/__init__.py +0 -0
- onetick/py/core/_csv_inspector.py +93 -0
- onetick/py/core/_internal/__init__.py +0 -0
- onetick/py/core/_internal/_manually_bound_value.py +6 -0
- onetick/py/core/_internal/_nodes_history.py +250 -0
- onetick/py/core/_internal/_op_utils/__init__.py +0 -0
- onetick/py/core/_internal/_op_utils/every_operand.py +9 -0
- onetick/py/core/_internal/_op_utils/is_const.py +10 -0
- onetick/py/core/_internal/_per_tick_scripts/tick_list_sort_template.script +121 -0
- onetick/py/core/_internal/_proxy_node.py +140 -0
- onetick/py/core/_internal/_state_objects.py +2312 -0
- onetick/py/core/_internal/_state_vars.py +93 -0
- onetick/py/core/_source/__init__.py +0 -0
- onetick/py/core/_source/_symbol_param.py +95 -0
- onetick/py/core/_source/schema.py +97 -0
- onetick/py/core/_source/source_methods/__init__.py +0 -0
- onetick/py/core/_source/source_methods/aggregations.py +809 -0
- onetick/py/core/_source/source_methods/applyers.py +296 -0
- onetick/py/core/_source/source_methods/columns.py +141 -0
- onetick/py/core/_source/source_methods/data_quality.py +301 -0
- onetick/py/core/_source/source_methods/debugs.py +272 -0
- onetick/py/core/_source/source_methods/drops.py +120 -0
- onetick/py/core/_source/source_methods/fields.py +619 -0
- onetick/py/core/_source/source_methods/filters.py +1002 -0
- onetick/py/core/_source/source_methods/joins.py +1413 -0
- onetick/py/core/_source/source_methods/merges.py +605 -0
- onetick/py/core/_source/source_methods/misc.py +1455 -0
- onetick/py/core/_source/source_methods/pandases.py +155 -0
- onetick/py/core/_source/source_methods/renames.py +356 -0
- onetick/py/core/_source/source_methods/sorts.py +183 -0
- onetick/py/core/_source/source_methods/switches.py +142 -0
- onetick/py/core/_source/source_methods/symbols.py +117 -0
- onetick/py/core/_source/source_methods/times.py +627 -0
- onetick/py/core/_source/source_methods/writes.py +986 -0
- onetick/py/core/_source/symbol.py +205 -0
- onetick/py/core/_source/tmp_otq.py +222 -0
- onetick/py/core/column.py +209 -0
- onetick/py/core/column_operations/__init__.py +0 -0
- onetick/py/core/column_operations/_methods/__init__.py +4 -0
- onetick/py/core/column_operations/_methods/_internal.py +28 -0
- onetick/py/core/column_operations/_methods/conversions.py +216 -0
- onetick/py/core/column_operations/_methods/methods.py +292 -0
- onetick/py/core/column_operations/_methods/op_types.py +160 -0
- onetick/py/core/column_operations/accessors/__init__.py +0 -0
- onetick/py/core/column_operations/accessors/_accessor.py +28 -0
- onetick/py/core/column_operations/accessors/decimal_accessor.py +104 -0
- onetick/py/core/column_operations/accessors/dt_accessor.py +537 -0
- onetick/py/core/column_operations/accessors/float_accessor.py +184 -0
- onetick/py/core/column_operations/accessors/str_accessor.py +1367 -0
- onetick/py/core/column_operations/base.py +1121 -0
- onetick/py/core/cut_builder.py +150 -0
- onetick/py/core/db_constants.py +20 -0
- onetick/py/core/eval_query.py +245 -0
- onetick/py/core/lambda_object.py +441 -0
- onetick/py/core/multi_output_source.py +232 -0
- onetick/py/core/per_tick_script.py +2256 -0
- onetick/py/core/query_inspector.py +464 -0
- onetick/py/core/source.py +1744 -0
- onetick/py/db/__init__.py +2 -0
- onetick/py/db/_inspection.py +1128 -0
- onetick/py/db/db.py +1327 -0
- onetick/py/db/utils.py +64 -0
- onetick/py/docs/__init__.py +0 -0
- onetick/py/docs/docstring_parser.py +112 -0
- onetick/py/docs/utils.py +81 -0
- onetick/py/functions.py +2398 -0
- onetick/py/license.py +190 -0
- onetick/py/log.py +88 -0
- onetick/py/math.py +935 -0
- onetick/py/misc.py +470 -0
- onetick/py/oqd/__init__.py +22 -0
- onetick/py/oqd/eps.py +1195 -0
- onetick/py/oqd/sources.py +325 -0
- onetick/py/otq.py +216 -0
- onetick/py/pyomd_mock.py +47 -0
- onetick/py/run.py +916 -0
- onetick/py/servers.py +173 -0
- onetick/py/session.py +1347 -0
- onetick/py/sources/__init__.py +19 -0
- onetick/py/sources/cache.py +167 -0
- onetick/py/sources/common.py +128 -0
- onetick/py/sources/csv.py +642 -0
- onetick/py/sources/custom.py +85 -0
- onetick/py/sources/data_file.py +305 -0
- onetick/py/sources/data_source.py +1045 -0
- onetick/py/sources/empty.py +94 -0
- onetick/py/sources/odbc.py +337 -0
- onetick/py/sources/order_book.py +271 -0
- onetick/py/sources/parquet.py +168 -0
- onetick/py/sources/pit.py +191 -0
- onetick/py/sources/query.py +495 -0
- onetick/py/sources/snapshots.py +419 -0
- onetick/py/sources/split_query_output_by_symbol.py +198 -0
- onetick/py/sources/symbology_mapping.py +123 -0
- onetick/py/sources/symbols.py +374 -0
- onetick/py/sources/ticks.py +825 -0
- onetick/py/sql.py +70 -0
- onetick/py/state.py +251 -0
- onetick/py/types.py +2131 -0
- onetick/py/utils/__init__.py +70 -0
- onetick/py/utils/acl.py +93 -0
- onetick/py/utils/config.py +186 -0
- onetick/py/utils/default.py +49 -0
- onetick/py/utils/file.py +38 -0
- onetick/py/utils/helpers.py +76 -0
- onetick/py/utils/locator.py +94 -0
- onetick/py/utils/perf.py +498 -0
- onetick/py/utils/query.py +49 -0
- onetick/py/utils/render.py +1374 -0
- onetick/py/utils/script.py +244 -0
- onetick/py/utils/temp.py +471 -0
- onetick/py/utils/types.py +120 -0
- onetick/py/utils/tz.py +84 -0
- onetick_py-1.177.0.dist-info/METADATA +137 -0
- onetick_py-1.177.0.dist-info/RECORD +152 -0
- onetick_py-1.177.0.dist-info/WHEEL +5 -0
- onetick_py-1.177.0.dist-info/entry_points.txt +2 -0
- onetick_py-1.177.0.dist-info/licenses/LICENSE +21 -0
- onetick_py-1.177.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Iterable, Type, Union, Optional
|
|
4
|
+
from contextlib import suppress, contextmanager
|
|
5
|
+
from textwrap import dedent
|
|
6
|
+
|
|
7
|
+
import dotenv
|
|
8
|
+
from onetick.py.otq import otq
|
|
9
|
+
from .utils import default_license_dir, default_license_file, get_local_number_of_cores
|
|
10
|
+
import onetick.py.types as ott
|
|
11
|
+
|
|
12
|
+
DEFAULT_LICENSE_DIR = default_license_dir()
|
|
13
|
+
DEFAULT_LICENSE_FILE = default_license_file()
|
|
14
|
+
|
|
15
|
+
DATETIME_FORMATS = (
|
|
16
|
+
'%Y/%m/%d %H:%M:%S.%f',
|
|
17
|
+
'%Y/%m/%d %H:%M:%S',
|
|
18
|
+
)
|
|
19
|
+
DATETIME_DESCRIPTION = (
|
|
20
|
+
"Format of the env variable: "
|
|
21
|
+
f"{', '.join(':code:`{}`'.format(fmt) for fmt in DATETIME_FORMATS)}."
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def parse_datetime(s):
|
|
26
|
+
for fmt in DATETIME_FORMATS:
|
|
27
|
+
with suppress(ValueError):
|
|
28
|
+
return datetime.strptime(s, fmt)
|
|
29
|
+
raise ValueError(
|
|
30
|
+
f"The datetime pattern is not supported for string '{s}'. "
|
|
31
|
+
f"Available patterns: {DATETIME_FORMATS}"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def parse_bool(value) -> Optional[bool]:
|
|
36
|
+
str_value = str(value).lower()
|
|
37
|
+
if str_value in ('1', 'true', 'yes'):
|
|
38
|
+
return True
|
|
39
|
+
elif str_value in ('0', 'false', 'no'):
|
|
40
|
+
return False
|
|
41
|
+
else:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def parse_true(value) -> bool:
|
|
46
|
+
return parse_bool(value) is True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def parse_bool_or_string(value) -> Union[bool, str]:
|
|
50
|
+
parsed_value = parse_bool(value)
|
|
51
|
+
if parsed_value is not None:
|
|
52
|
+
return parsed_value
|
|
53
|
+
else:
|
|
54
|
+
return str(value)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _env_func_concurrency(value: str) -> Optional[int]:
|
|
58
|
+
if not value:
|
|
59
|
+
return None
|
|
60
|
+
if value == 'local_number_of_cores':
|
|
61
|
+
return get_local_number_of_cores()
|
|
62
|
+
return int(value)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def default_query_concurrency():
|
|
66
|
+
concurrency = config.default_concurrency
|
|
67
|
+
if concurrency is None:
|
|
68
|
+
from onetick.py.compatibility import is_zero_concurrency_supported
|
|
69
|
+
# TODO: this logic should be in the default value of otp.config.default_concurrency,
|
|
70
|
+
# but there are complex problems with circular import in this case
|
|
71
|
+
if is_zero_concurrency_supported():
|
|
72
|
+
concurrency = 0
|
|
73
|
+
else:
|
|
74
|
+
concurrency = 1
|
|
75
|
+
return concurrency
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def default_presort_concurrency():
|
|
79
|
+
if config.presort_force_default_concurrency:
|
|
80
|
+
return default_query_concurrency()
|
|
81
|
+
else:
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class _nothing(type):
|
|
86
|
+
def __repr__(cls):
|
|
87
|
+
return cls.__name__
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class nothing(metaclass=_nothing):
|
|
91
|
+
"""
|
|
92
|
+
This is nothing.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class OtpProperty:
|
|
97
|
+
"""
|
|
98
|
+
.. attribute:: {name}
|
|
99
|
+
:type: {base_type}
|
|
100
|
+
:value: {base_value}
|
|
101
|
+
|
|
102
|
+
{description}
|
|
103
|
+
|
|
104
|
+
{env_var_name}
|
|
105
|
+
|
|
106
|
+
{env_var_desc}
|
|
107
|
+
"""
|
|
108
|
+
def __init__(self, description, base_default, env_var_name=None, env_var_func=None,
|
|
109
|
+
env_var_desc=None, set_value=nothing, allowed_types: Union[Type, Iterable] = nothing,
|
|
110
|
+
validator_func=None):
|
|
111
|
+
self._base_default = base_default
|
|
112
|
+
self._env_var_name = env_var_name
|
|
113
|
+
self._env_var_func = env_var_func
|
|
114
|
+
self._env_var_desc = env_var_desc
|
|
115
|
+
self._set_value = set_value
|
|
116
|
+
self._description = description
|
|
117
|
+
if self._base_default is nothing:
|
|
118
|
+
self._allowed_types = []
|
|
119
|
+
else:
|
|
120
|
+
self._allowed_types = [type(self._base_default)]
|
|
121
|
+
if allowed_types is not nothing:
|
|
122
|
+
if isinstance(allowed_types, Iterable):
|
|
123
|
+
self._allowed_types.extend(allowed_types)
|
|
124
|
+
else:
|
|
125
|
+
self._allowed_types.append(allowed_types)
|
|
126
|
+
self._allowed_types = tuple(set(self._allowed_types)) # type: ignore[assignment]
|
|
127
|
+
# will be monkeypatched later
|
|
128
|
+
self._name = None
|
|
129
|
+
if validator_func is None:
|
|
130
|
+
self._validator_func = lambda x: x
|
|
131
|
+
else:
|
|
132
|
+
self._validator_func = validator_func
|
|
133
|
+
|
|
134
|
+
def _get_doc(self, name):
|
|
135
|
+
env_var_name = ''
|
|
136
|
+
env_var_desc = ''
|
|
137
|
+
if self._env_var_name is not None:
|
|
138
|
+
env_var_name = f'Can be set using environment variable :envvar:`{self._env_var_name}`.'
|
|
139
|
+
if self._env_var_desc is not None:
|
|
140
|
+
env_var_desc = self._env_var_desc
|
|
141
|
+
return self.__class__.__doc__.format(
|
|
142
|
+
name=name,
|
|
143
|
+
description=self._description,
|
|
144
|
+
base_type=','.join(t.__name__ for t in self._allowed_types),
|
|
145
|
+
base_value=repr(self._base_default),
|
|
146
|
+
env_var_name=env_var_name,
|
|
147
|
+
env_var_desc=env_var_desc
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def __get__(self, obj, objtype=None):
|
|
151
|
+
if self._set_value is not nothing:
|
|
152
|
+
return self._set_value
|
|
153
|
+
if self._env_var_name:
|
|
154
|
+
env_var_value = os.environ.get(self._env_var_name, None)
|
|
155
|
+
if env_var_value is not None:
|
|
156
|
+
if self._env_var_func:
|
|
157
|
+
return self._env_var_func(env_var_value)
|
|
158
|
+
return env_var_value
|
|
159
|
+
if obj is not None:
|
|
160
|
+
# get value from default config
|
|
161
|
+
if self._env_var_name and self._env_var_name in obj.default_config:
|
|
162
|
+
var_value = obj.default_config[self._env_var_name]
|
|
163
|
+
if self._env_var_func:
|
|
164
|
+
return self._env_var_func(var_value)
|
|
165
|
+
return var_value
|
|
166
|
+
if self._base_default is nothing:
|
|
167
|
+
raise ValueError(f'onetick.py.config.{self._name} is not set!')
|
|
168
|
+
return self._base_default
|
|
169
|
+
|
|
170
|
+
def __set__(self, obj, value):
|
|
171
|
+
# assigning to nothing is permitted
|
|
172
|
+
# assigning to nothing will reset value to default
|
|
173
|
+
if not isinstance(value, self._allowed_types) and value is not nothing:
|
|
174
|
+
raise ValueError(f'Type of passed configuration value "{type(value)}" should be one of '
|
|
175
|
+
f'the allowed types for this configuration {self._allowed_types}')
|
|
176
|
+
if value is nothing:
|
|
177
|
+
self._set_value = value
|
|
178
|
+
else:
|
|
179
|
+
self._set_value = self._validator_func(value)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class OtpDerivedProperty:
|
|
183
|
+
"""
|
|
184
|
+
.. attribute:: {name}
|
|
185
|
+
:type: {base_type}
|
|
186
|
+
:value: {base_value}
|
|
187
|
+
|
|
188
|
+
{description}
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
def __init__(self, description, definition_function):
|
|
192
|
+
self._description = description
|
|
193
|
+
self.__definition_function = definition_function
|
|
194
|
+
|
|
195
|
+
def __get__(self, obj, objtype=None):
|
|
196
|
+
return self.__definition_function(obj)
|
|
197
|
+
|
|
198
|
+
def _get_doc(self, name, base_object):
|
|
199
|
+
value = self.__definition_function(base_object, docs=True)
|
|
200
|
+
return self.__doc__.format(
|
|
201
|
+
name=name,
|
|
202
|
+
description=self._description,
|
|
203
|
+
base_type=type(value).__name__,
|
|
204
|
+
base_value=value,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def __set__(self, obj, value):
|
|
208
|
+
raise AttributeError('It\'s not allowed to change a derived property. Change source properties, and its value '
|
|
209
|
+
'will be updated automatically.')
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class OtpShowStackInfoProperty(OtpProperty):
|
|
213
|
+
"""
|
|
214
|
+
.. attribute:: {name}
|
|
215
|
+
:type: {base_type}
|
|
216
|
+
:value: {base_value}
|
|
217
|
+
|
|
218
|
+
{description}
|
|
219
|
+
"""
|
|
220
|
+
@staticmethod
|
|
221
|
+
def parser(value):
|
|
222
|
+
return parse_true(value)
|
|
223
|
+
|
|
224
|
+
def __init__(self, *args, **kwargs):
|
|
225
|
+
super().__init__(*args, **kwargs)
|
|
226
|
+
# set default value on module loading
|
|
227
|
+
self.__set_in_onetick_query__()
|
|
228
|
+
|
|
229
|
+
def __get__(self, obj, objtype=None):
|
|
230
|
+
value = super().__get__(obj, objtype)
|
|
231
|
+
return self.parser(value)
|
|
232
|
+
|
|
233
|
+
def __set__(self, obj, value):
|
|
234
|
+
super().__set__(obj, value)
|
|
235
|
+
self.__set_in_onetick_query__()
|
|
236
|
+
|
|
237
|
+
def __set_in_onetick_query__(self):
|
|
238
|
+
value = 1 if self.__get__(None) else 0
|
|
239
|
+
otq.API_CONFIG['SHOW_STACK_INFO'] = value
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def document_config(cls):
|
|
243
|
+
manually_set_properties_doc = ''
|
|
244
|
+
changeable_properties_doc = ''
|
|
245
|
+
derived_properties_doc = ''
|
|
246
|
+
|
|
247
|
+
manually_set_options = cls.manually_set_options()
|
|
248
|
+
for b in manually_set_options:
|
|
249
|
+
manually_set_properties_doc += cls.__dict__[b]._get_doc(b)
|
|
250
|
+
for c in cls.get_changeable_config_options():
|
|
251
|
+
cls.__dict__[c]._name = c
|
|
252
|
+
if c not in manually_set_options:
|
|
253
|
+
changeable_properties_doc += cls.__dict__[c]._get_doc(c)
|
|
254
|
+
for d in cls.get_derived_config_options():
|
|
255
|
+
cls.__dict__[d]._name = d
|
|
256
|
+
derived_properties_doc += cls.__dict__[d]._get_doc(d, base_object=cls)
|
|
257
|
+
|
|
258
|
+
cls.__doc__ = cls.__doc__.format(
|
|
259
|
+
manually_set_properties=manually_set_properties_doc,
|
|
260
|
+
changeable_properties=changeable_properties_doc,
|
|
261
|
+
derived_properties=derived_properties_doc,
|
|
262
|
+
)
|
|
263
|
+
cls.__doc__ = dedent(cls.__doc__)
|
|
264
|
+
|
|
265
|
+
return cls
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@document_config
|
|
269
|
+
class Config:
|
|
270
|
+
"""
|
|
271
|
+
This object is used to access ``onetick.py`` configuration variables.
|
|
272
|
+
|
|
273
|
+
Configuration variables may be accessed via :code:`otp.config['...']` syntax, e.g. :code:`otp.config['tz']`.
|
|
274
|
+
|
|
275
|
+
Configuration variables may be changed by:
|
|
276
|
+
|
|
277
|
+
* during python runtime by modifying properties of object ``otp.config``,
|
|
278
|
+
* by setting environment variables *before* importing ``onetick.py`` module.
|
|
279
|
+
|
|
280
|
+
During python runtime you can modify properties of ``otp.config`` object either directly or via context manager:
|
|
281
|
+
``with otp.config('property', 'value'):``
|
|
282
|
+
|
|
283
|
+
Also special environment variable ``OTP_DEFAULT_CONFIG_PATH`` can be used to specify a file,
|
|
284
|
+
from which configuration variables will be taken.
|
|
285
|
+
This file will be read only once on module loading or when getting one of the configuration variables
|
|
286
|
+
when the environment variable is discovered.
|
|
287
|
+
The names of the variables in this file are the same as the names of environment variables.
|
|
288
|
+
|
|
289
|
+
In case several methods of setting configuration variables are used,
|
|
290
|
+
the following order of priority is in place:
|
|
291
|
+
|
|
292
|
+
1. Value that is set by modifying object ``otp.config``
|
|
293
|
+
2. Value that is set via environment variable
|
|
294
|
+
3. Value that is set in file ``OTP_DEFAULT_CONFIG_PATH``
|
|
295
|
+
4. Default value specified in the source code
|
|
296
|
+
|
|
297
|
+
To reset configuration value that has been set by modifying object ``otp.config``,
|
|
298
|
+
special value ``otp.config.default`` should be assigned to it.
|
|
299
|
+
|
|
300
|
+
Most of the config vars are optional and have default values,
|
|
301
|
+
but some of them need to be set manually.
|
|
302
|
+
|
|
303
|
+
There are also some environment variables that do not have
|
|
304
|
+
corresponding property in ``otp.config`` object:
|
|
305
|
+
|
|
306
|
+
* ``OTP_BASE_FOLDER_FOR_GENERATED_RESOURCE``:
|
|
307
|
+
a folder where all intermediate queries, files and databases
|
|
308
|
+
generated by ``onetick-py`` are located.
|
|
309
|
+
The default value is system-dependent, e.g. some generated
|
|
310
|
+
directory with a unique name under a standard directory **/tmp** for Linux.
|
|
311
|
+
|
|
312
|
+
**The following properties must be set manually in most cases:**
|
|
313
|
+
{manually_set_properties}
|
|
314
|
+
|
|
315
|
+
**The following properties can be changed:**
|
|
316
|
+
{changeable_properties}
|
|
317
|
+
|
|
318
|
+
**The following properties are derived and thus read-only:**
|
|
319
|
+
{derived_properties}
|
|
320
|
+
"""
|
|
321
|
+
__default_config = None
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def default_config(self):
|
|
325
|
+
default_config_path = os.environ.get('OTP_DEFAULT_CONFIG_PATH')
|
|
326
|
+
if not default_config_path:
|
|
327
|
+
return {}
|
|
328
|
+
if self.__default_config is None:
|
|
329
|
+
default_config = dotenv.dotenv_values(default_config_path)
|
|
330
|
+
available_option_names = []
|
|
331
|
+
for name, option in self.get_changeable_config_options().items():
|
|
332
|
+
if option._env_var_name:
|
|
333
|
+
available_option_names.append(option._env_var_name)
|
|
334
|
+
diff = set(default_config).difference(available_option_names)
|
|
335
|
+
if diff:
|
|
336
|
+
raise ValueError(f'Configuration options {diff} from file'
|
|
337
|
+
f' OTP_DEFAULT_CONFIG_PATH="{default_config_path}" are not supported.'
|
|
338
|
+
f' Available options: {available_option_names}.')
|
|
339
|
+
Config.__default_config = default_config
|
|
340
|
+
return self.__default_config or {}
|
|
341
|
+
|
|
342
|
+
def __getitem__(self, item):
|
|
343
|
+
if item not in self.__class__.__dict__.keys():
|
|
344
|
+
raise AttributeError(f'"{item}" is not in the list of onetick.py config options!')
|
|
345
|
+
return self.__class__.__dict__[item].__get__(self)
|
|
346
|
+
|
|
347
|
+
def __setitem__(self, item, value):
|
|
348
|
+
if item not in self.__class__.__dict__.keys():
|
|
349
|
+
raise AttributeError(f'"{item}" is not in the list of onetick.py config options!')
|
|
350
|
+
self.__class__.__dict__[item].__set__(self, value)
|
|
351
|
+
|
|
352
|
+
def get(self, key, default=None):
|
|
353
|
+
try:
|
|
354
|
+
return self.__getitem__(key)
|
|
355
|
+
except ValueError:
|
|
356
|
+
return default
|
|
357
|
+
|
|
358
|
+
def __setattr__(self, item, value):
|
|
359
|
+
"""
|
|
360
|
+
To avoid accidental declaration of non-existing properties, e.g. `otp.config.timezone = "GMT"`
|
|
361
|
+
"""
|
|
362
|
+
self.__setitem__(item, value)
|
|
363
|
+
|
|
364
|
+
@contextmanager
|
|
365
|
+
def __call__(self, name, value):
|
|
366
|
+
old_value = self[name]
|
|
367
|
+
try:
|
|
368
|
+
self[name] = value
|
|
369
|
+
yield
|
|
370
|
+
finally:
|
|
371
|
+
self[name] = old_value
|
|
372
|
+
|
|
373
|
+
@classmethod
|
|
374
|
+
def get_changeable_config_options(cls):
|
|
375
|
+
"""
|
|
376
|
+
useful for tests where you may want to memorize all existing configuration options before changing them
|
|
377
|
+
"""
|
|
378
|
+
return {
|
|
379
|
+
option: value
|
|
380
|
+
for option, value in cls.__dict__.items()
|
|
381
|
+
if isinstance(value, OtpProperty)
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@classmethod
|
|
385
|
+
def get_derived_config_options(cls):
|
|
386
|
+
return {
|
|
387
|
+
option: value
|
|
388
|
+
for option, value in cls.__dict__.items()
|
|
389
|
+
if isinstance(value, OtpDerivedProperty)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
@classmethod
|
|
393
|
+
def manually_set_options(cls):
|
|
394
|
+
return {
|
|
395
|
+
option: value
|
|
396
|
+
for option, value in cls.__dict__.items()
|
|
397
|
+
if isinstance(value, OtpProperty) and value._base_default is nothing
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
default = nothing
|
|
401
|
+
|
|
402
|
+
tz = OtpProperty(
|
|
403
|
+
description='Default timezone used for running queries and creating databases, '
|
|
404
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`. '
|
|
405
|
+
'Default value is the local timezone of your machine.',
|
|
406
|
+
base_default=None,
|
|
407
|
+
allowed_types=str,
|
|
408
|
+
env_var_name='OTP_DEFAULT_TZ',
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
context = OtpProperty(
|
|
412
|
+
description='Default context used for running queries, '
|
|
413
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`.'
|
|
414
|
+
'Note: In WebAPI mode it will have `None` value.',
|
|
415
|
+
base_default='DEFAULT' if not otq.webapi else None,
|
|
416
|
+
allowed_types=[str],
|
|
417
|
+
env_var_name='OTP_CONTEXT',
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
default_start_time = OtpProperty(
|
|
421
|
+
description='Default start time used for running queries, '
|
|
422
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`.',
|
|
423
|
+
base_default=nothing,
|
|
424
|
+
allowed_types=[datetime, ott.datetime],
|
|
425
|
+
env_var_name='OTP_DEFAULT_START_TIME',
|
|
426
|
+
env_var_func=parse_datetime,
|
|
427
|
+
env_var_desc=DATETIME_DESCRIPTION,
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
default_end_time = OtpProperty(
|
|
431
|
+
description='Default end time used for running queries, '
|
|
432
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`.',
|
|
433
|
+
base_default=nothing,
|
|
434
|
+
allowed_types=[datetime, ott.datetime],
|
|
435
|
+
env_var_name='OTP_DEFAULT_END_TIME',
|
|
436
|
+
env_var_func=parse_datetime,
|
|
437
|
+
env_var_desc=DATETIME_DESCRIPTION,
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
default_db = OtpProperty(
|
|
441
|
+
description='Default database name used for running queries, '
|
|
442
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`.',
|
|
443
|
+
base_default=nothing,
|
|
444
|
+
allowed_types=str,
|
|
445
|
+
env_var_name='OTP_DEFAULT_DB',
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
default_symbol = OtpProperty(
|
|
449
|
+
description='Default symbol name used for running queries, '
|
|
450
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`.',
|
|
451
|
+
base_default=nothing,
|
|
452
|
+
allowed_types=str,
|
|
453
|
+
env_var_name='OTP_DEFAULT_SYMBOL',
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
default_symbology = OtpProperty(
|
|
457
|
+
description='Default database symbology.',
|
|
458
|
+
base_default='BZX',
|
|
459
|
+
env_var_name='OTP_DEFAULT_SYMBOLOGY',
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
def _default_db_symbol(obj, docs=False): # noqa
|
|
463
|
+
try:
|
|
464
|
+
return obj.default_db + '::' + obj.default_symbol
|
|
465
|
+
except (ValueError, TypeError):
|
|
466
|
+
if not docs:
|
|
467
|
+
raise
|
|
468
|
+
|
|
469
|
+
default_db_symbol = OtpDerivedProperty(
|
|
470
|
+
description='Default symbol with database. '
|
|
471
|
+
'Defined with :py:attr:`default_db` and :py:attr:`default_symbol` '
|
|
472
|
+
'as string **default_db::default_symbol**.',
|
|
473
|
+
definition_function=_default_db_symbol,
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
def _default_date(obj, docs=False): # noqa
|
|
477
|
+
try:
|
|
478
|
+
return datetime.combine(obj.default_start_time.date(), datetime.min.time())
|
|
479
|
+
except (ValueError, TypeError, AttributeError):
|
|
480
|
+
if not docs:
|
|
481
|
+
raise
|
|
482
|
+
|
|
483
|
+
default_date = OtpDerivedProperty(
|
|
484
|
+
description='Default date. '
|
|
485
|
+
'Defined as a date part of :py:attr:`default_start_time`.',
|
|
486
|
+
definition_function=_default_date,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
default_concurrency = OtpProperty(
|
|
490
|
+
description='Default concurrency level used for running queries, '
|
|
491
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`. '
|
|
492
|
+
'Default value is ``None`` which means that the value is adaptive '
|
|
493
|
+
'and is set to 0 (meaning concurrency will be auto-assigned by OneTick server) '
|
|
494
|
+
'on the latest OneTick versions where it is supported '
|
|
495
|
+
'or to 1 (meaning no concurrency) on older versions. '
|
|
496
|
+
'Special value ``local_number_of_cores`` can be used to set concurrency '
|
|
497
|
+
'to the number of cores of the machine where python code executes '
|
|
498
|
+
'(this corresponds to the previous default logic still expected by some users).',
|
|
499
|
+
base_default=None,
|
|
500
|
+
allowed_types=[type(None), int, str],
|
|
501
|
+
env_var_name='OTP_DEFAULT_CONCURRENCY',
|
|
502
|
+
env_var_func=_env_func_concurrency,
|
|
503
|
+
validator_func=lambda x: _env_func_concurrency(str(x) if x is not None else '')
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
presort_force_default_concurrency = OtpProperty(
|
|
507
|
+
description='By default concurrency value for PRESORT EPs is empty '
|
|
508
|
+
'and inherited from the concurrency level set in the query where this EP is used. '
|
|
509
|
+
'However, is some cases it may be desirable '
|
|
510
|
+
'to force setting default concurrency level for all PRESORT EPs '
|
|
511
|
+
'(this corresponds to the previous default logic still expected by some users), '
|
|
512
|
+
'for example when PRESORT is located in the first stage query and cannot inherit '
|
|
513
|
+
'concurrency from the main query.',
|
|
514
|
+
base_default=False,
|
|
515
|
+
allowed_types=[bool],
|
|
516
|
+
env_var_name='OTP_PRESORT_FORCE_DEFAULT_CONCURRENCY',
|
|
517
|
+
env_var_func=parse_true,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# default batch size is set to 0, so the number of symbols in batch is not limited
|
|
521
|
+
# it should work better in simple cases, but may use too much memory for complex queries
|
|
522
|
+
default_batch_size = OtpProperty(
|
|
523
|
+
description='Default batch size used for running queries, '
|
|
524
|
+
'e.g. with :py:func:`otp.run<onetick.py.run>`. '
|
|
525
|
+
'Batch size is the maximum number of symbols that are processed at once. '
|
|
526
|
+
'The value of 0 means unlimited -- works faster for simple queries, '
|
|
527
|
+
'but may consume too much memory for complex queries.',
|
|
528
|
+
base_default=0,
|
|
529
|
+
env_var_name='OTP_DEFAULT_BATCH_SIZE',
|
|
530
|
+
env_var_func=int,
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
default_license_dir = OtpProperty(
|
|
534
|
+
description='Default path for license directory. '
|
|
535
|
+
'Needed for user to be allowed to use OneTick API. '
|
|
536
|
+
'Default value is system-dependent: '
|
|
537
|
+
'**/license** for Linux systems and '
|
|
538
|
+
'**C:/OMD/client_data/config/license_repository** for Windows systems.',
|
|
539
|
+
base_default=DEFAULT_LICENSE_DIR,
|
|
540
|
+
env_var_name='OTP_DEFAULT_LICENSE_DIR',
|
|
541
|
+
allowed_types=str,
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
default_license_file = OtpProperty(
|
|
545
|
+
description='Default path for license file. '
|
|
546
|
+
'Needed for user to be allowed to use OneTick API. '
|
|
547
|
+
'Default value is system-dependent: '
|
|
548
|
+
'**/license/license.dat** for Linux systems and '
|
|
549
|
+
'**C:/OMD/client_data/config/license.dat** for Windows systems.',
|
|
550
|
+
base_default=DEFAULT_LICENSE_FILE,
|
|
551
|
+
env_var_name='OTP_DEFAULT_LICENSE_FILE',
|
|
552
|
+
allowed_types=str,
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
default_fault_tolerance = OtpProperty(
|
|
556
|
+
description='Default value for USE_FT query property.',
|
|
557
|
+
base_default='FALSE',
|
|
558
|
+
env_var_name='OTP_DEFAULT_FAULT_TOLERANCE',
|
|
559
|
+
allowed_types=str,
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
default_username = OtpProperty(
|
|
563
|
+
description='Default username to call queries. '
|
|
564
|
+
'By default the name of the owner of the current process is used.',
|
|
565
|
+
base_default=None,
|
|
566
|
+
allowed_types=str,
|
|
567
|
+
env_var_name='OTP_DEFAULT_USERNAME',
|
|
568
|
+
)
|
|
569
|
+
|
|
570
|
+
default_auth_username = OtpProperty(
|
|
571
|
+
description='Default username used for authentication.',
|
|
572
|
+
base_default=None,
|
|
573
|
+
allowed_types=str,
|
|
574
|
+
env_var_name='OTP_DEFAULT_AUTH_USERNAME',
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
default_password = OtpProperty(
|
|
578
|
+
description='Default password used for authentication.',
|
|
579
|
+
base_default=None,
|
|
580
|
+
allowed_types=str,
|
|
581
|
+
env_var_name='OTP_DEFAULT_PASSWORD',
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
http_address = OtpProperty(
|
|
585
|
+
description='Default HTTP server used as WebAPI endpoint.',
|
|
586
|
+
base_default=None,
|
|
587
|
+
allowed_types=str,
|
|
588
|
+
env_var_name='OTP_HTTP_ADDRESS',
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
http_username = OtpProperty(
|
|
592
|
+
description='Username used for WebAPI authentication.',
|
|
593
|
+
base_default=None,
|
|
594
|
+
allowed_types=str,
|
|
595
|
+
env_var_name='OTP_HTTP_USERNAME',
|
|
596
|
+
)
|
|
597
|
+
|
|
598
|
+
http_password = OtpProperty(
|
|
599
|
+
description='Password used for WebAPI authentication.',
|
|
600
|
+
base_default=None,
|
|
601
|
+
allowed_types=str,
|
|
602
|
+
env_var_name='OTP_HTTP_PASSWORD',
|
|
603
|
+
)
|
|
604
|
+
|
|
605
|
+
http_proxy = OtpProperty(
|
|
606
|
+
description='HTTP proxy used for WebAPI requests.',
|
|
607
|
+
base_default=None,
|
|
608
|
+
allowed_types=str,
|
|
609
|
+
env_var_name='HTTP_PROXY',
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
https_proxy = OtpProperty(
|
|
613
|
+
description='HTTPS proxy used for WebAPI requests.',
|
|
614
|
+
base_default=None,
|
|
615
|
+
allowed_types=str,
|
|
616
|
+
env_var_name='HTTPS_PROXY',
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
access_token = OtpProperty(
|
|
620
|
+
description='SSO access token for WebAPI endpoint.',
|
|
621
|
+
base_default=None,
|
|
622
|
+
allowed_types=str,
|
|
623
|
+
env_var_name='OTP_ACCESS_TOKEN',
|
|
624
|
+
)
|
|
625
|
+
|
|
626
|
+
client_id = OtpProperty(
|
|
627
|
+
description='Client ID for obtaining SSO access token.',
|
|
628
|
+
base_default=None,
|
|
629
|
+
allowed_types=str,
|
|
630
|
+
env_var_name='OTP_CLIENT_ID',
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
client_secret = OtpProperty(
|
|
634
|
+
description='Client Secret for obtaining SSO access token.',
|
|
635
|
+
base_default=None,
|
|
636
|
+
allowed_types=str,
|
|
637
|
+
env_var_name='OTP_CLIENT_SECRET',
|
|
638
|
+
)
|
|
639
|
+
|
|
640
|
+
access_token_url = OtpProperty(
|
|
641
|
+
description='URL for obtaining SSO access token.',
|
|
642
|
+
base_default=None,
|
|
643
|
+
allowed_types=str,
|
|
644
|
+
env_var_name='OTP_ACCESS_TOKEN_URL',
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
trusted_certificates_file = OtpProperty(
|
|
648
|
+
description='Either a boolean, in which case it controls whether we verify the server TLS certificate '
|
|
649
|
+
'or a string with the path to the file with list of '
|
|
650
|
+
'trusted Certificate Authority certificates for WebAPI requests. '
|
|
651
|
+
'Default behaviour implies verification is enabled.',
|
|
652
|
+
base_default=None,
|
|
653
|
+
allowed_types=(bool, str),
|
|
654
|
+
env_var_name='OTP_SSL_CERT_FILE',
|
|
655
|
+
env_var_func=parse_bool_or_string,
|
|
656
|
+
)
|
|
657
|
+
|
|
658
|
+
max_expected_ticks_per_symbol = OtpProperty(
|
|
659
|
+
description='Expected maximum number of ticks per symbol (used for performance optimizations). '
|
|
660
|
+
'Default is 2000.',
|
|
661
|
+
base_default=None,
|
|
662
|
+
allowed_types=int,
|
|
663
|
+
env_var_name='OTP_MAX_EXPECTED_TICKS_PER_SYMBOL',
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
show_stack_info = OtpShowStackInfoProperty(
|
|
667
|
+
description='Show stack info (filename and line or stack trace) in OneTick exceptions.',
|
|
668
|
+
base_default=False,
|
|
669
|
+
allowed_types=(str, bool, int),
|
|
670
|
+
env_var_name='OTP_SHOW_STACK_INFO',
|
|
671
|
+
env_var_func=parse_true,
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
log_symbol = OtpProperty(
|
|
675
|
+
description='Log currently executed symbol. Note, this only works with unbound symbols. '
|
|
676
|
+
'Note, in this case :py:func:`otp.run<onetick.py.run>` does not produce the output '
|
|
677
|
+
'so it should be used only for debugging purposes.',
|
|
678
|
+
base_default=False,
|
|
679
|
+
allowed_types=(str, bool, int),
|
|
680
|
+
env_var_name='OTP_LOG_SYMBOL',
|
|
681
|
+
env_var_func=parse_true,
|
|
682
|
+
)
|
|
683
|
+
|
|
684
|
+
ignore_ticks_in_unentitled_time_range = OtpProperty(
|
|
685
|
+
description='Default value for IGNORE_TICKS_IN_UNENTITLED_TIME_RANGE query property.',
|
|
686
|
+
base_default=False,
|
|
687
|
+
env_var_name='OTP_IGNORE_TICKS_IN_UNENTITLED_TIME_RANGE',
|
|
688
|
+
allowed_types=(str, bool, int),
|
|
689
|
+
env_var_func=parse_true,
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
main_query_generated_filename = OtpProperty(
|
|
693
|
+
description='The name of the .otq file with generated main query executed by otp.run.',
|
|
694
|
+
base_default='',
|
|
695
|
+
env_var_name='OTP_MAIN_QUERY_GENERATED_FILENAME',
|
|
696
|
+
allowed_types=str,
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
logging = OtpProperty(
|
|
700
|
+
description='The logging level string or path to the file with configuration. '
|
|
701
|
+
'Check the documentation of python logging module for the configuration formats. '
|
|
702
|
+
'JSON format (in the file with .json suffix) and python configparser formats are supported.',
|
|
703
|
+
base_default='WARNING',
|
|
704
|
+
env_var_name='OTP_LOGGING',
|
|
705
|
+
allowed_types=str,
|
|
706
|
+
)
|
|
707
|
+
|
|
708
|
+
otq_debug_mode = OtpProperty(
|
|
709
|
+
description='Enable .otq files debug mode. '
|
|
710
|
+
'If set to True, onetick.py will keep all generated otq files and '
|
|
711
|
+
'log their paths to the console.',
|
|
712
|
+
base_default=False,
|
|
713
|
+
env_var_name='OTP_OTQ_DEBUG_MODE',
|
|
714
|
+
allowed_types=(str, bool, int),
|
|
715
|
+
env_var_func=parse_true,
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
allow_lowercase_in_saved_fields = OtpProperty(
|
|
719
|
+
description='Allow using lower case characters in field names that are being stored in Onetick databases. '
|
|
720
|
+
'If set to False, onetick.py would not allow saving fields with lower case characters '
|
|
721
|
+
'to a database.',
|
|
722
|
+
base_default=True,
|
|
723
|
+
allowed_types=bool,
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
clean_up_tmp_files = OtpProperty(
|
|
727
|
+
description='Control deleting temporary files created by onetick-py. '
|
|
728
|
+
'Temporary files are OneTick configuration files and generated .otq queries.',
|
|
729
|
+
base_default=True,
|
|
730
|
+
env_var_name='OTP_CLEAN_UP_TMP_FILES',
|
|
731
|
+
allowed_types=(str, bool, int),
|
|
732
|
+
env_var_func=parse_true,
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
default_schema_policy = OtpProperty(
|
|
736
|
+
description='Default schema policy when querying onetick database. '
|
|
737
|
+
'See parameter ``schema_policy`` in :class:`otp.DataSource <onetick.py.DataSource>` '
|
|
738
|
+
'for the list of supported values.',
|
|
739
|
+
base_default=None,
|
|
740
|
+
env_var_name='OTP_DEFAULT_SCHEMA_POLICY',
|
|
741
|
+
allowed_types=str,
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
disable_compatibility_checks = OtpProperty(
|
|
745
|
+
description='Disable compatibility checks when querying OneTick database. '
|
|
746
|
+
'Using this parameter outside test environment could lead to unexpected errors.',
|
|
747
|
+
base_default=False,
|
|
748
|
+
allowed_types=bool,
|
|
749
|
+
env_var_name='OTP_DISABLE_COMPATIBILITY_CHECKS',
|
|
750
|
+
)
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
def get_options_table(cls):
|
|
754
|
+
options_table = ('\n'
|
|
755
|
+
'.. csv-table::\n'
|
|
756
|
+
' :header: "Name", "Environment Variable", "Description"\n'
|
|
757
|
+
' :widths: auto\n\n')
|
|
758
|
+
for name, prop in cls.get_changeable_config_options().items():
|
|
759
|
+
name = f':py:attr:`otp.config.{name}<onetick.py.configuration.Config.{name}>`'
|
|
760
|
+
options_table += f' {name},"``{prop._env_var_name}``","{prop._description}"\n'
|
|
761
|
+
for name, prop in cls.get_derived_config_options().items():
|
|
762
|
+
name = f':py:attr:`otp.config.{name}<onetick.py.configuration.Config.{name}>`'
|
|
763
|
+
options_table += f' {name},"","{prop._description}"\n'
|
|
764
|
+
return options_table
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
class OptionsTable:
|
|
768
|
+
__doc__ = get_options_table(Config)
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
config = Config()
|