Skip to content

Commit fc05078

Browse files
authored
prepare release 0.9.3 (#543)
1 parent dcc785b commit fc05078

15 files changed

+139
-42
lines changed

Diff for: requirements.test.py2.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ tox==3.2.1
1616
typing==3.6.6
1717
virtualenv==16.0.0
1818
xlwt==1.3.0
19-
xlrd==1.1.0
19+
xlrd==1.2.0
2020
click==7.0
21-
lxml==4.5.2
21+
lxml==4.6.2
2222
enum34==1.1.10

Diff for: requirements.test.py3.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ tox==3.2.1
1616
typing==3.6.6; python_version < '3.5'
1717
virtualenv==16.0.0
1818
xlwt==1.3.0
19-
xlrd==1.1.0
20-
lxml==4.5.2
19+
xlrd==1.2.0
20+
lxml==4.6.2
2121
click==7.0
2222
xlsxwriter==1.2.8
2323
pyaml==20.4.0

Diff for: requirements.tox.txt

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ typing==3.6.6; python_version < '3.5'
88
virtualenv==16.4.1
99
click==7.0
1010
enum34==1.1.10; python_version <= '2.7'
11+
xlrd==1.2.0

Diff for: requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
click
22
lxml
33
xlwt
4-
xlrd
4+
xlrd==1.2.0
55
xlsxwriter
66
pyyaml
77
future

Diff for: src/canmatrix/canmatrix.py

+12-25
Original file line numberDiff line numberDiff line change
@@ -1351,35 +1351,18 @@ def unpack(self, data, report_error=True):
13511351

13521352
return returnDict
13531353

1354-
def _has_sub_multiplexer(self, parent_multiplexer_name):
1354+
def _get_sub_multiplexer(self, parent_multiplexer_name, parent_multiplexer_value):
13551355
"""
1356-
check if any sub-multiplexer in frame
1357-
used for complex-multiplexed frame decoding
1358-
1359-
:param parent_multiplexer_name: string with name of parent multiplexer
1360-
:return: True or False
1361-
"""
1362-
for signal in self.signals:
1363-
if signal.is_multiplexer and signal.muxer_for_signal == parent_multiplexer_name:
1364-
return True
1365-
return False
1366-
1367-
def _get_sub_multiplexer(self, parent_multiplexer_name, parent_multiplexer_value, decoded):
1368-
"""
1369-
get any sub-multiplexer in frame for decoded data
1370-
return multiplexers name and value
1371-
used for complex-multiplexed frame decoding
1356+
get any sub-multiplexer in frame used
1357+
for complex-multiplexed frame decoding
13721358
13731359
:param parent_multiplexer_name: string with name of parent multiplexer
13741360
:param parent_multiplexer_value: raw_value (int) of parent multiplexer
1375-
:param decoded: OrderedDictionary which is returned from canmatrix.Frame.unpack
1376-
:return: muxer_name and muxer_value
1361+
:return: muxer signal or None
13771362
"""
13781363
for signal in self.signals:
13791364
if signal.is_multiplexer and signal.muxer_for_signal == parent_multiplexer_name and signal.multiplexer_value_in_range(parent_multiplexer_value):
1380-
muxer_value = decoded[signal.name].raw_value
1381-
muxer_name = signal.name
1382-
return muxer_name, muxer_value
1365+
return signal
13831366

13841367
def _filter_signals_for_multiplexer(self, multiplexer_name, multiplexer_value):
13851368
"""
@@ -1417,11 +1400,15 @@ def decode(self, data):
14171400
multiplex_name = None
14181401
multiplex_value = None
14191402

1420-
while self._has_sub_multiplexer(multiplex_name):
1421-
multiplex_name, multiplex_value = self._get_sub_multiplexer(multiplex_name, multiplex_value, decoded)
1422-
decoded_values[multiplex_name] = decoded[multiplex_name]
1403+
sub_multiplexer = self._get_sub_multiplexer(multiplex_name, multiplex_value)
1404+
while sub_multiplexer is not None:
1405+
multiplex_name = sub_multiplexer.name
1406+
multiplex_signal = decoded_values[multiplex_name] = decoded[multiplex_name]
1407+
multiplex_value = multiplex_signal.raw_value
14231408
filtered_signals += self._filter_signals_for_multiplexer(multiplex_name, multiplex_value)
14241409

1410+
sub_multiplexer = self._get_sub_multiplexer(multiplex_name, multiplex_value)
1411+
14251412
for signal in filtered_signals:
14261413
decoded_values[signal.name] = decoded[signal.name]
14271414
return decoded_values

Diff for: src/canmatrix/formats/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
importlib.import_module("canmatrix.formats." + module)
2828
loadedFormats.append(module)
2929
except ImportError:
30-
logger.exception("%s is not supported", module)
30+
logger.warning("%s is not supported", module)
3131

3232
for loadedModule in loadedFormats:
3333
supportedFormats[loadedModule] = []

Diff for: src/canmatrix/formats/arxml.py

+11-7
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,7 @@ def decode_ethernet_helper(ea, float_factory):
17321732
pdu_sig_mapping = ea.findall("I-SIGNAL-TO-I-PDU-MAPPING", ipdu)
17331733

17341734
get_signals(pdu_sig_mapping, target_frame, ea, None, float_factory)
1735+
target_frame.update_receiver()
17351736
db.add_frame(target_frame)
17361737
return found_matrixes
17371738

@@ -1750,14 +1751,14 @@ def decode_flexray_helper(ea, float_factory):
17501751
found_matrixes[channel_name] = db
17511752

17521753
frames = ea.findall("FLEXRAY-FRAME-TRIGGERING", pc)
1753-
for frame in frames:
1754+
for frame_element in frames:
17541755
frame_counter += 1
1755-
slot_id = int(ea.get_child(frame, "SLOT-ID").text)
1756-
base_cycle = ea.get_child(frame, "BASE-CYCLE").text
1757-
ipdu_triggerings = ea.get_children(frame, "I-PDU-TRIGGERING")
1758-
frame_repetition_cycle = ea.find_children_by_path(frame, "CYCLE-REPETITION/CYCLE-REPETITION")[0].text
1759-
network_endpoints = pc.findall('.//' + ns + "NETWORK-ENDPOINT")
1760-
frame_size = int(ea.find_children_by_path(frame, "FRAME/FRAME-LENGTH")[0].text)
1756+
slot_id = int(ea.get_child(frame_element, "SLOT-ID").text)
1757+
base_cycle = ea.get_child(frame_element, "BASE-CYCLE").text
1758+
ipdu_triggerings = ea.get_children(frame_element, "I-PDU-TRIGGERING")
1759+
frame_repetition_cycle = ea.find_children_by_path(frame_element, "CYCLE-REPETITION/CYCLE-REPETITION")[0].text
1760+
network_endpoints = pc.findall('.//' + ea.ns + "NETWORK-ENDPOINT")
1761+
frame_size = int(ea.find_children_by_path(frame_element, "FRAME/FRAME-LENGTH")[0].text)
17611762
frame = canmatrix.Frame(size = frame_size, arbitration_id = frame_counter)
17621763
frame.slot_id = slot_id
17631764
frame.base_cycle = base_cycle
@@ -1888,7 +1889,10 @@ def decode_can_helper(ea, float_factory, ignore_cluster_info):
18881889
sig_value_hash[sig.name] = 0
18891890
frame_data = frame.encode(sig_value_hash)
18901891
frame.add_attribute("GenMsgStartValue", "".join(["%02x" % x for x in frame_data]))
1892+
frame.update_receiver()
18911893
found_matrixes[bus_name] = db
1894+
1895+
18921896
return found_matrixes
18931897

18941898
def load(file, **options):

Diff for: src/canmatrix/formats/dbc.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from builtins import *
3636

3737
import canmatrix
38-
38+
import canmatrix.utils
3939
logger = logging.getLogger(__name__)
4040

4141

@@ -755,13 +755,15 @@ def add_frame_by_id(new_frame): # type: (canmatrix.Frame) -> None
755755
if temp:
756756
frame_id = temp.group(1)
757757
signal_name = temp.group(2)
758-
temp_list = temp.group(3).split('"')
758+
temp_list = list(canmatrix.utils.escape_aware_split(temp.group(3), '"'))
759+
759760
if frame_id.isnumeric(): # value for Frame
760761
try:
761762
frame = get_frame_by_id(canmatrix.ArbitrationId.from_compound_integer(int(frame_id)))
762763
sg = frame.signal_by_name(signal_name)
763764
for i in range(math.floor(len(temp_list) / 2)):
764765
val = temp_list[i * 2 + 1]
766+
val = val.replace('\\"', '"')
765767
if sg:
766768
sg.add_values(temp_list[i * 2], val)
767769
except:
@@ -930,7 +932,7 @@ def add_frame_by_id(new_frame): # type: (canmatrix.Frame) -> None
930932
ecu.name = ecu.attributes.get("SystemNodeLongSymbol")[1:-1]
931933
ecu.del_attribute("SystemNodeLongSymbol")
932934
for frame in db.frames:
933-
frame.cycle_time = int(frame.attributes.get("GenMsgCycleTime", 0))
935+
frame.cycle_time = int(float(frame.attributes.get("GenMsgCycleTime", 0)))
934936
if frame.attributes.get("SystemMessageLongSymbol", None) is not None:
935937
frame.name = frame.attributes.get("SystemMessageLongSymbol")[1:-1]
936938
frame.del_attribute("SystemMessageLongSymbol")

Diff for: src/canmatrix/formats/json.py

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def dump(db, f, **options):
9393
symbolic_frame = {"name": frame.name,
9494
"id": int(frame.arbitration_id.id),
9595
"is_extended_frame": frame.arbitration_id.extended,
96+
"is_fd": frame.is_fd,
9697
"signals": symbolic_signals}
9798
frame_attributes = {
9899
attr: frame.attribute(attr)
@@ -146,6 +147,7 @@ def dump(db, f, **options):
146147
{"name": frame.name,
147148
"id": int(frame.arbitration_id.id),
148149
"is_extended_frame": frame.arbitration_id.extended,
150+
"is_fd": frame.is_fd,
149151
"signals": symbolic_signals,
150152
"attributes": frame_attributes,
151153
"comment": frame.comment,

Diff for: src/canmatrix/formats/sym.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,10 @@ class Mode(object):
442442
is_float = False
443443
is_ascii = False
444444
enumeration = None
445-
if index_offset != 1:
445+
446+
if tmp_mux == "Mux":
447+
is_signed = False
448+
elif index_offset != 1 :
446449
is_signed = True
447450
else:
448451
is_signed = False

Diff for: src/canmatrix/tests/test_dbc.py

+27
Original file line numberDiff line numberDiff line change
@@ -478,4 +478,31 @@ def test_missing_space():
478478
matrix = canmatrix.formats.dbc.load(dbc, dbcImportEncoding="utf8")
479479
assert matrix.frames[0].signals[0].name == "sig1"
480480

481+
def test_escaped_quotes():
482+
dbc = io.BytesIO(textwrap.dedent(r'''
483+
BO_ 17 Frame_1: 8 Vector__XXX
484+
SG_ Signal : 0|8@1-(1,0)[0|0] "" Vector__XXX
485+
486+
VAL_ 17 Signal 0 "zero" 1 "one " 2 "string with \"escaped\" double quotes";
487+
''').encode('utf-8'))
488+
matrix = canmatrix.formats.dbc.load(dbc, dbcImportEncoding="utf8")
489+
assert matrix.frames[0].signals[0].values[2] == r'string with "escaped" double quotes'
490+
491+
492+
def test_float_cycle_time():
493+
dbc = io.BytesIO(textwrap.dedent(u'''\
494+
BO_ 17 Frame_1: 8 Vector__XXX
495+
SG_ sig2 : 8|8@1- (1,0) [0|0] "" Vector__XXX
496+
SG_ sig1 : 0|8@1- (1,0) [0|0] "" Vector__XXX
497+
498+
499+
BA_DEF_ BO_ "GenMsgCycleTime" INT 10 3600000;
500+
BA_ "GenMsgCycleTime" BO_ 17 100.0;
501+
''').encode('utf-8'))
502+
503+
504+
matrix = canmatrix.formats.dbc.load(dbc, dbcImportEncoding="utf8")
505+
506+
assert matrix.frames[0].cycle_time == 100
507+
481508

Diff for: src/canmatrix/tests/test_json.py

+4
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def test_import_min_max():
8888
"comment": "",
8989
"id": 10,
9090
"is_extended_frame": false,
91+
"is_fd": false,
9192
"length": 6,
9293
"name": "test_frame",
9394
"signals": [
@@ -122,6 +123,7 @@ def test_import_native():
122123
"comment": "",
123124
"id": 10,
124125
"is_extended_frame": false,
126+
"is_fd": false,
125127
"length": 6,
126128
"name": "test_frame",
127129
"signals": [
@@ -167,6 +169,7 @@ def test_import_export_enums():
167169
"comment": "",
168170
"id": 10,
169171
"is_extended_frame": false,
172+
"is_fd": false,
170173
"length": 6,
171174
"name": "test_frame",
172175
"signals": [
@@ -218,3 +221,4 @@ def test_export_all_native():
218221
assert (data['messages'][0]['signals'][0]['max'] == 42)
219222
assert (data['messages'][0]['signals'][0]['factor'] == 0.123)
220223
assert (data['messages'][0]['signals'][0]['offset'] == 1)
224+
assert (data['messages'][0]['is_fd'] is False)

Diff for: src/canmatrix/tests/test_sym.py

+44
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import textwrap
55
from itertools import chain
6+
from pprint import pprint
67

78
import pytest
89

@@ -353,4 +354,47 @@ def test_types_read():
353354
"Double",
354355
"Float", ])
355356

357+
@pytest.mark.parametrize(
358+
'var_name,data,raw_value',
359+
(
360+
('VarMux1', bytearray([1, 12, 0, 0, 0, 0, 0, 0]), 12),
361+
('VarMux2', bytearray([2, 0, 0, 0, 23, 0, 0, 0]), 23),
362+
('VarMux200', bytearray([200, 0, 0, 0, 0, 0, 34, 0]), 34),
363+
)
364+
)
365+
def test_mux_decode(var_name,data,raw_value):
366+
f = io.BytesIO('''\
367+
FormatVersion=5.0 // Do not edit this line!
368+
Title="Types Test"
369+
370+
FormatVersion=5.0 // Do not edit this line!
371+
Title="Test Symbols File"
372+
373+
{SENDRECEIVE}
374+
375+
[MuxTestFrame]
376+
ID=002h
377+
DLC=8
378+
Mux=Mux1 0,8 1
379+
Var=VarMux1 unsigned 8,8
380+
381+
[MuxTestFrame]
382+
DLC=8
383+
Mux=Mux2 0,8 2
384+
Var=VarMux2 unsigned 32,8
385+
386+
[MuxTestFrame]
387+
DLC=8
388+
Mux=Mux200 0,8 C8h
389+
Var=VarMux200 unsigned 48,8
390+
'''.encode('utf-8'),
391+
)
392+
393+
matrix = canmatrix.formats.sym.load(f)
394+
# Check no errors loading the matrix
395+
assert matrix.load_errors == []
356396

397+
frame = matrix.frame_by_name("MuxTestFrame")
398+
r = frame.decode(data)
399+
assert var_name in r.keys(), "Signal {}, not decoded. Only : {}".format(var_name, ','.join(r for r in r.keys()))
400+
assert r[var_name].raw_value == raw_value

Diff for: src/canmatrix/utils.py

+20
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@ def quote_aware_space_split(in_line): # type: (str) -> typing.List[str]
2020
return [item.decode('utf-8') for item in shlex.split(in_line.strip().encode('utf-8'))]
2121

2222

23+
# https://stackoverflow.com/questions/18092354/python-split-string-without-splitting-escaped-character
24+
def escape_aware_split(string, delimiter):
25+
if len(delimiter) != 1:
26+
raise ValueError('Invalid delimiter: ' + delimiter)
27+
ln = len(string)
28+
i = 0
29+
j = 0
30+
while j < ln:
31+
if string[j] == '\\':
32+
if j + 1 >= ln:
33+
yield string[i:j]
34+
return
35+
j += 1
36+
elif string[j] == delimiter:
37+
yield string[i:j]
38+
i = j + 1
39+
j += 1
40+
yield string[i:j]
41+
42+
2343
def quote_aware_comma_split(string): # type: (str) -> typing.List[str]
2444
"""
2545
Split a string containing comma separated list of fields.

Diff for: test/test.py

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ def run_tests():
4444
export_types.sort()
4545
# TODO: support testing of xlsx
4646
# export_types.remove('xlsx')
47+
if "xlsx" in import_types:
48+
# todo issue #541
49+
import_types.remove("xlsx")
4750
if "fibex" in export_types:
4851
export_types.remove('fibex')
4952

0 commit comments

Comments
 (0)