Skip to content

Commit fd3be01

Browse files
committed
Merge branch 'master' into feature-asyncio
2 parents aa292a6 + 11b540a commit fd3be01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1210
-328
lines changed

.github/workflows/pythonpackage.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,12 @@ jobs:
2727
- name: Install dependencies
2828
run: |
2929
python -m pip install --upgrade pip
30-
pip install pytest
30+
pip install pytest pytest-cov
3131
pip install -e .
3232
- name: Test with pytest
3333
run: |
34-
pytest -v
34+
pytest -v --cov=canopen --cov-report=xml --cov-branch
35+
- name: Upload coverage reports to Codecov
36+
uses: codecov/codecov-action@v4
37+
with:
38+
token: ${{ secrets.CODECOV_TOKEN }}

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The aim of the project is to support the most common parts of the CiA 301
66
standard in a simple Pythonic interface. It is mainly targeted for testing and
77
automation tasks rather than a standard compliant master implementation.
88

9-
The library supports Python 3.6+.
9+
The library supports Python 3.8+.
1010

1111
This library is the asyncio port of CANopen. See below for code example.
1212

canopen/emcy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def get_desc(self) -> str:
165165
return ""
166166

167167
def __str__(self):
168-
text = "Code 0x{:04X}".format(self.code)
168+
text = f"Code 0x{self.code:04X}"
169169
description = self.get_desc()
170170
if description:
171171
text = text + ", " + description

canopen/lss.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def __send_configure(self, req_cs, value1=0, value2=0):
369369
raise LssError("Response message is not for the request")
370370

371371
if error_code != ERROR_NONE:
372-
error_msg = "LSS Error: %d" % error_code
372+
error_msg = f"LSS Error: {error_code}"
373373
raise LssError(error_msg)
374374

375375
# FIXME: Make async implementation "__asend_command"
@@ -387,9 +387,7 @@ def __send_command(self, message):
387387
:rtype: bytes
388388
"""
389389

390-
message_str = " ".join(["{:02x}".format(x) for x in message])
391-
logger.info(
392-
"Sending LSS message {}".format(message_str))
390+
logger.info("Sending LSS message %s", message.hex(" ").upper())
393391

394392
response = None
395393
if not self.responses.empty():

canopen/network.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from collections.abc import MutableMapping
33
import logging
44
import threading
5-
from typing import Callable, Dict, Iterable, List, Optional, Union, TYPE_CHECKING
5+
from typing import Callable, Dict, Iterator, List, Optional, Union, TYPE_CHECKING
66
import asyncio
77

88
if TYPE_CHECKING:
@@ -98,7 +98,7 @@ def unsubscribe(self, can_id, callback=None) -> None:
9898
else:
9999
self.subscribers[can_id].remove(callback)
100100

101-
def connect(self, *args, **kwargs) -> "Network":
101+
def connect(self, *args, **kwargs) -> Network:
102102
"""Connect to CAN bus using python-can.
103103
104104
Arguments are passed directly to :class:`can.BusABC`. Typically these
@@ -246,7 +246,7 @@ def send_message(self, can_id: int, data: bytes, remote: bool = False) -> None:
246246

247247
def send_periodic(
248248
self, can_id: int, data: bytes, period: float, remote: bool = False
249-
) -> "PeriodicMessageTask":
249+
) -> PeriodicMessageTask:
250250
"""Start sending a message periodically.
251251
252252
:param can_id:
@@ -316,7 +316,7 @@ def __delitem__(self, node_id: int):
316316
self.nodes[node_id].remove_network()
317317
del self.nodes[node_id]
318318

319-
def __iter__(self) -> Iterable[int]:
319+
def __iter__(self) -> Iterator[int]:
320320
return iter(self.nodes)
321321

322322
def __len__(self) -> int:
@@ -337,7 +337,7 @@ def __init__(
337337
bus,
338338
remote: bool = False,
339339
):
340-
"""
340+
"""
341341
:param can_id:
342342
CAN-ID of the message
343343
:param data:

canopen/nmt.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,17 @@ async def _wait_for_bootup():
225225
except asyncio.TimeoutError:
226226
raise NmtError("Timeout waiting for boot-up message")
227227

228-
def add_hearbeat_callback(self, callback: Callable[[int], None]):
228+
def add_heartbeat_callback(self, callback: Callable[[int], None]):
229229
"""Add function to be called on heartbeat reception.
230230
231231
:param callback:
232232
Function that should accept an NMT state as only argument.
233233
"""
234234
self._callbacks.append(callback)
235235

236+
# Compatibility with previous typo
237+
add_hearbeat_callback = add_heartbeat_callback
238+
236239
def start_node_guarding(self, period: float):
237240
"""Starts the node guarding mechanism.
238241
@@ -289,29 +292,29 @@ def send_command(self, code: int) -> None:
289292

290293
def on_write(self, index, data, **kwargs):
291294
if index == 0x1017:
292-
hearbeat_time, = struct.unpack_from("<H", data)
293-
if hearbeat_time == 0:
295+
heartbeat_time, = struct.unpack_from("<H", data)
296+
if heartbeat_time == 0:
294297
self.stop_heartbeat()
295298
else:
296-
self.start_heartbeat(hearbeat_time)
299+
self.start_heartbeat(heartbeat_time)
297300

298301
def start_heartbeat(self, heartbeat_time_ms: int):
299-
"""Start the hearbeat service.
302+
"""Start the heartbeat service.
300303
301-
:param hearbeat_time
304+
:param heartbeat_time_ms
302305
The heartbeat time in ms. If the heartbeat time is 0
303306
the heartbeating will not start.
304307
"""
305308
self._heartbeat_time_ms = heartbeat_time_ms
306309

307310
self.stop_heartbeat()
308311
if heartbeat_time_ms > 0:
309-
logger.info("Start the hearbeat timer, interval is %d ms", self._heartbeat_time_ms)
312+
logger.info("Start the heartbeat timer, interval is %d ms", self._heartbeat_time_ms)
310313
self._send_task = self.network.send_periodic(
311314
0x700 + self.id, [self._state], heartbeat_time_ms / 1000.0)
312315

313316
def stop_heartbeat(self):
314-
"""Stop the hearbeat service."""
317+
"""Stop the heartbeat service."""
315318
if self._send_task is not None:
316319
logger.info("Stop the heartbeat timer")
317320
self._send_task.stop()

canopen/node/local.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def get_data(
9999
return obj.encode_raw(obj.default)
100100

101101
# Resource not available
102-
logger.info("Resource unavailable for 0x%X:%d", index, subindex)
102+
logger.info("Resource unavailable for 0x%04X:%02X", index, subindex)
103103
raise SdoAbortedError(0x060A0023)
104104

105105
def set_data(

canopen/node/remote.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,15 @@ def __load_configuration_helper(self, index, subindex, name, value):
135135
"""
136136
try:
137137
if subindex is not None:
138-
logger.info(str('SDO [{index:#06x}][{subindex:#06x}]: {name}: {value:#06x}'.format(
139-
index=index,
140-
subindex=subindex,
141-
name=name,
142-
value=value)))
138+
logger.info('SDO [0x%04X][0x%02X]: %s: %#06x',
139+
index, subindex, name, value)
143140
# NOTE: Blocking call - OK. Protected in SdoClient
144141
self.sdo[index][subindex].raw = value
145142
else:
146143
# NOTE: Blocking call - OK. Protected in SdoClient
147144
self.sdo[index].raw = value
148-
logger.info(str('SDO [{index:#06x}]: {name}: {value:#06x}'.format(
149-
index=index,
150-
name=name,
151-
value=value)))
145+
logger.info('SDO [0x%04X]: %s: %#06x',
146+
index, name, value)
152147
except SdoCommunicationError as e:
153148
logger.warning(str(e))
154149
except SdoAbortedError as e:
@@ -157,7 +152,8 @@ def __load_configuration_helper(self, index, subindex, name, value):
157152
if e.code != 0x06010002:
158153
# Abort codes other than "Attempt to write a read-only object"
159154
# should still be reported.
160-
logger.warning('[ERROR SETTING object {0:#06x}:{1:#06x}] {2}'.format(index, subindex, str(e)))
155+
logger.warning('[ERROR SETTING object 0x%04X:%02X] %s',
156+
index, subindex, e)
161157
raise
162158

163159
def load_configuration(self):

0 commit comments

Comments
 (0)