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,286 @@
|
|
|
1
|
+
from typing import List, Dict, TYPE_CHECKING, Tuple, Optional, Union
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from collections import namedtuple
|
|
4
|
+
from onetick.py.compatibility import is_supported_agg_option_price
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from onetick.py.core.source import Source # hack for annotations
|
|
8
|
+
|
|
9
|
+
from onetick.py.core.column import Column
|
|
10
|
+
from onetick.py import types as ott
|
|
11
|
+
from onetick.py.otq import otq
|
|
12
|
+
import onetick.py as otp
|
|
13
|
+
|
|
14
|
+
from ._base import _Aggregation, operation_gb, operation_replacer, _MultiColumnAggregation
|
|
15
|
+
from onetick.py.aggregations.other import (
|
|
16
|
+
FirstTick, LastTick, OptionPrice, Ranking, Percentile, PortfolioPrice, MultiPortfolioPrice,
|
|
17
|
+
)
|
|
18
|
+
from onetick.py.aggregations.high_low import HighTick, LowTick
|
|
19
|
+
from onetick.py.aggregations.generic import Generic
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Compute(_Aggregation):
|
|
23
|
+
@property
|
|
24
|
+
def NAME(self):
|
|
25
|
+
return "COMPUTE"
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def EP(self):
|
|
29
|
+
try:
|
|
30
|
+
return otq.compute
|
|
31
|
+
except AttributeError:
|
|
32
|
+
return otq.ComputeEp
|
|
33
|
+
|
|
34
|
+
FIELDS_MAPPING = deepcopy(_Aggregation.FIELDS_MAPPING)
|
|
35
|
+
FIELDS_MAPPING['all_fields'] = 'SHOW_ALL_FIELDS'
|
|
36
|
+
FIELDS_TO_SKIP = ['column_name']
|
|
37
|
+
|
|
38
|
+
DISALLOWED_FIELDS = ["running", "all_fields", "bucket_interval", "bucket_time",
|
|
39
|
+
"bucket_units", "end_condition_per_group", "boundary_tick_bucket", "group_by"]
|
|
40
|
+
# [bucket_end_condition, all_fields] can not be used without bucket_units=flexible -> already disallowed
|
|
41
|
+
|
|
42
|
+
_validations_to_skip = ['running_all_fields']
|
|
43
|
+
|
|
44
|
+
def __init__(self,
|
|
45
|
+
*args,
|
|
46
|
+
**kwargs):
|
|
47
|
+
super().__init__(column=Column('Time'), *args, **kwargs)
|
|
48
|
+
|
|
49
|
+
self.aggrs = {}
|
|
50
|
+
self.has_multi_column_aggregations = False
|
|
51
|
+
|
|
52
|
+
# Aggregation from `all_fields` parameter is saved as regular aggregation in `self.aggrs` with empty field name
|
|
53
|
+
if isinstance(self.all_fields, str):
|
|
54
|
+
if self.all_fields.lower() not in ["last", "first", "high", "low", "when_ticks_exit_window"]:
|
|
55
|
+
raise ValueError(f"Unknown all_fields '{self.all_fields}' policy provided.")
|
|
56
|
+
|
|
57
|
+
if isinstance(self.all_fields, str) and self.all_fields.lower() != "when_ticks_exit_window":
|
|
58
|
+
if self.running:
|
|
59
|
+
raise ValueError(
|
|
60
|
+
"`all_fields` can't be one of 'last', 'first', 'high' or 'low' when `running=True`"
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
aggr_class = globals()[self.all_fields.capitalize() + "Tick"]
|
|
64
|
+
aggr_args = {}
|
|
65
|
+
if self.all_fields in {"high", "low"}:
|
|
66
|
+
aggr_args['column'] = "PRICE"
|
|
67
|
+
|
|
68
|
+
all_fields_aggr = aggr_class(**aggr_args)
|
|
69
|
+
|
|
70
|
+
self.add('', all_fields_aggr)
|
|
71
|
+
|
|
72
|
+
if isinstance(self.all_fields, (HighTick, LowTick)):
|
|
73
|
+
self.add('', self.all_fields)
|
|
74
|
+
|
|
75
|
+
if self.all_fields is True and not self.running:
|
|
76
|
+
self.add('', FirstTick())
|
|
77
|
+
|
|
78
|
+
def add(self, name: str, aggr: _Aggregation):
|
|
79
|
+
"""Adds aggregation for multiple aggregation"""
|
|
80
|
+
self._validate_aggregation(aggr)
|
|
81
|
+
if name in self.aggrs:
|
|
82
|
+
raise KeyError(f'You are trying to output two aggregations to one field: "{name}"')
|
|
83
|
+
|
|
84
|
+
if name == '' and not isinstance(aggr, (FirstTick, LastTick, HighTick, LowTick)):
|
|
85
|
+
raise ValueError(
|
|
86
|
+
'Only one instance of FirstTick, LastTick, HighTick or LowTick aggregation '
|
|
87
|
+
'is allowed to have empty name in order to save compatibility with `all_fields` parameter'
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if aggr.is_multi_column_aggregation:
|
|
91
|
+
self.has_multi_column_aggregations = True
|
|
92
|
+
|
|
93
|
+
self.aggrs[name] = aggr
|
|
94
|
+
|
|
95
|
+
def _validate_aggregation(self, aggr: _Aggregation):
|
|
96
|
+
if not isinstance(aggr, _Aggregation):
|
|
97
|
+
raise TypeError(f"It is allowed to pass only aggregations, but got '{type(aggr)}'")
|
|
98
|
+
|
|
99
|
+
if isinstance(aggr, OptionPrice) and not is_supported_agg_option_price():
|
|
100
|
+
raise NotImplementedError(f".agg() method does not support {type(aggr)} on OneTick {otp.__build__} build")
|
|
101
|
+
|
|
102
|
+
if isinstance(aggr, Ranking):
|
|
103
|
+
raise ValueError('Using ranking aggregation in otp.Source.agg method is not supported. '
|
|
104
|
+
'Use otp.agg.ranking.apply() or otp.Source.ranking() methods.')
|
|
105
|
+
|
|
106
|
+
if isinstance(aggr, Percentile):
|
|
107
|
+
raise ValueError('Using percentile aggregation in otp.Source.agg method is not supported. '
|
|
108
|
+
'Use otp.agg.percentile.apply() or otp.Source.percentile() methods.')
|
|
109
|
+
|
|
110
|
+
if isinstance(aggr, PortfolioPrice) and getattr(aggr, 'symbols'):
|
|
111
|
+
raise ValueError('It\'s not allowed to pass `symbols` parameter while using `portfolio_price` '
|
|
112
|
+
'in compute or `Source.agg`')
|
|
113
|
+
|
|
114
|
+
if isinstance(aggr, MultiPortfolioPrice):
|
|
115
|
+
raise ValueError('Using multi_portfolio_price aggregation in otp.Source.agg method is not supported, '
|
|
116
|
+
'because it outputs multiple ticks at once. '
|
|
117
|
+
'Use otp.agg.percentile.apply() or otp.Source.percentile() methods.')
|
|
118
|
+
|
|
119
|
+
for field in self.DISALLOWED_FIELDS:
|
|
120
|
+
if field not in aggr.FIELDS_TO_SKIP and getattr(aggr, field) != aggr.FIELDS_DEFAULT[field]:
|
|
121
|
+
raise ValueError(f'"{field}" parameter can not be specified in multiple aggregation')
|
|
122
|
+
|
|
123
|
+
def validate_input_columns(self, src: 'Source'):
|
|
124
|
+
self._validate_aggregation_with_source(src)
|
|
125
|
+
|
|
126
|
+
def _validate_aggregation_with_source(self, src: 'Source'):
|
|
127
|
+
for name, aggr in self.aggrs.items():
|
|
128
|
+
aggr.validate_input_columns(src)
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def ep_params(self) -> Dict:
|
|
132
|
+
all_fields_orig = self.all_fields
|
|
133
|
+
if self.has_multi_column_aggregations:
|
|
134
|
+
self.all_fields = False
|
|
135
|
+
params = super().ep_params
|
|
136
|
+
if self.has_multi_column_aggregations:
|
|
137
|
+
self.all_fields = all_fields_orig
|
|
138
|
+
|
|
139
|
+
params['append_output_field_name'] = self.has_multi_column_aggregations
|
|
140
|
+
|
|
141
|
+
what_to_compute = []
|
|
142
|
+
for name, aggr in self.aggrs.items():
|
|
143
|
+
if name:
|
|
144
|
+
str_aggr = str(aggr) + " " + name
|
|
145
|
+
else:
|
|
146
|
+
agg_params = [f'{k}={aggr._attr2str(v)}' for k, v in aggr.ep_params.items()]
|
|
147
|
+
agg_params.append("KEEP_INITIAL_SCHEMA='true'")
|
|
148
|
+
str_aggr = aggr.NAME + "(" + ",".join(agg_params) + ")"
|
|
149
|
+
|
|
150
|
+
what_to_compute.append(str_aggr)
|
|
151
|
+
|
|
152
|
+
if what_to_compute:
|
|
153
|
+
params['COMPUTE'] = ','.join(what_to_compute)
|
|
154
|
+
|
|
155
|
+
return params
|
|
156
|
+
|
|
157
|
+
def to_ep(self, *args, **kwargs) -> otq.EpBase:
|
|
158
|
+
params = dict((k.lower(), v) for k, v in self.ep_params.items())
|
|
159
|
+
return self.EP(**params)
|
|
160
|
+
|
|
161
|
+
@operation_gb
|
|
162
|
+
@operation_replacer
|
|
163
|
+
def apply(self, src: 'Source') -> 'Source':
|
|
164
|
+
if not self.aggrs:
|
|
165
|
+
raise TypeError('Nothing to aggregate')
|
|
166
|
+
|
|
167
|
+
res = src.copy()
|
|
168
|
+
res, what_to_wrap = self._ts_to_long(res)
|
|
169
|
+
schema = self._get_common_schema(res, [key for key in self.aggrs.keys() if key])
|
|
170
|
+
|
|
171
|
+
# run _modify_source like it is in apply
|
|
172
|
+
for aggr in self.aggrs.values():
|
|
173
|
+
if isinstance(aggr, Generic):
|
|
174
|
+
aggr_schema = aggr._detect_query_fun_schema(res)
|
|
175
|
+
|
|
176
|
+
if aggr._query is None:
|
|
177
|
+
raise RuntimeError('Generic aggregation was not initialized correctly.')
|
|
178
|
+
|
|
179
|
+
# keep only fields from schema
|
|
180
|
+
query = aggr._query.table(**aggr_schema, strict=True)
|
|
181
|
+
|
|
182
|
+
# add LAST_TICK EP
|
|
183
|
+
default_tick = ','.join(f'{field} {ott.type2str(dtype)}' for field, dtype in aggr_schema.items())
|
|
184
|
+
aggr._query = query.sink(otq.LastTick(default_tick=default_tick), inplace=False)
|
|
185
|
+
|
|
186
|
+
# set empty query params for Generic aggregations
|
|
187
|
+
aggr._set_query_params()
|
|
188
|
+
|
|
189
|
+
aggr._modify_source(res)
|
|
190
|
+
|
|
191
|
+
# it's important to validate input schema before sinking
|
|
192
|
+
res.sink(self.to_ep())
|
|
193
|
+
|
|
194
|
+
for name, aggr in self.aggrs.items():
|
|
195
|
+
if not name:
|
|
196
|
+
# No need to check `all_fields` aggregation: it will have the same schema, as input source
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
if not aggr.is_multi_column_aggregation:
|
|
200
|
+
agg_out_schema = aggr._get_output_schema(res, name=name)
|
|
201
|
+
else:
|
|
202
|
+
aggr_schema_base = aggr._get_output_schema(res)
|
|
203
|
+
if aggr.is_all_columns_aggregation:
|
|
204
|
+
aggr_schema_base = src.schema
|
|
205
|
+
|
|
206
|
+
agg_out_schema = {f'{name}.{key}': value for key, value in aggr_schema_base.items()}
|
|
207
|
+
|
|
208
|
+
schema.update(agg_out_schema)
|
|
209
|
+
|
|
210
|
+
res.schema.set(**schema)
|
|
211
|
+
|
|
212
|
+
if self.has_multi_column_aggregations:
|
|
213
|
+
res = self._remove_all_fields_tick_suffix(res)
|
|
214
|
+
|
|
215
|
+
res = self._long_to_ts(res, what_to_wrap)
|
|
216
|
+
return res
|
|
217
|
+
|
|
218
|
+
def _ts_to_long(self, src: 'Source') -> Tuple['Source', List]:
|
|
219
|
+
"""Convert nsectime columns to long, so aggregation can work in a proper way"""
|
|
220
|
+
res = src.copy()
|
|
221
|
+
forward_result = namedtuple('forward_result', ('aggr', 'columns'))
|
|
222
|
+
what_to_wrap = []
|
|
223
|
+
for name, aggr in self.aggrs.items():
|
|
224
|
+
if '_ts_to_long' in dir(aggr) and callable(aggr._ts_to_long):
|
|
225
|
+
res, col, convert_back = aggr._ts_to_long(res, name)
|
|
226
|
+
if convert_back:
|
|
227
|
+
what_to_wrap.append(forward_result(aggr, col))
|
|
228
|
+
for r in what_to_wrap:
|
|
229
|
+
self.aggrs[r.columns.tmp_out_column] = self.aggrs.pop(r.columns.out_column)
|
|
230
|
+
return res, what_to_wrap
|
|
231
|
+
|
|
232
|
+
def _long_to_ts(self, src: 'Source', what_to_wrap: List) -> 'Source':
|
|
233
|
+
"""Convert long columns to nsectime if needed (used along with _ts_to_long)"""
|
|
234
|
+
res = src.copy()
|
|
235
|
+
for r in what_to_wrap:
|
|
236
|
+
res = r.aggr._long_to_ts(res, r.columns)
|
|
237
|
+
self.aggrs[r.columns.out_column] = self.aggrs.pop(r.columns.tmp_out_column)
|
|
238
|
+
return res
|
|
239
|
+
|
|
240
|
+
def _remove_all_fields_tick_suffix(self, src: 'Source') -> 'Source':
|
|
241
|
+
"""
|
|
242
|
+
renames columns (in query and schema) after compute with multi-column aggregations
|
|
243
|
+
"""
|
|
244
|
+
schema = src.schema.copy()
|
|
245
|
+
rename_rule = {}
|
|
246
|
+
fields_to_drop = []
|
|
247
|
+
|
|
248
|
+
for name, aggr in self.aggrs.items():
|
|
249
|
+
if aggr.is_all_columns_aggregation or isinstance(aggr, Generic):
|
|
250
|
+
# In case of Generic: remove TICK_TIME field returned by LAST_TICK from generic aggregation
|
|
251
|
+
field_name = name if name else aggr.DEFAULT_OUTPUT_NAME
|
|
252
|
+
tick_time_field = f'{field_name}.TICK_TIME'
|
|
253
|
+
schema.update(**{tick_time_field: ott.nsectime})
|
|
254
|
+
fields_to_drop.append(tick_time_field)
|
|
255
|
+
|
|
256
|
+
if aggr.is_multi_column_aggregation:
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
new_name = f'{name}.{aggr.DEFAULT_OUTPUT_NAME}'
|
|
260
|
+
schema[new_name] = schema.pop(name)
|
|
261
|
+
rename_rule[new_name] = name
|
|
262
|
+
|
|
263
|
+
res = src.copy()
|
|
264
|
+
res.schema.set(**schema)
|
|
265
|
+
|
|
266
|
+
if fields_to_drop:
|
|
267
|
+
res.drop(fields_to_drop, inplace=True)
|
|
268
|
+
|
|
269
|
+
if rename_rule:
|
|
270
|
+
res.rename(rename_rule, inplace=True)
|
|
271
|
+
|
|
272
|
+
all_fields_aggr = self.aggrs.get('')
|
|
273
|
+
if all_fields_aggr:
|
|
274
|
+
# drop first_tick columns duplicating group_by columns
|
|
275
|
+
all_fields_tick_name = all_fields_aggr.DEFAULT_OUTPUT_NAME
|
|
276
|
+
|
|
277
|
+
for group_by in self.group_by:
|
|
278
|
+
group_by_name = group_by
|
|
279
|
+
if isinstance(group_by, Column):
|
|
280
|
+
group_by_name = group_by.name
|
|
281
|
+
first_tick_field = f'{all_fields_tick_name}.{group_by_name}'
|
|
282
|
+
res.sink(otq.Passthrough(fields=first_tick_field, drop_fields=True))
|
|
283
|
+
|
|
284
|
+
res.sink(otq.RenameFieldsEp(rename_fields=rf"{all_fields_tick_name}\.(.*)=\1", use_regex=True))
|
|
285
|
+
|
|
286
|
+
return res
|