Skip to content

Commit d8693fd

Browse files
authored
VER: Release 0.36.1
2 parents 3794bd6 + d90b27f commit d8693fd

File tree

17 files changed

+302
-92
lines changed

17 files changed

+302
-92
lines changed

CHANGELOG.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
# Changelog
22

3+
## 0.36.1 - 2025-06-17
4+
5+
### Bug fixes
6+
- Updated conversion error messages in `TryFrom<RecordRef> for RecordRefEnum` for
7+
release of DBN version 3
8+
- Updated `TryFrom<RecordRef> for RecordRefEnum` for versioning of `StatMsg`,
9+
`SystemMsg`, and `ErrorMsg`
10+
- Fixed conversion of `BboMsg` in `TryFrom<RecordRef> for RecordRefEnum`
11+
- Implemented `AsyncDecodeRecordRef` and `AsyncDecodeRecord` for `AsyncDecoder` and
12+
`AsyncRecordDecoder`
13+
- Fixed setting of `ts_out` property of `DbnFsm` based on decoded metadata. This
14+
was preventing `ts_out` from being correctly decoded in the Python `DBNDecoder`
15+
- Fixed decoding of `ts_out` with first records in `DBNDecoder`
16+
317
## 0.36.0 - 2025-06-10
418

519
### Enhancements
@@ -191,8 +205,8 @@ upgrading the input to DBNv3.
191205
## 0.29.0 - 2025-03-17
192206

193207
### Enhancements
194-
- Added new venues, datasets, and publishers for ICE Futures US, ICE Futures Europe
195-
(Financial products), Eurex, and European Energy Exchange (EEX)
208+
- Added new venues, datasets, and publishers for ICE Futures US, ICE Europe Financials
209+
products, Eurex, and European Energy Exchange (EEX)
196210
- Added new `SkipBytes` and `AsyncSkipBytes` traits which are a subset of the `Seek`
197211
and `AsyncSeek` traits respectively, only supporting seeking forward from the current
198212
position

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ resolver = "2"
1111
[workspace.package]
1212
authors = ["Databento <[email protected]>"]
1313
edition = "2021"
14-
version = "0.36.0"
14+
version = "0.36.1"
1515
documentation = "https://databento.com/docs"
1616
repository = "https://github.com/databento/dbn"
1717
license = "Apache-2.0"

python/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "databento-dbn"
3-
version = "0.36.0"
3+
version = "0.36.1"
44
description = "Python bindings for encoding and decoding Databento Binary Encoding (DBN)"
55
authors = ["Databento <[email protected]>"]
66
license = "Apache-2.0"
@@ -17,7 +17,7 @@ build-backend = "maturin"
1717

1818
[project]
1919
name = "databento-dbn"
20-
version = "0.36.0"
20+
version = "0.36.1"
2121
authors = [
2222
{ name = "Databento", email = "[email protected]" }
2323
]

python/src/dbn_decoder.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ impl DbnDecoder {
4747
}
4848

4949
fn decode(&mut self) -> PyResult<Vec<PyObject>> {
50-
let ts_out = self.fsm.ts_out();
50+
let mut ts_out = self.fsm.ts_out();
5151
let mut py_recs = Vec::new();
5252
loop {
5353
let mut rec_refs = Vec::new();
5454
match self.fsm.process_all(&mut rec_refs, None) {
5555
ProcessResult::ReadMore(_) => return Ok(py_recs),
5656
ProcessResult::Metadata(metadata) => {
57+
ts_out = self.fsm.ts_out();
5758
py_recs.push(Python::with_gil(|py| metadata.into_py_any(py))?)
5859
}
5960
ProcessResult::Record(_) => {
@@ -254,6 +255,44 @@ except Exception:
254255
}).unwrap();
255256
}
256257

258+
#[test]
259+
fn test_dbn_decoder_ts_out() {
260+
setup();
261+
Python::with_gil(|py| {
262+
Python::run(
263+
py,
264+
c_str!(
265+
r#"from _lib import DBNDecoder, DBNError, Metadata, Schema, SType
266+
267+
metadata = Metadata(
268+
version=3,
269+
dataset="IFUS.IMPACT",
270+
schema=Schema.MBO,
271+
start=1,
272+
stype_in=SType.RAW_SYMBOL,
273+
stype_out=SType.INSTRUMENT_ID,
274+
end=2,
275+
ts_out=True,
276+
symbols=[],
277+
partial=[],
278+
not_found=[],
279+
mappings=[]
280+
)
281+
metadata_bytes = bytes(metadata)
282+
decoder = DBNDecoder()
283+
decoder.write(metadata_bytes)
284+
records = decoder.decode()
285+
for record in records:
286+
assert record.ts_out is not None
287+
"#
288+
),
289+
None,
290+
None,
291+
)
292+
})
293+
.unwrap();
294+
}
295+
257296
#[test]
258297
fn test_dbn_decoder_no_metadata() {
259298
setup();

rust/dbn-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ name = "dbn"
1616
path = "src/main.rs"
1717

1818
[dependencies]
19-
dbn = { path = "../dbn", version = "=0.36.0", default-features = false }
19+
dbn = { path = "../dbn", version = "=0.36.1", default-features = false }
2020

2121
anyhow = { workspace = true }
2222
clap = { version = "4.5", features = ["derive", "wrap_help"] }

rust/dbn/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ serde = ["dep:serde", "time/parsing", "time/serde"]
2525
trivial_copy = []
2626

2727
[dependencies]
28-
dbn-macros = { version = "=0.36.0", path = "../dbn-macros" }
28+
dbn-macros = { version = "=0.36.1", path = "../dbn-macros" }
2929

3030
async-compression = { version = "0.4.23", features = ["tokio", "zstd"], optional = true }
3131
csv = { workspace = true }

rust/dbn/src/decode.rs

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub use stream::StreamIterDecoder;
3030

3131
use std::{io::Seek, mem};
3232

33-
use crate::{HasRType, Metadata, Record, RecordRef, VersionUpgradePolicy};
33+
use crate::{HasRType, Metadata, RecordRef, VersionUpgradePolicy};
3434

3535
/// Trait for types that decode references to DBN records of a dynamic type.
3636
pub trait DecodeRecordRef {
@@ -94,22 +94,6 @@ pub trait DecodeRecord {
9494
}
9595
}
9696

97-
fn decode_record_from_ref<T: HasRType>(rec_ref: Option<RecordRef>) -> crate::Result<Option<&T>> {
98-
if let Some(rec_ref) = rec_ref {
99-
rec_ref
100-
.get::<T>()
101-
.ok_or_else(|| {
102-
crate::Error::conversion::<T>(format!(
103-
"record with rtype {:#04X}",
104-
rec_ref.header().rtype
105-
))
106-
})
107-
.map(Some)
108-
} else {
109-
Ok(None)
110-
}
111-
}
112-
11397
/// A trait alias for DBN decoders with metadata.
11498
pub trait DecodeDbn: DecodeRecord + DecodeRecordRef + DbnMetadata {}
11599

@@ -199,7 +183,7 @@ pub trait AsyncDecodeRecord {
199183
/// # Cancel safety
200184
/// This method is not cancellation safe. If used within a `tokio::select!` statement
201185
/// partially decoded records will be lost and the stream may be corrupted.
202-
async fn decode_records<T: HasRType + Clone>(mut self) -> crate::Result<Vec<T>>
186+
async fn decode_records<T: HasRType + Clone>(&mut self) -> crate::Result<Vec<T>>
203187
where
204188
Self: Sized,
205189
{
@@ -277,13 +261,13 @@ impl FromLittleEndianSlice for u16 {
277261
}
278262
}
279263

280-
#[cfg(test)]
281-
mod tests {
282-
pub const TEST_DATA_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests/data");
283-
}
284-
285264
#[cfg(feature = "async")]
286265
pub use self::dbn::{
287266
AsyncDecoder as AsyncDbnDecoder, AsyncMetadataDecoder as AsyncDbnMetadataDecoder,
288267
AsyncRecordDecoder as AsyncDbnRecordDecoder,
289268
};
269+
270+
#[cfg(test)]
271+
mod tests {
272+
pub const TEST_DATA_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests/data");
273+
}

rust/dbn/src/decode/dbn/async.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ use crate::{
1010
decode::{
1111
dbn::fsm::{DbnFsm, ProcessResult},
1212
zstd::zstd_decoder,
13-
AsyncSkipBytes, DbnMetadata, VersionUpgradePolicy, ZSTD_FILE_BUFFER_CAPACITY,
13+
AsyncDecodeRecord, AsyncDecodeRecordRef, AsyncSkipBytes, DbnMetadata, VersionUpgradePolicy,
14+
ZSTD_FILE_BUFFER_CAPACITY,
1415
},
15-
HasRType, Metadata, Record, RecordRef, Result, DBN_VERSION,
16+
HasRType, Metadata, RecordRef, Result, DBN_VERSION,
1617
};
1718

1819
/// An async decoder for Databento Binary Encoding (DBN), both metadata and records.
@@ -240,6 +241,24 @@ where
240241
}
241242
}
242243

244+
impl<R> AsyncDecodeRecordRef for Decoder<R>
245+
where
246+
R: io::AsyncReadExt + Unpin,
247+
{
248+
async fn decode_record_ref(&mut self) -> crate::Result<Option<RecordRef>> {
249+
self.decoder.decode_ref().await
250+
}
251+
}
252+
253+
impl<R> AsyncDecodeRecord for Decoder<R>
254+
where
255+
R: io::AsyncReadExt + Unpin,
256+
{
257+
async fn decode_record<'a, T: HasRType + 'a>(&'a mut self) -> crate::Result<Option<&'a T>> {
258+
self.decoder.decode().await
259+
}
260+
}
261+
243262
/// An async decoder for files and streams of Databento Binary Encoding (DBN) records.
244263
pub struct RecordDecoder<R>
245264
where
@@ -343,20 +362,13 @@ where
343362
/// This method is cancel safe. It can be used within a `tokio::select!` statement
344363
/// without the potential for corrupting the input stream.
345364
pub async fn decode<'a, T: HasRType + 'a>(&'a mut self) -> Result<Option<&'a T>> {
346-
let rec_ref = self.decode_ref().await?;
347-
if let Some(rec_ref) = rec_ref {
348-
rec_ref
349-
.get::<T>()
350-
.ok_or_else(|| {
351-
crate::Error::conversion::<T>(format!(
352-
"record with rtype {:#04X}",
353-
rec_ref.header().rtype
354-
))
355-
})
356-
.map(Some)
357-
} else {
358-
Ok(None)
359-
}
365+
self.decode_ref().await.and_then(|rec| {
366+
if let Some(rec) = rec {
367+
rec.try_get().map(Some)
368+
} else {
369+
Ok(None)
370+
}
371+
})
360372
}
361373

362374
/// Tries to decode all records into a `Vec`. This eagerly decodes the data.
@@ -428,6 +440,24 @@ where
428440
}
429441
}
430442

443+
impl<R> AsyncDecodeRecordRef for RecordDecoder<R>
444+
where
445+
R: io::AsyncReadExt + Unpin,
446+
{
447+
async fn decode_record_ref(&mut self) -> crate::Result<Option<RecordRef>> {
448+
self.decode_ref().await
449+
}
450+
}
451+
452+
impl<R> AsyncDecodeRecord for RecordDecoder<R>
453+
where
454+
R: io::AsyncReadExt + Unpin,
455+
{
456+
async fn decode_record<'a, T: HasRType + 'a>(&'a mut self) -> crate::Result<Option<&'a T>> {
457+
self.decode().await
458+
}
459+
}
460+
431461
impl<R> RecordDecoder<R>
432462
where
433463
R: AsyncSkipBytes + io::AsyncReadExt + Unpin,
@@ -665,8 +695,8 @@ mod tests {
665695
AsyncEncodeRecord, DbnEncodable,
666696
},
667697
rtype, v1, v2, Bbo1SMsg, CbboMsg, Cmbp1Msg, Error, ErrorMsg, ImbalanceMsg,
668-
InstrumentDefMsg, MboMsg, Mbp10Msg, Mbp1Msg, OhlcvMsg, RecordHeader, Result, Schema,
669-
StatMsg, StatusMsg, TbboMsg, TradeMsg, WithTsOut,
698+
InstrumentDefMsg, MboMsg, Mbp10Msg, Mbp1Msg, OhlcvMsg, Record, RecordHeader, Result,
699+
Schema, StatMsg, StatusMsg, TbboMsg, TradeMsg, WithTsOut,
670700
};
671701

672702
#[rstest]

0 commit comments

Comments
 (0)