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.
Files changed (152) hide show
  1. locator_parser/__init__.py +0 -0
  2. locator_parser/acl.py +73 -0
  3. locator_parser/actions.py +262 -0
  4. locator_parser/common.py +368 -0
  5. locator_parser/io.py +43 -0
  6. locator_parser/locator.py +150 -0
  7. onetick/__init__.py +101 -0
  8. onetick/doc_utilities/__init__.py +3 -0
  9. onetick/doc_utilities/napoleon.py +40 -0
  10. onetick/doc_utilities/ot_doctest.py +140 -0
  11. onetick/doc_utilities/snippets.py +279 -0
  12. onetick/lib/__init__.py +4 -0
  13. onetick/lib/instance.py +141 -0
  14. onetick/py/__init__.py +293 -0
  15. onetick/py/_stack_info.py +89 -0
  16. onetick/py/_version.py +2 -0
  17. onetick/py/aggregations/__init__.py +11 -0
  18. onetick/py/aggregations/_base.py +648 -0
  19. onetick/py/aggregations/_docs.py +948 -0
  20. onetick/py/aggregations/compute.py +286 -0
  21. onetick/py/aggregations/functions.py +2216 -0
  22. onetick/py/aggregations/generic.py +104 -0
  23. onetick/py/aggregations/high_low.py +80 -0
  24. onetick/py/aggregations/num_distinct.py +83 -0
  25. onetick/py/aggregations/order_book.py +501 -0
  26. onetick/py/aggregations/other.py +1014 -0
  27. onetick/py/backports.py +26 -0
  28. onetick/py/cache.py +374 -0
  29. onetick/py/callback/__init__.py +5 -0
  30. onetick/py/callback/callback.py +276 -0
  31. onetick/py/callback/callbacks.py +131 -0
  32. onetick/py/compatibility.py +798 -0
  33. onetick/py/configuration.py +771 -0
  34. onetick/py/core/__init__.py +0 -0
  35. onetick/py/core/_csv_inspector.py +93 -0
  36. onetick/py/core/_internal/__init__.py +0 -0
  37. onetick/py/core/_internal/_manually_bound_value.py +6 -0
  38. onetick/py/core/_internal/_nodes_history.py +250 -0
  39. onetick/py/core/_internal/_op_utils/__init__.py +0 -0
  40. onetick/py/core/_internal/_op_utils/every_operand.py +9 -0
  41. onetick/py/core/_internal/_op_utils/is_const.py +10 -0
  42. onetick/py/core/_internal/_per_tick_scripts/tick_list_sort_template.script +121 -0
  43. onetick/py/core/_internal/_proxy_node.py +140 -0
  44. onetick/py/core/_internal/_state_objects.py +2312 -0
  45. onetick/py/core/_internal/_state_vars.py +93 -0
  46. onetick/py/core/_source/__init__.py +0 -0
  47. onetick/py/core/_source/_symbol_param.py +95 -0
  48. onetick/py/core/_source/schema.py +97 -0
  49. onetick/py/core/_source/source_methods/__init__.py +0 -0
  50. onetick/py/core/_source/source_methods/aggregations.py +809 -0
  51. onetick/py/core/_source/source_methods/applyers.py +296 -0
  52. onetick/py/core/_source/source_methods/columns.py +141 -0
  53. onetick/py/core/_source/source_methods/data_quality.py +301 -0
  54. onetick/py/core/_source/source_methods/debugs.py +272 -0
  55. onetick/py/core/_source/source_methods/drops.py +120 -0
  56. onetick/py/core/_source/source_methods/fields.py +619 -0
  57. onetick/py/core/_source/source_methods/filters.py +1002 -0
  58. onetick/py/core/_source/source_methods/joins.py +1413 -0
  59. onetick/py/core/_source/source_methods/merges.py +605 -0
  60. onetick/py/core/_source/source_methods/misc.py +1455 -0
  61. onetick/py/core/_source/source_methods/pandases.py +155 -0
  62. onetick/py/core/_source/source_methods/renames.py +356 -0
  63. onetick/py/core/_source/source_methods/sorts.py +183 -0
  64. onetick/py/core/_source/source_methods/switches.py +142 -0
  65. onetick/py/core/_source/source_methods/symbols.py +117 -0
  66. onetick/py/core/_source/source_methods/times.py +627 -0
  67. onetick/py/core/_source/source_methods/writes.py +986 -0
  68. onetick/py/core/_source/symbol.py +205 -0
  69. onetick/py/core/_source/tmp_otq.py +222 -0
  70. onetick/py/core/column.py +209 -0
  71. onetick/py/core/column_operations/__init__.py +0 -0
  72. onetick/py/core/column_operations/_methods/__init__.py +4 -0
  73. onetick/py/core/column_operations/_methods/_internal.py +28 -0
  74. onetick/py/core/column_operations/_methods/conversions.py +216 -0
  75. onetick/py/core/column_operations/_methods/methods.py +292 -0
  76. onetick/py/core/column_operations/_methods/op_types.py +160 -0
  77. onetick/py/core/column_operations/accessors/__init__.py +0 -0
  78. onetick/py/core/column_operations/accessors/_accessor.py +28 -0
  79. onetick/py/core/column_operations/accessors/decimal_accessor.py +104 -0
  80. onetick/py/core/column_operations/accessors/dt_accessor.py +537 -0
  81. onetick/py/core/column_operations/accessors/float_accessor.py +184 -0
  82. onetick/py/core/column_operations/accessors/str_accessor.py +1367 -0
  83. onetick/py/core/column_operations/base.py +1121 -0
  84. onetick/py/core/cut_builder.py +150 -0
  85. onetick/py/core/db_constants.py +20 -0
  86. onetick/py/core/eval_query.py +245 -0
  87. onetick/py/core/lambda_object.py +441 -0
  88. onetick/py/core/multi_output_source.py +232 -0
  89. onetick/py/core/per_tick_script.py +2256 -0
  90. onetick/py/core/query_inspector.py +464 -0
  91. onetick/py/core/source.py +1744 -0
  92. onetick/py/db/__init__.py +2 -0
  93. onetick/py/db/_inspection.py +1128 -0
  94. onetick/py/db/db.py +1327 -0
  95. onetick/py/db/utils.py +64 -0
  96. onetick/py/docs/__init__.py +0 -0
  97. onetick/py/docs/docstring_parser.py +112 -0
  98. onetick/py/docs/utils.py +81 -0
  99. onetick/py/functions.py +2398 -0
  100. onetick/py/license.py +190 -0
  101. onetick/py/log.py +88 -0
  102. onetick/py/math.py +935 -0
  103. onetick/py/misc.py +470 -0
  104. onetick/py/oqd/__init__.py +22 -0
  105. onetick/py/oqd/eps.py +1195 -0
  106. onetick/py/oqd/sources.py +325 -0
  107. onetick/py/otq.py +216 -0
  108. onetick/py/pyomd_mock.py +47 -0
  109. onetick/py/run.py +916 -0
  110. onetick/py/servers.py +173 -0
  111. onetick/py/session.py +1347 -0
  112. onetick/py/sources/__init__.py +19 -0
  113. onetick/py/sources/cache.py +167 -0
  114. onetick/py/sources/common.py +128 -0
  115. onetick/py/sources/csv.py +642 -0
  116. onetick/py/sources/custom.py +85 -0
  117. onetick/py/sources/data_file.py +305 -0
  118. onetick/py/sources/data_source.py +1045 -0
  119. onetick/py/sources/empty.py +94 -0
  120. onetick/py/sources/odbc.py +337 -0
  121. onetick/py/sources/order_book.py +271 -0
  122. onetick/py/sources/parquet.py +168 -0
  123. onetick/py/sources/pit.py +191 -0
  124. onetick/py/sources/query.py +495 -0
  125. onetick/py/sources/snapshots.py +419 -0
  126. onetick/py/sources/split_query_output_by_symbol.py +198 -0
  127. onetick/py/sources/symbology_mapping.py +123 -0
  128. onetick/py/sources/symbols.py +374 -0
  129. onetick/py/sources/ticks.py +825 -0
  130. onetick/py/sql.py +70 -0
  131. onetick/py/state.py +251 -0
  132. onetick/py/types.py +2131 -0
  133. onetick/py/utils/__init__.py +70 -0
  134. onetick/py/utils/acl.py +93 -0
  135. onetick/py/utils/config.py +186 -0
  136. onetick/py/utils/default.py +49 -0
  137. onetick/py/utils/file.py +38 -0
  138. onetick/py/utils/helpers.py +76 -0
  139. onetick/py/utils/locator.py +94 -0
  140. onetick/py/utils/perf.py +498 -0
  141. onetick/py/utils/query.py +49 -0
  142. onetick/py/utils/render.py +1374 -0
  143. onetick/py/utils/script.py +244 -0
  144. onetick/py/utils/temp.py +471 -0
  145. onetick/py/utils/types.py +120 -0
  146. onetick/py/utils/tz.py +84 -0
  147. onetick_py-1.177.0.dist-info/METADATA +137 -0
  148. onetick_py-1.177.0.dist-info/RECORD +152 -0
  149. onetick_py-1.177.0.dist-info/WHEEL +5 -0
  150. onetick_py-1.177.0.dist-info/entry_points.txt +2 -0
  151. onetick_py-1.177.0.dist-info/licenses/LICENSE +21 -0
  152. onetick_py-1.177.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,94 @@
1
+ import datetime as dt
2
+
3
+ import onetick.py as otp
4
+ from onetick.py.otq import otq
5
+
6
+ import onetick.py.core._source
7
+ import onetick.py.functions
8
+ import onetick.py.db._inspection
9
+ from onetick.py.core.source import Source
10
+
11
+ from .. import utils, configuration
12
+
13
+ from .common import update_node_tick_type
14
+
15
+
16
+ class Empty(Source):
17
+ """
18
+ Empty data source
19
+
20
+ Parameters
21
+ ----------
22
+ db: str
23
+ Name of the database from which to take schema.
24
+ symbol: str, list of str, :class:`Source`, :class:`query`, :py:func:`eval query <onetick.py.eval>`
25
+ Symbol(s) from which data should be taken.
26
+ tick_type: str,
27
+ Name of the tick_type from which to take schema.
28
+ start, end: :py:class:`datetime.datetime`, :py:class:`otp.datetime <onetick.py.datetime>`, \
29
+ :py:class:`onetick.py.adaptive`
30
+ Time interval from which the data should be taken.
31
+ schema: dict
32
+ Schema to use in case db and/or tick_type are not set.
33
+ kwargs:
34
+ Deprecated. Use ``schema`` instead.
35
+ Schema to use in case db and/or tick_type are not set.
36
+
37
+ Examples
38
+ --------
39
+ We can define schema:
40
+
41
+ >>> data = otp.Empty(schema={'A': str, 'B': int})
42
+ >>> otp.run(data)
43
+ Empty DataFrame
44
+ Columns: [A, B, Time]
45
+ Index: []
46
+ >>> data.schema
47
+ {'A': <class 'str'>, 'B': <class 'int'>}
48
+
49
+ Or we can get schema from the database:
50
+
51
+ >>> data = otp.Empty(db='SOME_DB', tick_type='TT')
52
+ >>> data.schema
53
+ {'X': <class 'int'>}
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ db=utils.adaptive_to_default,
59
+ symbol=utils.adaptive_to_default,
60
+ tick_type=utils.adaptive,
61
+ start=utils.adaptive,
62
+ end=utils.adaptive,
63
+ schema=None,
64
+ **kwargs,
65
+ ):
66
+ if self._try_default_constructor(schema=schema, **kwargs):
67
+ return
68
+
69
+ schema = self._select_schema(schema, kwargs)
70
+
71
+ columns = {}
72
+
73
+ if (tick_type is not utils.adaptive and
74
+ db != configuration.config.get('default_db') and db is not utils.adaptive_to_default):
75
+ try:
76
+ db_obj = onetick.py.db._inspection.DB(db)
77
+ params = {'tick_type': tick_type}
78
+ if end is not utils.adaptive:
79
+ params['end'] = end
80
+ columns = db_obj.schema(**params)
81
+ except Exception:
82
+ pass # do not raise an exception if no data found, because it is empty _source and does not matter
83
+
84
+ else:
85
+ columns = schema
86
+
87
+ super().__init__(
88
+ _symbols=symbol, _start=start, _end=end, _base_ep_func=lambda: self.base_ep(db), schema=columns,
89
+ )
90
+
91
+ def base_ep(self, db):
92
+ src = Source(otq.TickGenerator(fields="long ___NOTHING___=0"))
93
+ update_node_tick_type(src, 'TICK_GENERATOR', db)
94
+ return src
@@ -0,0 +1,337 @@
1
+ from typing import Optional, List
2
+
3
+ import onetick.py as otp
4
+ from onetick.py.otq import otq
5
+
6
+ import onetick.py.db._inspection
7
+ from onetick.py.core.source import Source
8
+
9
+ from .. import utils, configuration
10
+ from ..core.column_operations.base import _Operation
11
+ from ..compatibility import is_odbc_query_supported
12
+
13
+ from .common import update_node_tick_type
14
+
15
+
16
+ class ODBC(Source):
17
+
18
+ _PROPERTIES = Source._PROPERTIES + [
19
+ '_dsn',
20
+ '_connection_string',
21
+ '_authentication_type',
22
+ '_user',
23
+ '_password',
24
+ '_sql',
25
+ '_symbology',
26
+ '_allow_unordered_ticks',
27
+ '_tz',
28
+ '_start_expr',
29
+ '_end_expr',
30
+ '_apply_symbol_name_history',
31
+ '_numeric_scale',
32
+ '_preserve_unicode_fields',
33
+ '_db',
34
+ '_tick_type',
35
+ '_symbols',
36
+ '_presort',
37
+ ]
38
+
39
+ def __init__(
40
+ self,
41
+ dsn: Optional[str] = None,
42
+ connection_string: Optional[str] = None,
43
+ authentication_type: str = 'credentials',
44
+ user: Optional[str] = None,
45
+ password: Optional[str] = None,
46
+ sql: Optional[str] = None,
47
+ start_expr: Optional[_Operation] = None,
48
+ end_expr: Optional[_Operation] = None,
49
+ tz=None,
50
+ allow_unordered_ticks=False,
51
+ numeric_scale=8,
52
+ preserve_unicode_fields: Optional[List[str]] = None,
53
+ symbology='',
54
+ apply_symbol_name_history=False,
55
+ start=utils.adaptive,
56
+ end=utils.adaptive,
57
+ db=utils.adaptive,
58
+ tick_type=utils.adaptive,
59
+ symbols=utils.adaptive_to_default,
60
+ presort=False,
61
+ schema=None,
62
+ **kwargs,
63
+ ):
64
+ """
65
+ Read from ODBC-compatible database and propagate the resulting data as a time series of ticks.
66
+
67
+ A time series is generated for every symbol of the query and the symbol name can be passed down to SQL query.
68
+
69
+ If an attribute with the name *TIMESTAMP* is present in the database schema,
70
+ it is assumed to be of either SQL DATE or SQL TIMESTAMP type, in which case output tick timestamps
71
+ will carry values of that field and the field itself will not be propagated.
72
+ If such a field is absent, output tick timestamps will be equal to query end time.
73
+
74
+ ODBC source supported only on OneTick versions starting from release 1.24
75
+ (or from development build 20231108-0)
76
+
77
+ Note
78
+ ----
79
+
80
+ To be able to use this class, you need to have a ODBC driver manager available on your machine
81
+ (comes with Windows OS; **unixodbc** package may need to be installed on UNIX OS).
82
+
83
+ Also, the following entry needs to be added to the main configuration file::
84
+
85
+ LOAD_ODBC_UDF=true
86
+
87
+ Parameters
88
+ ----------
89
+ dsn: str
90
+ Target database's source name registered in ODBC configuration.
91
+ connection_string: str
92
+ ODBC connection string. The format depends on the database you are trying to connect.
93
+ Example for SQLite database::
94
+
95
+ DRIVER={SQLite3};Database=/path/to/the/database.db
96
+
97
+ This parameter is mutually exclusive
98
+ with parameters ``dsn``, ``user``, ``password`` and ``authentication_type``.
99
+ authentication_type: str ('system' or 'credentials')
100
+
101
+ - **system**: in this case a trusted connection to the database will be used.
102
+ If authentication is enabled in the server configuration file
103
+ (see the OneTick Installation and Administration Guide for details),
104
+ the client will be authenticated and the client's credentials will be used for connection;
105
+ otherwise, server credentials will be used.
106
+ - **credentials**: username and password specified with parameter ``connection_string``
107
+ or with parameters ``user`` and ``password`` will be used to connect to the database.
108
+
109
+ user: str, optional
110
+ The connection user name.
111
+
112
+ Ignored if ``authentication_type`` is **system**.
113
+ password: str, optional
114
+ The connection password.
115
+
116
+ Ignored if ``authentication_type`` is **system**.
117
+ sql: str
118
+ A query in SQL language, which may optionally contain parameter placeholders.
119
+
120
+ There are 3 types of placeholders: **<_SYMBOL_NAME>**, **<_START_TIME>**, and **<_END_TIME>**.
121
+
122
+ **<_SYMBOL_NAME>** will be replaced by the pure symbol name part of the query.
123
+
124
+ **<_START_TIME>** and **<_END_TIME>** will be replaced by values of parameters
125
+ ``start_expr`` and ``end_expr`` or, if they are not set, with values taken from query start and end times.
126
+
127
+ These timestamps will be inserted in the format ``YYYY-MM-DD HH:MM:SS.sss TIMEZONE``.
128
+
129
+ start_expr: str or :py:class:`~onetick.py.Operation`
130
+ A constant string expression used to replace the **<_START_TIME>** placeholder in an ``sql`` query.
131
+ Tick-dependent columns can't be used in this expression, only meta fields such as
132
+ *TIMESTAMP*, *_START_TIME*, and *_END_TIME* are allowed.
133
+ end_expr: str or :py:class:`~onetick.py.Operation`
134
+ A constant string expression used to replace the **<_END_TIME>** placeholder in an ``sql`` query.
135
+ Tick-dependent columns can't be used in this expression, only meta fields such as
136
+ *TIMESTAMP*, *_START_TIME*, and *_END_TIME* are allowed.
137
+ tz: str
138
+ The timezone used to interpret *TIMESTAMP* and other datetime columns in the database.
139
+ By default :py:attr:`tz<onetick.py.configuration.Config.tz>` is used.
140
+
141
+ allow_unordered_ticks: bool
142
+ If set to False, this class will raise an exception when unordered ticks will be encountered.
143
+
144
+ If set to True, processing ticks unordered by timestamp will be allowed
145
+ (exception may still be raised by other EPs of the graph that require ticks to be ordered).
146
+
147
+ numeric_scale: int
148
+ Number of digits after the decimal point for SQL_NUMERIC and SQL_DECIMAL data types.
149
+ Precision (maximum number of digits) is always set to 34.
150
+ preserve_unicode_fields: list of str
151
+ By default ODBC queries all data as ANSI,
152
+ ODBC Driver Manager then tries to convert Unicode characters to ANSI.
153
+
154
+ This parameter is a list of fields, which have Unicode types in the data source
155
+ and will be propagated without conversion.
156
+
157
+ UNICODE_CHAR_TYPE field property will be set to UCS-2 for these fields.
158
+
159
+ symbology: str
160
+ If specified, **<_SYMBOL_NAME>** placeholder in ``sql`` query will be replaced with
161
+ the mapping of the symbol name of the query for provided symbology.
162
+
163
+ apply_symbol_name_history: bool
164
+ If set to False, ODBC will not take into account the symbol name history
165
+ when substituting the SQL query with actual symbol names.
166
+
167
+ If set to True, ODBC will resolve symbol name changes according to the reference data
168
+ by substituting the SQL query accordingly,
169
+ provided the symbol date is specified in :py:func:`otp.run <onetick.py.run>` when running the query and
170
+ the SQL query contains all three placeholders **<_SYMBOL_NAME>**, **<_START_TIME>**, **<_END_TIME>**.
171
+
172
+ Note that ODBC data source needs to support "UNION ALL" syntax for this functionality to work.
173
+
174
+ start:
175
+ Custom start time of the query.
176
+ By default the start time used by :py:func:`otp.run <onetick.py.run>` will be inherited.
177
+ end:
178
+ Custom end time of the query.
179
+ By default the start time used by :py:func:`otp.run <onetick.py.run>` will be inherited.
180
+ db: str
181
+ Custom database name for the node of the graph.
182
+ By default the database used by :py:func:`otp.run <onetick.py.run>` will be inherited.
183
+ tick_type: str
184
+ Custom tick type for the node of the graph.
185
+ By default "ANY" tick type will be set.
186
+ symbols: str or list of str
187
+ Custom symbol name for the node of the graph or list of symbols.
188
+ If list of symbols is specified, ticks from different symbols will be merged into one source.
189
+
190
+ Separate ODBC connection will be created for each processed symbol.
191
+ To avoid this and have a single connection per thread, ``presort`` parameter can be specified.
192
+
193
+ By default the symbol name used by :py:func:`otp.run <onetick.py.run>` will be inherited.
194
+ presort: bool
195
+ Adds **PRESORT** EP before merging bound symbols specified in ``symbols``.
196
+ That make ODBC use single connection for all symbols.
197
+ schema: dict
198
+ Set the schema of the python :py:class:`~onetick.py.Source` object of this class.
199
+
200
+ Schema can't be taken automatically from the database, so it should be set manually
201
+ for python-level type checking to work.
202
+ kwargs:
203
+ Deprecated. Use ``schema`` instead.
204
+ Set the schema of the python :py:class:`~onetick.py.Source` object of this class.
205
+
206
+ See also
207
+ --------
208
+ **ODBC_QUERY** OneTick event processor
209
+
210
+ Examples
211
+ --------
212
+
213
+ Connect with database's ``dsn``, manually set schema, get all data from TEST_TABLE:
214
+
215
+ >>> data = otp.ODBC(dsn='testdb_dsn', sql='select * from TEST_TABLE',
216
+ ... schema={'A': str, 'B': int, 'C': float, 'D': otp.nsectime}) # doctest: +SKIP
217
+ >>> otp.run(data) # doctest: +SKIP
218
+ Time A B C D
219
+ 0 2003-12-04 A1 1975 8.12345 2022-01-01 12:13:14.111
220
+ 1 2003-12-04 A2 1971 7.98765 2022-01-02 22:23:24.222
221
+
222
+ Connect using ``connection_string`` parameter:
223
+
224
+ >>> data = otp.ODBC(connection_string='DRIVER={SQLite3};Database=/path/to/the/database',
225
+ ... sql='select * from TEST_TABLE') # doctest: +SKIP
226
+ >>> otp.run(data) # doctest: +SKIP
227
+ Time A B C D
228
+ 0 2003-12-04 A1 1975 8.12345 2022-01-01 12:13:14.111
229
+ 1 2003-12-04 A2 1971 7.98765 2022-01-02 22:23:24.222
230
+
231
+ Substitute start time placeholder with ``start_expr`` parameter:
232
+
233
+ >>> data = otp.ODBC(
234
+ ... dsn='testdb_dsn',
235
+ ... sql='select * from TEST_TIMESTAMP where TIMESTAMP >= "<_START_TIME>"',
236
+ ... start_expr=(otp.meta_fields['START_TIME'] + otp.Day(1)).dt.strftime('%Y-%m-%d %H:%M:%S.%q')
237
+ ... ) # doctest: +SKIP
238
+ >>> otp.run(data, start=otp.dt(2022, 1, 1), end=otp.dt(2022, 1, 3)) # doctest: +SKIP
239
+ Time A
240
+ 0 2022-01-02 22:23:24.222 2
241
+
242
+ Use parameter ``allow_unordered_ticks`` if needed:
243
+
244
+ >>> data = otp.ODBC(dsn='testdb_dsn',
245
+ ... sql='select * from TEST_UNORDERED',
246
+ ... allow_unordered_ticks=True) # doctest: +SKIP
247
+ >>> otp.run(data, start=otp.dt(2022, 1, 1), end=otp.dt(2022, 1, 3)) # doctest: +SKIP
248
+ Time A
249
+ 0 2022-01-02 22:23:24.222 2
250
+ 1 2022-01-01 12:13:14.111 1
251
+ """
252
+ if self._try_default_constructor(schema=schema, **kwargs):
253
+ return
254
+
255
+ if not is_odbc_query_supported():
256
+ raise RuntimeError("ODBC source is not supported in this version of OneTick, "
257
+ "it is available starting from release 1.24 (or development build 20231108)")
258
+
259
+ if not dsn and not connection_string:
260
+ raise ValueError("One of the parameters 'dsn' or 'connection_string' must be specified")
261
+
262
+ if authentication_type not in {'system', 'credentials'}:
263
+ raise ValueError(f"Unknown value for parameter 'authentication_type': {authentication_type}")
264
+
265
+ if connection_string and any([dsn, user, password, authentication_type == 'system']):
266
+ raise ValueError("Parameter 'connection_string' is used instead of parameters"
267
+ " 'dsn', 'user', 'password' and 'authentication_type'")
268
+
269
+ if not sql:
270
+ raise ValueError("Parameter 'sql' must be set")
271
+
272
+ if not isinstance(numeric_scale, int) or not 0 <= numeric_scale <= 34:
273
+ raise ValueError("Unsupported value for parameter 'numeric_scale'")
274
+
275
+ self._dsn = dsn
276
+ self._connection_string = connection_string
277
+ self._authentication_type = authentication_type
278
+ self._user = user
279
+ self._password = password
280
+ self._sql = sql
281
+ self._symbology = symbology
282
+ self._allow_unordered_ticks = allow_unordered_ticks
283
+ self._apply_symbol_name_history = apply_symbol_name_history
284
+ self._numeric_scale = numeric_scale
285
+ self._preserve_unicode_fields = preserve_unicode_fields
286
+ self._tz = tz
287
+ self._start_expr = start_expr
288
+ self._end_expr = end_expr
289
+ self._db = db
290
+ self._tick_type = tick_type
291
+ self._symbols = symbols
292
+ self._presort = presort
293
+
294
+ # if we have a list of symbols, they will be merged in self.base_ep()
295
+ if isinstance(symbols, list):
296
+ symbols = None
297
+
298
+ super().__init__(
299
+ _symbols=symbols, _start=start, _end=end, _base_ep_func=lambda: self.base_ep(schema=schema, **kwargs),
300
+ schema=schema, **kwargs,
301
+ )
302
+
303
+ def base_ep(self, schema=None, **kwargs):
304
+
305
+ src = Source(
306
+ otq.Omd_odbcQuery(
307
+ dsn=self._dsn or '',
308
+ connection_string=self._connection_string or '',
309
+ authentication_type='System' if self._authentication_type == 'system' else 'Username/Password',
310
+ user=self._user or '',
311
+ password=self._password or '',
312
+ sql=self._sql,
313
+ symbology=self._symbology or '',
314
+ allow_unordered_ticks=self._allow_unordered_ticks,
315
+ apply_symbol_name_history=self._apply_symbol_name_history,
316
+ numeric_scale=self._numeric_scale,
317
+ preserve_unicode_fields=','.join(self._preserve_unicode_fields or []),
318
+ tz=self._tz or configuration.config.get('tz') or '',
319
+ start_time_expr=str(self._start_expr) if self._start_expr is not None else '',
320
+ end_time_expr=str(self._end_expr) if self._end_expr is not None else '',
321
+ ),
322
+ schema=schema,
323
+ **kwargs,
324
+ )
325
+
326
+ db = self._db
327
+
328
+ if isinstance(self._symbols, list):
329
+ if self._presort:
330
+ src.sink(otq.Presort().symbols(self._symbols))
331
+ src.sink(otq.Merge(identify_input_ts=False))
332
+ else:
333
+ src.sink(otq.Merge(identify_input_ts=False).symbols(self._symbols))
334
+
335
+ update_node_tick_type(src, self._tick_type, db)
336
+
337
+ return src