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.
Files changed (70) hide show
  1. dbckit-1.0.0/.github/workflows/ci.yml +52 -0
  2. dbckit-1.0.0/.github/workflows/release.yml +38 -0
  3. dbckit-1.0.0/.gitignore +29 -0
  4. dbckit-1.0.0/CHANGELOG.md +116 -0
  5. dbckit-1.0.0/LICENSE +21 -0
  6. dbckit-1.0.0/PKG-INFO +270 -0
  7. dbckit-1.0.0/README.md +218 -0
  8. dbckit-1.0.0/ROADMAP.md +38 -0
  9. dbckit-1.0.0/dbckit/__init__.py +79 -0
  10. dbckit-1.0.0/dbckit/_cycle_time.py +66 -0
  11. dbckit-1.0.0/dbckit/cli.py +1168 -0
  12. dbckit-1.0.0/dbckit/codec/__init__.py +5 -0
  13. dbckit-1.0.0/dbckit/codec/_signal_type.py +32 -0
  14. dbckit-1.0.0/dbckit/codec/decoder.py +67 -0
  15. dbckit-1.0.0/dbckit/codec/encoder.py +114 -0
  16. dbckit-1.0.0/dbckit/codec/frame.py +141 -0
  17. dbckit-1.0.0/dbckit/io.py +29 -0
  18. dbckit-1.0.0/dbckit/model/__init__.py +25 -0
  19. dbckit-1.0.0/dbckit/model/database.py +232 -0
  20. dbckit-1.0.0/dbckit/model/message.py +73 -0
  21. dbckit-1.0.0/dbckit/model/signal.py +115 -0
  22. dbckit-1.0.0/dbckit/mutations/__init__.py +7 -0
  23. dbckit-1.0.0/dbckit/mutations/_cycle_time.py +59 -0
  24. dbckit-1.0.0/dbckit/mutations/attribute.py +171 -0
  25. dbckit-1.0.0/dbckit/mutations/message.py +127 -0
  26. dbckit-1.0.0/dbckit/mutations/node.py +52 -0
  27. dbckit-1.0.0/dbckit/mutations/signal.py +168 -0
  28. dbckit-1.0.0/dbckit/mutations/signal_group.py +101 -0
  29. dbckit-1.0.0/dbckit/operations/__init__.py +37 -0
  30. dbckit-1.0.0/dbckit/operations/codegen.py +300 -0
  31. dbckit-1.0.0/dbckit/operations/diff.py +131 -0
  32. dbckit-1.0.0/dbckit/operations/extract.py +98 -0
  33. dbckit-1.0.0/dbckit/operations/j1939.py +73 -0
  34. dbckit-1.0.0/dbckit/operations/log.py +232 -0
  35. dbckit-1.0.0/dbckit/operations/merge.py +72 -0
  36. dbckit-1.0.0/dbckit/parser/__init__.py +4 -0
  37. dbckit-1.0.0/dbckit/parser/dbc.lark +117 -0
  38. dbckit-1.0.0/dbckit/parser/grammar.py +487 -0
  39. dbckit-1.0.0/dbckit/parser/tokenizer.py +16 -0
  40. dbckit-1.0.0/dbckit/py.typed +1 -0
  41. dbckit-1.0.0/dbckit/serializer.py +267 -0
  42. dbckit-1.0.0/dbckit/validator.py +302 -0
  43. dbckit-1.0.0/dbckit/views.py +422 -0
  44. dbckit-1.0.0/docs/api-reference.md +1055 -0
  45. dbckit-1.0.0/docs/cli.md +353 -0
  46. dbckit-1.0.0/docs/dbc-support.md +169 -0
  47. dbckit-1.0.0/docs/releasing.md +65 -0
  48. dbckit-1.0.0/pyproject.toml +78 -0
  49. dbckit-1.0.0/scripts/create_sample_dbc.py +109 -0
  50. dbckit-1.0.0/tests/__init__.py +0 -0
  51. dbckit-1.0.0/tests/fixtures/complex.dbc +57 -0
  52. dbckit-1.0.0/tests/fixtures/extended.dbc +15 -0
  53. dbckit-1.0.0/tests/fixtures/golden/LICENSE.opendbc.txt +7 -0
  54. dbckit-1.0.0/tests/fixtures/golden/LICENSE.python-can.txt +165 -0
  55. dbckit-1.0.0/tests/fixtures/golden/README.md +17 -0
  56. dbckit-1.0.0/tests/fixtures/golden/opendbc_comma_body.dbc +89 -0
  57. dbckit-1.0.0/tests/fixtures/golden/python_can_logfile.asc +39 -0
  58. dbckit-1.0.0/tests/fixtures/simple.dbc +52 -0
  59. dbckit-1.0.0/tests/test_api.py +642 -0
  60. dbckit-1.0.0/tests/test_cli.py +457 -0
  61. dbckit-1.0.0/tests/test_codec.py +432 -0
  62. dbckit-1.0.0/tests/test_fidelity_gaps.py +322 -0
  63. dbckit-1.0.0/tests/test_golden_fixtures.py +31 -0
  64. dbckit-1.0.0/tests/test_io.py +52 -0
  65. dbckit-1.0.0/tests/test_log.py +264 -0
  66. dbckit-1.0.0/tests/test_mutations.py +366 -0
  67. dbckit-1.0.0/tests/test_operations.py +680 -0
  68. dbckit-1.0.0/tests/test_parser.py +266 -0
  69. dbckit-1.0.0/tests/test_serializer.py +266 -0
  70. 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
@@ -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