dbckit 1.0.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.
- dbckit-1.0.0/.github/workflows/ci.yml +52 -0
- dbckit-1.0.0/.github/workflows/release.yml +38 -0
- dbckit-1.0.0/.gitignore +29 -0
- dbckit-1.0.0/CHANGELOG.md +116 -0
- dbckit-1.0.0/LICENSE +21 -0
- dbckit-1.0.0/PKG-INFO +270 -0
- dbckit-1.0.0/README.md +218 -0
- dbckit-1.0.0/ROADMAP.md +38 -0
- dbckit-1.0.0/dbckit/__init__.py +79 -0
- dbckit-1.0.0/dbckit/_cycle_time.py +66 -0
- dbckit-1.0.0/dbckit/cli.py +1168 -0
- dbckit-1.0.0/dbckit/codec/__init__.py +5 -0
- dbckit-1.0.0/dbckit/codec/_signal_type.py +32 -0
- dbckit-1.0.0/dbckit/codec/decoder.py +67 -0
- dbckit-1.0.0/dbckit/codec/encoder.py +114 -0
- dbckit-1.0.0/dbckit/codec/frame.py +141 -0
- dbckit-1.0.0/dbckit/io.py +29 -0
- dbckit-1.0.0/dbckit/model/__init__.py +25 -0
- dbckit-1.0.0/dbckit/model/database.py +232 -0
- dbckit-1.0.0/dbckit/model/message.py +73 -0
- dbckit-1.0.0/dbckit/model/signal.py +115 -0
- dbckit-1.0.0/dbckit/mutations/__init__.py +7 -0
- dbckit-1.0.0/dbckit/mutations/_cycle_time.py +59 -0
- dbckit-1.0.0/dbckit/mutations/attribute.py +171 -0
- dbckit-1.0.0/dbckit/mutations/message.py +127 -0
- dbckit-1.0.0/dbckit/mutations/node.py +52 -0
- dbckit-1.0.0/dbckit/mutations/signal.py +168 -0
- dbckit-1.0.0/dbckit/mutations/signal_group.py +101 -0
- dbckit-1.0.0/dbckit/operations/__init__.py +37 -0
- dbckit-1.0.0/dbckit/operations/codegen.py +300 -0
- dbckit-1.0.0/dbckit/operations/diff.py +131 -0
- dbckit-1.0.0/dbckit/operations/extract.py +98 -0
- dbckit-1.0.0/dbckit/operations/j1939.py +73 -0
- dbckit-1.0.0/dbckit/operations/log.py +232 -0
- dbckit-1.0.0/dbckit/operations/merge.py +72 -0
- dbckit-1.0.0/dbckit/parser/__init__.py +4 -0
- dbckit-1.0.0/dbckit/parser/dbc.lark +117 -0
- dbckit-1.0.0/dbckit/parser/grammar.py +487 -0
- dbckit-1.0.0/dbckit/parser/tokenizer.py +16 -0
- dbckit-1.0.0/dbckit/py.typed +1 -0
- dbckit-1.0.0/dbckit/serializer.py +267 -0
- dbckit-1.0.0/dbckit/validator.py +302 -0
- dbckit-1.0.0/dbckit/views.py +422 -0
- dbckit-1.0.0/docs/api-reference.md +1055 -0
- dbckit-1.0.0/docs/cli.md +353 -0
- dbckit-1.0.0/docs/dbc-support.md +169 -0
- dbckit-1.0.0/docs/releasing.md +65 -0
- dbckit-1.0.0/pyproject.toml +78 -0
- dbckit-1.0.0/scripts/create_sample_dbc.py +109 -0
- dbckit-1.0.0/tests/__init__.py +0 -0
- dbckit-1.0.0/tests/fixtures/complex.dbc +57 -0
- dbckit-1.0.0/tests/fixtures/extended.dbc +15 -0
- dbckit-1.0.0/tests/fixtures/golden/LICENSE.opendbc.txt +7 -0
- dbckit-1.0.0/tests/fixtures/golden/LICENSE.python-can.txt +165 -0
- dbckit-1.0.0/tests/fixtures/golden/README.md +17 -0
- dbckit-1.0.0/tests/fixtures/golden/opendbc_comma_body.dbc +89 -0
- dbckit-1.0.0/tests/fixtures/golden/python_can_logfile.asc +39 -0
- dbckit-1.0.0/tests/fixtures/simple.dbc +52 -0
- dbckit-1.0.0/tests/test_api.py +642 -0
- dbckit-1.0.0/tests/test_cli.py +457 -0
- dbckit-1.0.0/tests/test_codec.py +432 -0
- dbckit-1.0.0/tests/test_fidelity_gaps.py +322 -0
- dbckit-1.0.0/tests/test_golden_fixtures.py +31 -0
- dbckit-1.0.0/tests/test_io.py +52 -0
- dbckit-1.0.0/tests/test_log.py +264 -0
- dbckit-1.0.0/tests/test_mutations.py +366 -0
- dbckit-1.0.0/tests/test_operations.py +680 -0
- dbckit-1.0.0/tests/test_parser.py +266 -0
- dbckit-1.0.0/tests/test_serializer.py +266 -0
- dbckit-1.0.0/tests/test_validator.py +242 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: "Test (Python ${{ matrix.python-version }})"
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Lint (ruff)
|
|
30
|
+
run: ruff check dbckit/
|
|
31
|
+
|
|
32
|
+
- name: Type-check (mypy)
|
|
33
|
+
run: mypy dbckit/
|
|
34
|
+
|
|
35
|
+
- name: Test + coverage gate (≥90%, CLI omitted)
|
|
36
|
+
run: pytest --cov=dbckit --cov-fail-under=90 -q
|
|
37
|
+
|
|
38
|
+
release-dry-run:
|
|
39
|
+
name: "Build check"
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
needs: test
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v4
|
|
44
|
+
- uses: actions/setup-python@v5
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.11"
|
|
47
|
+
- name: Install build
|
|
48
|
+
run: pip install build
|
|
49
|
+
- name: Build sdist and wheel
|
|
50
|
+
run: python -m build
|
|
51
|
+
- name: Verify dist contents
|
|
52
|
+
run: ls -lh dist/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
name: "Build distributions"
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.12"
|
|
16
|
+
- name: Install build
|
|
17
|
+
run: pip install build
|
|
18
|
+
- name: Build sdist and wheel
|
|
19
|
+
run: python -m build
|
|
20
|
+
- uses: actions/upload-artifact@v4
|
|
21
|
+
with:
|
|
22
|
+
name: dist
|
|
23
|
+
path: dist/
|
|
24
|
+
|
|
25
|
+
publish:
|
|
26
|
+
name: "Publish to PyPI"
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
needs: build
|
|
29
|
+
environment: pypi
|
|
30
|
+
permissions:
|
|
31
|
+
id-token: write
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/download-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
- name: Publish (trusted publishing / OIDC)
|
|
38
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
dbckit-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
|
|
3
|
+
.claude/
|
|
4
|
+
.venv/
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
|
|
8
|
+
.env
|
|
9
|
+
.env.*
|
|
10
|
+
!.env.example
|
|
11
|
+
|
|
12
|
+
.tox/
|
|
13
|
+
.nox/
|
|
14
|
+
.hypothesis/
|
|
15
|
+
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
coverage.xml
|
|
19
|
+
junit.xml
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
|
|
25
|
+
dist/
|
|
26
|
+
build/
|
|
27
|
+
*.egg-info/
|
|
28
|
+
|
|
29
|
+
docs/archive/
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to dbckit are documented here.
|
|
4
|
+
|
|
5
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
Versioning follows [Semantic Versioning](https://semver.org/) from 1.0.0 onward.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [1.0.0] — 2026-07-15
|
|
13
|
+
|
|
14
|
+
Initial public release.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
**Models and API**
|
|
19
|
+
|
|
20
|
+
- Typed Pydantic v2 data models: `Database`, `Message`, `Signal`, `SignalGroup`,
|
|
21
|
+
`Node`, environment variables, value tables, and attribute definitions, with
|
|
22
|
+
`py.typed` shipped in the package.
|
|
23
|
+
- Database-bound `MessageView` / `SignalView` / `NodeView` returned by navigation
|
|
24
|
+
methods — the supported surface for modifying or deleting existing entities.
|
|
25
|
+
- Copy-on-write editing: every mutation returns a new `Database` and never
|
|
26
|
+
mutates its input.
|
|
27
|
+
|
|
28
|
+
**Parsing and serialization**
|
|
29
|
+
|
|
30
|
+
- DBC parser and deterministic serializer covering `VERSION`, `NS_`, `BS_`,
|
|
31
|
+
`BU_`, `VAL_TABLE_`, `BO_`/`SG_`, `SIG_GROUP_`, `CM_` (database, node,
|
|
32
|
+
message, signal, and environment variable), `BA_DEF_`/`BA_DEF_DEF_`/`BA_`,
|
|
33
|
+
`VAL_`, `BO_TX_BU_`, `SIG_VALTYPE_`, and `EV_`/`ENVVAR_DATA_`, with semantic
|
|
34
|
+
round trips for all supported sections.
|
|
35
|
+
- Extended (29-bit) frame support via the DBC bit-31 convention, round-tripping
|
|
36
|
+
`Message.is_extended_frame`.
|
|
37
|
+
- Strict UTF-8 loading with cp1252 fallback, plus explicit `encoding=`
|
|
38
|
+
overrides on `load()` and `save()`.
|
|
39
|
+
- Clear, targeted errors for unsupported constructs: extended multiplexing
|
|
40
|
+
(`mXM` indicators and `SG_MUL_VAL_` sections) is rejected during parsing, and
|
|
41
|
+
dangling `CM_`/`BA_`/`VAL_`/`SIG_VALTYPE_`/`ENVVAR_DATA_` references fail
|
|
42
|
+
with section-specific diagnostics instead of being silently discarded.
|
|
43
|
+
- `Message.cycle_time` synchronized with the `GenMsgCycleTime` attribute across
|
|
44
|
+
parsing, construction, mutation, and serialization.
|
|
45
|
+
|
|
46
|
+
**Codec**
|
|
47
|
+
|
|
48
|
+
- Frame- and signal-level encode/decode (`decode_frame`, `encode_frame`,
|
|
49
|
+
`decode_signal`, `encode_signal`) for integer and IEEE-754 float/double
|
|
50
|
+
(`SIG_VALTYPE_`) signals, in Intel and Motorola byte order.
|
|
51
|
+
- Simple multiplexing (`M`/`mX`) on decode and encode, with selector
|
|
52
|
+
auto-inference and inactive-variant filtering.
|
|
53
|
+
- Documented overflow and error behavior: out-of-range values clamp by default
|
|
54
|
+
and raise with `strict=True`; unspecified signals are zero-filled; bytes
|
|
55
|
+
missing from short payloads read as zero.
|
|
56
|
+
|
|
57
|
+
**Validation**
|
|
58
|
+
|
|
59
|
+
- `validate()` returning structured issues (severity, code, location, message)
|
|
60
|
+
for duplicate and invalid IDs, duplicate signals, signal overlap and
|
|
61
|
+
overflow, multiplexing problems (`MUX_INVALID`, `MUX_MISSING_SELECTOR`,
|
|
62
|
+
`MUX_SELECTOR_OUT_OF_RANGE`, `MUX_OVERLAP`), missing senders/receivers, and
|
|
63
|
+
attribute violations.
|
|
64
|
+
|
|
65
|
+
**Editing**
|
|
66
|
+
|
|
67
|
+
- View-level edits: rename, field updates, signal add/delete/rename/update,
|
|
68
|
+
sender add/remove, arbitration-ID changes (with signal-group reference
|
|
69
|
+
rewrites and collision handling), value-table choices, attribute set/unset,
|
|
70
|
+
and delete.
|
|
71
|
+
- Database-level creation and definitions: `add_message`, `add_node`,
|
|
72
|
+
`define_attribute`, `delete_attribute`, and signal-group operations
|
|
73
|
+
(add/remove a group, add/remove signals within a group).
|
|
74
|
+
|
|
75
|
+
**Operations**
|
|
76
|
+
|
|
77
|
+
- `diff()` with field-level message changes plus signal, signal-group,
|
|
78
|
+
environment-variable, and attribute-value diffs; `merge()` with
|
|
79
|
+
`raise`/`ours`/`theirs` strategies.
|
|
80
|
+
- `extract()` by arbitration IDs, message names, and sender/receiver node
|
|
81
|
+
names (selectors combine as a union), preserving environment variables.
|
|
82
|
+
- `search_messages()` / `search_signals()`, and attribute-based J1939 lookup
|
|
83
|
+
(`find_messages_by_pgn`, `find_signals_by_spn`, `Database.message_by_pgn`,
|
|
84
|
+
`Database.signal_by_spn`).
|
|
85
|
+
|
|
86
|
+
**Log and frame decoding**
|
|
87
|
+
|
|
88
|
+
- `decode_log()` streaming decoded frames from Vector CANalyzer `.asc` files,
|
|
89
|
+
including 29-bit `x`-suffixed identifiers; multiplexed frames omit inactive
|
|
90
|
+
variants.
|
|
91
|
+
- The structural `FrameLike` contract and pure `decode_frames()` iterator for
|
|
92
|
+
decoding third-party frame objects without file I/O; `RawFrame` and
|
|
93
|
+
`DecodedFrame` carry optional channel and extended-frame metadata.
|
|
94
|
+
- Reader extensibility: `register_reader()` as a stable public extension
|
|
95
|
+
point, lazy discovery through the `dbckit.readers` entry-point group, and
|
|
96
|
+
API/CLI format overrides for oddly named log files.
|
|
97
|
+
|
|
98
|
+
**Code generation**
|
|
99
|
+
|
|
100
|
+
- `codegen()` targets: `python` (self-contained dataclasses with working
|
|
101
|
+
`decode()`/`encode()`), `markdown`, `json-schema`, and `c` (experimental).
|
|
102
|
+
|
|
103
|
+
**CLI**
|
|
104
|
+
|
|
105
|
+
- `dbckit` command (via the `cli` extra) with `db`, `message`, `signal`,
|
|
106
|
+
`node`, `attribute`, `decode`, `encode`, and `codegen` groups; `table`,
|
|
107
|
+
`json`, and `csv` output; non-zero exit codes on validation errors in every
|
|
108
|
+
output format.
|
|
109
|
+
|
|
110
|
+
**Docs, fixtures, and CI**
|
|
111
|
+
|
|
112
|
+
- API reference, DBC support matrix, CLI reference, and release process docs.
|
|
113
|
+
- Pinned, licensed golden fixtures from `commaai/opendbc` and `python-can`,
|
|
114
|
+
covering semantic DBC round trips and a real Vector-format ASC trace.
|
|
115
|
+
- GitHub Actions CI: tests, ruff, mypy, coverage ≥ 90%, and build check on
|
|
116
|
+
Python 3.11–3.14.
|
dbckit-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 André Delgado
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dbckit-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dbckit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A Python library for working with DBC (CAN database) files
|
|
5
|
+
Project-URL: Homepage, https://canforge.io/dbckit
|
|
6
|
+
Project-URL: Repository, https://github.com/canforge/dbckit
|
|
7
|
+
Project-URL: Changelog, https://github.com/canforge/dbckit/blob/main/CHANGELOG.md
|
|
8
|
+
Author-email: André Delgado <andre@adelgado.io>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 André Delgado
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: CAN,DBC,automotive,canbus
|
|
32
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
40
|
+
Requires-Python: >=3.11
|
|
41
|
+
Requires-Dist: lark>=1.1
|
|
42
|
+
Requires-Dist: pydantic>=2.0
|
|
43
|
+
Provides-Extra: cli
|
|
44
|
+
Requires-Dist: typer[rich]>=0.9; extra == 'cli'
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: mypy; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
49
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
50
|
+
Requires-Dist: typer[rich]>=0.9; extra == 'dev'
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
# dbckit
|
|
54
|
+
|
|
55
|
+
`dbckit` is a Python library for working with **DBC (CAN database) files**.
|
|
56
|
+
|
|
57
|
+
Use it to:
|
|
58
|
+
|
|
59
|
+
- load and inspect DBC files
|
|
60
|
+
- decode CAN payloads into physical signal values — integers, floats, and doubles
|
|
61
|
+
- encode signal values back into CAN payloads
|
|
62
|
+
- validate DBC content
|
|
63
|
+
- apply deterministic edits and write the result back out
|
|
64
|
+
- diff, merge, extract, and search databases
|
|
65
|
+
- decode CAN log files (`.asc` built in, extensible readers) and in-memory frame streams
|
|
66
|
+
|
|
67
|
+
## Install
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install dbckit
|
|
71
|
+
pip install "dbckit[cli]" # adds the dbckit command-line tool
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Requires Python `>=3.11`.
|
|
75
|
+
|
|
76
|
+
## Design
|
|
77
|
+
|
|
78
|
+
`dbckit` is built around typed data models with database-bound Views:
|
|
79
|
+
|
|
80
|
+
- `Database` is for navigation, top-level creation, cross-database operations,
|
|
81
|
+
and persistence.
|
|
82
|
+
- `MessageView`, `SignalView`, and `NodeView` (returned by `db.message()`,
|
|
83
|
+
`msg.signal()`, `db.node()`) are the normal way to modify or delete existing
|
|
84
|
+
entities.
|
|
85
|
+
- Edit operations are copy-on-write: they return a new `Database` and never
|
|
86
|
+
mutate the original.
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
import dbckit
|
|
92
|
+
|
|
93
|
+
db = dbckit.load("vehicle.dbc")
|
|
94
|
+
|
|
95
|
+
# inspect
|
|
96
|
+
print(db.version, len(db.messages))
|
|
97
|
+
|
|
98
|
+
msg = db.message(0x1F4)
|
|
99
|
+
sig = msg.signal("EngineSpeed")
|
|
100
|
+
print(sig.start_bit, sig.length, sig.factor, sig.unit)
|
|
101
|
+
|
|
102
|
+
# decode / encode a frame payload
|
|
103
|
+
values = msg.decode(bytes([0xE8, 0x03, 0, 0, 0, 0, 0, 0]))
|
|
104
|
+
raw = msg.encode({"EngineSpeed": 825.0, "EngineTemp": 90.0})
|
|
105
|
+
|
|
106
|
+
# validate
|
|
107
|
+
for issue in dbckit.validate(db):
|
|
108
|
+
print(issue.severity, issue.code, issue.location)
|
|
109
|
+
|
|
110
|
+
# edits return a new Database
|
|
111
|
+
db2 = sig.update(factor=0.5)
|
|
112
|
+
db3 = db2.message(0x1F4).rename("MotorData")
|
|
113
|
+
db4 = db3.node("ECU1").rename("EngineECU")
|
|
114
|
+
|
|
115
|
+
db4.save("vehicle.updated.dbc")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Features
|
|
119
|
+
|
|
120
|
+
### Parse and I/O
|
|
121
|
+
|
|
122
|
+
`dbckit.load()` / `dbckit.save()` for files, `dbckit.parse()` / `dbckit.dump()`
|
|
123
|
+
for strings. Loading tries strict UTF-8 first and falls back to cp1252 (common
|
|
124
|
+
in Vector-exported files); pass `encoding=` to either function to force one:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
db = dbckit.load("vehicle.dbc", encoding="latin-1")
|
|
128
|
+
dbckit.save(db, "copy.dbc", encoding="utf-8")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Codec
|
|
132
|
+
|
|
133
|
+
Message-level `decode_frame()` / `encode_frame()` and signal-level
|
|
134
|
+
`decode_signal()` / `encode_signal()`. Both integer signals and IEEE-754
|
|
135
|
+
float/double signals (`SIG_VALTYPE_`) are supported, in Intel and Motorola
|
|
136
|
+
byte order. Encoding clamps out-of-range values by default; pass `strict=True`
|
|
137
|
+
to raise `ValueError` instead. Unspecified signals are zero-filled.
|
|
138
|
+
|
|
139
|
+
Simple DBC multiplexing (one `M` selector, `mX` variants) is fully supported
|
|
140
|
+
for decode, encode, and validation. Extended/nested multiplexing (`m0M`) is
|
|
141
|
+
unsupported and rejected during parsing with a clear error.
|
|
142
|
+
|
|
143
|
+
### Editing
|
|
144
|
+
|
|
145
|
+
Views cover renames, field updates, signal add/delete, sender and receiver
|
|
146
|
+
edits, arbitration-ID changes, value-table choices, and attribute values.
|
|
147
|
+
`Database` covers top-level creation and signal groups:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from dbckit import Message, Signal, Node, SignalGroup
|
|
151
|
+
|
|
152
|
+
db2 = db.add_node(Node(name="Gateway"))
|
|
153
|
+
db3 = db2.add_message(Message(arbitration_id=0x400, name="BrakeData", length=8))
|
|
154
|
+
db4 = db3.message(0x400).add_signal(Signal(name="BrakePressure", start_bit=0, length=16))
|
|
155
|
+
db5 = db4.message(0x400).set_attribute("GenMsgCycleTime", 20)
|
|
156
|
+
db6 = db5.add_signal_group(SignalGroup(name="BrakeGroup", message_id=0x400, repetitions=1))
|
|
157
|
+
db7 = db6.add_signal_to_group(0x400, "BrakeGroup", "BrakePressure")
|
|
158
|
+
db7.save("vehicle.updated.dbc")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Validation
|
|
162
|
+
|
|
163
|
+
`dbckit.validate(db)` returns structured issues (severity, code, location,
|
|
164
|
+
message) covering duplicate/invalid IDs, signal overlap and overflow,
|
|
165
|
+
multiplexing problems, missing senders/receivers, and attribute violations.
|
|
166
|
+
The full issue-code list is in the [API reference](docs/api-reference.md).
|
|
167
|
+
|
|
168
|
+
### Operations
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
result = dbckit.diff(db_a, db_b)
|
|
172
|
+
merged = dbckit.merge(db_a, db_b, strategy="ours") # raise | ours | theirs
|
|
173
|
+
|
|
174
|
+
sub = dbckit.extract(db, [0x100, 0x200])
|
|
175
|
+
sub = dbckit.extract(db, message_names=["EngineData"], node_names=["Gateway"])
|
|
176
|
+
|
|
177
|
+
messages = dbckit.search_messages(db, "engine")
|
|
178
|
+
pairs = dbckit.search_signals(db, "speed")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
J1939 helpers look up messages and signals by explicit `PGN`/`SPN` attribute
|
|
182
|
+
values:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
matches = dbckit.find_messages_by_pgn(db, 61444)
|
|
186
|
+
owner, sig = db.signal_by_spn(177)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Log and frame decoding
|
|
190
|
+
|
|
191
|
+
`decode_log()` streams decoded frames from a log file. Vector CANalyzer `.asc`
|
|
192
|
+
is built in (including extended 29-bit IDs); other formats plug in through
|
|
193
|
+
`register_reader()` or the `dbckit.readers` entry-point group, and
|
|
194
|
+
`format=` overrides extension-based detection for oddly named files:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
for frame in dbckit.decode_log(db, "trace.asc"):
|
|
198
|
+
print(frame.timestamp, hex(frame.arbitration_id), frame.signals)
|
|
199
|
+
|
|
200
|
+
frames = dbckit.decode_log(db, "capture.txt", format="asc")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`decode_frames()` does the same for any iterable of frame objects — no file
|
|
204
|
+
I/O required. Anything with `timestamp`, `arbitration_id`, and `data`
|
|
205
|
+
attributes satisfies the `FrameLike` protocol, so frames from `python-can` or
|
|
206
|
+
your own tooling decode directly:
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
decoded = dbckit.decode_frames(db, my_frames) # Iterator[DecodedFrame]
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Code generation
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
header = dbckit.codegen(db, "c") # experimental
|
|
216
|
+
module = dbckit.codegen(db, "python") # dataclasses with decode()/encode()
|
|
217
|
+
doc = dbckit.codegen(db, "markdown")
|
|
218
|
+
schema = dbckit.codegen(db, "json-schema")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## CLI
|
|
222
|
+
|
|
223
|
+
The `cli` extra installs a `dbckit` command with `db`, `message`, `signal`,
|
|
224
|
+
`node`, `attribute`, `decode`, `encode`, and `codegen` groups. Output formats
|
|
225
|
+
are `table`, `json`, and `csv`.
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
dbckit db info --db vehicle.dbc
|
|
229
|
+
dbckit db validate --db vehicle.dbc
|
|
230
|
+
dbckit db diff base.dbc changed.dbc
|
|
231
|
+
dbckit message list --db vehicle.dbc
|
|
232
|
+
dbckit signal layout --db vehicle.dbc 0x1F4
|
|
233
|
+
dbckit decode frame --db vehicle.dbc 0x1F4 "E8 03 00 00 00 00 00 00"
|
|
234
|
+
dbckit decode log --db vehicle.dbc trace.asc
|
|
235
|
+
dbckit codegen markdown --db vehicle.dbc --out docs.md
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
See the [CLI reference](docs/cli.md) for every command and option.
|
|
239
|
+
|
|
240
|
+
## Scope and Caveats
|
|
241
|
+
|
|
242
|
+
- Classic CAN DBC workflows are the supported surface; CAN FD is untested and
|
|
243
|
+
FD-specific flags such as `VFrameFormat` are not interpreted.
|
|
244
|
+
- `.sym`, `.kcd`, and ARXML database formats are out of scope.
|
|
245
|
+
- J1939 helpers use explicit `PGN`/`SPN` attribute values only; they do not
|
|
246
|
+
derive PGNs from 29-bit arbitration IDs.
|
|
247
|
+
- Frame encoding zero-fills unspecified signals and ignores `GenSigStartValue`.
|
|
248
|
+
- Mutation helpers are pure at the `Database` level, but the underlying
|
|
249
|
+
Pydantic models are not frozen objects.
|
|
250
|
+
|
|
251
|
+
## Documentation
|
|
252
|
+
|
|
253
|
+
- [API reference](docs/api-reference.md) — the detailed public API contract,
|
|
254
|
+
including codec overflow/error behavior and validation issue codes
|
|
255
|
+
- [DBC support matrix](docs/dbc-support.md) — which DBC sections and
|
|
256
|
+
constructs are fully, partially, or not supported
|
|
257
|
+
- [CLI reference](docs/cli.md) — every command and option
|
|
258
|
+
|
|
259
|
+
## Development
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
python -m venv .venv
|
|
263
|
+
source .venv/bin/activate
|
|
264
|
+
pip install -e ".[dev]"
|
|
265
|
+
pytest
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## License
|
|
269
|
+
|
|
270
|
+
MIT
|