databento 0.76.0__tar.gz → 0.78.0__tar.gz

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 (41) hide show
  1. {databento-0.76.0 → databento-0.78.0}/PKG-INFO +3 -3
  2. {databento-0.76.0 → databento-0.78.0}/README.md +1 -1
  3. {databento-0.76.0 → databento-0.78.0}/databento/common/bentologging.py +3 -2
  4. {databento-0.76.0 → databento-0.78.0}/databento/common/dbnstore.py +20 -14
  5. {databento-0.76.0 → databento-0.78.0}/databento/common/enums.py +7 -2
  6. {databento-0.76.0 → databento-0.78.0}/databento/common/parsing.py +9 -6
  7. {databento-0.76.0 → databento-0.78.0}/databento/common/publishers.py +31 -0
  8. {databento-0.76.0 → databento-0.78.0}/databento/common/symbology.py +3 -2
  9. {databento-0.76.0 → databento-0.78.0}/databento/common/types.py +6 -4
  10. {databento-0.76.0 → databento-0.78.0}/databento/common/validation.py +3 -2
  11. {databento-0.76.0 → databento-0.78.0}/databento/historical/api/batch.py +3 -2
  12. {databento-0.76.0 → databento-0.78.0}/databento/live/client.py +21 -14
  13. {databento-0.76.0 → databento-0.78.0}/databento/live/gateway.py +6 -4
  14. {databento-0.76.0 → databento-0.78.0}/databento/live/protocol.py +11 -9
  15. {databento-0.76.0 → databento-0.78.0}/databento/live/session.py +57 -9
  16. databento-0.78.0/databento/version.py +1 -0
  17. {databento-0.76.0 → databento-0.78.0}/pyproject.toml +2 -2
  18. databento-0.76.0/databento/version.py +0 -1
  19. {databento-0.76.0 → databento-0.78.0}/LICENSE +0 -0
  20. {databento-0.76.0 → databento-0.78.0}/databento/__init__.py +0 -0
  21. {databento-0.76.0 → databento-0.78.0}/databento/common/__init__.py +0 -0
  22. {databento-0.76.0 → databento-0.78.0}/databento/common/constants.py +0 -0
  23. {databento-0.76.0 → databento-0.78.0}/databento/common/cram.py +0 -0
  24. {databento-0.76.0 → databento-0.78.0}/databento/common/error.py +0 -0
  25. {databento-0.76.0 → databento-0.78.0}/databento/common/http.py +0 -0
  26. {databento-0.76.0 → databento-0.78.0}/databento/common/iterator.py +0 -0
  27. {databento-0.76.0 → databento-0.78.0}/databento/common/system.py +0 -0
  28. {databento-0.76.0 → databento-0.78.0}/databento/historical/__init__.py +0 -0
  29. {databento-0.76.0 → databento-0.78.0}/databento/historical/api/__init__.py +0 -0
  30. {databento-0.76.0 → databento-0.78.0}/databento/historical/api/metadata.py +0 -0
  31. {databento-0.76.0 → databento-0.78.0}/databento/historical/api/symbology.py +0 -0
  32. {databento-0.76.0 → databento-0.78.0}/databento/historical/api/timeseries.py +0 -0
  33. {databento-0.76.0 → databento-0.78.0}/databento/historical/client.py +0 -0
  34. {databento-0.76.0 → databento-0.78.0}/databento/live/__init__.py +0 -0
  35. {databento-0.76.0 → databento-0.78.0}/databento/py.typed +0 -0
  36. {databento-0.76.0 → databento-0.78.0}/databento/reference/__init__.py +0 -0
  37. {databento-0.76.0 → databento-0.78.0}/databento/reference/api/__init__.py +0 -0
  38. {databento-0.76.0 → databento-0.78.0}/databento/reference/api/adjustment.py +0 -0
  39. {databento-0.76.0 → databento-0.78.0}/databento/reference/api/corporate.py +0 -0
  40. {databento-0.76.0 → databento-0.78.0}/databento/reference/api/security.py +0 -0
  41. {databento-0.76.0 → databento-0.78.0}/databento/reference/client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databento
3
- Version: 0.76.0
3
+ Version: 0.78.0
4
4
  Summary: Official Python client library for Databento
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -21,7 +21,7 @@ Classifier: Topic :: Software Development :: Libraries
21
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
22
  Requires-Dist: aiohttp (>=3.8.3,<4.0.0) ; python_version < "3.12"
23
23
  Requires-Dist: aiohttp (>=3.9.0,<4.0.0) ; python_version >= "3.12"
24
- Requires-Dist: databento-dbn (>=0.55.0,<0.56.0)
24
+ Requires-Dist: databento-dbn (>=0.58.0,<0.59.0)
25
25
  Requires-Dist: numpy (>=1.23.5) ; python_version < "3.12"
26
26
  Requires-Dist: numpy (>=1.26.0) ; python_version >= "3.12"
27
27
  Requires-Dist: pandas (>=1.5.3,<4.0.0)
@@ -69,7 +69,7 @@ The library is fully compatible with distributions of Anaconda 2023.x and above.
69
69
  The minimum dependencies as found in the `pyproject.toml` are also listed below:
70
70
  - python = "^3.10"
71
71
  - aiohttp = "^3.8.3"
72
- - databento-dbn = "~0.55.0"
72
+ - databento-dbn = "~0.58.0"
73
73
  - numpy = ">=1.23.5"
74
74
  - pandas = ">=1.5.3"
75
75
  - pip-system-certs = ">=4.0" (Windows only)
@@ -32,7 +32,7 @@ The library is fully compatible with distributions of Anaconda 2023.x and above.
32
32
  The minimum dependencies as found in the `pyproject.toml` are also listed below:
33
33
  - python = "^3.10"
34
34
  - aiohttp = "^3.8.3"
35
- - databento-dbn = "~0.55.0"
35
+ - databento-dbn = "~0.58.0"
36
36
  - numpy = ">=1.23.5"
37
37
  - pandas = ">=1.5.3"
38
38
  - pip-system-certs = ">=4.0" (Windows only)
@@ -5,8 +5,9 @@ import logging
5
5
 
6
6
  def enable_logging(level: int | str = logging.INFO) -> None:
7
7
  """
8
- Enable logging for the Databento module. This function should be used for
9
- simple applications and examples. It is advisable to configure your own
8
+ Enable logging for the Databento module.
9
+
10
+ This function should be used for simple applications and examples. It is advisable to configure your own
10
11
  logging for serious applications.
11
12
 
12
13
  Parameters
@@ -244,8 +244,9 @@ class MemoryDataSource(DataSource):
244
244
  @property
245
245
  def name(self) -> str:
246
246
  """
247
- Return the name of the source buffer. Equivalent to `repr` of the
248
- input.
247
+ Return the name of the source buffer.
248
+
249
+ Equivalent to `repr` of the input.
249
250
 
250
251
  Returns
251
252
  -------
@@ -269,8 +270,9 @@ class MemoryDataSource(DataSource):
269
270
  @property
270
271
  def reader(self) -> BytesIO:
271
272
  """
272
- Return a reader for this buffer. The reader beings at the start of the
273
- buffer.
273
+ Return a reader for this buffer.
274
+
275
+ The reader beings at the start of the buffer.
274
276
 
275
277
  Returns
276
278
  -------
@@ -391,8 +393,7 @@ class DBNStore:
391
393
  while True:
392
394
  raw = reader.read(DBNStore.DBN_READ_SIZE)
393
395
  if raw:
394
- decoder.write(raw)
395
- records = decoder.decode()
396
+ records = decoder.write_and_decode(raw)
396
397
  for record in records:
397
398
  if isinstance(record, databento_dbn.Metadata):
398
399
  continue
@@ -416,8 +417,9 @@ class DBNStore:
416
417
  @property
417
418
  def compression(self) -> Compression:
418
419
  """
419
- Return the data compression format (if any). This is determined by
420
- inspecting the data.
420
+ Return the data compression format (if any).
421
+
422
+ This is determined by inspecting the data.
421
423
 
422
424
  Returns
423
425
  -------
@@ -441,8 +443,9 @@ class DBNStore:
441
443
  @property
442
444
  def end(self) -> pd.Timestamp | None:
443
445
  """
444
- Return the query end for the data. If None, the end time was not known
445
- when the data was generated.
446
+ Return the query end for the data.
447
+
448
+ If None, the end time was not known when the data was generated.
446
449
 
447
450
  Returns
448
451
  -------
@@ -546,11 +549,13 @@ class DBNStore:
546
549
  @property
547
550
  def schema(self) -> Schema | None:
548
551
  """
549
- Return the DBN record schema. If None, may contain one or more schemas.
552
+ Return the DBN record schema.
553
+
554
+ If None, may contain one or more schemas.
550
555
 
551
556
  Returns
552
557
  -------
553
- Schema or None
558
+ Schema or None
554
559
 
555
560
  """
556
561
  schema = self._metadata.schema
@@ -577,8 +582,9 @@ class DBNStore:
577
582
  @property
578
583
  def stype_in(self) -> SType | None:
579
584
  """
580
- Return the query input symbology type for the data. If None, the
581
- records may contain mixed STypes.
585
+ Return the query input symbology type for the data.
586
+
587
+ If None, the records may contain mixed STypes.
582
588
 
583
589
  Returns
584
590
  -------
@@ -85,8 +85,10 @@ def coercible(enum_type: type[M]) -> type[M]:
85
85
 
86
86
  class StringyMixin:
87
87
  """
88
- Mixin class for overloading __str__ on Enum types. This will use the
89
- Enumerations subclass, if any, to modify the behavior of str().
88
+ Mixin class for overloading __str__ on Enum types.
89
+
90
+ This will use the Enumerations subclass, if any, to modify the
91
+ behavior of str().
90
92
 
91
93
  For subclasses of enum.Flag a comma separated string of names is
92
94
  returned. For integer enumerations, the lowercase member name is
@@ -134,6 +136,7 @@ class SplitDuration(StringyMixin, str, Enum):
134
136
  DAY = "day"
135
137
  WEEK = "week"
136
138
  MONTH = "month"
139
+ YEAR = "year"
137
140
  NONE = "none"
138
141
 
139
142
 
@@ -195,6 +198,8 @@ class RecordFlags(StringyMixin, IntFlag): # type: ignore
195
198
  """
196
199
  Represents record flags.
197
200
 
201
+ Attributes
202
+ ----------
198
203
  F_LAST
199
204
  Marks the last record in a single event for a given `instrument_id`.
200
205
  F_TOB
@@ -168,8 +168,9 @@ def symbols_list_to_list(
168
168
  @symbols_list_to_list.register(cls=Integral)
169
169
  def _(symbols: Integral, stype_in: SType) -> list[str]:
170
170
  """
171
- Dispatch method for optional_symbols_list_to_list. Handles integral types,
172
- alerting when an integer is given for STypes that expect strings.
171
+ Dispatch method for optional_symbols_list_to_list.
172
+
173
+ Handles integral types, alerting when an integer is given for STypes that expect strings.
173
174
 
174
175
  See Also
175
176
  --------
@@ -187,8 +188,9 @@ def _(symbols: Integral, stype_in: SType) -> list[str]:
187
188
  @symbols_list_to_list.register(cls=str)
188
189
  def _(symbols: str, stype_in: SType) -> list[str]:
189
190
  """
190
- Dispatch method for optional_symbols_list_to_list. Handles str, splitting
191
- on commas and validating smart symbology.
191
+ Dispatch method for optional_symbols_list_to_list.
192
+
193
+ Handles str, splitting on commas and validating smart symbology.
192
194
 
193
195
  See Also
194
196
  --------
@@ -212,8 +214,9 @@ def _(symbols: str, stype_in: SType) -> list[str]:
212
214
  @symbols_list_to_list.register(cls=Iterable)
213
215
  def _(symbols: Iterable[Any], stype_in: SType) -> list[str]:
214
216
  """
215
- Dispatch method for optional_symbols_list_to_list. Handles Iterables by
216
- dispatching the individual members.
217
+ Dispatch method for optional_symbols_list_to_list.
218
+
219
+ Handles Iterables by dispatching the individual members.
217
220
 
218
221
  See Also
219
222
  --------
@@ -126,6 +126,8 @@ class Venue(StringyMixin, str, Enum):
126
126
  MX2 Options.
127
127
  IEXO
128
128
  IEX Options LLC.
129
+ CGIF
130
+ Cboe Global Indices Feed.
129
131
 
130
132
  """
131
133
 
@@ -184,6 +186,7 @@ class Venue(StringyMixin, str, Enum):
184
186
  OCEA = "OCEA"
185
187
  MXTO = "MXTO"
186
188
  IEXO = "IEXO"
189
+ CGIF = "CGIF"
187
190
 
188
191
  @classmethod
189
192
  def from_int(cls, value: int) -> Venue:
@@ -300,6 +303,8 @@ class Venue(StringyMixin, str, Enum):
300
303
  return Venue.MXTO
301
304
  if value == 55:
302
305
  return Venue.IEXO
306
+ if value == 56:
307
+ return Venue.CGIF
303
308
  raise ValueError(f"Integer value {value} does not correspond with any Venue variant")
304
309
 
305
310
  def to_int(self) -> int:
@@ -416,6 +421,8 @@ class Venue(StringyMixin, str, Enum):
416
421
  return 54
417
422
  if self == Venue.IEXO:
418
423
  return 55
424
+ if self == Venue.CGIF:
425
+ return 56
419
426
  raise ValueError("Invalid Venue")
420
427
 
421
428
  @property
@@ -533,6 +540,8 @@ class Venue(StringyMixin, str, Enum):
533
540
  return "MX2 Options"
534
541
  if self == Venue.IEXO:
535
542
  return "IEX Options LLC"
543
+ if self == Venue.CGIF:
544
+ return "Cboe Global Indices Feed"
536
545
  raise ValueError("Unexpected Venue value")
537
546
 
538
547
 
@@ -624,6 +633,8 @@ class Dataset(StringyMixin, str, Enum):
624
633
  CFE Depth.
625
634
  OCEA_MEMOIR
626
635
  Blue Ocean ATS MEMOIR Depth.
636
+ CGIF_TITANIUM
637
+ Cboe Titanium Cboe Global Indices Feed.
627
638
 
628
639
  """
629
640
 
@@ -668,6 +679,7 @@ class Dataset(StringyMixin, str, Enum):
668
679
  XEEE_EOBI = "XEEE.EOBI"
669
680
  XCBF_PITCH = "XCBF.PITCH"
670
681
  OCEA_MEMOIR = "OCEA.MEMOIR"
682
+ CGIF_TITANIUM = "CGIF.TITANIUM"
671
683
 
672
684
  @classmethod
673
685
  def from_int(cls, value: int) -> Dataset:
@@ -756,6 +768,8 @@ class Dataset(StringyMixin, str, Enum):
756
768
  return Dataset.XCBF_PITCH
757
769
  if value == 41:
758
770
  return Dataset.OCEA_MEMOIR
771
+ if value == 42:
772
+ return Dataset.CGIF_TITANIUM
759
773
  raise ValueError(f"Integer value {value} does not correspond with any Dataset variant")
760
774
 
761
775
  def to_int(self) -> int:
@@ -844,6 +858,8 @@ class Dataset(StringyMixin, str, Enum):
844
858
  return 40
845
859
  if self == Dataset.OCEA_MEMOIR:
846
860
  return 41
861
+ if self == Dataset.CGIF_TITANIUM:
862
+ return 42
847
863
  raise ValueError("Invalid Dataset")
848
864
 
849
865
  @property
@@ -933,6 +949,8 @@ class Dataset(StringyMixin, str, Enum):
933
949
  return "CFE Depth"
934
950
  if self == Dataset.OCEA_MEMOIR:
935
951
  return "Blue Ocean ATS MEMOIR Depth"
952
+ if self == Dataset.CGIF_TITANIUM:
953
+ return "Cboe Titanium Cboe Global Indices Feed"
936
954
  raise ValueError("Unexpected Dataset value")
937
955
 
938
956
 
@@ -1160,6 +1178,8 @@ class Publisher(StringyMixin, str, Enum):
1160
1178
  OPRA - MEMX MX2 Options.
1161
1179
  OPRA_PILLAR_IEXO
1162
1180
  OPRA - IEX Options LLC.
1181
+ CGIF_TITANIUM_CGIF
1182
+ Cboe Global Indices Feed.
1163
1183
 
1164
1184
  """
1165
1185
 
@@ -1272,6 +1292,7 @@ class Publisher(StringyMixin, str, Enum):
1272
1292
  OCEA_MEMOIR_OCEA = "OCEA.MEMOIR.OCEA"
1273
1293
  OPRA_PILLAR_MXTO = "OPRA.PILLAR.MXTO"
1274
1294
  OPRA_PILLAR_IEXO = "OPRA.PILLAR.IEXO"
1295
+ CGIF_TITANIUM_CGIF = "CGIF.TITANIUM.CGIF"
1275
1296
 
1276
1297
  @classmethod
1277
1298
  def from_int(cls, value: int) -> Publisher:
@@ -1496,6 +1517,8 @@ class Publisher(StringyMixin, str, Enum):
1496
1517
  return Publisher.OPRA_PILLAR_MXTO
1497
1518
  if value == 109:
1498
1519
  return Publisher.OPRA_PILLAR_IEXO
1520
+ if value == 110:
1521
+ return Publisher.CGIF_TITANIUM_CGIF
1499
1522
  raise ValueError(f"Integer value {value} does not correspond with any Publisher variant")
1500
1523
 
1501
1524
  def to_int(self) -> int:
@@ -1720,6 +1743,8 @@ class Publisher(StringyMixin, str, Enum):
1720
1743
  return 108
1721
1744
  if self == Publisher.OPRA_PILLAR_IEXO:
1722
1745
  return 109
1746
+ if self == Publisher.CGIF_TITANIUM_CGIF:
1747
+ return 110
1723
1748
  raise ValueError("Invalid Publisher")
1724
1749
 
1725
1750
  @property
@@ -1945,6 +1970,8 @@ class Publisher(StringyMixin, str, Enum):
1945
1970
  return Venue.MXTO
1946
1971
  if self == Publisher.OPRA_PILLAR_IEXO:
1947
1972
  return Venue.IEXO
1973
+ if self == Publisher.CGIF_TITANIUM_CGIF:
1974
+ return Venue.CGIF
1948
1975
  raise ValueError("Unexpected Publisher value")
1949
1976
 
1950
1977
  @property
@@ -2170,6 +2197,8 @@ class Publisher(StringyMixin, str, Enum):
2170
2197
  return Dataset.OPRA_PILLAR
2171
2198
  if self == Publisher.OPRA_PILLAR_IEXO:
2172
2199
  return Dataset.OPRA_PILLAR
2200
+ if self == Publisher.CGIF_TITANIUM_CGIF:
2201
+ return Dataset.CGIF_TITANIUM
2173
2202
  raise ValueError("Unexpected Publisher value")
2174
2203
 
2175
2204
  @property
@@ -2395,4 +2424,6 @@ class Publisher(StringyMixin, str, Enum):
2395
2424
  return "OPRA - MEMX MX2 Options"
2396
2425
  if self == Publisher.OPRA_PILLAR_IEXO:
2397
2426
  return "OPRA - IEX Options LLC"
2427
+ if self == Publisher.CGIF_TITANIUM_CGIF:
2428
+ return "Cboe Global Indices Feed"
2398
2429
  raise ValueError("Unexpected Publisher value")
@@ -645,8 +645,9 @@ class InstrumentMap:
645
645
 
646
646
  def build_symbol_map(self) -> dict[int, list[tuple[dt.date, dt.date, str]]]:
647
647
  """
648
- Build a simple symbol map. This is to interface with methods of
649
- databento-dbn.
648
+ Build a simple symbol map.
649
+
650
+ This is to interface with methods of databento-dbn.
650
651
 
651
652
  Returns
652
653
  -------
@@ -22,8 +22,9 @@ _T = TypeVar("_T")
22
22
 
23
23
  class Default(Generic[_T]):
24
24
  """
25
- A container for a default value. This is to be used when a callable wants
26
- to detect if a default parameter value is being used.
25
+ A container for a default value.
26
+
27
+ This is to be used when a callable wants to detect if a default parameter value is being used.
27
28
 
28
29
  Example
29
30
  -------
@@ -152,8 +153,9 @@ class ClientStream:
152
153
 
153
154
  def write(self, data: bytes) -> None:
154
155
  """
155
- Write data to the underlying stream. Any exceptions encountered will be
156
- dispatched to the exception callback, if defined.
156
+ Write data to the underlying stream.
157
+
158
+ Any exceptions encountered will be dispatched to the exception callback, if defined.
157
159
 
158
160
  Parameters
159
161
  ----------
@@ -20,8 +20,9 @@ E = TypeVar("E", bound=Enum)
20
20
 
21
21
  def validate_path(value: PathLike[str] | str, param: str) -> Path:
22
22
  """
23
- Validate whether the given value is a valid path. This also expands user
24
- directories to form valid paths.
23
+ Validate whether the given value is a valid path.
24
+
25
+ This also expands user directories to form valid paths.
25
26
 
26
27
  Parameters
27
28
  ----------
@@ -122,7 +122,7 @@ class BatchHttpAPI(BentoHttpAPI):
122
122
  `dbn`.
123
123
  split_symbols : bool, default False
124
124
  If files should be split by raw symbol. Cannot be requested with `'ALL_SYMBOLS'`.
125
- split_duration : SplitDuration or str {'day', 'week', 'month', 'none'}, default 'day'
125
+ split_duration : SplitDuration or str {'day', 'week', 'month', 'year', 'none'}, default 'day'
126
126
  The maximum time duration before batched data is split into multiple files.
127
127
  A week starts on Sunday UTC.
128
128
  split_size : int, optional
@@ -588,7 +588,8 @@ class _BatchJob:
588
588
  """
589
589
  Helper class for downloading multiple batch files from a job.
590
590
 
591
- Supports sync and async downloads using a shared `ThreadPoolExecutor`.
591
+ Supports sync and async downloads using a shared
592
+ `ThreadPoolExecutor`.
592
593
 
593
594
  """
594
595
 
@@ -159,8 +159,9 @@ class Live:
159
159
  @property
160
160
  def dataset(self) -> str:
161
161
  """
162
- Return the dataset for this live client. If no subscriptions have been
163
- made an empty string will be returned.
162
+ Return the dataset for this live client.
163
+
164
+ If no subscriptions have been made an empty string will be returned.
164
165
 
165
166
  Returns
166
167
  -------
@@ -234,8 +235,9 @@ class Live:
234
235
  @property
235
236
  def session_id(self) -> str | None:
236
237
  """
237
- Return the session ID for the current session. If `None`, the client is
238
- not connected.
238
+ Return the session ID for the current session.
239
+
240
+ If `None`, the client is not connected.
239
241
 
240
242
  Returns
241
243
  -------
@@ -279,8 +281,9 @@ class Live:
279
281
  @property
280
282
  def symbology_map(self) -> dict[int, str | int]:
281
283
  """
282
- Return the symbology map for this client session. A symbol mapping is
283
- added when the client receives a SymbolMappingMsg.
284
+ Return the symbology map for this client session.
285
+
286
+ A symbol mapping is added when the client receives a SymbolMappingMsg.
284
287
 
285
288
  This can be used to transform an `instrument_id` in a DBN record
286
289
  to the input symbology.
@@ -398,8 +401,9 @@ class Live:
398
401
  exception_callback: ExceptionCallback | None = None,
399
402
  ) -> None:
400
403
  """
401
- Add a callback for handling client reconnection events. This will only
402
- be called when using a reconnection policy other than
404
+ Add a callback for handling client reconnection events.
405
+
406
+ This will only be called when using a reconnection policy other than
403
407
  `ReconnectPolicy.NONE` and if the session has been started with
404
408
  `Live.start`.
405
409
 
@@ -614,8 +618,9 @@ class Live:
614
618
  timeout: float | None = None,
615
619
  ) -> None:
616
620
  """
617
- Block until the session closes or a timeout is reached. A session will
618
- close after the remote gateway disconnects, or after `Live.stop` or
621
+ Block until the session closes or a timeout is reached.
622
+
623
+ A session will close after the remote gateway disconnects, or after `Live.stop` or
619
624
  `Live.terminate` are called.
620
625
 
621
626
  If a `timeout` is specified, `Live.terminate` will be called when the
@@ -661,8 +666,9 @@ class Live:
661
666
  timeout: float | None = None,
662
667
  ) -> None:
663
668
  """
664
- Coroutine to wait until the session closes or a timeout is reached. A
665
- session will close when the remote gateway disconnects, or after
669
+ Coroutine to wait until the session closes or a timeout is reached.
670
+
671
+ A session will close when the remote gateway disconnects, or after
666
672
  `Live.stop` or `Live.terminate` are called.
667
673
 
668
674
  If a `timeout` is specified, `Live.terminate` will be called when the
@@ -718,8 +724,9 @@ class Live:
718
724
 
719
725
  class LiveIterator:
720
726
  """
721
- Iterator class for the `Live` client. Automatically starts the client when
722
- created and will stop it when destroyed. This provides context-manager-like
727
+ Iterator class for the `Live` client.
728
+
729
+ Automatically starts the client when created and will stop it when destroyed. This provides context-manager-like
723
730
  behavior to for loops.
724
731
 
725
732
  Parameters
@@ -194,8 +194,9 @@ class GatewayDecoder:
194
194
 
195
195
  def write(self, data: bytes) -> None:
196
196
  """
197
- Write data to the decoder's buffer. This will make the data available
198
- for decoding.
197
+ Write data to the decoder's buffer.
198
+
199
+ This will make the data available for decoding.
199
200
 
200
201
  Parameters
201
202
  ----------
@@ -208,8 +209,9 @@ class GatewayDecoder:
208
209
 
209
210
  def decode(self) -> list[GatewayControl]:
210
211
  """
211
- Decode messages from the decoder's buffer. This will consume decoded
212
- data from the buffer.
212
+ Decode messages from the decoder's buffer.
213
+
214
+ This will consume decoded data from the buffer.
213
215
 
214
216
  Returns
215
217
  -------
@@ -150,8 +150,9 @@ class DatabentoLiveProtocol(asyncio.BufferedProtocol):
150
150
  @property
151
151
  def is_streaming(self) -> bool:
152
152
  """
153
- True if the session has started streaming. This occurs when the
154
- SessionStart message is sent to the gateway.
153
+ True if the session has started streaming.
154
+
155
+ This occurs when the SessionStart message is sent to the gateway.
155
156
 
156
157
  Returns
157
158
  -------
@@ -255,7 +256,7 @@ class DatabentoLiveProtocol(asyncio.BufferedProtocol):
255
256
 
256
257
  """
257
258
  logger.debug("read %d bytes from remote gateway", nbytes)
258
- data = self.__buffer[:nbytes]
259
+ data = bytes(memoryview(self.__buffer)[:nbytes])
259
260
 
260
261
  if self.authenticated.done():
261
262
  self._process_dbn(data)
@@ -266,8 +267,9 @@ class DatabentoLiveProtocol(asyncio.BufferedProtocol):
266
267
 
267
268
  def received_metadata(self, metadata: databento_dbn.Metadata) -> None:
268
269
  """
269
- Call when the protocol receives a Metadata header. This is always sent
270
- by the gateway before any data records.
270
+ Call when the protocol receives a Metadata header.
271
+
272
+ This is always sent by the gateway before any data records.
271
273
 
272
274
  Parameters
273
275
  ----------
@@ -297,8 +299,9 @@ class DatabentoLiveProtocol(asyncio.BufferedProtocol):
297
299
  subscription_id: int | None = None,
298
300
  ) -> list[SubscriptionRequest]:
299
301
  """
300
- Send a SubscriptionRequest to the gateway. Returns a list of all
301
- subscription requests sent to the gateway.
302
+ Send a SubscriptionRequest to the gateway.
303
+
304
+ Returns a list of all subscription requests sent to the gateway.
302
305
 
303
306
  Parameters
304
307
  ----------
@@ -375,8 +378,7 @@ class DatabentoLiveProtocol(asyncio.BufferedProtocol):
375
378
  raise ValueError("not connected")
376
379
 
377
380
  try:
378
- self._dbn_decoder.write(bytes(data))
379
- records = self._dbn_decoder.decode()
381
+ records = self._dbn_decoder.write_and_decode(data)
380
382
  except Exception:
381
383
  logger.exception("error decoding DBN record")
382
384
  self.__transport.close()
@@ -36,6 +36,9 @@ logger = logging.getLogger(__name__)
36
36
  AUTH_TIMEOUT_SECONDS: Final = 30.0
37
37
  CONNECT_TIMEOUT_SECONDS: Final = 10.0
38
38
  DBN_QUEUE_CAPACITY: Final = 2**20
39
+ DBN_QUEUE_LAG_THRESHOLD: Final = 128
40
+ DBN_QUEUE_MAX_LAG_NS: Final = 1_000_000_000
41
+ DBN_QUEUE_FULL_WARNING_INTERVAL_S: Final = 60.0
39
42
  DEFAULT_REMOTE_PORT: Final = 13000
40
43
  CLIENT_TIMEOUT_MARGIN_SECONDS: Final = 10
41
44
 
@@ -48,6 +51,8 @@ class DBNQueue(queue.SimpleQueue): # type: ignore [type-arg]
48
51
  def __init__(self) -> None:
49
52
  super().__init__()
50
53
  self._enabled = threading.Event()
54
+ self._front_ts_index: int | None = None
55
+ self._back_ts_index: int | None = None
51
56
 
52
57
  def is_enabled(self) -> bool:
53
58
  """
@@ -62,7 +67,16 @@ class DBNQueue(queue.SimpleQueue): # type: ignore [type-arg]
62
67
  """
63
68
  Return True when the queue has reached capacity; False otherwise.
64
69
  """
65
- return self.qsize() > DBN_QUEUE_CAPACITY
70
+ if self.qsize() > DBN_QUEUE_CAPACITY:
71
+ return True
72
+ if (
73
+ self.qsize() > DBN_QUEUE_LAG_THRESHOLD
74
+ and self._front_ts_index is not None
75
+ and self._back_ts_index is not None
76
+ and self._back_ts_index - self._front_ts_index > DBN_QUEUE_MAX_LAG_NS
77
+ ):
78
+ return True
79
+ return False
66
80
 
67
81
  def enable(self) -> None:
68
82
  """
@@ -106,6 +120,9 @@ class DBNQueue(queue.SimpleQueue): # type: ignore [type-arg]
106
120
 
107
121
  """
108
122
  if self._enabled.wait(timeout):
123
+ if self._front_ts_index is None:
124
+ self._front_ts_index = item.ts_index
125
+ self._back_ts_index = item.ts_index
109
126
  return super().put(item, block, timeout)
110
127
  if timeout is not None:
111
128
  raise BentoError(f"queue is not enabled after {timeout} second(s)")
@@ -131,9 +148,34 @@ class DBNQueue(queue.SimpleQueue): # type: ignore [type-arg]
131
148
 
132
149
  """
133
150
  if self.is_enabled():
151
+ if self._front_ts_index is None:
152
+ self._front_ts_index = item.ts_index
153
+ self._back_ts_index = item.ts_index
134
154
  return super().put_nowait(item)
135
155
  raise BentoError("queue is not enabled")
136
156
 
157
+ def get(
158
+ self,
159
+ block: bool = True,
160
+ timeout: float | None = None,
161
+ ) -> DBNRecord:
162
+ record = super().get(block, timeout)
163
+ if self.empty():
164
+ self._front_ts_index = None
165
+ self._back_ts_index = None
166
+ else:
167
+ self._front_ts_index = record.ts_index
168
+ return record
169
+
170
+ def get_nowait(self) -> DBNRecord:
171
+ record = super().get_nowait()
172
+ if self.empty():
173
+ self._front_ts_index = None
174
+ self._back_ts_index = None
175
+ else:
176
+ self._front_ts_index = record.ts_index
177
+ return record
178
+
137
179
 
138
180
  @dataclasses.dataclass
139
181
  class SessionMetadata:
@@ -160,8 +202,9 @@ class SessionMetadata:
160
202
 
161
203
  def check(self, other: databento_dbn.Metadata) -> None:
162
204
  """
163
- Verify the Metadata is compatible with another Metadata message. This
164
- is used to ensure DBN streams are compatible with one another.
205
+ Verify the Metadata is compatible with another Metadata message.
206
+
207
+ This is used to ensure DBN streams are compatible with one another.
165
208
 
166
209
  Parameters
167
210
  ----------
@@ -225,6 +268,7 @@ class _SessionProtocol(DatabentoLiveProtocol):
225
268
  self._user_streams = user_streams
226
269
  self._last_ts_event: int | None = None
227
270
  self._last_msg_loop_time: float = math.inf
271
+ self._last_queue_full_warning_t: float = -math.inf
228
272
 
229
273
  def received_metadata(self, metadata: databento_dbn.Metadata) -> None:
230
274
  if self._metadata:
@@ -282,10 +326,13 @@ class _SessionProtocol(DatabentoLiveProtocol):
282
326
  self._dbn_queue.put(record)
283
327
  # DBNQueue has no max size; so check if it's above capacity, and if so, pause reading
284
328
  if self._dbn_queue.is_full():
285
- logger.warning(
286
- "record queue is full; %d record(s) to be processed",
287
- self._dbn_queue.qsize(),
288
- )
329
+ now = self._loop.time()
330
+ if now - self._last_queue_full_warning_t >= DBN_QUEUE_FULL_WARNING_INTERVAL_S:
331
+ logger.warning(
332
+ "record queue is full; %d record(s) to be processed",
333
+ self._dbn_queue.qsize(),
334
+ )
335
+ self._last_queue_full_warning_t = now
289
336
  self.transport.pause_reading()
290
337
 
291
338
 
@@ -485,8 +532,9 @@ class LiveSession:
485
532
  snapshot: bool = False,
486
533
  ) -> int:
487
534
  """
488
- Send a subscription request on the current connection. This will create
489
- a new connection if there is no active connection to the gateway.
535
+ Send a subscription request on the current connection.
536
+
537
+ This will create a new connection if there is no active connection to the gateway.
490
538
 
491
539
  Parameters
492
540
  ----------
@@ -0,0 +1 @@
1
+ __version__ = "0.78.0"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "databento"
3
- version = "0.76.0"
3
+ version = "0.78.0"
4
4
  description = "Official Python client library for Databento"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -10,7 +10,7 @@ dynamic = [ "classifiers" ]
10
10
  dependencies = [
11
11
  "aiohttp>=3.8.3,<4.0.0; python_version < '3.12'",
12
12
  "aiohttp>=3.9.0,<4.0.0; python_version >= '3.12'",
13
- "databento-dbn~=0.55.0",
13
+ "databento-dbn~=0.58.0",
14
14
  "numpy>=1.23.5; python_version < '3.12'",
15
15
  "numpy>=1.26.0; python_version >= '3.12'",
16
16
  "pandas>=1.5.3,<4.0.0",
@@ -1 +0,0 @@
1
- __version__ = "0.76.0"
File without changes