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.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.3.0.tar.gz (12.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.3.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: auserial-0.3.0.tar.gz
  • Upload date:
  • Size: 12.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.3.0.tar.gz
Algorithm Hash digest
SHA256 ef1da2b7a732215f22956b5ce70c11066eff7367d253533b3be71f8edab85494
MD5 1859b41702b155dc05d23e2c81d8b5b4
BLAKE2b-256 ed47ba3ad5e572ae39eea5ce74a4450784b0123b7b1f3060ba3bfe844c30c201

See more details on using hashes here.

File details

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

File metadata

  • Download URL: auserial-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 9.2 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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3943984989fe0a9cd433d440e735be47e21168a4672dd82cc4c92e98407bcfdd
MD5 8dc1fcdd63bee222488f18f16b3b97e9
BLAKE2b-256 a195fbd6c9f862212a62c9f1f957c0bdf3c579c9df439eefe94f251f4cce3bf7

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