Skip to content

Commit 4f129e5

Browse files
committed
move all checks to tox, use uv in CI
1 parent 47748a1 commit 4f129e5

File tree

7 files changed

+105
-110
lines changed

7 files changed

+105
-110
lines changed

.github/workflows/ci.yml

Lines changed: 31 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,26 @@ env:
1212
jobs:
1313
test:
1414
runs-on: ${{ matrix.os }}
15-
continue-on-error: ${{ matrix.experimental }} # See: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idcontinue-on-error
1615
strategy:
1716
matrix:
1817
os: [ubuntu-latest, macos-latest, windows-latest]
19-
experimental: [false]
20-
python-version: [
21-
"3.9",
22-
"3.10",
23-
"3.11",
24-
"3.12",
25-
"3.13",
26-
"pypy-3.9",
27-
"pypy-3.10",
18+
env: [
19+
"py39",
20+
"py310",
21+
"py311",
22+
"py312",
23+
"py313", "py313t",
24+
"py314", "py314t",
25+
"pypy310",
26+
"pypy311",
2827
]
2928
fail-fast: false
3029
steps:
3130
- uses: actions/checkout@v4
32-
- name: Set up Python ${{ matrix.python-version }}
33-
uses: actions/setup-python@v5
34-
with:
35-
python-version: ${{ matrix.python-version }}
36-
allow-prereleases: true
37-
- name: Install dependencies
38-
run: |
39-
python -m pip install --upgrade pip
40-
pip install tox
31+
- name: Install uv
32+
uses: astral-sh/setup-uv@v6
33+
- name: Install tox
34+
run: uv tool install tox --with tox-uv
4135
- name: Setup SocketCAN
4236
if: ${{ matrix.os == 'ubuntu-latest' }}
4337
run: |
@@ -46,11 +40,11 @@ jobs:
4640
sudo ./test/open_vcan.sh
4741
- name: Test with pytest via tox
4842
run: |
49-
tox -e gh
43+
tox -e ${{ matrix.env }}
5044
env:
5145
# SocketCAN tests currently fail with PyPy because it does not support raw CAN sockets
5246
# See: https://foss.heptapod.net/pypy/pypy/-/issues/3809
53-
TEST_SOCKETCAN: "${{ matrix.os == 'ubuntu-latest' && ! startsWith(matrix.python-version, 'pypy' ) }}"
47+
TEST_SOCKETCAN: "${{ matrix.os == 'ubuntu-latest' && ! startsWith(matrix.env, 'pypy' ) }}"
5448
- name: Coveralls Parallel
5549
uses: coverallsapp/github-action@v2
5650
with:
@@ -73,69 +67,25 @@ jobs:
7367
runs-on: ubuntu-latest
7468
steps:
7569
- uses: actions/checkout@v4
76-
- name: Set up Python
77-
uses: actions/setup-python@v5
78-
with:
79-
python-version: "3.13"
80-
- name: Install dependencies
81-
run: |
82-
python -m pip install --upgrade pip
83-
pip install --group lint -e .
84-
- name: mypy 3.9
85-
run: |
86-
mypy --python-version 3.9 .
87-
- name: mypy 3.10
70+
- name: Install uv
71+
uses: astral-sh/setup-uv@v6
72+
- name: Install tox
73+
run: uv tool install tox --with tox-uv
74+
- name: Run linters
8875
run: |
89-
mypy --python-version 3.10 .
90-
- name: mypy 3.11
76+
tox -e lint
77+
- name: Run type checker
9178
run: |
92-
mypy --python-version 3.11 .
93-
- name: mypy 3.12
94-
run: |
95-
mypy --python-version 3.12 .
96-
- name: mypy 3.13
97-
run: |
98-
mypy --python-version 3.13 .
99-
- name: ruff
100-
run: |
101-
ruff check can
102-
- name: pylint
103-
run: |
104-
pylint \
105-
can/**.py \
106-
can/io \
107-
doc/conf.py \
108-
examples/**.py \
109-
can/interfaces/socketcan
110-
111-
format:
112-
runs-on: ubuntu-latest
113-
steps:
114-
- uses: actions/checkout@v4
115-
- name: Set up Python
116-
uses: actions/setup-python@v5
117-
with:
118-
python-version: "3.10"
119-
- name: Install dependencies
120-
run: |
121-
python -m pip install --upgrade pip
122-
pip install --group lint
123-
- name: Code Format Check with Black
124-
run: |
125-
black --check --verbose .
79+
tox -e type
12680
12781
docs:
12882
runs-on: ubuntu-latest
12983
steps:
13084
- uses: actions/checkout@v4
131-
- name: Set up Python
132-
uses: actions/setup-python@v5
133-
with:
134-
python-version: "3.13"
135-
- name: Install dependencies
136-
run: |
137-
python -m pip install --upgrade pip
138-
pip install tox
85+
- name: Install uv
86+
uses: astral-sh/setup-uv@v6
87+
- name: Install tox
88+
run: uv tool install tox --with tox-uv
13989
- name: Build documentation
14090
run: |
14191
tox -e docs
@@ -147,14 +97,12 @@ jobs:
14797
- uses: actions/checkout@v4
14898
with:
14999
fetch-depth: 0 # fetch tags for setuptools-scm
150-
- name: Set up Python
151-
uses: actions/setup-python@v5
152-
with:
153-
python-version: "3.10"
100+
- name: Install uv
101+
uses: astral-sh/setup-uv@v6
154102
- name: Build wheel and sdist
155-
run: pipx run build
103+
run: uvx --from build pyproject-build --installer uv
156104
- name: Check build artifacts
157-
run: pipx run twine check --strict dist/*
105+
run: uvx twine check --strict dist/*
158106
- name: Save artifacts
159107
uses: actions/upload-artifact@v4
160108
with:

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ __pycache__/
1818
# Distribution / packaging
1919
.Python
2020
env/
21-
venv/
21+
.venv*/
22+
venv*/
2223
build/
2324
develop-eggs/
2425
dist/

can/io/mf4.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ def file_size(self) -> int:
186186
"""Return an estimate of the current file size in bytes."""
187187
# TODO: find solution without accessing private attributes of asammdf
188188
return cast(
189-
"int", self._mdf._tempfile.tell() # pylint: disable=protected-access
189+
"int",
190+
self._mdf._tempfile.tell(), # pylint: disable=protected-access,no-member
190191
)
191192

192193
def stop(self) -> None:

pyproject.toml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["setuptools >= 67.7", "setuptools_scm>=8"]
2+
requires = ["setuptools >= 77.0", "setuptools_scm>=8"]
33
build-backend = "setuptools.build_meta"
44

55
[project]
@@ -13,7 +13,7 @@ dependencies = [
1313
"typing_extensions>=3.10.0.0",
1414
]
1515
requires-python = ">=3.9"
16-
license = { text = "LGPL v3" }
16+
license = "LGPL-3.0-only"
1717
classifiers = [
1818
"Development Status :: 5 - Production/Stable",
1919
"Environment :: Console",
@@ -22,7 +22,6 @@ classifiers = [
2222
"Intended Audience :: Information Technology",
2323
"Intended Audience :: Manufacturing",
2424
"Intended Audience :: Telecommunications Industry",
25-
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
2625
"Natural Language :: English",
2726
"Operating System :: MacOS",
2827
"Operating System :: Microsoft :: Windows",
@@ -99,9 +98,13 @@ test = [
9998
"pytest-cov==4.0.0",
10099
"coverage==6.5.0",
101100
"hypothesis~=6.35.0",
102-
"pyserial~=3.5",
103101
"parameterized~=0.8",
104102
]
103+
dev = [
104+
{include-group = "docs"},
105+
{include-group = "lint"},
106+
{include-group = "test"},
107+
]
105108

106109
[tool.setuptools.dynamic]
107110
readme = { file = "README.rst" }
@@ -193,8 +196,8 @@ ignore = [
193196
known-first-party = ["can"]
194197

195198
[tool.pylint]
199+
extension-pkg-allow-list = ["curses"]
196200
disable = [
197-
"c-extension-no-member",
198201
"cyclic-import",
199202
"duplicate-code",
200203
"fixme",

test/back2back_test.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,23 +272,21 @@ def test_sub_second_timestamp_resolution(self):
272272
self.bus2.recv(0)
273273
self.bus2.recv(0)
274274

275-
@unittest.skipIf(IS_CI, "fails randomly when run on CI server")
276275
def test_send_periodic_duration(self):
277276
"""
278277
Verify that send_periodic only transmits for the specified duration.
279278
280279
Regression test for #1713.
281280
"""
282-
for params in [(0.01, 0.003), (0.1, 0.011), (1, 0.4)]:
283-
duration, period = params
281+
for duration, period in [(0.01, 0.003), (0.1, 0.011), (1, 0.4)]:
284282
messages = []
285283

286284
self.bus2.send_periodic(can.Message(), period, duration)
287-
while (msg := self.bus1.recv(period * 1.25)) is not None:
285+
while (msg := self.bus1.recv(period + self.TIMEOUT)) is not None:
288286
messages.append(msg)
289287

290-
delta_t = round(messages[-1].timestamp - messages[0].timestamp, 2)
291-
assert delta_t <= duration
288+
delta_t = messages[-1].timestamp - messages[0].timestamp
289+
assert delta_t < duration + 0.05
292290

293291

294292
@unittest.skipUnless(TEST_INTERFACE_SOCKETCAN, "skip testing of socketcan")

test/test_socketcan.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"""
66
import ctypes
77
import struct
8+
import sys
89
import unittest
910
import warnings
1011
from unittest.mock import patch
@@ -34,6 +35,7 @@ def setUp(self):
3435
self._ctypes_sizeof = ctypes.sizeof
3536
self._ctypes_alignment = ctypes.alignment
3637

38+
@unittest.skipIf(sys.version_info >= (3, 14), "Fails on Python 3.14 or newer")
3739
@patch("ctypes.sizeof")
3840
@patch("ctypes.alignment")
3941
def test_bcm_header_factory_32_bit_sizeof_long_4_alignof_long_4(
@@ -103,6 +105,7 @@ def side_effect_ctypes_alignment(value):
103105
]
104106
self.assertEqual(expected_fields, BcmMsgHead._fields_)
105107

108+
@unittest.skipIf(sys.version_info >= (3, 14), "Fails on Python 3.14 or newer")
106109
@patch("ctypes.sizeof")
107110
@patch("ctypes.alignment")
108111
def test_bcm_header_factory_32_bit_sizeof_long_4_alignof_long_long_8(
@@ -172,6 +175,7 @@ def side_effect_ctypes_alignment(value):
172175
]
173176
self.assertEqual(expected_fields, BcmMsgHead._fields_)
174177

178+
@unittest.skipIf(sys.version_info >= (3, 14), "Fails on Python 3.14 or newer")
175179
@patch("ctypes.sizeof")
176180
@patch("ctypes.alignment")
177181
def test_bcm_header_factory_64_bit_sizeof_long_8_alignof_long_8(

tox.ini

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
1+
# https://tox.wiki/en/latest/config.html
12
[tox]
2-
min_version = 4.22
3+
min_version = 4.26
4+
env_list = py,lint,type,docs
35

46
[testenv]
7+
passenv =
8+
CI
9+
GITHUB_*
10+
COVERALLS_*
11+
PY_COLORS
12+
TEST_SOCKETCAN
513
dependency_groups =
614
test
7-
deps =
8-
asammdf>=6.0; platform_python_implementation=="CPython" and python_version<"3.14"
9-
msgpack~=1.1.0; python_version<"3.14"
10-
pywin32>=305; platform_system=="Windows" and platform_python_implementation=="CPython" and python_version<"3.14"
15+
extras =
16+
canalystii
17+
mf4
18+
multicast
19+
pywin32
20+
serial
21+
viewer
1122
commands =
1223
pytest {posargs}
24+
25+
[testenv:py314]
1326
extras =
1427
canalystii
28+
serial
29+
pywin32
1530

16-
[testenv:gh]
17-
passenv =
18-
CI
19-
GITHUB_*
20-
COVERALLS_*
21-
PY_COLORS
22-
TEST_SOCKETCAN
31+
[testenv:{py313t,py314t,pypy310,pypy311}]
32+
extras =
33+
canalystii
34+
serial
2335

2436
[testenv:docs]
2537
description = Build and test the documentation
@@ -33,11 +45,39 @@ commands =
3345
python -m sphinx -b html -Wan --keep-going doc build
3446
python -m sphinx -b doctest -W --keep-going doc build
3547

48+
[testenv:lint]
49+
description = Run linters
50+
basepython = py313
51+
dependency_groups =
52+
lint
53+
extras =
54+
viewer
55+
commands =
56+
black --check .
57+
ruff check can examples doc
58+
pylint \
59+
can/**.py \
60+
can/io \
61+
doc/conf.py \
62+
examples/**.py \
63+
can/interfaces/socketcan
64+
65+
[testenv:type]
66+
description = Run type checker
67+
basepython = py313
68+
dependency_groups =
69+
lint
70+
extras =
71+
commands =
72+
mypy --python-version 3.9 .
73+
mypy --python-version 3.10 .
74+
mypy --python-version 3.11 .
75+
mypy --python-version 3.12 .
76+
mypy --python-version 3.13 .
3677

3778
[pytest]
3879
testpaths = test
39-
addopts = -v --timeout=300 --cov=can --cov-config=tox.ini --cov-report=lcov --cov-report=term
40-
80+
addopts = -v --timeout=300 --cov=can --cov-config=tox.ini --cov-report=lcov --cov-report=term --color=yes
4181

4282
[coverage:run]
4383
# we could also use branch coverage

0 commit comments

Comments
 (0)