dbckit 1.0.0__py3-none-any.whl
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/__init__.py +79 -0
- dbckit/_cycle_time.py +66 -0
- dbckit/cli.py +1168 -0
- dbckit/codec/__init__.py +5 -0
- dbckit/codec/_signal_type.py +32 -0
- dbckit/codec/decoder.py +67 -0
- dbckit/codec/encoder.py +114 -0
- dbckit/codec/frame.py +141 -0
- dbckit/io.py +29 -0
- dbckit/model/__init__.py +25 -0
- dbckit/model/database.py +232 -0
- dbckit/model/message.py +73 -0
- dbckit/model/signal.py +115 -0
- dbckit/mutations/__init__.py +7 -0
- dbckit/mutations/_cycle_time.py +59 -0
- dbckit/mutations/attribute.py +171 -0
- dbckit/mutations/message.py +127 -0
- dbckit/mutations/node.py +52 -0
- dbckit/mutations/signal.py +168 -0
- dbckit/mutations/signal_group.py +101 -0
- dbckit/operations/__init__.py +37 -0
- dbckit/operations/codegen.py +300 -0
- dbckit/operations/diff.py +131 -0
- dbckit/operations/extract.py +98 -0
- dbckit/operations/j1939.py +73 -0
- dbckit/operations/log.py +232 -0
- dbckit/operations/merge.py +72 -0
- dbckit/parser/__init__.py +4 -0
- dbckit/parser/dbc.lark +117 -0
- dbckit/parser/grammar.py +487 -0
- dbckit/parser/tokenizer.py +16 -0
- dbckit/py.typed +1 -0
- dbckit/serializer.py +267 -0
- dbckit/validator.py +302 -0
- dbckit/views.py +422 -0
- dbckit-1.0.0.dist-info/METADATA +270 -0
- dbckit-1.0.0.dist-info/RECORD +40 -0
- dbckit-1.0.0.dist-info/WHEEL +4 -0
- dbckit-1.0.0.dist-info/entry_points.txt +2 -0
- dbckit-1.0.0.dist-info/licenses/LICENSE +21 -0
dbckit/__init__.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""dbckit — parse, inspect, encode, decode, and transform DBC (CAN database) files."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
# ── codec ─────────────────────────────────────────────────────────────────────
|
|
5
|
+
from dbckit.codec import decode_frame, decode_signal, encode_frame, encode_signal
|
|
6
|
+
|
|
7
|
+
# ── io ────────────────────────────────────────────────────────────────────────
|
|
8
|
+
from dbckit.io import load, save
|
|
9
|
+
|
|
10
|
+
# ── models ────────────────────────────────────────────────────────────────────
|
|
11
|
+
from dbckit.model.database import (
|
|
12
|
+
AttributeDefinition,
|
|
13
|
+
AttributeKind,
|
|
14
|
+
Database,
|
|
15
|
+
Issue,
|
|
16
|
+
Node,
|
|
17
|
+
)
|
|
18
|
+
from dbckit.model.message import Message
|
|
19
|
+
from dbckit.model.signal import BitSlot, ByteOrder, Signal, SignalGroup, ValueTable
|
|
20
|
+
|
|
21
|
+
# ── operations ────────────────────────────────────────────────────────────────
|
|
22
|
+
from dbckit.operations import (
|
|
23
|
+
AscReader,
|
|
24
|
+
CodegenTarget,
|
|
25
|
+
DecodedFrame,
|
|
26
|
+
DiffResult,
|
|
27
|
+
FrameLike,
|
|
28
|
+
MergeStrategy,
|
|
29
|
+
MessageDiff,
|
|
30
|
+
RawFrame,
|
|
31
|
+
SignalDiff,
|
|
32
|
+
codegen,
|
|
33
|
+
decode_frames,
|
|
34
|
+
decode_log,
|
|
35
|
+
diff,
|
|
36
|
+
extract,
|
|
37
|
+
find_messages_by_pgn,
|
|
38
|
+
find_signals_by_spn,
|
|
39
|
+
merge,
|
|
40
|
+
register_reader,
|
|
41
|
+
search_messages,
|
|
42
|
+
search_signals,
|
|
43
|
+
)
|
|
44
|
+
from dbckit.parser.grammar import parse_string
|
|
45
|
+
from dbckit.parser.tokenizer import normalize
|
|
46
|
+
from dbckit.serializer import dump
|
|
47
|
+
from dbckit.validator import validate
|
|
48
|
+
|
|
49
|
+
# ── views ─────────────────────────────────────────────────────────────────────
|
|
50
|
+
from dbckit.views import MessageView, NodeView, SignalView
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
# models
|
|
54
|
+
"Database", "Message", "Signal", "SignalGroup", "Node",
|
|
55
|
+
"ByteOrder", "ValueTable", "BitSlot",
|
|
56
|
+
"AttributeDefinition", "AttributeKind", "Issue",
|
|
57
|
+
# views
|
|
58
|
+
"MessageView", "SignalView", "NodeView",
|
|
59
|
+
# parse / io
|
|
60
|
+
"parse", "load", "dump", "save",
|
|
61
|
+
# validate
|
|
62
|
+
"validate",
|
|
63
|
+
# codec
|
|
64
|
+
"decode_frame", "encode_frame", "decode_signal", "encode_signal",
|
|
65
|
+
# operations
|
|
66
|
+
"diff", "DiffResult", "MessageDiff", "SignalDiff",
|
|
67
|
+
"merge", "MergeStrategy",
|
|
68
|
+
"extract",
|
|
69
|
+
"search_messages", "search_signals",
|
|
70
|
+
"find_messages_by_pgn", "find_signals_by_spn",
|
|
71
|
+
"codegen", "CodegenTarget",
|
|
72
|
+
"decode_frames", "decode_log", "DecodedFrame", "FrameLike", "RawFrame",
|
|
73
|
+
"AscReader", "register_reader",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def parse(text: str) -> Database:
|
|
78
|
+
"""Parse a DBC-formatted string and return a Database model."""
|
|
79
|
+
return parse_string(normalize(text))
|
dbckit/_cycle_time.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Shared helpers for the DBC ``GenMsgCycleTime`` convention."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from decimal import Decimal, InvalidOperation
|
|
5
|
+
from math import isfinite
|
|
6
|
+
from typing import Any, Protocol
|
|
7
|
+
|
|
8
|
+
CYCLE_TIME_ATTRIBUTE = "GenMsgCycleTime"
|
|
9
|
+
AUTO_CYCLE_TIME_MINIMUM = 0
|
|
10
|
+
AUTO_CYCLE_TIME_MAXIMUM = 2_147_483_647
|
|
11
|
+
AUTO_CYCLE_TIME_DEFAULT = 0
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CycleTimeDefinition(Protocol):
|
|
15
|
+
"""The range fields needed from an attribute definition."""
|
|
16
|
+
|
|
17
|
+
minimum: float | None
|
|
18
|
+
maximum: float | None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def coerce_cycle_time(value: Any) -> int:
|
|
22
|
+
"""Return *value* as an integer cycle time or raise ``ValueError``."""
|
|
23
|
+
if isinstance(value, bool):
|
|
24
|
+
raise ValueError("GenMsgCycleTime must be an integer, not a boolean")
|
|
25
|
+
try:
|
|
26
|
+
decimal = Decimal(str(value))
|
|
27
|
+
except (InvalidOperation, ValueError, TypeError):
|
|
28
|
+
raise ValueError(f"GenMsgCycleTime must be an integer, got {value!r}") from None
|
|
29
|
+
if not decimal.is_finite() or decimal != decimal.to_integral_value():
|
|
30
|
+
raise ValueError(f"GenMsgCycleTime must be an integer, got {value!r}")
|
|
31
|
+
return int(decimal)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def validate_cycle_time(
|
|
35
|
+
value: Any,
|
|
36
|
+
definition: CycleTimeDefinition | None = None,
|
|
37
|
+
) -> int:
|
|
38
|
+
"""Coerce and validate a cycle time against an effective definition."""
|
|
39
|
+
cycle_time = coerce_cycle_time(value)
|
|
40
|
+
minimum = (
|
|
41
|
+
AUTO_CYCLE_TIME_MINIMUM if definition is None else definition.minimum
|
|
42
|
+
)
|
|
43
|
+
maximum = (
|
|
44
|
+
AUTO_CYCLE_TIME_MAXIMUM if definition is None else definition.maximum
|
|
45
|
+
)
|
|
46
|
+
if minimum is not None and (not isfinite(minimum) or cycle_time < minimum):
|
|
47
|
+
raise ValueError(
|
|
48
|
+
f"GenMsgCycleTime value {cycle_time} is outside the declared range "
|
|
49
|
+
f"[{_format_bound(minimum)}, {_format_bound(maximum)}]"
|
|
50
|
+
)
|
|
51
|
+
if maximum is not None and (not isfinite(maximum) or cycle_time > maximum):
|
|
52
|
+
raise ValueError(
|
|
53
|
+
f"GenMsgCycleTime value {cycle_time} is outside the declared range "
|
|
54
|
+
f"[{_format_bound(minimum)}, {_format_bound(maximum)}]"
|
|
55
|
+
)
|
|
56
|
+
return cycle_time
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _format_bound(value: float | None) -> str:
|
|
60
|
+
if value is None:
|
|
61
|
+
return "unbounded"
|
|
62
|
+
if not isfinite(value):
|
|
63
|
+
return str(value)
|
|
64
|
+
if value == int(value):
|
|
65
|
+
return str(int(value))
|
|
66
|
+
return str(value)
|