Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## 0.58.0 - 2025-07-08

#### Enhancements
- Changed the `tz` parameter in `DBNStore.to_df()` to accept `datetime.tzinfo` instead of `pytz.BaseTzInfo` explicitly
- Modified the dependency specification for `databento_dbn` to allow for compatible patch versions
- Upgraded `databento-dbn` to 0.36.2
- Fixed change in behavior where Python `DBNDecoder.decode()` wouldn't always decode all available data on the first call

## 0.57.1 - 2025-06-17

#### Enhancements
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ The library is fully compatible with the latest distribution of Anaconda 3.9 and
The minimum dependencies as found in the `pyproject.toml` are also listed below:
- python = "^3.9"
- aiohttp = "^3.8.3"
- databento-dbn = "0.36.1"
- numpy= ">=1.23.5"
- databento-dbn = "~0.36.1"
- numpy = ">=1.23.5"
- pandas = ">=1.5.3"
- pip-system-certs = ">=4.0" (Windows only)
- pyarrow = ">=13.0.0"
Expand Down
24 changes: 15 additions & 9 deletions databento/common/dbnstore.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from __future__ import annotations

import abc
import datetime
import decimal
import itertools
import logging
import warnings
import zoneinfo
from collections.abc import Generator
from collections.abc import Iterator
from collections.abc import Mapping
Expand All @@ -28,7 +30,6 @@
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
import pytz
import zstandard
from databento_dbn import FIXED_PRICE_SCALE
from databento_dbn import UNDEF_PRICE
Expand Down Expand Up @@ -859,7 +860,7 @@ def to_df(
pretty_ts: bool = ...,
map_symbols: bool = ...,
schema: Schema | str | None = ...,
tz: pytz.BaseTzInfo | str = ...,
tz: datetime.tzinfo | str = ...,
count: None = ...,
) -> pd.DataFrame: ...

Expand All @@ -870,7 +871,7 @@ def to_df(
pretty_ts: bool = ...,
map_symbols: bool = ...,
schema: Schema | str | None = ...,
tz: pytz.BaseTzInfo | str = ...,
tz: datetime.tzinfo | str = ...,
count: int = ...,
) -> DataFrameIterator: ...

Expand All @@ -880,8 +881,8 @@ def to_df(
pretty_ts: bool = True,
map_symbols: bool = True,
schema: Schema | str | None = None,
tz: pytz.BaseTzInfo | str | Default[pytz.BaseTzInfo] = Default[pytz.BaseTzInfo](
pytz.UTC,
tz: datetime.tzinfo | str | Default[datetime.tzinfo] = Default[datetime.tzinfo](
datetime.timezone.utc,
),
count: int | None = None,
) -> pd.DataFrame | DataFrameIterator:
Expand Down Expand Up @@ -909,7 +910,7 @@ def to_df(
schema : Schema or str, optional
The DBN schema for the dataframe.
This is only required when reading a DBN stream with mixed record types.
tz : pytz.BaseTzInfo or str, default UTC
tz : datetime.tzinfo or str, default UTC
If `pretty_ts` is `True`, all timestamps will be converted to the specified timezone.
count : int, optional
If set, instead of returning a single `DataFrame` a `DataFrameIterator`
Expand Down Expand Up @@ -939,8 +940,13 @@ def to_df(
"A timezone was specified when `pretty_ts` is `False`. Did you mean to set `pretty_ts=True`?",
)

if not isinstance(tz, pytz.BaseTzInfo):
tz = pytz.timezone(tz)
if isinstance(tz, str):
tz = zoneinfo.ZoneInfo(tz)
elif not isinstance(tz, datetime.tzinfo):
raise ValueError(
f"The value {tz!r} is not a valid datetime.tzinfo",
)

if schema is None:
if self.schema is None:
raise ValueError("a schema must be specified for mixed DBN data")
Expand Down Expand Up @@ -1442,7 +1448,7 @@ def __init__(
count: int | None,
struct_type: type[DBNRecord],
instrument_map: InstrumentMap,
tz: pytz.BaseTzInfo,
tz: datetime.tzinfo,
price_type: PriceType = PriceType.FLOAT,
pretty_ts: bool = True,
map_symbols: bool = True,
Expand Down
2 changes: 1 addition & 1 deletion databento/historical/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def get_dataset_range(

Returns
-------
dict[str, str]
dict[str, str | dict[str, str]]
The available range for the dataset.

"""
Expand Down
2 changes: 1 addition & 1 deletion databento/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.57.1"
__version__ = "0.58.0"
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "databento"
version = "0.57.1"
version = "0.58.0"
description = "Official Python client library for Databento"
authors = [
"Databento <support@databento.com>",
Expand Down Expand Up @@ -32,7 +32,7 @@ aiohttp = [
{version = "^3.8.3", python = "<3.12"},
{version = "^3.9.0", python = "^3.12"}
]
databento-dbn = "0.36.1"
databento-dbn = "~=0.36.2"
numpy = [
{version = ">=1.23.5", python = "<3.12"},
{version = ">=1.26.0", python = "^3.12"}
Expand Down
47 changes: 44 additions & 3 deletions tests/test_historical_bento.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import collections
import datetime as dt
import decimal
import zoneinfo
from io import BytesIO
from pathlib import Path
from typing import Any
Expand Down Expand Up @@ -1567,11 +1568,51 @@ def test_dbnstore_to_df_with_timezone(
df.reset_index(inplace=True)

# Assert
expected_timezone = pytz.timezone(timezone)._utcoffset
expected_timezone = zoneinfo.ZoneInfo(timezone).utcoffset(None)
failures = []
struct = SCHEMA_STRUCT_MAP[schema]
for field in struct._timestamp_fields:
if df[field].dt.tz._utcoffset != expected_timezone:
if df[field].dt.tz.utcoffset(None) != expected_timezone:
failures.append(field)

assert not failures


@pytest.mark.parametrize(
"timezone",
[
pytz.timezone("US/Central"),
pytz.timezone("US/Eastern"),
pytz.timezone("Europe/Vienna"),
pytz.timezone("Asia/Dubai"),
pytz.timezone("UTC"),
],
)
@pytest.mark.parametrize(
"schema",
[pytest.param(schema, id=str(schema)) for schema in Schema.variants()],
)
def test_dbnstore_to_df_with_pytz_timezone(
test_data_path: Callable[[Dataset, Schema], Path],
schema: Schema,
timezone: pytz.BaseTzInfo,
) -> None:
"""
Test that setting the `tz` parameter in `DBNStore.to_df` accepts `pytz`
timezone objects.
"""
# Arrange
dbnstore = DBNStore.from_file(path=test_data_path(Dataset.GLBX_MDP3, schema))

# Act
df = dbnstore.to_df(tz=timezone)
df.reset_index(inplace=True)

# Assert
failures = []
struct = SCHEMA_STRUCT_MAP[schema]
for field in struct._timestamp_fields:
if df[field].dt.tz != timezone:
failures.append(field)

assert not failures
Expand All @@ -1591,7 +1632,7 @@ def test_dbnstore_to_df_with_timezone_pretty_ts_error(
with pytest.raises(ValueError):
dbnstore.to_df(
pretty_ts=False,
tz=pytz.UTC,
tz=zoneinfo.ZoneInfo("UTC"),
)


Expand Down