This release is a pre-release and may not be stable for production use.
Automotive for Python
A library for synchronous and asynchronous CAN, ISO-TP, and UDS, powered by the
automotive Rust crate. The distribution and import name are both automotive.
Rust handles adapter I/O, protocol framing, validation, and timing; Python
provides reusable configuration objects, typed values, context managers, and
documented services.
Requires CPython 3.11+ and builds locally with maturin. This directory contains the Python package, its Rust extension, examples, and Scapy ECU regression tests.
Read the Python documentation for the user guide, examples, and generated API reference.
Installation and development
To test the alpha release from PyPI in another uv project:
uv add --prerelease allow automotive
To test the library from Git in another uv project, run this inside the Nix development shell:
uv add "automotive @ git+https://github.com/I-CAN-hack/automotive.git#subdirectory=python"
For development, run the following from the repository root. The Nix shell provides uv, the Rust toolchain, and native build dependencies:
nix develop
cd python
uv sync
uv run python examples/uds.py
uv check
uv format
uv check runs ty; uv format runs Ruff with default settings and a
120-character line length. uv sync installs the project and development tools;
the lockfile records their versions. Use uv run maturin develop after changing
Rust code when working directly in the installed development environment.
For Rust formatting, run cargo fmt --all.
The Python extension always includes every adapter supported on its platform: SocketCAN on Linux, panda and PEAK USB adapters, and Vector and J2534 on Windows. Vendor drivers/DLLs and USB permissions remain necessary. The Rust crate retains feature flags for Rust applications.
Basic usage
Minimal setup retains the Rust defaults. Use CanAdapter() for automatic discovery,
PeakAdapter() for default PEAK settings, or SocketCanAdapter("can0") to select
a SocketCAN interface directly. Constructors open the device immediately:
import asyncio
from automotive.adapters import CanAdapter
from automotive.protocols.uds import DataIdentifier, UDSClient
from automotive.transports.isotp import IsoTP
async def main():
adapter = CanAdapter()
transport = IsoTP.from_id(adapter, 0x7A1)
uds = UDSClient(transport)
response = await uds.read_data_by_identifier(DataIdentifier.VIN)
print(response)
asyncio.run(main())
Synchronous usage
The synchronous API mirrors the async module layout under automotive.sync.
Use ordinary constructors, method calls, and receive iterators:
from automotive.sync.adapters import SocketCanAdapter
from automotive.sync.protocols.uds import DataIdentifier, UDSClient
from automotive.sync.transports.isotp import IsoTP
adapter = SocketCanAdapter("can0")
transport = IsoTP.from_id(adapter, 0x7A1)
uds = UDSClient(transport)
print(uds.read_data_by_identifier(DataIdentifier.VIN))
CanAdapter(), PeakAdapter(config), and the other named adapter classes live in
automotive.sync.adapters. The import paths match their async counterparts:
| Async module | Sync module |
|---|---|
automotive.adapters |
automotive.sync.adapters |
automotive.adapters.j2534 |
automotive.sync.adapters.j2534 |
automotive.transports |
automotive.sync.transports |
automotive.transports.isotp |
automotive.sync.transports.isotp |
automotive.protocols.uds |
automotive.sync.protocols.uds |
automotive.can |
automotive.sync.can |
automotive.can.bitrate |
automotive.sync.can.bitrate |
automotive.errors |
automotive.sync.errors |
Both APIs share the same configuration classes, frames, enums, result types, and exceptions. These can be imported through either module hierarchy.
Hardware and subscriptions are released when their last owner is dropped.
Both APIs expose a shared Transport base class accepted by UDSClient.
IsoTP and J2534NativeIsoTP implement this interface. Future transports such
as DoIP and HSFZ can use the same interface without depending on CAN or ISO-TP.
Transports, clients, and receivers retain their underlying resources, so they
can outlive the adapter variable. For deterministic cleanup, use close() on
synchronous resources or await aclose() on asynchronous resources. with and
async with remain supported as optional cleanup patterns.
recv() subscribes immediately. Synchronous receivers support for and next();
async receivers support async for and anext(). Drop or close raw ISO-TP
receivers before making UDS requests on the same transport. Native J2534
transports and reusable device handles have synchronous counterparts too.
One background event loop runs the existing async implementation and shuts down at process exit. Adapter construction opens hardware synchronously in both APIs, including inside an async function; Rust releases the GIL during device opening. Use the async API for awaitable sends and receives in asyncio applications. Suppression scopes in the synchronous API are local to the calling thread and context. Ctrl+C interrupts a blocking wait; an active Rust UDS exchange still drains before the next request, matching async cancellation.
Configuration
Reusable configs expose advanced settings without Rust-style builders:
import asyncio
from automotive.adapters import PeakAdapter, PeakConfig
from automotive.can import Identifier
from automotive.can.bitrate import BitrateSettings
from automotive.protocols.uds import DataIdentifier, UDSClient, UDSConfig
from automotive.transports.isotp import IsoTP, IsoTPConfig
adapter_config = PeakConfig(
bitrate=BitrateSettings(
bitrate=500_000, sample_point=0.8,
data_bitrate=2_000_000, data_sample_point=0.8,
),
tx_timeout=1.0,
)
transport_config = IsoTPConfig(
tx_id=Identifier.extended(0x18DA10F1),
fd=True, max_dlen=32, block_size=8,
receive_separation_time_min=0.0003,
)
uds_config = UDSConfig(request_timeout=10.0, strict=True)
async def main():
adapter = PeakAdapter(adapter_config)
transport = IsoTP(adapter, transport_config)
uds = UDSClient(transport, uds_config)
print(await uds.read_data_by_identifier(DataIdentifier.VIN))
asyncio.run(main())
All Python durations are seconds. Omitting settings retains Rust defaults;
explicit bitrate settings start without presets, so a nominal bitrate alone
selects Classic CAN. Vector retains shared access and existing timing when no
bitrate settings are supplied. resolved_bitrate reports the calculated timing;
SocketCAN selects an existing OS-configured interface.
Payload inputs accept bytes, bytearray, and contiguous byte-oriented
memoryview objects; payload results are bytes. Named codes are Python
IntEnum members, raw numbers are accepted, and unknown received codes are
preserved. Invalid arguments use Python's ValueError/TypeError/OverflowError;
deadlines use TimeoutError; disconnects use ConnectionError. Protocol
exceptions retain NRCs or full response bytes. See automotive.errors.
Receive subscriptions are created by recv() immediately: create one before
sending, then use async for, anext(), and aclose(). Hardware, transports,
and receivers also support async with. Drop or close raw ISO-TP receivers before
using UDS on the same transport; raw CAN monitoring can run alongside UDS.
UDS exchanges on a transport are serialized. A cancelled queued call does not
transmit; an active cancelled exchange drains under the lock before the next
call starts. Closing the parent interrupts dependent operations. Set
request_timeout when an overall bound is needed, including repeated NRC 0x78.
UDS retries idle transport receive timeouts on the same stream without resending
the request or extending P2/P2*. IsoTPConfig.timeout need not exceed the UDS
response waits; transmission and frame-reassembly timeouts still fail the request.
Use an ordinary context manager to suppress positive responses. Suppression supports nested scopes, restores its previous setting on exit, and is local to the current async task. Tasks created inside the scope inherit its context; already-running tasks are unaffected. Negative responses still raise errors.
with uds.suppress_positive_responses():
await uds.tester_present()
await uds.tester_present() # Requires a positive response again.
Examples and API documentation
The async Python examples and their counterparts in examples/sync/ mirror every
Rust example, including CAN transmission, PEAK bitrate configuration, ISO-TP, UDS,
and firmware queries. The synchronous firmware query visits ECUs sequentially;
the async version queries them concurrently.
Read installed API documentation using
uv run python -m pydoc automotive.protocols.uds, or Python's help().
Run uv run python examples/can_sender.py to send one Classic CAN frame.
Use uv run python examples/sync/can_sender.py for the synchronous version.
Run uv run python examples/configure_bitrate.py to configure a PEAK PCAN-USB FD
adapter, or use examples/sync/configure_bitrate.py for the synchronous version.
End-to-end regression tests
On Linux, create vcan0 from the repository root:
scripts/set_up_vcan.sh
The setup script requires sudo. Then run:
cd python
uv run pytest --run-vcan -q
The regression suite starts the existing Scapy ECU scripts, verifies readiness,
and closes/reaps them after each scenario. It exercises all 14 implemented UDS
service IDs through both APIs, transfer round trips, suppression and pending
responses, strict validation, cancellation, and ISO-TP Classic/FD framing and
flow control.
Tests run serially on vcan0; do not run the Rust and Python virtual-CAN suites
concurrently. Without --run-vcan, the hardware-dependent tests are skipped;
explicit runs fail if prerequisites are unavailable.
Metadata
Release files for automotive 0.5.0a3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| automotive-0.5.0a3.tar.gz | 297.0 kB | Without provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| automotive-0.5.0a3-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| automotive-0.5.0a3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| automotive-0.5.0a3-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ ARMv7l | Details |
| automotive-0.5.0a3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| automotive-0.5.0a3-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 5.6 MB
Release files / automotive-0.5.0a3.tar.gz
| Download URL | automotive-0.5.0a3.tar.gz |
|---|---|
| Size | 297.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
26ed6f74c6978a285fb6567be99c59a7c0948ea73f5d8585e00c132a42aea59c
|
|
BLAKE2b-256 checksum How to use checksums |
8fdf2d370b67158faa82cba42f2953e5a7f24fb4dc780c108ac5f9ca5566cee4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / automotive-0.5.0a3-cp311-abi3-win_amd64.whl
| Download URL | automotive-0.5.0a3-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 998.9 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
aa4af2ce5681777dda2d7e4f12bc78f2a64ed3fba37ad487fcc801fd73005c99
|
|
BLAKE2b-256 checksum How to use checksums |
650d1345e50d37615c474897042e07ba7f6082a9bf1b539aece62dcd82dec1bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / automotive-0.5.0a3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | automotive-0.5.0a3-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 918.7 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
5eed7a8e1be17e469a78bff23df1fac5d8d8062cf904832d3246a8f6d55b21d2
|
|
BLAKE2b-256 checksum How to use checksums |
c8de9e946ed6271ee52344acbc7f4d0d0054a539f0a28903b9163c1eb5ef7ea4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / automotive-0.5.0a3-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
| Download URL | automotive-0.5.0a3-cp311-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl |
|---|---|
| Size | 851.0 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ ARMv7l abi3 |
|
SHA-256 checksum How to use checksums |
1727d7933847527c5f3e3a0d414c7f81977b3f7125dc3b030de70264dd41392f
|
|
BLAKE2b-256 checksum How to use checksums |
377b339367a8ea6937f0e3463b90bfebb202f5a5fb901680496a9468c40f6372
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / automotive-0.5.0a3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | automotive-0.5.0a3-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 892.5 kB |
| Tags | CPython 3.11 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
bced160448f2e7134441cf4c5aeb40f623fc6b08de377391be35c120fd407b98
|
|
BLAKE2b-256 checksum How to use checksums |
ab1e2d9d7cdd7526e5b2e7404015b099cff8cc89b9ecea96d4c5792f8aeae9a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / automotive-0.5.0a3-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | automotive-0.5.0a3-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
f0320dfb823dca45f3335a23fc91705719819a7c8964c74ff314ffd15a09166d
|
|
BLAKE2b-256 checksum How to use checksums |
03d5e5635506dfe922f73cf57868acdfc8250ad07a99a97c67a68b3bca18fbc3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.11","id":"zokor","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for automotive 0.5.0a3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.