Skip to content

Commit a773d3c

Browse files
authored
VER: Release 0.67.0
See release notes.
2 parents 688bcad + c00e308 commit a773d3c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+303
-143
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## 0.67.0 - 2025-12-02
4+
5+
#### Enhancements
6+
- Added a property `Live.subscription_requests` which returns a list of tuples containing every `SubscriptionRequest` for the live session
7+
- Changed the return value of `Live.subscribe()` to `int`, the value of the subscription ID, which can be used to index into the `Live.subscription_requests` property
8+
- Added feature to automatically monitor for hung connections in the `Live` client
9+
- Hung connections will be disconnected client side with a `BentoError`
10+
- Added new venue, dataset, and publisher for Cboe Futures Exchange (`XCBF.PITCH`)
11+
12+
#### Breaking changes
13+
- Several log messages have been reformatted to improve clarity and reduce redundancy, especially at debug levels
14+
- The `map_symbols` parameter for `Historical.batch.submit_job()` now defaults to `True` for JSON and CSV encodings
15+
316
## 0.66.0 - 2025-11-18
417

518
#### Enhancements

databento/common/publishers.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class Venue(StringyMixin, str, Enum):
118118
Eurex Exchange.
119119
XEEE
120120
European Energy Exchange.
121+
XCBF
122+
Cboe Futures Exchange.
121123
122124
"""
123125

@@ -172,6 +174,7 @@ class Venue(StringyMixin, str, Enum):
172174
IFLL = "IFLL"
173175
XEUR = "XEUR"
174176
XEEE = "XEEE"
177+
XCBF = "XCBF"
175178

176179
@classmethod
177180
def from_int(cls, value: int) -> Venue:
@@ -280,6 +283,8 @@ def from_int(cls, value: int) -> Venue:
280283
return Venue.XEUR
281284
if value == 51:
282285
return Venue.XEEE
286+
if value == 52:
287+
return Venue.XCBF
283288
raise ValueError(f"Integer value {value} does not correspond with any Venue variant")
284289

285290
def to_int(self) -> int:
@@ -388,6 +393,8 @@ def to_int(self) -> int:
388393
return 50
389394
if self == Venue.XEEE:
390395
return 51
396+
if self == Venue.XCBF:
397+
return 52
391398
raise ValueError("Invalid Venue")
392399

393400
@property
@@ -497,6 +504,8 @@ def description(self) -> str:
497504
return "Eurex Exchange"
498505
if self == Venue.XEEE:
499506
return "European Energy Exchange"
507+
if self == Venue.XCBF:
508+
return "Cboe Futures Exchange"
500509
raise ValueError("Unexpected Venue value")
501510

502511

@@ -584,6 +593,8 @@ class Dataset(StringyMixin, str, Enum):
584593
Eurex EOBI.
585594
XEEE_EOBI
586595
European Energy Exchange EOBI.
596+
XCBF_PITCH
597+
Cboe Futures Exchange PITCH.
587598
588599
"""
589600

@@ -626,6 +637,7 @@ class Dataset(StringyMixin, str, Enum):
626637
IFLL_IMPACT = "IFLL.IMPACT"
627638
XEUR_EOBI = "XEUR.EOBI"
628639
XEEE_EOBI = "XEEE.EOBI"
640+
XCBF_PITCH = "XCBF.PITCH"
629641

630642
@classmethod
631643
def from_int(cls, value: int) -> Dataset:
@@ -710,6 +722,8 @@ def from_int(cls, value: int) -> Dataset:
710722
return Dataset.XEUR_EOBI
711723
if value == 39:
712724
return Dataset.XEEE_EOBI
725+
if value == 40:
726+
return Dataset.XCBF_PITCH
713727
raise ValueError(f"Integer value {value} does not correspond with any Dataset variant")
714728

715729
def to_int(self) -> int:
@@ -794,6 +808,8 @@ def to_int(self) -> int:
794808
return 38
795809
if self == Dataset.XEEE_EOBI:
796810
return 39
811+
if self == Dataset.XCBF_PITCH:
812+
return 40
797813
raise ValueError("Invalid Dataset")
798814

799815
@property
@@ -879,6 +895,8 @@ def description(self) -> str:
879895
return "Eurex EOBI"
880896
if self == Dataset.XEEE_EOBI:
881897
return "European Energy Exchange EOBI"
898+
if self == Dataset.XCBF_PITCH:
899+
return "Cboe Futures Exchange PITCH"
882900
raise ValueError("Unexpected Dataset value")
883901

884902

@@ -1096,6 +1114,8 @@ class Publisher(StringyMixin, str, Enum):
10961114
Eurex EOBI - Off-Market Trades.
10971115
XEEE_EOBI_XOFF
10981116
European Energy Exchange EOBI - Off-Market Trades.
1117+
XCBF_PITCH_XCBF
1118+
Cboe Futures Exchange.
10991119
11001120
"""
11011121

@@ -1203,6 +1223,7 @@ class Publisher(StringyMixin, str, Enum):
12031223
XEEE_EOBI_XEEE = "XEEE.EOBI.XEEE"
12041224
XEUR_EOBI_XOFF = "XEUR.EOBI.XOFF"
12051225
XEEE_EOBI_XOFF = "XEEE.EOBI.XOFF"
1226+
XCBF_PITCH_XCBF = "XCBF.PITCH.XCBF"
12061227

12071228
@classmethod
12081229
def from_int(cls, value: int) -> Publisher:
@@ -1417,6 +1438,8 @@ def from_int(cls, value: int) -> Publisher:
14171438
return Publisher.XEUR_EOBI_XOFF
14181439
if value == 104:
14191440
return Publisher.XEEE_EOBI_XOFF
1441+
if value == 105:
1442+
return Publisher.XCBF_PITCH_XCBF
14201443
raise ValueError(f"Integer value {value} does not correspond with any Publisher variant")
14211444

14221445
def to_int(self) -> int:
@@ -1631,6 +1654,8 @@ def to_int(self) -> int:
16311654
return 103
16321655
if self == Publisher.XEEE_EOBI_XOFF:
16331656
return 104
1657+
if self == Publisher.XCBF_PITCH_XCBF:
1658+
return 105
16341659
raise ValueError("Invalid Publisher")
16351660

16361661
@property
@@ -1846,6 +1871,8 @@ def venue(self) -> Venue:
18461871
return Venue.XOFF
18471872
if self == Publisher.XEEE_EOBI_XOFF:
18481873
return Venue.XOFF
1874+
if self == Publisher.XCBF_PITCH_XCBF:
1875+
return Venue.XCBF
18491876
raise ValueError("Unexpected Publisher value")
18501877

18511878
@property
@@ -2061,6 +2088,8 @@ def dataset(self) -> Dataset:
20612088
return Dataset.XEUR_EOBI
20622089
if self == Publisher.XEEE_EOBI_XOFF:
20632090
return Dataset.XEEE_EOBI
2091+
if self == Publisher.XCBF_PITCH_XCBF:
2092+
return Dataset.XCBF_PITCH
20642093
raise ValueError("Unexpected Publisher value")
20652094

20662095
@property
@@ -2276,4 +2305,6 @@ def description(self) -> str:
22762305
return "Eurex EOBI - Off-Market Trades"
22772306
if self == Publisher.XEEE_EOBI_XOFF:
22782307
return "European Energy Exchange EOBI - Off-Market Trades"
2308+
if self == Publisher.XCBF_PITCH_XCBF:
2309+
return "Cboe Futures Exchange"
22792310
raise ValueError("Unexpected Publisher value")

databento/common/types.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import datetime as dt
22
import logging
3+
import pathlib
4+
import warnings
35
from collections.abc import Callable
46
from os import PathLike
5-
import pathlib
6-
from typing import Generic
77
from typing import IO
8+
from typing import Generic
89
from typing import TypedDict
910
from typing import TypeVar
10-
import warnings
1111

1212
import databento_dbn
1313
import pandas as pd
1414

1515
from databento.common.error import BentoWarning
1616

17+
1718
logger = logging.getLogger(__name__)
1819

1920
DBNRecord = (
@@ -188,14 +189,14 @@ def write(self, data: bytes) -> None:
188189
except Exception as exc:
189190
if self._exc_fn is None:
190191
self._warn(
191-
f"stream '{self.stream_name}' encountered an exception without an exception handler: {repr(exc)}",
192+
f"stream '{self.stream_name}' encountered an exception without an exception handler: {exc!r}",
192193
)
193194
else:
194195
try:
195196
self._exc_fn(exc)
196197
except Exception as inner_exc:
197198
self._warn(
198-
f"exception callback '{self.exc_callback_name}' encountered an exception: {repr(inner_exc)}",
199+
f"exception callback '{self.exc_callback_name}' encountered an exception: {inner_exc!r}",
199200
)
200201
raise inner_exc from exc
201202
raise exc
@@ -258,14 +259,14 @@ def call(self, record: DBNRecord) -> None:
258259
except Exception as exc:
259260
if self._exc_fn is None:
260261
self._warn(
261-
f"callback '{self.callback_name}' encountered an exception without an exception callback: {repr(exc)}",
262+
f"callback '{self.callback_name}' encountered an exception without an exception callback: {exc!r}",
262263
)
263264
else:
264265
try:
265266
self._exc_fn(exc)
266267
except Exception as inner_exc:
267268
self._warn(
268-
f"exception callback '{self.exc_callback_name}' encountered an exception: {repr(inner_exc)}",
269+
f"exception callback '{self.exc_callback_name}' encountered an exception: {inner_exc!r}",
269270
)
270271
raise inner_exc from exc
271272
raise exc

databento/historical/api/batch.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def submit_job(
7171
compression: Compression | str = "zstd",
7272
pretty_px: bool = False,
7373
pretty_ts: bool = False,
74-
map_symbols: bool = False,
74+
map_symbols: bool | None = None,
7575
split_symbols: bool = False,
7676
split_duration: SplitDuration | str = "day",
7777
split_size: int | None = None,
@@ -116,9 +116,10 @@ def submit_job(
116116
pretty_ts : bool, default False
117117
If timestamps should be formatted as ISO 8601 strings.
118118
Only applicable for 'csv' or 'json' encodings.
119-
map_symbols : bool, default False
120-
If the requested symbol should be appended to every text encoded record.
121-
Only applicable for 'csv' or 'json' encodings.
119+
map_symbols : bool, optional
120+
If a symbol field should be included with every text encoded record.
121+
If `None`, will default to `True` for `csv` and `json` encodings and `False` for
122+
`dbn`.
122123
split_symbols : bool, default False
123124
If files should be split by raw symbol. Cannot be requested with `'ALL_SYMBOLS'`.
124125
split_duration : SplitDuration or str {'day', 'week', 'month', 'none'}, default 'day'
@@ -149,6 +150,10 @@ def submit_job(
149150
"""
150151
stype_in_valid = validate_enum(stype_in, SType, "stype_in")
151152
symbols_list = symbols_list_to_list(symbols, stype_in_valid)
153+
encoding_valid = validate_enum(encoding, Encoding, "encoding")
154+
155+
if map_symbols is None:
156+
map_symbols = encoding_valid != Encoding.DBN
152157

153158
data: dict[str, object | None] = {
154159
"dataset": validate_semantic_string(dataset, "dataset"),
@@ -158,7 +163,7 @@ def submit_job(
158163
"schema": str(validate_enum(schema, Schema, "schema")),
159164
"stype_in": str(stype_in_valid),
160165
"stype_out": str(validate_enum(stype_out, SType, "stype_out")),
161-
"encoding": str(validate_enum(encoding, Encoding, "encoding")),
166+
"encoding": str(encoding_valid),
162167
"compression": (
163168
str(validate_enum(compression, Compression, "compression")) if compression else None
164169
),
@@ -292,7 +297,9 @@ def download(
292297
293298
"""
294299
if keep_zip and filename_to_download:
295-
raise ValueError("Cannot specify an individual file to download when `keep_zip=True`")
300+
raise ValueError(
301+
"Cannot specify an individual file to download when `keep_zip=True`",
302+
)
296303

297304
batch_download = _BatchJob(
298305
self,
@@ -369,7 +376,9 @@ async def download_async(
369376
370377
"""
371378
if keep_zip and filename_to_download:
372-
raise ValueError("Cannot specify an individual file to download when `keep_zip=True`")
379+
raise ValueError(
380+
"Cannot specify an individual file to download when `keep_zip=True`",
381+
)
373382

374383
batch_download = _BatchJob(
375384
self,
@@ -458,7 +467,9 @@ def _download_batch_file(
458467
) as response:
459468
check_http_error(response)
460469
with open(output_path, mode=mode) as f:
461-
for chunk in response.iter_content(chunk_size=HTTP_STREAMING_READ_SIZE):
470+
for chunk in response.iter_content(
471+
chunk_size=HTTP_STREAMING_READ_SIZE,
472+
):
462473
f.write(chunk)
463474

464475
# Successfully wrote some data, reset attempts counter
@@ -548,7 +559,9 @@ def _download_batch_zip(
548559
) as response:
549560
check_http_error(response)
550561
with open(output_path, mode="wb") as f:
551-
for chunk in response.iter_content(chunk_size=HTTP_STREAMING_READ_SIZE):
562+
for chunk in response.iter_content(
563+
chunk_size=HTTP_STREAMING_READ_SIZE,
564+
):
552565
f.write(chunk)
553566
except BentoHttpError as exc:
554567
if exc.http_status == 429:
@@ -615,7 +628,9 @@ def __init__(
615628
urls = file_detail["urls"]
616629
except KeyError as exc:
617630
missing_key = exc.args[0]
618-
raise BentoError(f"Batch job manifest missing key '{missing_key}'") from None
631+
raise BentoError(
632+
f"Batch job manifest missing key '{missing_key}'",
633+
) from None
619634
except TypeError:
620635
raise BentoError("Error parsing job manifest") from None
621636

0 commit comments

Comments
 (0)