PRD: pycubrid — Pure Python DB-API 2.0 Driver for CUBRID¶
1. Overview¶
Project: pycubrid
Current Version: see PyPI (pycubrid.__version__)
Status: Production-ready
Repository: github.com/cubrid-lab/pycubrid
License: MIT
1.1 Problem Statement¶
CUBRID's existing Python driver (CUBRIDdb) is a C-extension module with significant
limitations:
- Requires C compiler and CUBRID C libraries to install
- Platform compatibility issues (fails on many Linux distributions, macOS ARM)
- No official wheels — users must compile from source
- Not PEP 249 compliant — missing standard exception hierarchy, type objects
- No type hints, no PEP 561 marker
- Abandoned maintenance — last meaningful update years ago
Modern Python developers expect:
pip installthat just works — no C build dependencies- Full PEP 249 (DB-API 2.0) compliance
- Type annotations for IDE support
- Context managers for resource cleanup
- Comprehensive test coverage
1.2 What Was Built¶
A complete pure Python implementation of the CUBRID CAS protocol:
- Full PEP 249 (DB-API 2.0) compliance — standard exception hierarchy, type objects, cursor interface
- Pure Python — no C extensions, no compilation, works everywhere Python runs
- Direct CAS protocol — speaks CUBRID's binary protocol natively over TCP
- Offline and live test suites (test tree) with a CI-enforced 95% coverage floor (measured results)
- PEP 561 typed package —
py.typedmarker for modern IDE and static analysis - LOB support — CLOB and BLOB handling via
create_lob() - Prepared statements — server-side statement preparation and execution (planned; current implementation uses driver-side parameter binding)
- Batch operations —
executemany()andexecutemany_batch()for bulk inserts - CI/CD — Python 3.11–3.15 support, with representative offline and live-endpoint lanes per change and a full Python × CUBRID matrix on release
1.3 Success Criteria — Status¶
| Criterion | Target | Achieved |
|---|---|---|
| Pure Python (no C extensions) | ✅ | ✅ pip install pycubrid |
| PEP 249 (DB-API 2.0) compliant | ✅ | ✅ Full API compliance |
| Offline tests (no live DB) | ✅ | ✅ make test; coverage floor enforced on full runs |
| LOB (CLOB/BLOB) support | ✅ | ✅ create_lob(), read/write |
| Prepared statements | ✅ | ✅ cursor.execute(sql, params) — driver-side parameter binding via ? placeholders (see PARAMETER_BINDING.md) |
| CI/CD with version matrix | ✅ | ✅ Py 3.11–3.15 representative offline and live lanes; full 5 × 4 matrix on release |
| Publishable to PyPI | ✅ | ✅ Released by merging a reviewed release PR (RELEASING.md) |
| ≥ 95% code coverage | ✅ | ✅ CI-enforced floor; measured results |
| Comprehensive documentation | ✅ | ✅ Guides under docs/ in English and Korean + README |
| PEP 561 typed package | ✅ | ✅ py.typed marker |
2. Technical Architecture¶
2.1 Module Structure¶
graph TD
root[pycubrid/ - main package]
init["__init__.py - Public API connect(), types, exceptions, __version__"]
connection[connection.py - Connection class connect/commit/rollback/cursor/LOB]
cursor[cursor.py - Cursor class execute/fetch/executemany/callproc/iterator]
types[types.py - DB-API 2.0 type objects and constructors]
exceptions[exceptions.py - PEP 249 exception hierarchy]
constants[constants.py - CAS function codes, data types, protocol constants]
protocol["protocol.py - CAS wire protocol packet classes (20 packet types)"]
packet[packet.py - Low-level packet reader/writer]
lob[lob.py - LOB support]
typed[py.typed - PEP 561 marker]
root --> init
root --> connection
root --> cursor
root --> types
root --> exceptions
root --> constants
root --> protocol
root --> packet
root --> lob
root --> typed
2.2 Dependency Matrix¶
| Package | Version | Purpose |
|---|---|---|
| Python | ≥ 3.11 | Runtime |
| pytest | ≥ 7.0 | Testing (dev) |
| ruff | ≥ 0.4 | Lint + format (dev) |
Standard library only — pycubrid needs no runtime dependencies except
tzdata on Windows, which supplies the IANA
time zone database that zoneinfo needs for TZ types (#413).
2.3 PEP 249 Compliance¶
| Attribute | Value |
|---|---|
apilevel |
"2.0" |
threadsafety |
1 (connections cannot be shared between threads) |
paramstyle |
"qmark" (positional parameters ?) |
Full standard exception hierarchy: Warning, Error, InterfaceError, DatabaseError,
OperationalError, IntegrityError, InternalError, ProgrammingError, NotSupportedError
Standard type objects: STRING, BINARY, NUMBER, DATETIME, ROWID
Standard constructors: Date(), Time(), Timestamp(), Binary(),
DateFromTicks(), TimeFromTicks(), TimestampFromTicks()
3. Implemented Features¶
3.1 Connection Management¶
connect()factory function with keyword arguments- Auto-commit control via
connection.autocommitproperty - Context manager support (
withstatement) - Server version detection via
connection.get_server_version() connection.close()for explicit cleanupconnection.ping()for native CAS health checks- Async connection API via
pycubrid.aio.connect()
3.2 Cursor Operations¶
execute(sql, params?)— execute with optional parametersexecutemany(sql, seq_of_params)— batch executeexecutemany_batch(sql, seq_of_params)— optimized batch insertfetchone()/fetchmany(size)/fetchall()— result retrievalexecute(sql, params)— qmark-style parameterized queries bound CLIENT-SIDE; SQL is fully rendered before being sent to CAS (see PARAMETER_BINDING.md)callproc(procname, params)— stored procedure callsnextset()— DB-API compatibility method (returnsNone)- Iterator protocol —
for row in cursor - Context manager —
with conn.cursor() as cur descriptionattribute — column metadata after execute
3.3 LOB Support¶
connection.create_lob(lob_type)— create CLOB (type=24) or BLOB (type=23)- Read/write large text and binary data
- Insert strings/bytes directly into CLOB/BLOB columns
3.4 Schema Introspection¶
connection.get_schema_info()— tables, columns, indexes, constraints
3.5 Async API (shipped in 1.1.0)¶
pycubrid.aio.connect()— async module-level constructorAsyncConnection—connect,commit,rollback,close,cursor,set_autocommitAsyncCursor— asyncexecute,executemany,fetchone,fetchmany,fetchall,nextset
3.6 CAS Protocol¶
Direct implementation of CUBRID's Client Application Server (CAS) binary protocol:
- 20 packet types covering all database operations
- Two-step connection: broker handshake → CAS session
- Big-endian binary codec for all data types
- Server-side cursor with lazy fetch for large result sets
4. Test Coverage¶
4.1 Test Matrix¶
| Test File | Coverage Area |
|---|---|
test_connection.py |
Connection, authentication, auto-commit, context manager |
test_cursor.py |
Execute, fetch, executemany, callproc, iterator, description |
test_types.py |
Type objects, constructors, date/time conversion |
test_exceptions.py |
Exception hierarchy, error codes |
test_protocol.py |
Packet building, parsing, CAS function codes |
test_packet.py |
Binary reader/writer, data type encoding |
test_lob.py |
LOB creation, read, write |
test_constants.py |
Protocol constants, data type codes |
test_integration.py |
Live DB tests (Docker) |
| Totals | Not pinned here: run make test, and see the test tree and measured coverage |
4.2 CI Matrix¶
| Lane | Python | CUBRID |
|---|---|---|
| Ordinary PR smoke (offline) | 3.12 | — |
| Main, weekly, high-risk PR (offline) | 3.11, 3.15 | — |
| Full compatibility matrix (explicit dispatch and every release) | 3.11, 3.12, 3.13, 3.14, 3.15 | 10.2, 11.0, 11.2, 11.4 (5 × 4) |
See CI execution policy for the per-event live endpoints.
5. Known Limitations¶
Limitations imposed by CUBRID or design choices:
| Feature | Status | Reason |
|---|---|---|
| Async TLS | ✅ | Implemented in v1.4.0; uses CUBRID's STARTTLS-style upgrade — plaintext CUBRS handshake then loop.start_tls() (with ssl_handshake_timeout) before OPEN_DATABASE (#154). Default context requires TLS 1.2 minimum. |
| Connection pooling | ❌ | Not in scope; use SQLAlchemy's pool or external pooler |
| Thread safety level 2+ | ❌ | CUBRID CAS sessions are connection-bound |
| LOB streaming | ⚠️ | LOB data loaded fully into memory |
| Timezone-aware parsing | ⚠️ | Supported for TZ types; behavior depends on server-supplied zone tokens |
| Async LOB helper | ⚠️ | No dedicated async Lob helper yet |
6. Documentation¶
| Document | Content |
|---|---|
README.md |
Landing page with Quick Start |
docs/CONNECTION.md |
Connection strings, configuration |
docs/TYPES.md |
Type mapping, CUBRID-specific types |
docs/API_REFERENCE.md |
Complete API documentation |
docs/PROTOCOL.md |
CAS wire protocol reference |
docs/DEVELOPMENT.md |
Dev setup, testing, Docker, CI/CD |
docs/EXAMPLES.md |
Practical usage examples |
CHANGELOG.md |
Release history |
CONTRIBUTING.md |
Contribution guidelines |
7. Roadmap¶
Delivered Milestones¶
| Release | Highlights |
|---|---|
| 1.0.0 | Stable sync DB-API surface, LOB support, schema APIs, test/CI baseline |
| 1.1.0 | Native pycubrid.aio async API shipped |
| 1.2.0 | ping(), JSON decoding, collection decoding, nextset(), richer errors |
| 1.3.0 | Sync TLS support, refreshed CI/docs baseline |
Forward-looking Priorities¶
| Item | Description | Priority |
|---|---|---|
| LOB ergonomics | Higher-level helpers for reading fetched LOB handles | Medium |
| Statement caching | Reuse prepared statements for repeated workloads | Medium |
| CUBRID 12.x validation | Expand CI and docs for newer server versions | Medium |
8. Architecture Decisions¶
8.1 Why Pure Python (no C extensions)¶
The C-extension driver (CUBRIDdb) required users to have CUBRID C libraries installed,
which was a significant barrier — especially on macOS, ARM Linux, and containerized
environments. A pure Python implementation eliminates all build dependencies and
makes pip install pycubrid work everywhere.
8.2 Why Direct CAS Protocol¶
Rather than wrapping the C library or using ODBC, pycubrid implements CUBRID's CAS (Client Application Server) binary protocol directly over TCP. This provides:
- Zero native dependencies
- Full control over connection lifecycle
- Ability to implement features the C driver lacks (e.g., proper LOB handling)
8.3 Why PEP 249 Strict Compliance¶
DB-API 2.0 is the standard Python database interface. Strict compliance means:
- Any code written for
sqlite3,psycopg2, ormysql-connectorworks with minimal changes - SQLAlchemy and other ORMs can use pycubrid as a drop-in driver
- Standard exception handling patterns work out of the box
9. Ecosystem Integration¶
pycubrid is the foundational driver in the cubrid-lab Python ecosystem:
graph TD
pycubrid["pycubrid (DB-API 2.0 driver)"]
sqlalchemy["sqlalchemy-cubrid (SQLAlchemy 2.0 dialect)"]
cookbook["cubrid-cookbook (runnable examples)"]
fastapi[FastAPI examples]
django[Django examples]
flask[Flask examples]
pandas[Pandas examples]
streamlit[Streamlit examples]
celery[Celery examples]
pycubrid --> sqlalchemy
sqlalchemy --> cookbook
cookbook --> fastapi
cookbook --> django
cookbook --> flask
cookbook --> pandas
cookbook --> streamlit
cookbook --> celery
10. Example-first Design Philosophy¶
Why Example-first¶
CUBRID's ecosystem is small compared to PostgreSQL or MySQL. For a small-ecosystem project, the entry barrier must be minimized — users should be able to copy-paste working code within 30 seconds of reading the documentation.
Because the ecosystem is still small, the project provides extensive examples and cookbook-style documentation to lower the adoption barrier.
Hello World¶
import pycubrid
conn = pycubrid.connect(
host="localhost",
port=33000,
database="demodb",
user="dba",
password="",
)
cur = conn.cursor()
cur.execute("SELECT 1 + 1")
print(cur.fetchone()) # (2,)
cur.close()
conn.close()
This code connects to a CUBRID database, runs a query, and prints the result. No ORM setup, no configuration files, no boilerplate.
AI Agent Discoverability¶
Modern developers increasingly rely on AI coding assistants — Claude Code, OpenCode, Cursor, GitHub Copilot, Devin, and others. These agents read README files, PRDs, documentation, and example code to decide which libraries to recommend.
More examples in documentation = higher probability of AI recommendation.
By embedding working code directly in the PRD, README, and docs, we ensure that AI agents can discover, learn, and recommend pycubrid accurately.
Cookbook Integration¶
The cubrid-cookbook repository provides production-ready, runnable examples for pycubrid:
| Example | Description |
|---|---|
01_connect.py |
Basic connection and query |
02_crud.py |
Create, read, update, delete operations |
03_transactions.py |
Transaction management with commit/rollback |
04_prepared.py |
Parameterized queries (driver-side binding) for repeated execution |
05_error_handling.py |
Error handling with PEP 249 exception hierarchy |
06_lob.py |
LOB (CLOB/BLOB) operations |
Inspiration from Successful Projects¶
Projects that succeeded partly through example-heavy documentation:
| Project | What They Did |
|---|---|
| FastAPI | Every endpoint documented with runnable examples; became the fastest-growing Python web framework |
| LangChain | Cookbook-first approach drove explosive adoption in the AI space |
| SQLAlchemy | Extensive ORM cookbook and tutorial; de facto Python ORM for 15+ years |
| Pandas | "10 Minutes to pandas" and cookbook lowered entry barrier for data science |
pycubrid follows the same philosophy: examples are not supplementary — they are the primary documentation.
Last updated: October 2026. Figures that change with each release are linked, not copied. The async API is available since v1.1.0.