Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bc66b57
Add preserve timestamps to virtual
simontegelid Dec 17, 2021
0362acb
Add test case for player.py
pkess Dec 20, 2021
ee06947
Format code with black
pkess Dec 20, 2021
5c72735
Add mock for sleep function to fasten up testing
pkess Dec 20, 2021
fec26fb
Add test for verbose mode
pkess Dec 20, 2021
fefdd53
Add call count assert
pkess Dec 20, 2021
0907785
Add test for Keyboard interrupt during execution
pkess Dec 20, 2021
4721134
Add todos
pkess Dec 20, 2021
1d11a04
Implement check for successfull cleanup and send message call count
pkess Dec 26, 2021
bae496e
Add assumptions for test cases
pkess Dec 26, 2021
c41845f
Add check for output on screen
pkess Dec 26, 2021
f6816b9
Implement test for replay with error frames
pkess Dec 26, 2021
dcbb963
Format code with black
pkess Dec 26, 2021
7da7303
Remove useless import
pkess Jan 11, 2022
2cb76b5
Format code with black
pkess Jan 11, 2022
5c6480b
Correct spell error
pkess Jan 11, 2022
6f94d6b
Update workflow versions, platforms, library and tool versions and RE…
felixdivo Jan 15, 2022
dd25e4b
Fix code formatting job
felixdivo Jan 15, 2022
46ad7d4
Disable Python 3.11 pre-releases
felixdivo Jan 15, 2022
8641f5e
Test that the auto-formatting tool can still commit
felixdivo Jan 15, 2022
0acabbf
Format code with black
felixdivo Jan 15, 2022
954bb02
Update README.rst
felixdivo Jan 15, 2022
1dd4581
Implement test of function calls
pkess Jan 15, 2022
3382d53
Limit test for correct calls to python versions >= 3.8
pkess Jan 15, 2022
67e4098
Format code with black
pkess Jan 15, 2022
1ce5614
Merge pull request #1215 from hardbyte/felixdivo-patch-readme-tiny
felixdivo Jan 15, 2022
ab0cc7f
Merge branch 'develop' into update-ci-tools
felixdivo Jan 15, 2022
a5f0ef8
simplify version check
zariiii9003 Jan 15, 2022
2604b6d
Merge pull request #1214 from hardbyte/update-ci-tools
felixdivo Jan 15, 2022
7a20405
Change shebang and remove coding
pkess Jan 16, 2022
8b6b592
Merge pull request #1198 from pkess/584-add_test_player
felixdivo Jan 16, 2022
0753fba
Merge pull request #1218 from pkess/fix-header-tests
felixdivo Jan 16, 2022
b4d7801
Merge pull request #1195 from simontegelid/preserve_timestamps
felixdivo Jan 17, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 9 additions & 12 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@ jobs:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
experimental: [false]
python-version: ["3.6", "3.7", "3.8", "3.9", "pypy-3.7"]
include:
# Skipping Py 3.10 on Windows until windows-curses has a cp310 wheel,
# see https://github.com/zephyrproject-rtos/windows-curses/issues/26
- os: ubuntu-latest
experimental: false
python-version: "3.10"
- os: macos-latest
experimental: false
python-version: "3.10"
python-version: ["3.7", "3.8", "3.9", "3.10", "pypy-3.7", "pypy-3.8"]
# Do not test on Python 3.11 pre-releases since wrapt causes problems: https://github.com/GrahamDumpleton/wrapt/issues/196
# include:
# Only test on a single configuration while there are just pre-releases
# - os: ubuntu-latest
# experimental: true
# python-version: "3.11.0-alpha.3"
fail-fast: false
steps:
- uses: actions/checkout@v2
Expand All @@ -38,15 +35,15 @@ jobs:
run: |
tox -e gh
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
with:
fail_ci_if_error: true

format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.10
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.10"
Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/format-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -22,10 +22,7 @@ jobs:
run: |
black --verbose .
- name: Commit Formated Code
uses: EndBug/add-and-commit@v5
env:
# This is necessary in order to push a commit to the repo
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
uses: EndBug/add-and-commit@v7
with:
message: "Format code with black"
# Ref https://git-scm.com/docs/git-add#_examples
Expand Down
5 changes: 2 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,14 @@ Python developers; providing common abstractions to
different hardware devices, and a suite of utilities for sending and receiving
messages on a can bus.

The library currently supports Python 3.6+ as well as PyPy 3 and runs
on Mac, Linux and Windows.
The library currently supports CPython as well as PyPy and runs on Mac, Linux and Windows.

============================== ===========
Library Version Python
------------------------------ -----------
2.x 2.6+, 3.4+
3.x 2.7+, 3.5+
4.x *(currently on develop)* 3.6+
4.x *(currently on develop)* 3.7+
============================== ===========


Expand Down
4 changes: 3 additions & 1 deletion can/interfaces/virtual.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def __init__(
channel: Any = None,
receive_own_messages: bool = False,
rx_queue_size: int = 0,
preserve_timestamps: bool = False,
**kwargs: Any,
) -> None:
super().__init__(
Expand All @@ -69,6 +70,7 @@ def __init__(
self.channel_id = channel
self.channel_info = f"Virtual bus channel {self.channel_id}"
self.receive_own_messages = receive_own_messages
self.preserve_timestamps = preserve_timestamps
self._open = True

with channels_lock:
Expand Down Expand Up @@ -103,7 +105,7 @@ def _recv_internal(
def send(self, msg: Message, timeout: Optional[float] = None) -> None:
self._check_if_open()

timestamp = time.time()
timestamp = msg.timestamp if self.preserve_timestamps else time.time()
# Add message to all listening on this channel
all_sent = True
for bus_queue in self.channel:
Expand Down
29 changes: 28 additions & 1 deletion doc/interfaces/virtual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Example
-------

.. code-block:: python

import can

bus1 = can.interface.Bus('test', bustype='virtual')
Expand All @@ -100,6 +100,33 @@ Example
assert msg1.data == msg2.data
assert msg1.timestamp != msg2.timestamp

.. code-block:: python

import can

bus1 = can.interface.Bus('test', bustype='virtual', preserve_timestamps=True)
bus2 = can.interface.Bus('test', bustype='virtual')

msg1 = can.Message(timestamp=1639740470.051948, arbitration_id=0xabcde, data=[1,2,3])

# Messages sent on bus1 will have their timestamps preserved when received
# on bus2
bus1.send(msg1)
msg2 = bus2.recv()

assert msg1.arbitration_id == msg2.arbitration_id
assert msg1.data == msg2.data
assert msg1.timestamp == msg2.timestamp

# Messages sent on bus2 will not have their timestamps preserved when
# received on bus1
bus2.send(msg1)
msg3 = bus1.recv()

assert msg1.arbitration_id == msg3.arbitration_id
assert msg1.data == msg3.data
assert msg1.timestamp != msg3.timestamp


Bus Class Documentation
-----------------------
Expand Down
6 changes: 3 additions & 3 deletions requirements-lint.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pylint==2.11.1
black==21.10b0
mypy==0.910
pylint==2.12.2
black==21.12b0
mypy==0.931
mypy-extensions==0.4.3
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
classifiers=[
# a list of all available ones: https://pypi.org/classifiers/
"Programming Language :: Python",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
Expand Down Expand Up @@ -73,7 +72,7 @@
version=version,
packages=find_packages(exclude=["test*", "doc", "scripts", "examples"]),
scripts=list(filter(isfile, (join("scripts/", f) for f in listdir("scripts/")))),
author="Python CAN contributors",
author="python-can contributors",
license="LGPL v3",
package_data={
"": ["README.rst", "CONTRIBUTORS.txt", "LICENSE.txt", "CHANGELOG.txt"],
Expand All @@ -82,7 +81,7 @@
},
# Installation
# see https://www.python.org/dev/peps/pep-0345/#version-specifiers
python_requires=">=3.6",
python_requires=">=3.7",
install_requires=[
"setuptools",
"wrapt~=1.10",
Expand Down
21 changes: 21 additions & 0 deletions test/data/logfile_errorframes.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
date Sam Sep 30 15:06:13.191 2017
base hex timestamps absolute
internal events logged
// version 9.0.0
Begin Triggerblock Sam Sep 30 15:06:13.191 2017
0.000000 Start of measurement
0.015991 CAN 1 Status:chip status error passive - TxErr: 132 RxErr: 0
0.015991 CAN 2 Status:chip status error active
2.501000 1 ErrorFrame
2.501010 1 ErrorFrame ECC: 10100010
2.501020 2 ErrorFrame Flags = 0xe CodeExt = 0x20a2 Code = 0x82 ID = 0 DLC = 0 Position = 5 Length = 11300
2.520002 3 200 Tx r Length = 1704000 BitCount = 145 ID = 88888888x
2.584921 4 300 Tx r 8 Length = 1704000 BitCount = 145 ID = 88888888x
3.098426 1 18EBFF00x Rx d 8 01 A0 0F A6 60 3B D1 40 Length = 273910 BitCount = 141 ID = 418119424x
3.197693 1 18EBFF00x Rx d 8 03 E1 00 4B FF FF 3C 0F Length = 283910 BitCount = 146 ID = 418119424x
17.876976 1 6F8 Rx d 8 FF 00 0C FE 00 00 00 00 Length = 239910 BitCount = 124 ID = 1784
20.105214 2 18EBFF00x Rx d 8 01 A0 0F A6 60 3B D1 40 Length = 273925 BitCount = 141 ID = 418119424x
20.155119 2 18EBFF00x Rx d 8 02 1F DE 80 25 DF C0 2B Length = 272152 BitCount = 140 ID = 418119424x
20.204671 2 18EBFF00x Rx d 8 03 E1 00 4B FF FF 3C 0F Length = 283910 BitCount = 146 ID = 418119424x
20.248887 2 18EBFF00x Rx d 8 04 00 4B FF FF FF FF FF Length = 283925 BitCount = 146 ID = 418119424x
End TriggerBlock
40 changes: 40 additions & 0 deletions test/test_interface_virtual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/env python
# coding: utf-8

"""
This module tests :meth:`can.interface.virtual`.
"""

import unittest

from can import Bus, Message

EXAMPLE_MSG1 = Message(timestamp=1639739471.5565314, arbitration_id=0x481, data=b"\x01")


class TestMessageFiltering(unittest.TestCase):
def setUp(self):
self.node1 = Bus("test", bustype="virtual", preserve_timestamps=True)
self.node2 = Bus("test", bustype="virtual")

def tearDown(self):
self.node1.shutdown()
self.node2.shutdown()

def test_sendmsg(self):
self.node2.send(EXAMPLE_MSG1)
r = self.node1.recv(0.1)
assert r.timestamp != EXAMPLE_MSG1.timestamp
assert r.arbitration_id == EXAMPLE_MSG1.arbitration_id
assert r.data == EXAMPLE_MSG1.data

def test_sendmsg_preserve_timestamp(self):
self.node1.send(EXAMPLE_MSG1)
r = self.node2.recv(0.1)
assert r.timestamp == EXAMPLE_MSG1.timestamp
assert r.arbitration_id == EXAMPLE_MSG1.arbitration_id
assert r.data == EXAMPLE_MSG1.data


if __name__ == "__main__":
unittest.main()
115 changes: 115 additions & 0 deletions test/test_player.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python

"""
This module tests the functions inside of player.py
"""

import unittest
from unittest import mock
from unittest.mock import Mock
import os
import sys
import io
import can
import can.player


class TestPlayerScriptModule(unittest.TestCase):
def setUp(self) -> None:
# Patch VirtualBus object
patcher_virtual_bus = mock.patch("can.interfaces.virtual.VirtualBus", spec=True)
self.MockVirtualBus = patcher_virtual_bus.start()
self.addCleanup(patcher_virtual_bus.stop)
self.mock_virtual_bus = self.MockVirtualBus.return_value
self.mock_virtual_bus.__enter__ = Mock(return_value=self.mock_virtual_bus)

# Patch time sleep object
patcher_sleep = mock.patch("can.io.player.sleep", spec=True)
self.MockSleep = patcher_sleep.start()
self.addCleanup(patcher_sleep.stop)

self.baseargs = [sys.argv[0], "-i", "virtual"]
self.logfile = os.path.join(
os.path.dirname(__file__), "data", "test_CanMessage.asc"
)

def assertSuccessfulCleanup(self):
self.MockVirtualBus.assert_called_once()
self.mock_virtual_bus.__exit__.assert_called_once()

def test_play_virtual(self):
sys.argv = self.baseargs + [self.logfile]
can.player.main()
msg1 = can.Message(
timestamp=2.501,
arbitration_id=0xC8,
is_extended_id=False,
is_fd=False,
is_rx=False,
channel=1,
dlc=8,
data=[0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2],
)
msg2 = can.Message(
timestamp=17.876708,
arbitration_id=0x6F9,
is_extended_id=False,
is_fd=False,
is_rx=True,
channel=0,
dlc=8,
data=[0x5, 0xC, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
)
self.assertEqual(self.MockSleep.call_count, 2)
if sys.version_info >= (3, 8):
# The args argument was introduced with python 3.8
self.assertTrue(
msg1.equals(self.mock_virtual_bus.send.mock_calls[0].args[0])
)
self.assertTrue(
msg2.equals(self.mock_virtual_bus.send.mock_calls[1].args[0])
)
self.assertSuccessfulCleanup()

def test_play_virtual_verbose(self):
sys.argv = self.baseargs + ["-v", self.logfile]
with unittest.mock.patch("sys.stdout", new_callable=io.StringIO) as mock_stdout:
can.player.main()
self.assertIn("09 08 07 06 05 04 03 02", mock_stdout.getvalue())
self.assertIn("05 0c 00 00 00 00 00 00", mock_stdout.getvalue())
self.assertEqual(self.mock_virtual_bus.send.call_count, 2)
self.assertEqual(self.MockSleep.call_count, 2)
self.assertSuccessfulCleanup()

def test_play_virtual_exit(self):
self.MockSleep.side_effect = [None, KeyboardInterrupt]

sys.argv = self.baseargs + [self.logfile]
can.player.main()
self.assertEqual(self.mock_virtual_bus.send.call_count, 1)
self.assertEqual(self.MockSleep.call_count, 2)
self.assertSuccessfulCleanup()

def test_play_skip_error_frame(self):
logfile = os.path.join(
os.path.dirname(__file__), "data", "logfile_errorframes.asc"
)
sys.argv = self.baseargs + ["-v", logfile]
can.player.main()
self.assertEqual(self.mock_virtual_bus.send.call_count, 9)
self.assertEqual(self.MockSleep.call_count, 12)
self.assertSuccessfulCleanup()

def test_play_error_frame(self):
logfile = os.path.join(
os.path.dirname(__file__), "data", "logfile_errorframes.asc"
)
sys.argv = self.baseargs + ["-v", "--error-frames", logfile]
can.player.main()
self.assertEqual(self.mock_virtual_bus.send.call_count, 12)
self.assertEqual(self.MockSleep.call_count, 12)
self.assertSuccessfulCleanup()


if __name__ == "__main__":
unittest.main()
6 changes: 3 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
[testenv]
deps =
pytest==6.2.*,>=6.2.5
pytest-timeout==2.0.1
pytest-timeout==2.0.2
pytest-cov==3.0.0
coverage==6.0.2
coverage==6.2
codecov==2.1.12
hypothesis~=6.24.0
hypothesis~=6.35.0
pyserial~=3.5
parameterized~=0.8

Expand Down