v0.1.13-alpha
🎉 v0.1.13 – “Unbreakable Resilience” 🎉
Our toughest release yet—nothing short of a tank can stop it! v0.1.13 rolls out across-the-board hardening: from collision-proof DBC prefixing and drop-summary logging, to upfront dtype checks, enum-mapping bulletproofing, and export utilities that never break your script.
✨ What’s New in v0.1.13
🛠 Collision-Tolerant DBC Merging
Frame-ID fallback
Unique signal prefixes now automatically include frame_id (or arbitration_id / sequence index) when message names collide—no more prefixing errors or silent overwrites.
Reserved-name protection
"timestamp" and "raw_timestamp" are never allowed as injected signals, so your timing columns stay pristine.
🔍 Drop-Summary & Filter Resilience
Drop-summary logging
iter_blf_chunks() now emits a concise “Decoded X/Y messages (Z dropped)” log so you always know exactly what made it through.
Filter-key safety
Non-string or unhashable filter_signals entries are quietly skipped—your pipeline never crashes on weird keys.
⚡ Immediate Type Safety
dtype_map validation
Every entry in dtype_map is checked at load time—invalid numpy/pandas dtypes raise a clear ValueError immediately, not halfway through processing.
Missing-signal injection
Integers → zero-filled, floats → NaN-filled, and—if interpolate_missing=True—linear interpolation for signals you know should be continuous.
🎨 Enum & Attribute Bulletproofing
String-based mapping
All enum values (including NameSignalValue objects) are converted via string lookups. Unknown raw values pass through, never crash or become NaN.
Rich metadata sidecars
Your custom DBC attributes (BA_DEF_SG_, etc.) ride along in df.attrs["signal_attributes"] and are exported to JSON automatically.
📂 Streamlined, Fail-Safe Exports
Auto-mkdir
to_csv() and to_parquet() now create parent directories for both data and metadata paths—no more “directory not found” errors.
Side-car metadata
Exports signal-attribute JSON alongside your data, keeping schema and semantics in sync.
Graceful failures
Parquet write errors are caught, logged, and raised as ValueError so you get a clear Python exception rather than a cryptic pyarrow traceback.
🔧 Quickstart
pip install canml==0.1.13from canml.canmlio import load_blf, to_csv, to_parquet, CanmlConfig
# 🔧 Configure for maximum resilience
cfg = CanmlConfig(
chunk_size=5000,
force_uniform_timing=True,
interpolate_missing=True,
dtype_map={"Speed": "float32", "RPM": "Int64"},
)
# 🚀 Full-file BLF decode with drop-summary logging & enum proofing
df = load_blf(
blf_path="drive.blf",
db="vehicle.dbc",
config=cfg,
message_ids={0x100, 0x200},
expected_signals=["Speed", "RPM"]
)
# 🔍 Inspect attributes & export
print(df.attrs["signal_attributes"])
to_csv(df, "out.csv", metadata_path="out_meta.json")
to_parquet(df, "out.parquet", metadata_path="out_meta.json")Huge thanks to everyone who pushed edge-case testing to the limit—canml is now truly unstoppable! 🎉