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.0.tar.gz (14.3 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.0-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: auserial-0.4.0.tar.gz
  • Upload date:
  • Size: 14.3 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.0.tar.gz
Algorithm Hash digest
SHA256 30f442daf68b86b0ff1aae0ac2a14d9aa617abc60a019c82185270768d0b52d4
MD5 5bfe43caba89b971867e6e76b1a1c331
BLAKE2b-256 5edcde6c99797a58e4faab1ce28d1a02cb7684af9d56b41fcf73f0ad54a62a42

See more details on using hashes here.

File details

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

File metadata

  • Download URL: auserial-0.4.0-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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6a02688177422f48daa480c6f96fb9cd2e66f5a38905ab141f4b35c11bbfd59f
MD5 28cd8f401baace204c23ca4a385af781
BLAKE2b-256 4ab9d60641ea260ae994c8198c206a172123201417b6a5bc4d6cffb1524a13e3

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