Ryan Malloy 300e1bf7b4 Phase 16: async API (informix_db.aio)
Ships AsyncConnection, AsyncCursor, and AsyncConnectionPool that
expose async/await versions of the sync API for use with FastAPI,
aiohttp, etc.

Strategy: thread-pool wrapping (aiopg pattern), not native async.
Each blocking I/O call is offloaded to a worker thread via
asyncio.to_thread. The event loop never blocks; queries run in
parallel up to the pool's max_size. Cost: ~250 lines, no changes
to the sync codebase. Native async (Phase 17) would require a
~2000-line transport abstraction refactor — deferred until a real
workload needs it.

For typical FastAPI/aiohttp workloads (request → one query → return),
this is functionally equivalent to native async. Each await yields
the loop while a worker thread does the I/O. Only differs for
hundreds-of-concurrent-connections workloads.

API mirrors the sync API one-to-one:

  import asyncio
  from informix_db import aio

  async def main():
      pool = await aio.create_pool(host=..., min_size=1, max_size=10)
      async with pool.connection() as conn:
          cur = await conn.cursor()
          await cur.execute("SELECT id FROM users WHERE name = ?", (name,))
          row = await cur.fetchone()
      await pool.close()

The async pool preserves the sync pool's eviction policy: connection
errors evict, application errors retain.

Tests: 9 integration tests in test_aio.py covering open/close,
async-with, simple/parameterized SELECT, async-for cursor iteration,
pool acquire/release, 20-query concurrent gather (verifies parallelism
through max_size=5 pool), pool async context manager, commit/rollback.

Total: 69 unit + 163 integration = 232 tests.

Pyproject changes:
* Added pytest-asyncio>=1.3.0 as dev dep
* asyncio_mode = "auto" so async tests don't need decorators

Architectural completion: with Phase 16, every backlog item is
done. The Phase 0 ambition — first pure-Python Informix driver,
no native deps — is now genuinely complete.
2026-05-04 14:58:19 -06:00
2026-05-04 14:58:19 -06:00

informix-db

Pure-Python driver for IBM Informix IDS, speaking the SQLI wire protocol over raw sockets. No IBM Client SDK. No JVM. No native libraries.

Status

🟢 Phase 1 complete. connect() / close() work end-to-end against a real Informix server. Cursor / execute / fetch land in Phase 2.

To our knowledge this is the first pure-socket Informix driver in any language — every other Informix driver (IfxPy, the legacy informixdb, ODBC bridges, Perl DBD::Informix) wraps either IBM's CSDK or the JDBC JAR.

Quick start

import informix_db

with informix_db.connect(
    host="127.0.0.1", port=9088,
    user="informix", password="in4mix",
    database="sysmaster", server="informix",
) as conn:
    # cursor() / execute() / fetchone() arrive in Phase 2
    pass

Test against the official Informix dev container

docker compose -f tests/docker-compose.yml up -d   # IBM Developer Edition, pinned by digest
uv sync --extra dev
uv run pytest                  # 34 unit tests (no Docker needed)
uv run pytest -m integration   # 6 integration tests (needs the container)

Phase 0 artifacts (still useful — they ARE the public reference)

License

MIT.

Description
Pure-Python driver for IBM Informix IDS — speaks the SQLI wire protocol over a raw socket. No CSDK, no JVM, no native libraries.
https://informix-db.warehack.ing
Readme MIT 716 KiB
Languages
Python 85.6%
MDX 8.1%
CSS 2.1%
Java 1.7%
Astro 1%
Other 1.4%