python-can hides the backend, and the Bus context manager is how you stop leaking it
The can package provides controller area network support for Python developers
At a glance
- What is it?
- python-can gives one Python API over many CAN hardware and protocol backends, with log playback in seven formats and four command line tools, and its main branch requires Python 3.10+ while older version lines support older interpreters.
- Who is it for?
- Adopt python-can if your work touches vehicle, marine, wheelchair or industrial CAN buses and you want one code path across SocketCAN, PCAN, Vector and virtual interfaces instead of vendor SDKs. Do not adopt it as a realtime control loop: the library is a bus abstraction with a notifier, and anything timing-critical belongs closer to the hardware.
- Can I use it commercially?
- Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 114 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One Bus object, many backends
The CAN bus itself is a standard for letting microcontrollers and devices talk to each other, with priority-based arbitration and deterministic communication, and it is used in cars, trucks, boats, wheelchairs and more.
What python-can adds is a layer of common abstractions so the same Python code talks to whichever hardware you have. The README lists support for many different backends and points to an interfaces page in the documentation for the list, which is the first page to read before choosing.
The API shape is small enough to hold in your head.
with can.Bus(interface='socketcan',
channel='vcan0',
receive_own_messages=True) as bus:
message = can.Message(arbitration_id=123, is_extended_id=True,
data=[0x11, 0x22, 0x33])
bus.send(message, timeout=0.2)
for msg in bus:
print(f"{msg.arbitration_id:X}: {msg.data}")Three things are worth noticing in that snippet. The interface name and the channel are constructor arguments, so switching from a SocketCAN interface to a vendor adapter is a string change rather than a rewrite. The with statement exists to call bus.shutdown() on block exit, which is the difference between a script and something you can run repeatedly. And receive_own_messages=True means the bus sees its own transmissions, which matters immediately when you start debugging.
Both normal and extended arbitration IDs are supported, along with CAN FD.
Seven log formats, which is the part that saves projects
The feature list is long, and one item stands out: the library supports many loggers and readers for playback in ASC (CANalyzer format), BLF (Binary Logging Format by Vector), MF4 (Measurement Data Format v4 by ASAM), TRC, CSV, SQLite and Canutils log.
That is the practically decisive capability in this library. A capture you did not record is useless to python-can, and a capture you recorded with one tool is often unreadable by another. Being able to read Vector BLF and ASAM MF4, the formats automotive engineers actually receive from suppliers, means an existing corpus becomes usable without a conversion step and without the vendor tools.
The rest of the feature list is about doing real work on a bus rather than in a toy. Receiving, sending and periodically sending messages. Efficient in-kernel or in-hardware filtering of messages on supported interfaces, which matters when a bus carries more traffic than Python can process and the filtering has to happen below your process. Bus configuration reading from a file or from environment variables, so a deployment can set the interface and channel without editing code.
The examples directory in the repository shows the shape of real work: send_one.py and send_multiple.py, receive_all.py, print_notifier.py, cyclic.py and cyclic_checksum.py for periodic transmission, serial_com.py for building a protocol on top, crc.py, vcan_filtered.py for the filtering path, asyncio_demo.py for the asynchronous API and simple_log_converter.py for format conversion.
Four command line tools ship with the package
python-can installs console scripts, which is easy to miss because the README mentions them only as command line tools for working with CAN buses with a documentation link.
pyproject.toml declares them.
[project.scripts]
can_logconvert = "can.logconvert:main"
can_logger = "can.logger:main"
can_player = "can.player:main"There is a fourth entry truncated in the visible configuration, can_viewer, which follows the same pattern.
Four tools, four jobs. can_logger records a bus to a log, can_player plays a log back onto a bus, can_logconvert converts between formats, and can_viewer inspects a log without touching hardware. That last one is the quietly useful one: examining a supplied capture on a laptop, with no CAN interface present at all, is a common first step in an automotive investigation.
Together they cover the loop a hardware team actually runs: log the problem, convert it to the format the supplier accepts, replay the fix, and inspect the result.
The version table is the compatibility story
The README carries a table mapping library versions to Python versions, and it is worth reading rather than assuming.
Library Version Python
------------------------------ -----------
2.x 2.6+, 3.4+
3.x 2.7+, 3.5+
4.0+ 3.7+
4.3+ 3.8+
4.6+ 3.9+
main branch 3.10+So there are still maintained-looking paths back to Python 2.6 on the 2.x line, and the current main branch requires 3.10. That table is also the answer to the question of which release to pin: pyproject.toml declares requires-python >= 3.10, and the classifiers list Python 3.10 through 3.14.
Release history is steady rather than fast: v4.6.1 from 2025-08-12, v4.6.0 from 2025-08-08 and v4.5.0 from 2024-11-28, with the last push on 2026-07-01.
The packaging is modern. Build requirements are setuptools 77.0 or newer with setuptools_scm 8, and the version and readme are dynamic rather than literal, so the version again comes from the git tags.
Runtime dependencies are three: wrapt between 1.10 and 3, packaging 23.1 or newer, and typing_extensions. No numpy, no compiled extension required for the core, which is why it installs cleanly across CPython and PyPy.
LGPL-3.0-only is the constraint to read before you ship
The licence is stated twice and consistently: LGPL in the repository metadata and license = "LGPL-3.0-only" in pyproject.toml, with copyright and licensing details in LICENSE.txt.
LGPL-3.0-only is a version-specific licence. It means the LGPL without the option of relicensing under a later version, so there is no path to a differently-licensed version of the same code.
For a Python library used as a dependency, LGPL obligations attach to how you distribute. Linking a shared library and shipping it with your product generally requires offering recipients the ability to replace it, and statically bundling it is the case that gets expensive. This is not legal advice, and the practical instruction is to have whoever owns your licensing review LGPL-3.0-only before you ship python-can inside a commercial artefact.
For internal tooling, a test harness or a research script, the question does not arise, and this is the majority of the project's use.
The rest of the operational picture is ordinary and healthy: classifiers for macOS, Windows and Linux, CPython and PyPy, topics covering embedded systems, hardware drivers, logging and monitoring, GitHub Actions for CI, Coveralls for coverage, Read the Docs for documentation, and the black formatter named in a badge. Development setup is documented in doc/development.rst, with tox.ini at the root for multi-environment runs and CONTRIBUTORS.txt alongside CONTRIBUTING.md.
Where the abstraction stops helping
python-can is a bus library, not a vehicle stack. It moves frames; it does not know that a particular arbitration ID is a steering angle.
The first boundary is timing. Iteration over a bus in a Python loop is convenient and adequate for logging, analysis and bring-up, and inadequate for anything that must respond within a deadline. The notifier is asynchronous and there is an asyncio example, which helps with fan-out to loggers and printers rather than with latency guarantees. If your design needs hard real-time behaviour, that belongs in code closer to the interface.
The second boundary is the backend itself. Filtering is described as efficient in-kernel or in-hardware on supported interfaces, which means the filter semantics are not identical everywhere. A rule that the kernel applies on SocketCAN may have to be applied in Python on an adapter that cannot do it, and the messages you see will not match.
The third is configuration portability. Bus configuration can come from a file or environment variables, which is good practice, but each backend has its own channel naming and its own optional dependencies, so a configuration that works on Linux with SocketCAN needs rewriting for a vendor adapter. The interfaces documentation page is where that mapping lives.
None of this makes the library a poor choice for its stated purpose. It makes it a choice to make deliberately, with the backend you actually have in mind.
Editorial conclusion
Adopt python-can if your work touches vehicle, marine, wheelchair or industrial CAN buses and you want one code path across SocketCAN, PCAN, Vector and virtual interfaces instead of vendor SDKs. Do not adopt it as a realtime control loop: the library is a bus abstraction with a notifier, and anything timing-critical belongs closer to the hardware. Verify first that your backend is on the interfaces list in the documentation, that your Python version matches the release you pin, since main now requires 3.10 while 4.3+ requires 3.8 and older lines go back much further, and that your log format is one of the seven with a reader. LGPL-3.0-only matters if you intend to ship it inside a product.
Frequently asked questions
How do I install python-can?
Install it with pip install python-can. It is also published on conda-forge. The main branch requires Python 3.10+, 4.6+ requires Python 3.9+, 4.3+ requires Python 3.8+, and the 2.x line lists Python 2.6+.
Which log formats can python-can read and write?
ASC in CANalyzer format, BLF from Vector, MF4 version 4 from ASAM, TRC, CSV, SQLite and Canutils log. Playback support through readers and loggers is listed as a feature of the library.
What command line tools does python-can install?
The package declares console scripts including can_logconvert for converting between formats, can_logger for recording a bus, can_player for playing a log back, and can_viewer for inspecting a log file without hardware.
How do I create a bus and send a message with python-can?
Use can.Bus with the interface and channel as arguments inside a with statement, which calls bus.shutdown() on exit. Build a can.Message with an arbitration_id, is_extended_id and data, then call bus.send with a timeout, and iterate over the bus to receive.
What licence is python-can released under?
LGPL-3.0-only, stated in pyproject.toml and LICENSE.txt. The only suffix means there is no option of relicensing the code under a later version of the LGPL.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/hardbyte-python-can)