onetick-py 1.162.2__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 +266 -0
  4. locator_parser/common.py +365 -0
  5. locator_parser/io.py +41 -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 +280 -0
  12. onetick/lib/__init__.py +4 -0
  13. onetick/lib/instance.py +138 -0
  14. onetick/py/__init__.py +290 -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 +645 -0
  19. onetick/py/aggregations/_docs.py +912 -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 +427 -0
  26. onetick/py/aggregations/other.py +1014 -0
  27. onetick/py/backports.py +26 -0
  28. onetick/py/cache.py +373 -0
  29. onetick/py/callback/__init__.py +5 -0
  30. onetick/py/callback/callback.py +275 -0
  31. onetick/py/callback/callbacks.py +131 -0
  32. onetick/py/compatibility.py +752 -0
  33. onetick/py/configuration.py +736 -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 +2307 -0
  45. onetick/py/core/_internal/_state_vars.py +87 -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 +810 -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 +270 -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 +1001 -0
  58. onetick/py/core/_source/source_methods/joins.py +1393 -0
  59. onetick/py/core/_source/source_methods/merges.py +566 -0
  60. onetick/py/core/_source/source_methods/misc.py +1325 -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 +702 -0
  68. onetick/py/core/_source/symbol.py +202 -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 +215 -0
  75. onetick/py/core/column_operations/_methods/methods.py +294 -0
  76. onetick/py/core/column_operations/_methods/op_types.py +150 -0
  77. onetick/py/core/column_operations/accessors/__init__.py +0 -0
  78. onetick/py/core/column_operations/accessors/_accessor.py +30 -0
  79. onetick/py/core/column_operations/accessors/decimal_accessor.py +92 -0
  80. onetick/py/core/column_operations/accessors/dt_accessor.py +464 -0
  81. onetick/py/core/column_operations/accessors/float_accessor.py +160 -0
  82. onetick/py/core/column_operations/accessors/str_accessor.py +1374 -0
  83. onetick/py/core/column_operations/base.py +1061 -0
  84. onetick/py/core/cut_builder.py +149 -0
  85. onetick/py/core/db_constants.py +20 -0
  86. onetick/py/core/eval_query.py +244 -0
  87. onetick/py/core/lambda_object.py +442 -0
  88. onetick/py/core/multi_output_source.py +193 -0
  89. onetick/py/core/per_tick_script.py +2253 -0
  90. onetick/py/core/query_inspector.py +465 -0
  91. onetick/py/core/source.py +1663 -0
  92. onetick/py/db/__init__.py +2 -0
  93. onetick/py/db/_inspection.py +1042 -0
  94. onetick/py/db/db.py +1423 -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 +2354 -0
  100. onetick/py/license.py +188 -0
  101. onetick/py/log.py +88 -0
  102. onetick/py/math.py +947 -0
  103. onetick/py/misc.py +437 -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 +211 -0
  108. onetick/py/pyomd_mock.py +47 -0
  109. onetick/py/run.py +841 -0
  110. onetick/py/servers.py +173 -0
  111. onetick/py/session.py +1342 -0
  112. onetick/py/sources/__init__.py +19 -0
  113. onetick/py/sources/cache.py +167 -0
  114. onetick/py/sources/common.py +126 -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 +1049 -0
  119. onetick/py/sources/empty.py +94 -0
  120. onetick/py/sources/odbc.py +337 -0
  121. onetick/py/sources/order_book.py +238 -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 +357 -0
  129. onetick/py/sources/ticks.py +825 -0
  130. onetick/py/sql.py +70 -0
  131. onetick/py/state.py +256 -0
  132. onetick/py/types.py +2056 -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 +499 -0
  141. onetick/py/utils/query.py +49 -0
  142. onetick/py/utils/render.py +1139 -0
  143. onetick/py/utils/script.py +244 -0
  144. onetick/py/utils/temp.py +471 -0
  145. onetick/py/utils/types.py +118 -0
  146. onetick/py/utils/tz.py +82 -0
  147. onetick_py-1.162.2.dist-info/METADATA +148 -0
  148. onetick_py-1.162.2.dist-info/RECORD +152 -0
  149. onetick_py-1.162.2.dist-info/WHEEL +5 -0
  150. onetick_py-1.162.2.dist-info/entry_points.txt +2 -0
  151. onetick_py-1.162.2.dist-info/licenses/LICENSE +21 -0
  152. onetick_py-1.162.2.dist-info/top_level.txt +2 -0
locator_parser/io.py ADDED
@@ -0,0 +1,41 @@
1
+ import weakref
2
+ from locator_parser.common import Reader, Writer
3
+
4
+
5
+ class FileWriter(Writer):
6
+
7
+ def __init__(self, file_path):
8
+ self.__path = file_path
9
+
10
+ super(FileWriter, self).__init__()
11
+
12
+ def flush(self):
13
+ with open(self.__path, "w") as fout:
14
+ for line in self.lines:
15
+ if line[-1:] != "\n":
16
+ line += "\n"
17
+
18
+ fout.write(line)
19
+
20
+
21
+ class PrintWriter(Writer):
22
+
23
+ def flush(self):
24
+ print("\n".join(self.lines))
25
+
26
+
27
+ class FileReader(Reader):
28
+
29
+ def __init__(self, file_path):
30
+ self.iterable_object = open(file_path.replace('"', ""), "r")
31
+ self.__finalizer = weakref.finalize(self, lambda x: x.close(), self.iterable_object)
32
+
33
+ super(FileReader, self).__init__()
34
+
35
+
36
+ class LinesReader(Reader):
37
+
38
+ def __init__(self, lines):
39
+ self.iterable_object = lines.split("\n")
40
+
41
+ super(LinesReader, self).__init__()
@@ -0,0 +1,150 @@
1
+ import os
2
+ import re
3
+
4
+ from locator_parser.common import Entity
5
+ from locator_parser.io import FileReader, PrintWriter
6
+ from locator_parser.actions import DoNothing
7
+
8
+
9
+ class Include(Entity):
10
+ TAG = "INCLUDE"
11
+ SINGLE = True
12
+ RECURSIVELY = False
13
+
14
+ def parse(self, reader, writer, action):
15
+ path = self.path
16
+ matched = re.search(r"\$\{(.*)\}", path)
17
+
18
+ # env variable found in the path
19
+ if matched:
20
+ if matched.group(0)[2:-1] not in os.environ:
21
+ raise Exception("Includes use not defined environment variable: % s" % matched.group(0))
22
+
23
+ path = path.replace(matched.group(0), os.environ[matched.group(0)[2:-1]])
24
+
25
+ # read locator recursivly
26
+ if Include.RECURSIVELY:
27
+ parse_locator(FileReader(path), PrintWriter(), action, recursively=True)
28
+
29
+
30
+ class Includes(Entity):
31
+ TAG = "INCLUDES"
32
+ CHILDREN = [Include]
33
+
34
+
35
+ class Location(Entity):
36
+ TAG = "LOCATION"
37
+ SINGLE = True
38
+
39
+
40
+ class Locations(Entity):
41
+ TAG = "LOCATIONS"
42
+ CHILDREN = [Location]
43
+
44
+
45
+ class RawDB(Entity):
46
+ TAG = "RAW_DB"
47
+ CHILDREN = [Locations]
48
+ HAS_PROPERTIES = True
49
+
50
+
51
+ class RawData(Entity):
52
+ TAG = "RAW_DATA"
53
+ CHILDREN = [RawDB]
54
+
55
+
56
+ class FeedOptions(Entity):
57
+ TAG = "OPTIONS"
58
+ SINGLE = True
59
+
60
+
61
+ class Feed(Entity):
62
+ TAG = "FEED"
63
+ HAS_PROPERTIES = True
64
+ CHILDREN = [FeedOptions]
65
+
66
+
67
+ class DB(Entity):
68
+ TAG = "DB"
69
+ CHILDREN = [Locations, RawData, Feed]
70
+ HAS_PROPERTIES = True
71
+
72
+
73
+ class DBs(Entity):
74
+ TAG = "DATABASES"
75
+ CHILDREN = [DB]
76
+
77
+
78
+ class ServerLocation(Entity):
79
+ TAG = "LOCATION"
80
+ SINGLE = True
81
+
82
+
83
+ class TickServers(Entity):
84
+ TAG = "TICK_SERVERS"
85
+ CHILDREN = [ServerLocation]
86
+
87
+
88
+ class CEPServerLocation(Entity):
89
+ TAG = "LOCATION"
90
+ SINGLE = True
91
+
92
+
93
+ class CEPTickServers(Entity):
94
+ TAG = "CEP_TICK_SERVERS"
95
+ CHILDREN = [CEPServerLocation]
96
+
97
+
98
+ class Range(Entity):
99
+ TAG = "RANGE"
100
+ SINGLE = True
101
+
102
+
103
+ class TimeInterval(Entity):
104
+ TAG = "TIME_INTERVAL"
105
+ HAS_PROPERTIES = True
106
+ CHILDREN = [Range]
107
+
108
+
109
+ class VirtualDB(Entity):
110
+ TAG = "DB"
111
+ HAS_PROPERTIES = True
112
+ CHILDREN = [TimeInterval]
113
+
114
+
115
+ class VirtualDBs(Entity):
116
+ TAG = "VIRTUAL_DATABASES"
117
+ CHILDREN = [VirtualDB]
118
+
119
+
120
+ def parse_locator(reader, writer, action=DoNothing(), recursively=False):
121
+ Include.RECURSIVELY = recursively
122
+ writer.refresh()
123
+ reader.set_writer(writer)
124
+
125
+ databases_p = DBs()
126
+ v_databases_p = VirtualDBs()
127
+ tick_servers_p = TickServers()
128
+ cep_tick_servers_p = CEPTickServers()
129
+ includes_p = Includes()
130
+
131
+ for _ in reader:
132
+ databases_p(reader, writer, action)
133
+ v_databases_p(reader, writer, action)
134
+ tick_servers_p(reader, writer, action)
135
+ cep_tick_servers_p(reader, writer, action)
136
+ includes_p(reader, writer, action)
137
+
138
+
139
+ # ----------------------------------------- #
140
+ # set parent
141
+ for _, cls in list(globals().items()):
142
+ try:
143
+ if issubclass(cls, Entity) and cls != Entity:
144
+ for child in cls.CHILDREN:
145
+ child.PARENT = Entity
146
+
147
+ if not cls.HAS_PROPERTIES and not cls.SINGLE:
148
+ child.PARENT = cls
149
+ except Exception:
150
+ continue
onetick/__init__.py ADDED
@@ -0,0 +1,101 @@
1
+ import sys
2
+
3
+
4
+ def __search_main_one_tick_dir():
5
+ try:
6
+ import onetick.query_webapi # noqa
7
+ # if onetick.query_webapi is imported successfully, do not raise any warnings
8
+ return __search_main_one_tick_dir_catch(show_warnings=False)
9
+ except ImportError:
10
+ return __search_main_one_tick_dir_catch(show_warnings=True)
11
+
12
+
13
+ def __search_main_one_tick_dir_catch(show_warnings=True): # noqa: C901
14
+ import os
15
+ import warnings
16
+ import sysconfig
17
+ from pathlib import Path
18
+
19
+ if os.environ.get('OTP_SKIP_OTQ_VALIDATION', False):
20
+ try:
21
+ import onetick_stubs # noqa
22
+ except ImportError:
23
+ if show_warnings:
24
+ warnings.warn(
25
+ "OTP_SKIP_OTQ_VALIDATION environment variable is set,"
26
+ " but onetick_stubs module is not available."
27
+ " Please, install onetick-query-stubs to avoid import errors"
28
+ " or unset OTP_SKIP_OTQ_VALIDATION to use onetick.query module."
29
+ )
30
+ return tuple()
31
+
32
+ config_vars = sysconfig.get_config_vars()
33
+
34
+ ot_bin_path = os.path.join("bin")
35
+ ot_python_path = os.path.join(ot_bin_path, "python")
36
+ ot_numpy_path = os.path.join(
37
+ ot_bin_path,
38
+ "numpy",
39
+ "python"
40
+ # short python version 27, 36, 37, etc
41
+ + config_vars["py_version_nodot"]
42
+ # suffix at the end, either empty string for python with the standard memory allocator,
43
+ # or 'm' for python with the py-malloc allocator
44
+ + config_vars["abiflags"],
45
+ )
46
+
47
+ if os.name == "nt":
48
+ default_main_one_tick_dir = "C:/OMD/one_market_data/one_tick"
49
+ elif os.name == "posix":
50
+ default_main_one_tick_dir = "/opt/one_market_data/one_tick"
51
+ else:
52
+ default_main_one_tick_dir = None
53
+
54
+ main_one_tick_dir = os.environ.get("MAIN_ONE_TICK_DIR")
55
+
56
+ if not main_one_tick_dir:
57
+ message = (
58
+ "MAIN_ONE_TICK_DIR environment variable is not set."
59
+ " It is a recommended way to let onetick-py know where OneTick python libraries are located."
60
+ )
61
+ if not default_main_one_tick_dir:
62
+ if show_warnings:
63
+ warnings.warn(message)
64
+ return
65
+ message += f" We will try to use default value for your system: {default_main_one_tick_dir}."
66
+ if show_warnings:
67
+ warnings.warn(message)
68
+ main_one_tick_dir = default_main_one_tick_dir
69
+
70
+ main_one_tick_dir = Path(main_one_tick_dir)
71
+
72
+ if not main_one_tick_dir.is_dir():
73
+ if show_warnings:
74
+ warnings.warn(
75
+ f"MAIN_ONE_TICK_DIR is set to '{main_one_tick_dir}',"
76
+ " but this path is not a directory or doesn't exist."
77
+ )
78
+ return
79
+
80
+ ot_bin_path = main_one_tick_dir / ot_bin_path
81
+ ot_python_path = main_one_tick_dir / ot_python_path
82
+
83
+ for directory in (ot_python_path, ot_bin_path):
84
+ if not directory.is_dir():
85
+ if show_warnings:
86
+ warnings.warn(
87
+ f"MAIN_ONE_TICK_DIR is set to '{main_one_tick_dir}',"
88
+ f" and it must contain '{directory}' directory,"
89
+ " but this path is not a directory or doesn't exist."
90
+ )
91
+ return
92
+
93
+ ot_numpy_path = main_one_tick_dir / ot_numpy_path
94
+
95
+ return (ot_bin_path, ot_python_path, ot_numpy_path)
96
+
97
+
98
+ for directory in __search_main_one_tick_dir() or []:
99
+ sys.path.append(str(directory))
100
+
101
+ __path__ = __import__("pkgutil").extend_path(__path__, __name__)
@@ -0,0 +1,3 @@
1
+ from .ot_doctest import (register_ot_directive,
2
+ apply_directive,
3
+ OTDoctestParser)
@@ -0,0 +1,40 @@
1
+ from typing import List
2
+ from sphinx.ext.napoleon.docstring import NumpyDocstring
3
+ from sphinx.locale import get_translation
4
+ from onetick.doc_utilities.snippets import parse_string
5
+
6
+
7
+ class OTNumpyDocstring(NumpyDocstring):
8
+
9
+ def _parse_examples_section(self, section: str) -> List[str]:
10
+
11
+ """Applies OT directives for all lines"""
12
+
13
+ # combining super()._parse_examples_section and super()._parse_generic_section
14
+ # due to super()._parse_examples_section just prepare parameters and
15
+ # super()._parse_generic_section get lines and modify them.
16
+ # but we need to add logic on lines but before super()._parse_generic_section modification
17
+ labels = {
18
+ 'example': get_translation('sphinx')('Example'),
19
+ 'examples': get_translation('sphinx')('Examples'),
20
+ }
21
+ use_admonition = self._config.napoleon_use_admonition_for_examples
22
+ section = labels.get(section.lower(), section)
23
+
24
+ lines = self._strip_empty(self._consume_to_next_section())
25
+ lines = self._dedent(lines)
26
+
27
+ # OneTick custom logic start
28
+ doc = parse_string('\n'.join(lines), caller='doc')
29
+ lines = doc.split('\n')
30
+ # OneTick custom logic end
31
+
32
+ if use_admonition:
33
+ header = '.. admonition:: %s' % section # noqa
34
+ lines = self._indent(lines, 3)
35
+ else:
36
+ header = '.. rubric:: %s' % section # noqa
37
+ if lines:
38
+ return [header, ''] + lines + ['']
39
+ else:
40
+ return [header, '']
@@ -0,0 +1,140 @@
1
+ import doctest
2
+ import re
3
+ import inspect
4
+
5
+ from typing import Union, Optional
6
+ from onetick.py.backports import Literal
7
+
8
+
9
+ def snippet_name(example: Union[doctest.Example, str], value):
10
+ if isinstance(example, doctest.Example):
11
+ example.name = value # type: ignore
12
+ return example
13
+
14
+
15
+ def skip_snippet(example: Union[doctest.Example, str], value):
16
+ if isinstance(example, doctest.Example):
17
+ example.skip_snippet = True # type: ignore
18
+ return example
19
+
20
+
21
+ def skip_example(example, value, caller=None):
22
+ if caller is not None and value != '' and value != caller: # do nothing if caller passed and value not caller
23
+ return example
24
+ if isinstance(example, doctest.Example):
25
+ example.skip = True
26
+ return example
27
+
28
+
29
+ OT_DIRECTIVES = {'skip-example': skip_example,
30
+ 'snippet-name': snippet_name,
31
+ 'skip-snippet': skip_snippet}
32
+
33
+
34
+ def register_ot_directive(directive, fun):
35
+ """
36
+ Register OT directive.
37
+
38
+ directive sintax: ... OTdirective: <directive>: <directive_parameter>;
39
+
40
+ Parameters
41
+ ----------
42
+ directive: str
43
+ directive name
44
+ fun: callable
45
+ fun will be executed if `directive` will be found
46
+ fun should have two positional parameters:
47
+ first: string or doctest.Example
48
+ second: direction parameter
49
+ fun should return str, doctest.Example or None
50
+ """
51
+ OT_DIRECTIVES[directive] = fun
52
+
53
+
54
+ class ApplyDirective:
55
+
56
+ _OT_DIRECTIVE_RE = r'(.*?)\s*# OTdirective: (.*)'
57
+ _OT_DIRECTIVE_PARSER = re.compile(r'\s*?(?P<func>[A-Za-z_\-0-9]*)\s*?:(?P<param>[^:;]*);')
58
+
59
+ def __init__(self, caller: Optional[str] = None):
60
+ self.caller = caller
61
+
62
+ def _get_directives(self, item):
63
+ is_example = isinstance(item, doctest.Example)
64
+ string = item
65
+ if is_example:
66
+ string = item.source
67
+ res = []
68
+ funcs = []
69
+ for doc in string.split('\n'):
70
+ s, f = self._get_directives_impl(doc)
71
+ res.append(s)
72
+ funcs.extend(f)
73
+
74
+ string = '\n'.join(res)
75
+ if is_example:
76
+ item.source = string
77
+ return item, funcs
78
+ return string, funcs
79
+
80
+ def _get_directives_impl(self, string: str):
81
+ directives = re.match(self._OT_DIRECTIVE_RE, string, re.MULTILINE | re.DOTALL)
82
+ if directives is None:
83
+ return string, {}
84
+ doc, directive_str = directives.groups()
85
+ funcs = []
86
+ for fun, v in re.findall(self._OT_DIRECTIVE_PARSER, directive_str):
87
+ if fun.strip() not in OT_DIRECTIVES:
88
+ raise KeyError(f"Unknown directive: '{fun.strip()}'. Original: '{directive_str}'")
89
+ funcs.append((OT_DIRECTIVES[fun.strip()], v.strip()))
90
+ return doc, funcs
91
+
92
+ def __call__(self, item):
93
+ doc, funcs = self._get_directives(item)
94
+ for fun, param in funcs:
95
+ params = {}
96
+ if self.caller and 'caller' in inspect.signature(fun).parameters.keys():
97
+ params['caller'] = self.caller
98
+ doc = fun(doc, param, **params)
99
+ return doc
100
+
101
+
102
+ def apply_directive(example: Union[doctest.Example, str], caller: Optional[str] = None):
103
+
104
+ """
105
+ Applies OT directive to `example`
106
+ Drops directive comment
107
+
108
+ See Also
109
+ --------
110
+ register_ot_directive
111
+ """
112
+
113
+ return ApplyDirective(caller)(example)
114
+
115
+
116
+ class OTDoctestParser(doctest.DocTestParser):
117
+
118
+ """
119
+ This class applicable only to parse doctest example!
120
+ Do not run tests with this parser!
121
+ """
122
+
123
+ def __init__(self, *args, caller: Optional[str] = None, **kwargs):
124
+ super().__init__(*args, **kwargs)
125
+ self.caller = caller
126
+
127
+ def _IS_BLANK_OR_COMMENT(self, value):
128
+
129
+ if value.strip().startswith('# OTdirective'):
130
+ return False
131
+ else:
132
+ return super()._IS_BLANK_OR_COMMENT(value)
133
+
134
+ def parse(self, *args, **kwargs):
135
+ """
136
+ Applies OT directive for all examples
137
+ """
138
+ examples = super().parse(*args, **kwargs)
139
+ res = [apply_directive(x, self.caller) for x in examples]
140
+ return res