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.2.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.2-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: auserial-0.4.2.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.2.tar.gz
Algorithm Hash digest
SHA256 ac765c5d7f24704505c4129499bed082056fbbac69025f9d7bbd1cc4ba5ae8d6
MD5 fded63adba9803cb1f07280b90df3d17
BLAKE2b-256 f4c6032b0e898d322de9ecaa0c2af3dd1cd8bafd979896698633fbc56d3d2ca9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: auserial-0.4.2-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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 00eb082260c72d1ff5587bf8673c24bfae4fa7dc230d700a91fea3a475d4b1f1
MD5 59a68ba96062996dcb433be40eeeb291
BLAKE2b-256 82a0a9003a1963e832255da03b82c4e326c9508497e104c495e8e44b68dc2c86

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