onetick-py 1.170.0__py3-none-any.whl → 1.172.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 (30) hide show
  1. onetick/py/__init__.py +8 -2
  2. onetick/py/_version.py +1 -1
  3. onetick/py/cache.py +3 -3
  4. onetick/py/callback/callbacks.py +1 -1
  5. onetick/py/configuration.py +35 -9
  6. onetick/py/core/_source/source_methods/misc.py +1 -1
  7. onetick/py/core/_source/source_methods/writes.py +48 -33
  8. onetick/py/core/column_operations/_methods/methods.py +1 -4
  9. onetick/py/core/column_operations/accessors/_accessor.py +4 -6
  10. onetick/py/core/column_operations/accessors/decimal_accessor.py +20 -8
  11. onetick/py/core/column_operations/accessors/dt_accessor.py +137 -68
  12. onetick/py/core/column_operations/accessors/float_accessor.py +35 -15
  13. onetick/py/core/column_operations/accessors/str_accessor.py +0 -7
  14. onetick/py/core/column_operations/base.py +72 -12
  15. onetick/py/core/multi_output_source.py +41 -2
  16. onetick/py/core/per_tick_script.py +2 -0
  17. onetick/py/db/_inspection.py +82 -49
  18. onetick/py/db/db.py +2 -2
  19. onetick/py/functions.py +7 -1
  20. onetick/py/math.py +374 -386
  21. onetick/py/misc.py +70 -38
  22. onetick/py/otq.py +18 -12
  23. onetick/py/run.py +75 -5
  24. onetick/py/sources/ticks.py +1 -1
  25. {onetick_py-1.170.0.dist-info → onetick_py-1.172.0.dist-info}/METADATA +4 -2
  26. {onetick_py-1.170.0.dist-info → onetick_py-1.172.0.dist-info}/RECORD +30 -30
  27. {onetick_py-1.170.0.dist-info → onetick_py-1.172.0.dist-info}/WHEEL +0 -0
  28. {onetick_py-1.170.0.dist-info → onetick_py-1.172.0.dist-info}/entry_points.txt +0 -0
  29. {onetick_py-1.170.0.dist-info → onetick_py-1.172.0.dist-info}/licenses/LICENSE +0 -0
  30. {onetick_py-1.170.0.dist-info → onetick_py-1.172.0.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,4 @@
1
+ import itertools
1
2
  import warnings
2
3
  from typing import Union, Iterable, Tuple, Optional, Any, Literal
3
4
  from datetime import date as dt_date, datetime, timedelta
@@ -7,6 +8,7 @@ from dateutil.tz import gettz
7
8
 
8
9
  import onetick.py as otp
9
10
  from onetick.py import configuration, utils
11
+ from onetick.py import types as ott
10
12
  from onetick.py.compatibility import is_native_plus_zstd_supported, is_show_db_list_show_description_supported
11
13
  from onetick.py.core import db_constants
12
14
  from onetick.py.otq import otq
@@ -909,10 +911,12 @@ class DB:
909
911
 
910
912
 
911
913
  def databases(
912
- context=utils.default, derived: bool = False, readable_only: bool = True, fetch_description: bool = False,
913
- ) -> dict[str, DB]:
914
+ context=utils.default, derived: bool = False, readable_only: bool = True,
915
+ fetch_description: Optional[bool] = None,
916
+ as_table: bool = False,
917
+ ) -> Union[dict[str, DB], pd.DataFrame]:
914
918
  """
915
- Gets all available databases in the ``context``
919
+ Gets all available databases in the ``context``.
916
920
 
917
921
  Parameters
918
922
  ----------
@@ -931,6 +935,9 @@ def databases(
931
935
  fetch_description: bool
932
936
  If set to True, retrieves descriptions for databases and puts them into ``description`` property of
933
937
  :py:class:`~onetick.py.DB` objects in a returned dict.
938
+ as_table: bool
939
+ If False (default), this function returns a dictionary of database names and database objects.
940
+ If True, returns a :pandas:`pandas.DataFrame` table where each row contains the info for each database.
934
941
 
935
942
  See also
936
943
  --------
@@ -940,50 +947,66 @@ def databases(
940
947
 
941
948
  Returns
942
949
  -------
943
- dict
944
- Dict where keys are database names and values are :class:`DB <onetick.py.db._inspection.DB>` objects
945
- with ``context`` specified.
946
- """
947
- if fetch_description and not is_show_db_list_show_description_supported():
948
- fetch_description = False
950
+ Dict where keys are database names and values are :class:`DB <onetick.py.db._inspection.DB>` objects
951
+ or :pandas:`pandas.DataFrame` object depending on ``as_table`` parameter.
949
952
 
950
- if readable_only:
951
- node = (
952
- otq.AccessInfo(info_type='DATABASES', show_for_all_users=False, deep_scan=True).tick_type('ANY')
953
- >> otq.Passthrough('DB_NAME,READ_ACCESS')
954
- >> otq.WhereClause(where='READ_ACCESS = 1')
955
- )
953
+ Examples
954
+ --------
956
955
 
957
- if fetch_description:
958
- join = otq.Join(
959
- left_source='LEFT', join_type='LEFT_OUTER', join_criteria='LEFT.DB_NAME = RIGHT.DATABASE_NAME'
960
- )
961
-
962
- _ = node.set_node_name('LEFT') >> join
963
- _ = (
964
- otq.ShowDbList(show_description=fetch_description).tick_type('ANY')
965
- >> otq.Passthrough('DATABASE_NAME,DESCRIPTION').set_node_name('RIGHT')
966
- >> join
967
- )
968
-
969
- node = (
970
- join >> otq.Passthrough('LEFT.DB_NAME,RIGHT.DESCRIPTION')
971
- >> otq.RenameFields("LEFT.DB_NAME=DB_NAME,RIGHT.DESCRIPTION=DESCRIPTION")
972
- )
973
- else:
974
- db_list_kwargs = {}
975
- output_fields = ['DATABASE_NAME']
976
- if fetch_description:
977
- db_list_kwargs['show_description'] = fetch_description
978
- output_fields.append('DESCRIPTION')
956
+ Get the dictionary of database names and objects:
979
957
 
980
- node = (
981
- otq.ShowDbList(**db_list_kwargs).tick_type('ANY')
982
- >> otq.Passthrough(','.join(output_fields))
983
- )
958
+ >>> otp.databases() # doctest: +SKIP
959
+ {'ABU_DHABI': <onetick.py.db._inspection.DB at 0x7f9413a5e8e0>,
960
+ 'ABU_DHABI_BARS': <onetick.py.db._inspection.DB at 0x7f9413a5ef40>,
961
+ 'ABU_DHABI_DAILY': <onetick.py.db._inspection.DB at 0x7f9413a5eac0>,
962
+ 'ALPHA': <onetick.py.db._inspection.DB at 0x7f9413a5e940>,
963
+ 'ALPHA_X': <onetick.py.db._inspection.DB at 0x7f9413a5e490>,
964
+ ...
965
+ }
966
+
967
+ Get a table with database info:
984
968
 
985
- if not fetch_description:
986
- node = node >> otq.AddField('DESCRIPTION', '""')
969
+ >>> otp.databases(as_table=True) # doctest: +SKIP
970
+ Time DB_NAME READ_ACCESS WRITE_ACCESS ...
971
+ 0 2003-01-01 ABU_DHABI 1 0 ...
972
+ 1 2003-01-01 ABU_DHABI_BARS 1 1 ...
973
+ 2 2003-01-01 ABU_DHABI_DAILY 1 1 ...
974
+ 3 2003-01-01 ALPHA 1 1 ...
975
+ 4 2003-01-01 ALPHA_X 1 1 ...
976
+ ... ... ... ... ... ...
977
+ """
978
+ show_db_list_kwargs = {}
979
+ if fetch_description is not None and is_show_db_list_show_description_supported() and (
980
+ 'show_description' in otq.ShowDbList.Parameters.list_parameters()
981
+ ):
982
+ show_db_list_kwargs['show_description'] = fetch_description
983
+
984
+ node = otq.AccessInfo(info_type='DATABASES', show_for_all_users=False, deep_scan=True).tick_type('ANY')
985
+ # for some reason ACCESS_INFO sometimes return several ticks
986
+ # for the same database with different SERVER_ADDRESS values
987
+ # so we get only the first tick
988
+ node = (
989
+ node >> otq.NumTicks(is_running_aggr=True, group_by='DB_NAME',
990
+ all_fields_for_sliding=False, output_field_name='NUM_TICKS')
991
+ >> otq.WhereClause(where='NUM_TICKS = 1')
992
+ >> otq.Passthrough('NUM_TICKS', drop_fields=True)
993
+ )
994
+ if readable_only:
995
+ node = node >> otq.WhereClause(where='READ_ACCESS = 1')
996
+
997
+ left = node.set_node_name('LEFT')
998
+ right = otq.ShowDbList(**show_db_list_kwargs).tick_type('ANY').set_node_name('RIGHT')
999
+ join = otq.Join(
1000
+ left_source='LEFT', join_type='INNER', join_criteria='LEFT.DB_NAME = RIGHT.DATABASE_NAME',
1001
+ add_source_prefix=False,
1002
+ )
1003
+ left >> join << right # pylint: disable=pointless-statement
1004
+ node = join >> otq.Passthrough('LEFT.TIMESTAMP,RIGHT.TIMESTAMP,DATABASE_NAME', drop_fields=True)
1005
+
1006
+ # times bigger than datetime.max are not representable in python
1007
+ max_dt = ott.value2str(datetime.max)
1008
+ node = node >> otq.UpdateFields(set=f'INTERVAL_START={max_dt}', where=f'INTERVAL_START > {max_dt}')
1009
+ node = node >> otq.UpdateFields(set=f'INTERVAL_END={max_dt}', where=f'INTERVAL_END > {max_dt}')
987
1010
 
988
1011
  dbs = otp.run(node,
989
1012
  symbols='LOCAL::',
@@ -992,15 +1015,20 @@ def databases(
992
1015
  end=db_constants.DEFAULT_END_DATE,
993
1016
  context=context)
994
1017
 
1018
+ if as_table:
1019
+ return dbs
1020
+
995
1021
  # WebAPI returns empty DataFrame (no columns) if there are no databases
996
1022
  if len(dbs) == 0:
997
1023
  return {}
998
1024
 
999
- db_list = list(dbs['DB_NAME'] if readable_only else dbs['DATABASE_NAME'])
1000
- merged_db_list = list(zip(db_list, dbs['DESCRIPTION']))
1025
+ db_list = list(dbs['DB_NAME'])
1026
+ db_description_list = dbs['DESCRIPTION'] if 'DESCRIPTION' in dbs else itertools.repeat('')
1027
+ merged_db_list = list(zip(db_list, db_description_list))
1001
1028
 
1002
1029
  db_dict = {
1003
- db_name: DB(db_name, description=db_description, context=context) for db_name, db_description in merged_db_list
1030
+ db_name: DB(db_name, description=db_description, context=context)
1031
+ for db_name, db_description in merged_db_list
1004
1032
  }
1005
1033
 
1006
1034
  if derived:
@@ -1018,6 +1046,7 @@ def derived_databases(
1018
1046
  selection_criteria='all',
1019
1047
  db=None,
1020
1048
  db_discovery_scope='query_host_only',
1049
+ as_table: bool = False,
1021
1050
  ) -> dict[str, DB]:
1022
1051
  """
1023
1052
  Gets available derived databases.
@@ -1052,6 +1081,9 @@ def derived_databases(
1052
1081
  an attempt will be performed to get derived databases from all reachable hosts.
1053
1082
  When *query_host_only* is specified,
1054
1083
  only derived databases from the host on which the query is performed will be returned.
1084
+ as_table: bool
1085
+ If False (default), this function returns a dictionary of database names and database objects.
1086
+ If True, returns a :pandas:`pandas.DataFrame` table where each row contains the info for each database.
1055
1087
 
1056
1088
  See also
1057
1089
  --------
@@ -1059,9 +1091,8 @@ def derived_databases(
1059
1091
 
1060
1092
  Returns
1061
1093
  -------
1062
- dict
1063
- Dict where keys are database names and values are :class:`DB <onetick.py.db._inspection.DB>` objects
1064
- with ``context`` specified.
1094
+ Dict where keys are database names and values are :class:`DB <onetick.py.db._inspection.DB>` objects
1095
+ or :pandas:`pandas.DataFrame` object depending on ``as_table`` parameter.
1065
1096
  """
1066
1097
  if start and end:
1067
1098
  time_range = otq.ShowDerivedDbList.TimeRange.QUERY_TIME_INTERVAL
@@ -1089,6 +1120,8 @@ def derived_databases(
1089
1120
  ep = ep.tick_type('ANY')
1090
1121
  db = db or 'LOCAL'
1091
1122
  dbs = otp.run(ep, symbols=f'{db}::', start=start, end=end, context=context)
1123
+ if as_table:
1124
+ return dbs
1092
1125
  if len(dbs) == 0:
1093
1126
  return {}
1094
1127
  db_list = list(dbs['DERIVED_DB_NAME'])
onetick/py/db/db.py CHANGED
@@ -110,8 +110,8 @@ def write_to_db(src: 'otp.Source',
110
110
  if timezone is None:
111
111
  timezone = configuration.config.tz
112
112
  if date is None or date is otp.adaptive:
113
- kwargs['start'] = start
114
- kwargs['end'] = end
113
+ kwargs['start_date'] = start
114
+ kwargs['end_date'] = end
115
115
  else:
116
116
  kwargs['date'] = date
117
117
 
onetick/py/functions.py CHANGED
@@ -2033,7 +2033,13 @@ def _add_element(cur_res, element, format_spec_additional=None):
2033
2033
  elif issubclass(element.dtype, float) and re.fullmatch(r'\.\d+f', format_spec_additional):
2034
2034
  # float has strange behavior when precision=0
2035
2035
  decimal_elem = element.apply(ott.decimal)
2036
- cur_res += decimal_elem.decimal.str(re.findall(r'\d+', format_spec_additional)[0])
2036
+ precision_str = re.findall(r'\d+', format_spec_additional)[0]
2037
+ try:
2038
+ precision = int(precision_str)
2039
+ except ValueError as exc:
2040
+ raise ValueError('Incorrect value for `precision` for formatting decimal number') from exc
2041
+
2042
+ cur_res += decimal_elem.decimal.str(precision)
2037
2043
  elif issubclass(element.dtype, (ott.nsectime, ott.msectime)):
2038
2044
  cur_res += element.dt.strftime(format_spec_additional)
2039
2045
  else: