python-can-cansub 2026.5.28__tar.gz → 2026.6.2__tar.gz

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.
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 2026.06.02
6
+
7
+ ### Added
8
+ - `CANSUB_ROOT_CERT`: path to the CANsub root certificate.
9
+
10
+ ### Changed
11
+ - Transmit sequences (on the device) are deleted on bus open.
12
+
13
+ ## 2026.06.01
14
+
15
+ ### Fixed
16
+ - `CyclicSendTask` with `duration=None` now working.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-can-cansub
3
- Version: 2026.5.28
3
+ Version: 2026.6.2
4
4
  Summary: CANsub python-can interface
5
5
  Project-URL: Homepage, https://csselectronics.com/
6
6
  Project-URL: Source, https://github.com/CSS-Electronics/python-can-cansub
@@ -0,0 +1,58 @@
1
+ # PyPI Release Workflow
2
+
3
+ This project is published to PyPI as `python-can-cansub`.
4
+
5
+ ## Prerequisites
6
+
7
+ Ensure the following tools are installed:
8
+
9
+ ```bash
10
+ pip install build twine
11
+ ```
12
+
13
+ ## Steps
14
+
15
+ ### 1. Set the version
16
+
17
+ Update the version in `pyproject.toml`:
18
+
19
+ ```toml
20
+ [project]
21
+ version = "YYYY.MM.DD"
22
+ ```
23
+
24
+ ### 2. Commit and push to the public repository
25
+
26
+ Follow the workflow in `README_REPO.md` to squash-merge changes onto `public-master` and push to GitHub.
27
+
28
+ ### 3. Build the distribution
29
+
30
+ From the repository root:
31
+
32
+ ```bash
33
+ python -m build
34
+ ```
35
+
36
+ This produces `dist/*.whl` and `dist/*.tar.gz`.
37
+
38
+ ### 4. Test upload to TestPyPI (optional but recommended)
39
+
40
+ ```bash
41
+ twine upload --repository testpypi dist/*
42
+ ```
43
+
44
+ Verify the package at https://test.pypi.org/project/python-can-cansub/
45
+
46
+ ### 5. Upload to PyPI
47
+
48
+ ```bash
49
+ twine upload dist/*
50
+ ```
51
+
52
+ ### 6. Clean up
53
+
54
+ Delete the `dist/` directory after a successful upload to avoid stale artifacts in future builds:
55
+
56
+ ```bash
57
+ rm -rf dist/
58
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "python-can-cansub"
7
- version = "2026.05.28"
7
+ version = "2026.06.02"
8
8
  authors = [
9
9
  { name="CSS Electronics" },
10
10
  { email="contact@csselectronics.com" },
@@ -0,0 +1,4 @@
1
+ from .cansub_protocol import CanSubErrorFrameType
2
+ from .cansub import CANSUB_ROOT_CERT, CanSub, CanSubHwFilter, CanSubCSVWriter, CanSubCSVReader, register_cansub_csv_writer
3
+ # Override the default CSV writer/reader
4
+ register_cansub_csv_writer()
@@ -14,6 +14,8 @@ from can.io.generic import TextIOMessageWriter, TextIOMessageReader
14
14
  from wsproto import ConnectionType, WSConnection, ConnectionState, events
15
15
  from python_can_cansub.cansub_protocol import cansub_protocol_decode, cansub_protocol_encode
16
16
 
17
+ CANSUB_ROOT_CERT: Path = Path(__file__).with_name("cansub_root_cert.crt")
18
+
17
19
  class CanSubHwFilter(TypedDict):
18
20
  is_extended: bool
19
21
  is_range: bool
@@ -135,7 +137,7 @@ class CanSub(can.BusABC):
135
137
  self.channel_info = f"{address}@{self.channel}"
136
138
 
137
139
  # Path to device root certificate
138
- self.cansub_cert = str(Path(__file__).with_name("cansub_root_cert.crt"))
140
+ self.cansub_cert = str(CANSUB_ROOT_CERT)
139
141
 
140
142
  # Perform REST interaction with the device in a persistent session
141
143
  self.api_url = f"https://{host}:{port}/api"
@@ -179,6 +181,16 @@ class CanSub(can.BusABC):
179
181
  # (Ensures that no messages get through until provided filters are set)
180
182
  self.set_hw_filters(None)
181
183
 
184
+ # Ensure that no transmit-sequences are configured before the channel is opened
185
+ try:
186
+ response = self.session.get(f"{self.api_url}/can/{self.channel}/transmit", timeout=self._net_timeout)
187
+ response.raise_for_status()
188
+ for transmit_id in response.json():
189
+ response = self.session.delete(f"{self.api_url}/can/{self.channel}/transmit/{transmit_id}", timeout=self._net_timeout)
190
+ response.raise_for_status()
191
+ except Exception as e:
192
+ raise can.exceptions.CanInitializationError(f"Failed to clear transmit sequences ({e})")
193
+
182
194
  # Set channel configuration
183
195
  phy_config = {
184
196
  "listen_only": self.listen_only,
@@ -722,7 +734,8 @@ class CyclicSendTask(LimitedDurationCyclicSendTaskABC, RestartableCyclicTaskABC)
722
734
  spacing_ms = int(self.period_ns / 1_000_000)
723
735
 
724
736
  if self.duration is None:
725
- limit = 0xFFFFFFFF
737
+ # Use max value (0xFFFFFFFF - 1) when duration is not provided.
738
+ limit = 0xFFFFFFFE
726
739
  else:
727
740
  limit = int(duration * 1000 / period_ms)
728
741
  limit = max(1, limit)
@@ -882,4 +895,3 @@ def register_cansub_csv_writer():
882
895
  from can.io.player import MESSAGE_READERS
883
896
  MESSAGE_WRITERS[".csv"] = CanSubCSVWriter
884
897
  MESSAGE_READERS[".csv"] = CanSubCSVReader
885
-
@@ -1,4 +0,0 @@
1
- from .cansub_protocol import CanSubErrorFrameType
2
- from .cansub import CanSub, CanSubHwFilter, CanSubCSVWriter, CanSubCSVReader, register_cansub_csv_writer
3
- # Override the default CSV writer/reader
4
- register_cansub_csv_writer()