ophyd-async 0.8.0a5__py3-none-any.whl → 0.9.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 (116) hide show
  1. ophyd_async/_version.py +2 -2
  2. ophyd_async/core/__init__.py +17 -46
  3. ophyd_async/core/_detector.py +68 -44
  4. ophyd_async/core/_device.py +120 -79
  5. ophyd_async/core/_device_filler.py +17 -8
  6. ophyd_async/core/_flyer.py +2 -2
  7. ophyd_async/core/_protocol.py +0 -28
  8. ophyd_async/core/_readable.py +30 -23
  9. ophyd_async/core/_settings.py +104 -0
  10. ophyd_async/core/_signal.py +164 -151
  11. ophyd_async/core/_signal_backend.py +4 -1
  12. ophyd_async/core/_soft_signal_backend.py +2 -1
  13. ophyd_async/core/_table.py +27 -14
  14. ophyd_async/core/_utils.py +30 -5
  15. ophyd_async/core/_yaml_settings.py +64 -0
  16. ophyd_async/epics/adandor/__init__.py +9 -0
  17. ophyd_async/epics/adandor/_andor.py +45 -0
  18. ophyd_async/epics/adandor/_andor_controller.py +49 -0
  19. ophyd_async/epics/adandor/_andor_io.py +36 -0
  20. ophyd_async/epics/adaravis/__init__.py +3 -1
  21. ophyd_async/epics/adaravis/_aravis.py +23 -37
  22. ophyd_async/epics/adaravis/_aravis_controller.py +21 -30
  23. ophyd_async/epics/adaravis/_aravis_io.py +4 -4
  24. ophyd_async/epics/adcore/__init__.py +15 -8
  25. ophyd_async/epics/adcore/_core_detector.py +41 -0
  26. ophyd_async/epics/adcore/_core_io.py +56 -31
  27. ophyd_async/epics/adcore/_core_logic.py +99 -84
  28. ophyd_async/epics/adcore/_core_writer.py +219 -0
  29. ophyd_async/epics/adcore/_hdf_writer.py +33 -59
  30. ophyd_async/epics/adcore/_jpeg_writer.py +26 -0
  31. ophyd_async/epics/adcore/_single_trigger.py +5 -4
  32. ophyd_async/epics/adcore/_tiff_writer.py +26 -0
  33. ophyd_async/epics/adcore/_utils.py +37 -36
  34. ophyd_async/epics/adkinetix/_kinetix.py +29 -24
  35. ophyd_async/epics/adkinetix/_kinetix_controller.py +15 -27
  36. ophyd_async/epics/adkinetix/_kinetix_io.py +7 -7
  37. ophyd_async/epics/adpilatus/__init__.py +2 -2
  38. ophyd_async/epics/adpilatus/_pilatus.py +28 -40
  39. ophyd_async/epics/adpilatus/_pilatus_controller.py +47 -25
  40. ophyd_async/epics/adpilatus/_pilatus_io.py +5 -5
  41. ophyd_async/epics/adsimdetector/__init__.py +3 -3
  42. ophyd_async/epics/adsimdetector/_sim.py +33 -17
  43. ophyd_async/epics/advimba/_vimba.py +23 -23
  44. ophyd_async/epics/advimba/_vimba_controller.py +21 -35
  45. ophyd_async/epics/advimba/_vimba_io.py +23 -23
  46. ophyd_async/epics/core/_aioca.py +52 -21
  47. ophyd_async/epics/core/_p4p.py +59 -16
  48. ophyd_async/epics/core/_pvi_connector.py +4 -2
  49. ophyd_async/epics/core/_signal.py +9 -2
  50. ophyd_async/epics/core/_util.py +10 -1
  51. ophyd_async/epics/eiger/_eiger_controller.py +10 -5
  52. ophyd_async/epics/eiger/_eiger_io.py +3 -3
  53. ophyd_async/epics/motor.py +26 -15
  54. ophyd_async/epics/sim/_ioc.py +29 -0
  55. ophyd_async/epics/{demo → sim}/_mover.py +12 -6
  56. ophyd_async/epics/{demo → sim}/_sensor.py +2 -2
  57. ophyd_async/epics/testing/__init__.py +24 -0
  58. ophyd_async/epics/testing/_example_ioc.py +91 -0
  59. ophyd_async/epics/testing/_utils.py +50 -0
  60. ophyd_async/epics/testing/test_records.db +174 -0
  61. ophyd_async/epics/testing/test_records_pva.db +177 -0
  62. ophyd_async/fastcs/core.py +2 -2
  63. ophyd_async/fastcs/panda/__init__.py +0 -2
  64. ophyd_async/fastcs/panda/_block.py +9 -9
  65. ophyd_async/fastcs/panda/_control.py +9 -4
  66. ophyd_async/fastcs/panda/_hdf_panda.py +7 -2
  67. ophyd_async/fastcs/panda/_table.py +4 -1
  68. ophyd_async/fastcs/panda/_trigger.py +7 -7
  69. ophyd_async/plan_stubs/__init__.py +14 -0
  70. ophyd_async/plan_stubs/_ensure_connected.py +11 -17
  71. ophyd_async/plan_stubs/_fly.py +2 -2
  72. ophyd_async/plan_stubs/_nd_attributes.py +7 -5
  73. ophyd_async/plan_stubs/_panda.py +13 -0
  74. ophyd_async/plan_stubs/_settings.py +125 -0
  75. ophyd_async/plan_stubs/_wait_for_awaitable.py +13 -0
  76. ophyd_async/sim/__init__.py +19 -0
  77. ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_detector_controller.py +9 -2
  78. ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_generator.py +13 -6
  79. ophyd_async/sim/{demo/_sim_motor.py → _sim_motor.py} +34 -32
  80. ophyd_async/tango/__init__.py +0 -43
  81. ophyd_async/tango/{signal → core}/__init__.py +7 -2
  82. ophyd_async/tango/{base_devices → core}/_base_device.py +38 -64
  83. ophyd_async/tango/{signal → core}/_signal.py +16 -4
  84. ophyd_async/tango/{base_devices → core}/_tango_readable.py +3 -4
  85. ophyd_async/tango/{signal → core}/_tango_transport.py +13 -15
  86. ophyd_async/tango/{demo → sim}/_counter.py +6 -7
  87. ophyd_async/tango/{demo → sim}/_mover.py +13 -9
  88. ophyd_async/testing/__init__.py +52 -0
  89. ophyd_async/testing/__pytest_assert_rewrite.py +4 -0
  90. ophyd_async/testing/_assert.py +176 -0
  91. ophyd_async/{core → testing}/_mock_signal_utils.py +15 -11
  92. ophyd_async/testing/_one_of_everything.py +126 -0
  93. ophyd_async/testing/_wait_for_pending.py +22 -0
  94. {ophyd_async-0.8.0a5.dist-info → ophyd_async-0.9.0.dist-info}/METADATA +50 -48
  95. ophyd_async-0.9.0.dist-info/RECORD +129 -0
  96. {ophyd_async-0.8.0a5.dist-info → ophyd_async-0.9.0.dist-info}/WHEEL +1 -1
  97. ophyd_async/core/_device_save_loader.py +0 -274
  98. ophyd_async/epics/adsimdetector/_sim_controller.py +0 -51
  99. ophyd_async/fastcs/panda/_utils.py +0 -16
  100. ophyd_async/sim/demo/__init__.py +0 -19
  101. ophyd_async/sim/testing/__init__.py +0 -0
  102. ophyd_async/tango/base_devices/__init__.py +0 -4
  103. ophyd_async-0.8.0a5.dist-info/RECORD +0 -112
  104. ophyd_async-0.8.0a5.dist-info/entry_points.txt +0 -2
  105. /ophyd_async/epics/{demo → sim}/__init__.py +0 -0
  106. /ophyd_async/epics/{demo → sim}/mover.db +0 -0
  107. /ophyd_async/epics/{demo → sim}/sensor.db +0 -0
  108. /ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/__init__.py +0 -0
  109. /ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_detector.py +0 -0
  110. /ophyd_async/sim/{demo/_pattern_detector → _pattern_detector}/_pattern_detector_writer.py +0 -0
  111. /ophyd_async/tango/{demo → sim}/__init__.py +0 -0
  112. /ophyd_async/tango/{demo → sim}/_detector.py +0 -0
  113. /ophyd_async/tango/{demo → sim}/_tango/__init__.py +0 -0
  114. /ophyd_async/tango/{demo → sim}/_tango/_servers.py +0 -0
  115. {ophyd_async-0.8.0a5.dist-info → ophyd_async-0.9.0.dist-info}/LICENSE +0 -0
  116. {ophyd_async-0.8.0a5.dist-info → ophyd_async-0.9.0.dist-info}/top_level.txt +0 -0
ophyd_async/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.8.0a5'
16
- __version_tuple__ = version_tuple = (0, 8, 0)
15
+ __version__ = version = '0.9.0'
16
+ __version_tuple__ = version_tuple = (0, 9, 0)
@@ -1,36 +1,17 @@
1
1
  from ._detector import (
2
2
  DetectorController,
3
+ DetectorControllerT,
3
4
  DetectorTrigger,
4
5
  DetectorWriter,
5
6
  StandardDetector,
6
7
  TriggerInfo,
7
8
  )
8
- from ._device import Device, DeviceCollector, DeviceConnector, DeviceVector
9
+ from ._device import Device, DeviceConnector, DeviceVector, init_devices
9
10
  from ._device_filler import DeviceFiller
10
- from ._device_save_loader import (
11
- all_at_once,
12
- get_signal_values,
13
- load_device,
14
- load_from_yaml,
15
- save_device,
16
- save_to_yaml,
17
- set_signal_values,
18
- walk_rw_signals,
19
- )
20
11
  from ._flyer import FlyerController, StandardFlyer
21
12
  from ._hdf_dataset import HDFDataset, HDFFile
22
13
  from ._log import config_ophyd_async_logging
23
14
  from ._mock_signal_backend import MockSignalBackend
24
- from ._mock_signal_utils import (
25
- callback_on_mock_put,
26
- get_mock,
27
- get_mock_put,
28
- mock_puts_blocked,
29
- reset_mock_put_calls,
30
- set_mock_put_proceeds,
31
- set_mock_value,
32
- set_mock_values,
33
- )
34
15
  from ._protocol import AsyncConfigurable, AsyncReadable, AsyncStageable
35
16
  from ._providers import (
36
17
  AutoIncrementFilenameProvider,
@@ -51,25 +32,26 @@ from ._readable import (
51
32
  StandardReadable,
52
33
  StandardReadableFormat,
53
34
  )
35
+ from ._settings import Settings, SettingsProvider
54
36
  from ._signal import (
55
37
  Signal,
38
+ SignalConnector,
56
39
  SignalR,
57
40
  SignalRW,
58
41
  SignalW,
59
42
  SignalX,
60
- assert_configuration,
61
- assert_emitted,
62
- assert_reading,
63
- assert_value,
43
+ observe_signals_value,
64
44
  observe_value,
65
45
  set_and_wait_for_other_value,
66
46
  set_and_wait_for_value,
67
47
  soft_signal_r_and_setter,
68
48
  soft_signal_rw,
69
49
  wait_for_value,
50
+ walk_rw_signals,
70
51
  )
71
52
  from ._signal_backend import (
72
53
  Array1D,
54
+ DTypeScalar_co,
73
55
  SignalBackend,
74
56
  SignalDatatype,
75
57
  SignalDatatypeT,
@@ -96,40 +78,26 @@ from ._utils import (
96
78
  in_micros,
97
79
  wait_for_connection,
98
80
  )
81
+ from ._yaml_settings import YamlSettingsProvider
99
82
 
100
83
  __all__ = [
101
84
  "DetectorController",
85
+ "DetectorControllerT",
102
86
  "DetectorTrigger",
103
87
  "DetectorWriter",
104
88
  "StandardDetector",
105
89
  "TriggerInfo",
106
90
  "Device",
107
91
  "DeviceConnector",
108
- "DeviceCollector",
92
+ "init_devices",
109
93
  "DeviceVector",
110
94
  "DeviceFiller",
111
- "all_at_once",
112
- "get_signal_values",
113
- "load_device",
114
- "load_from_yaml",
115
- "save_device",
116
- "save_to_yaml",
117
- "set_signal_values",
118
- "walk_rw_signals",
119
95
  "StandardFlyer",
120
96
  "FlyerController",
121
97
  "HDFDataset",
122
98
  "HDFFile",
123
99
  "config_ophyd_async_logging",
124
100
  "MockSignalBackend",
125
- "callback_on_mock_put",
126
- "get_mock",
127
- "get_mock_put",
128
- "mock_puts_blocked",
129
- "reset_mock_put_calls",
130
- "set_mock_put_proceeds",
131
- "set_mock_value",
132
- "set_mock_values",
133
101
  "AsyncConfigurable",
134
102
  "AsyncReadable",
135
103
  "AsyncStageable",
@@ -148,22 +116,24 @@ __all__ = [
148
116
  "HintedSignal",
149
117
  "StandardReadable",
150
118
  "StandardReadableFormat",
119
+ "Settings",
120
+ "SettingsProvider",
151
121
  "Signal",
122
+ "SignalConnector",
152
123
  "SignalR",
153
124
  "SignalRW",
154
125
  "SignalW",
155
126
  "SignalX",
156
- "assert_configuration",
157
- "assert_emitted",
158
- "assert_reading",
159
- "assert_value",
160
127
  "observe_value",
128
+ "observe_signals_value",
161
129
  "set_and_wait_for_value",
162
130
  "set_and_wait_for_other_value",
163
131
  "soft_signal_r_and_setter",
164
132
  "soft_signal_rw",
165
133
  "wait_for_value",
134
+ "walk_rw_signals",
166
135
  "Array1D",
136
+ "DTypeScalar_co",
167
137
  "SignalBackend",
168
138
  "make_datakey",
169
139
  "StrictEnum",
@@ -190,4 +160,5 @@ __all__ = [
190
160
  "in_micros",
191
161
  "wait_for_connection",
192
162
  "completed_status",
163
+ "YamlSettingsProvider",
193
164
  ]
@@ -5,10 +5,15 @@ import time
5
5
  from abc import ABC, abstractmethod
6
6
  from collections.abc import AsyncGenerator, AsyncIterator, Callable, Iterator, Sequence
7
7
  from functools import cached_property
8
+ from typing import (
9
+ Generic,
10
+ TypeVar,
11
+ )
8
12
 
9
13
  from bluesky.protocols import (
10
14
  Collectable,
11
15
  Flyable,
16
+ Hints,
12
17
  Preparable,
13
18
  Reading,
14
19
  Stageable,
@@ -30,13 +35,13 @@ class DetectorTrigger(StrictEnum):
30
35
  """Type of mechanism for triggering a detector to take frames"""
31
36
 
32
37
  #: Detector generates internal trigger for given rate
33
- internal = "internal"
38
+ INTERNAL = "internal"
34
39
  #: Expect a series of arbitrary length trigger signals
35
- edge_trigger = "edge_trigger"
40
+ EDGE_TRIGGER = "edge_trigger"
36
41
  #: Expect a series of constant width external gate signals
37
- constant_gate = "constant_gate"
42
+ CONSTANT_GATE = "constant_gate"
38
43
  #: Expect a series of variable width external gate signals
39
- variable_gate = "variable_gate"
44
+ VARIABLE_GATE = "variable_gate"
40
45
 
41
46
 
42
47
  class TriggerInfo(BaseModel):
@@ -53,7 +58,7 @@ class TriggerInfo(BaseModel):
53
58
  #: - 3 times for final flat field images
54
59
  number_of_triggers: NonNegativeInt | list[NonNegativeInt]
55
60
  #: Sort of triggers that will be sent
56
- trigger: DetectorTrigger = Field(default=DetectorTrigger.internal)
61
+ trigger: DetectorTrigger = Field(default=DetectorTrigger.INTERNAL)
57
62
  #: What is the minimum deadtime between triggers
58
63
  deadtime: float | None = Field(default=None, ge=0)
59
64
  #: What is the maximum high time of the triggers
@@ -87,7 +92,7 @@ class DetectorController(ABC):
87
92
  """For a given exposure, how long should the time between exposures be"""
88
93
 
89
94
  @abstractmethod
90
- async def prepare(self, trigger_info: TriggerInfo):
95
+ async def prepare(self, trigger_info: TriggerInfo) -> None:
91
96
  """
92
97
  Do all necessary steps to prepare the detector for triggers.
93
98
 
@@ -157,6 +162,23 @@ class DetectorWriter(ABC):
157
162
  async def close(self) -> None:
158
163
  """Close writer, blocks until I/O is complete"""
159
164
 
165
+ @property
166
+ def hints(self) -> Hints:
167
+ return {}
168
+
169
+
170
+ # Add type var for controller so we can define
171
+ # StandardDetector[KinetixController, ADWriter] for example
172
+ DetectorControllerT = TypeVar("DetectorControllerT", bound=DetectorController)
173
+ DetectorWriterT = TypeVar("DetectorWriterT", bound=DetectorWriter)
174
+
175
+
176
+ def _ensure_trigger_info_exists(trigger_info: TriggerInfo | None) -> TriggerInfo:
177
+ # make absolute sure we realy have a valid TriggerInfo ... mostly for pylance
178
+ if trigger_info is None:
179
+ raise RuntimeError("Trigger info must be set before calling this method.")
180
+ return trigger_info
181
+
160
182
 
161
183
  class StandardDetector(
162
184
  Device,
@@ -168,6 +190,7 @@ class StandardDetector(
168
190
  Flyable,
169
191
  Collectable,
170
192
  WritesStreamAssets,
193
+ Generic[DetectorControllerT, DetectorWriterT],
171
194
  ):
172
195
  """
173
196
  Useful detector base class for step and fly scanning detectors.
@@ -176,8 +199,8 @@ class StandardDetector(
176
199
 
177
200
  def __init__(
178
201
  self,
179
- controller: DetectorController,
180
- writer: DetectorWriter,
202
+ controller: DetectorControllerT,
203
+ writer: DetectorWriterT,
181
204
  config_sigs: Sequence[SignalR] = (),
182
205
  name: str = "",
183
206
  connector: DeviceConnector | None = None,
@@ -211,19 +234,11 @@ class StandardDetector(
211
234
  self._initial_frame: int = 0
212
235
  super().__init__(name, connector=connector)
213
236
 
214
- @property
215
- def controller(self) -> DetectorController:
216
- return self._controller
217
-
218
- @property
219
- def writer(self) -> DetectorWriter:
220
- return self._writer
221
-
222
237
  @AsyncStatus.wrap
223
238
  async def stage(self) -> None:
224
239
  # Disarm the detector, stop file writing.
225
240
  await self._check_config_sigs()
226
- await asyncio.gather(self.writer.close(), self.controller.disarm())
241
+ await asyncio.gather(self._writer.close(), self._controller.disarm())
227
242
  self._trigger_info = None
228
243
 
229
244
  async def _check_config_sigs(self):
@@ -244,7 +259,7 @@ class StandardDetector(
244
259
  @AsyncStatus.wrap
245
260
  async def unstage(self) -> None:
246
261
  # Stop data writing.
247
- await asyncio.gather(self.writer.close(), self.controller.disarm())
262
+ await asyncio.gather(self._writer.close(), self._controller.disarm())
248
263
 
249
264
  async def read_configuration(self) -> dict[str, Reading]:
250
265
  return await merge_gathered_dicts(sig.read() for sig in self._config_sigs)
@@ -265,21 +280,25 @@ class StandardDetector(
265
280
  await self.prepare(
266
281
  TriggerInfo(
267
282
  number_of_triggers=1,
268
- trigger=DetectorTrigger.internal,
283
+ trigger=DetectorTrigger.INTERNAL,
269
284
  deadtime=None,
270
285
  livetime=None,
271
286
  frame_timeout=None,
272
287
  )
273
288
  )
274
- assert self._trigger_info
275
- assert self._trigger_info.trigger is DetectorTrigger.internal
289
+
290
+ self._trigger_info = _ensure_trigger_info_exists(self._trigger_info)
291
+ if self._trigger_info.trigger is not DetectorTrigger.INTERNAL:
292
+ msg = "The trigger method can only be called with INTERNAL triggering"
293
+ raise ValueError(msg)
294
+
276
295
  # Arm the detector and wait for it to finish.
277
- indices_written = await self.writer.get_indices_written()
278
- await self.controller.arm()
279
- await self.controller.wait_for_idle()
296
+ indices_written = await self._writer.get_indices_written()
297
+ await self._controller.arm()
298
+ await self._controller.wait_for_idle()
280
299
  end_observation = indices_written + 1
281
300
 
282
- async for index in self.writer.observe_indices_written(
301
+ async for index in self._writer.observe_indices_written(
283
302
  DEFAULT_TIMEOUT
284
303
  + (self._trigger_info.livetime or 0)
285
304
  + (self._trigger_info.deadtime or 0)
@@ -303,28 +322,29 @@ class StandardDetector(
303
322
  Args:
304
323
  value: TriggerInfo describing how to trigger the detector
305
324
  """
306
- if value.trigger != DetectorTrigger.internal:
307
- assert (
308
- value.deadtime
309
- ), "Deadtime must be supplied when in externally triggered mode"
310
- if value.deadtime:
311
- required = self.controller.get_deadtime(value.livetime)
312
- assert required <= value.deadtime, (
313
- f"Detector {self.controller} needs at least {required}s deadtime, "
314
- f"but trigger logic provides only {value.deadtime}s"
325
+ if value.trigger != DetectorTrigger.INTERNAL and not value.deadtime:
326
+ msg = "Deadtime must be supplied when in externally triggered mode"
327
+ raise ValueError(msg)
328
+ required_deadtime = self._controller.get_deadtime(value.livetime)
329
+ if value.deadtime and required_deadtime > value.deadtime:
330
+ msg = (
331
+ f"Detector {self._controller} needs at least {required_deadtime}s "
332
+ f"deadtime, but trigger logic provides only {value.deadtime}s"
315
333
  )
334
+ raise ValueError(msg)
335
+
316
336
  self._trigger_info = value
317
337
  self._number_of_triggers_iter = iter(
318
338
  self._trigger_info.number_of_triggers
319
339
  if isinstance(self._trigger_info.number_of_triggers, list)
320
340
  else [self._trigger_info.number_of_triggers]
321
341
  )
322
- self._initial_frame = await self.writer.get_indices_written()
342
+ self._initial_frame = await self._writer.get_indices_written()
323
343
  self._describe, _ = await asyncio.gather(
324
- self.writer.open(value.multiplier), self.controller.prepare(value)
344
+ self._writer.open(value.multiplier), self._controller.prepare(value)
325
345
  )
326
- if value.trigger != DetectorTrigger.internal:
327
- await self.controller.arm()
346
+ if value.trigger != DetectorTrigger.INTERNAL:
347
+ await self._controller.arm()
328
348
  self._fly_start = time.monotonic()
329
349
 
330
350
  @AsyncStatus.wrap
@@ -342,8 +362,8 @@ class StandardDetector(
342
362
 
343
363
  @WatchableAsyncStatus.wrap
344
364
  async def complete(self):
345
- assert self._trigger_info
346
- indices_written = self.writer.observe_indices_written(
365
+ self._trigger_info = _ensure_trigger_info_exists(self._trigger_info)
366
+ indices_written = self._writer.observe_indices_written(
347
367
  self._trigger_info.frame_timeout
348
368
  or (
349
369
  DEFAULT_TIMEOUT
@@ -372,7 +392,7 @@ class StandardDetector(
372
392
  self._completable_frames = 0
373
393
  self._frames_to_complete = 0
374
394
  self._number_of_triggers_iter = None
375
- await self.controller.wait_for_idle()
395
+ await self._controller.wait_for_idle()
376
396
 
377
397
  async def describe_collect(self) -> dict[str, DataKey]:
378
398
  return self._describe
@@ -384,9 +404,13 @@ class StandardDetector(
384
404
  # The index is optional, and provided for fly scans, however this needs to be
385
405
  # retrieved for step scans.
386
406
  if index is None:
387
- index = await self.writer.get_indices_written()
388
- async for doc in self.writer.collect_stream_docs(index):
407
+ index = await self._writer.get_indices_written()
408
+ async for doc in self._writer.collect_stream_docs(index):
389
409
  yield doc
390
410
 
391
411
  async def get_index(self) -> int:
392
- return await self.writer.get_indices_written()
412
+ return await self._writer.get_indices_written()
413
+
414
+ @property
415
+ def hints(self) -> Hints:
416
+ return self._writer.hints