Skip to main content

Truly async serial port for Linux/macOS using epoll/kqueue

Project description

🟧 AUSerial

Truly async serial port for Linux/macOS using epoll/kqueue

PyPI Downloads Platform Python AsyncIO License

Why AUSerial?

AUSerial (Async Unix Serial) is a minimal, dependency-free async serial port for asyncio applications. It relies only on the standard library (os, termios, asyncio) and plugs directly into the event loop via add_reader / add_writer — which under the hood use epoll (Linux) or kqueue (macOS).

Comparison to existing librairies

Library Backend Cost
pyserial Blocking reads Freezes the event loop
aioserial run_in_executor around pyserial One thread per I/O operation
pyserial-asyncio Transport/Protocol callback API Verbose, subclass boilerplate
AUSerial Direct add_reader / add_writer Zero threads, zero polling

Features

  • 🪶 ~80 lines, no external dependencies — just the standard library
  • Truly non-blocking — no thread pool, no busy loop
  • 🔒 Concurrency-safe — internal locks prevent concurrent read/write conflicts
  • 🧹 Clean resource management — async context manager + idempotent close()
  • 🧯 Proper error propagation through Futures (no silent failures)
  • 🧵 Pending operations are cancelled cleanly on close

Installation

pip install auserial

Or from source:

git clone https://github.com/papyDoctor/auserial.git
cd auserial
pip install -e .

Quick Start

import asyncio
from auserial import AUSerial

async def main():
    async with AUSerial("/dev/ttyUSB0") as serial:
        await serial.write(b"AT\r\n")
        data = await serial.read()
        print(f"Received: {data!r}")

asyncio.run(main())

Custom baudrate

import termios
from auserial import AUSerial

async with AUSerial("/dev/ttyUSB0", baudrate=termios.B9600) as serial:
    ...

Timeout

import asyncio

from auserial import AUSerial


async def main():
    async with AUSerial("/dev/cu.usbmodem21301") as serial:
        await serial.write(b"AT\r\n")
        try:
            data = await asyncio.wait_for(serial.read(), timeout=1.0)
        except TimeoutError:
            print("No response within 1s")
        else:
            print(f"Received: {data!r}")


asyncio.run(main())

Discovering ports

from auserial import list_ports

for p in list_ports():
    print(p.path, p.description, p.hwid)
# /dev/cu.usbmodem21301  Raspberry Pi Pico  USB VID:PID=2E8A:0008 SER=E660B4400765AB25

list_ports() is synchronous and returns list[PortInfo]. On Linux it reads USB metadata from /sys/class/tty/<name>/device/. On macOS it parses ioreg output and links each /dev/cu.* to its USB ancestor (Bluetooth and debug consoles are filtered out). Pure stdlib, no extra dependency.

API

Method / function Description
AUSerial(path, baudrate=...) Opens the tty in non-blocking mode
await serial.open() Binds the instance to the current event loop
await serial.read(n_bytes=64) Waits until data is available, returns bytes
await serial.read_until(terminator=b"\n") Reads until the terminator is found, returns bytes
await serial.write(data) Waits until writable, returns bytes written
serial.close() Cancels pending I/O and closes the fd
list_ports() -> list[PortInfo] Enumerate available serial ports (sync)
PortInfo(path, description, hwid) NamedTuple returned by list_ports()

The AUSerial class also implements __aenter__ / __aexit__, so async with is the recommended usage pattern.

Limitations

  • Unix-only. Relies on termios and add_reader, which require an epoll/kqueue-compatible file descriptor. Windows needs a different implementation (IOCP).
  • A single call to write() issues one os.write — short writes are returned as-is (caller retries with the remainder if needed).

Examples

More usage patterns live in examples/.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

auserial-0.4.1.tar.gz (14.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

auserial-0.4.1-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file auserial-0.4.1.tar.gz.

File metadata

  • Download URL: auserial-0.4.1.tar.gz
  • Upload date:
  • Size: 14.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for auserial-0.4.1.tar.gz
Algorithm Hash digest
SHA256 e3cff3e91d5151b4346d70dd7c9979341f9df91cc3ed534751033c7c03a7dc5a
MD5 cfe63cbc9de176994fa8f71531b4ab0b
BLAKE2b-256 59cfec6e68aa9c9a43f1553c8cd7f0b2b21312e92e869f900e29601cd079b9b8

See more details on using hashes here.

File details

Details for the file auserial-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: auserial-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for auserial-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 02cf76b24f22bc0a5bfc4f9a767ecda2a3aab425dab1673f5e835bb7b1a7fd24
MD5 b6083698ecd175967339f541f0dc02c9
BLAKE2b-256 05ec3c8d53c25b9f72be59f048309e8d1cfb4ac5f7ea186c0c952d1e564a7286

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page