PRD: pycubrid — CUBRID용 순수 Python DB-API 2.0 드라이버 (한국어)¶
🌐 PRD.md의 번역입니다. 영어 원문이 표준이며, CI가 영어 원문과의 구조 일치를 검사합니다.
1. 개요¶
프로젝트: pycubrid
현재 버전: PyPI 참고 (pycubrid.__version__)
상태: 프로덕션 사용 가능
저장소: github.com/cubrid-lab/pycubrid
라이선스: MIT
1.1 문제 정의¶
CUBRID의 기존 Python 드라이버(CUBRIDdb)는 C 확장 모듈이며 다음과 같은 중대한
제약이 있습니다:
- 설치하려면 C 컴파일러와 CUBRID C 라이브러리가 필요합니다
- 플랫폼 호환성 문제가 있습니다(많은 Linux 배포판과 macOS ARM에서 실패)
- 공식 wheel이 없어 사용자가 소스에서 직접 컴파일해야 합니다
- PEP 249를 준수하지 않습니다 — 표준 예외 계층과 타입 객체가 없습니다
- 타입 힌트도, PEP 561 마커도 없습니다
- 유지보수가 중단되었습니다 — 마지막 의미 있는 업데이트가 수년 전입니다
현대의 Python 개발자는 다음을 기대합니다:
- 그냥 동작하는
pip install— C 빌드 의존성 없음 - 완전한 PEP 249(DB-API 2.0) 준수
- IDE 지원을 위한 타입 어노테이션
- 자원 정리를 위한 컨텍스트 매니저
- 포괄적인 테스트 커버리지
1.2 구현된 내용¶
CUBRID CAS 프로토콜의 완전한 순수 Python 구현입니다:
- 완전한 PEP 249(DB-API 2.0) 준수 — 표준 예외 계층, 타입 객체, 커서 인터페이스
- 순수 Python — C 확장도 컴파일도 없으며 Python이 실행되는 어디서나 동작합니다
- 직접 CAS 프로토콜 — TCP 위에서 CUBRID의 바이너리 프로토콜을 네이티브로 사용합니다
- 오프라인 및 라이브 테스트 스위트 (테스트 트리), CI로 강제하는 95% 커버리지 하한 (측정 결과)
- PEP 561 타입 지정 패키지 — 현대적 IDE와 정적 분석을 위한
py.typed마커 - LOB 지원 —
create_lob()을 통한 CLOB·BLOB 처리 - Prepared statement — 서버 측 문장 준비와 실행 (계획됨; 현재 구현은 드라이버 측 파라미터 바인딩을 사용합니다)
- 배치 연산 — 대량 삽입을 위한
executemany()와executemany_batch() - CI/CD — Python 3.11–3.15 지원, 변경별 대표 오프라인·라이브 엔드포인트 검사, 릴리스 시 Python × CUBRID 전체 매트릭스
1.3 성공 기준 — 현황¶
| 기준 | 목표 | 달성 |
|---|---|---|
| 순수 Python (C 확장 없음) | ✅ | ✅ pip install pycubrid |
| PEP 249 (DB-API 2.0) 준수 | ✅ | ✅ 완전한 API 준수 |
| 오프라인 테스트 (라이브 DB 불필요) | ✅ | ✅ make test. 전체 실행에서 커버리지 하한 강제 |
| LOB (CLOB/BLOB) 지원 | ✅ | ✅ create_lob(), 읽기/쓰기 |
| Prepared statement | ✅ | ✅ cursor.execute(sql, params) — ? 플레이스홀더를 통한 드라이버 측 파라미터 바인딩 (PARAMETER_BINDING.md 참고) |
| 버전 매트릭스를 갖춘 CI/CD | ✅ | ✅ Py 3.11–3.15 대표 오프라인·라이브 검사, 릴리스 시 전체 5 × 4 매트릭스 |
| PyPI에 게시 가능 | ✅ | ✅ 검토한 릴리스 PR을 머지하면 릴리스 (RELEASING.md) |
| 코드 커버리지 ≥ 95% | ✅ | ✅ CI로 강제하는 하한. 측정 결과 |
| 포괄적인 문서 | ✅ | ✅ docs/ 아래 영어·한국어 가이드 + README |
| PEP 561 타입 지정 패키지 | ✅ | ✅ py.typed 마커 |
2. 기술 아키텍처¶
2.1 모듈 구조¶
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 의존성 매트릭스¶
| 패키지 | 버전 | 용도 |
|---|---|---|
| Python | ≥ 3.11 | 런타임 |
| pytest | ≥ 7.0 | 테스트 (개발용) |
| ruff | ≥ 0.4 | 린트 + 포맷 (개발용) |
표준 라이브러리만 사용 — pycubrid는 런타임 의존성이 필요 없습니다. 단,
Windows에서는 zoneinfo가 TZ 타입에 필요로 하는 IANA 타임존 데이터베이스를
제공하는 tzdata가 예외입니다(#413).
2.3 PEP 249 준수¶
| 속성 | 값 |
|---|---|
apilevel |
"2.0" |
threadsafety |
1 (연결은 스레드 간에 공유할 수 없습니다) |
paramstyle |
"qmark" (위치 파라미터 ?) |
완전한 표준 예외 계층: Warning, Error, InterfaceError, DatabaseError,
OperationalError, IntegrityError, InternalError, ProgrammingError, NotSupportedError
표준 타입 객체: STRING, BINARY, NUMBER, DATETIME, ROWID
표준 생성자: Date(), Time(), Timestamp(), Binary(),
DateFromTicks(), TimeFromTicks(), TimestampFromTicks()
3. 구현된 기능¶
3.1 연결 관리¶
- 키워드 인자를 받는
connect()팩토리 함수 connection.autocommit프로퍼티를 통한 오토커밋 제어- 컨텍스트 매니저 지원(
with문) connection.get_server_version()을 통한 서버 버전 감지- 명시적 정리를 위한
connection.close() - 네이티브 CAS 상태 검사를 위한
connection.ping() pycubrid.aio.connect()를 통한 비동기 연결 API
3.2 커서 연산¶
execute(sql, params?)— 선택적 파라미터와 함께 실행executemany(sql, seq_of_params)— 배치 실행executemany_batch(sql, seq_of_params)— 최적화된 배치 삽입fetchone()/fetchmany(size)/fetchall()— 결과 조회execute(sql, params)— 클라이언트 측에서 바인딩되는 qmark 방식의 파라미터화된 쿼리; SQL은 CAS로 전송되기 전에 완전히 렌더링됩니다(PARAMETER_BINDING.md 참고)callproc(procname, params)— 저장 프로시저 호출nextset()— DB-API 호환 메서드(None반환)- 이터레이터 프로토콜 —
for row in cursor - 컨텍스트 매니저 —
with conn.cursor() as cur description속성 — 실행 후의 컬럼 메타데이터
3.3 LOB 지원¶
connection.create_lob(lob_type)— CLOB(type=24) 또는 BLOB(type=23) 생성- 대용량 텍스트와 바이너리 데이터의 읽기/쓰기
- 문자열/바이트를 CLOB/BLOB 컬럼에 직접 삽입
3.4 스키마 인트로스펙션¶
connection.get_schema_info()— 테이블, 컬럼, 인덱스, 제약 조건
3.5 비동기 API (1.1.0에서 출시)¶
pycubrid.aio.connect()— 비동기 모듈 수준 생성자AsyncConnection—connect,commit,rollback,close,cursor,set_autocommitAsyncCursor— 비동기execute,executemany,fetchone,fetchmany,fetchall,nextset
3.6 CAS 프로토콜¶
CUBRID의 Client Application Server(CAS) 바이너리 프로토콜을 직접 구현합니다:
- 모든 데이터베이스 연산을 다루는 20개 패킷 타입
- 2단계 연결: 브로커 핸드셰이크 → CAS 세션
- 모든 데이터 타입을 위한 빅엔디언 바이너리 코덱
- 대용량 결과 집합을 위한 지연 fetch 방식의 서버 측 커서
4. 테스트 커버리지¶
4.1 테스트 매트릭스¶
| 테스트 파일 | 커버리지 영역 |
|---|---|
test_connection.py |
연결, 인증, 오토커밋, 컨텍스트 매니저 |
test_cursor.py |
execute, fetch, executemany, callproc, 이터레이터, description |
test_types.py |
타입 객체, 생성자, 날짜/시간 변환 |
test_exceptions.py |
예외 계층, 오류 코드 |
test_protocol.py |
패킷 생성, 파싱, CAS 함수 코드 |
test_packet.py |
바이너리 리더/라이터, 데이터 타입 인코딩 |
test_lob.py |
LOB 생성, 읽기, 쓰기 |
test_constants.py |
프로토콜 상수, 데이터 타입 코드 |
test_integration.py |
라이브 DB 테스트 (Docker) |
| 합계 | 수치를 여기에 고정해 두지 않습니다. make test를 실행하고 테스트 트리와 측정된 커버리지를 참고하세요 |
4.2 CI 매트릭스¶
| 검사 | Python | CUBRID |
|---|---|---|
| 일반 PR 스모크 (오프라인) | 3.12 | — |
| main, 주간, 고위험 PR (오프라인) | 3.11, 3.15 | — |
| 전체 호환성 매트릭스 (명시적 수동 실행과 모든 릴리스) | 3.11, 3.12, 3.13, 3.14, 3.15 | 10.2, 11.0, 11.2, 11.4 (5 × 4) |
이벤트별 라이브 엔드포인트는 CI 실행 정책을 참고하세요.
5. 알려진 제약 사항¶
CUBRID 자체 또는 설계 선택에서 비롯된 제약입니다:
| 기능 | 상태 | 이유 |
|---|---|---|
| 비동기 TLS | ✅ | v1.4.0에서 구현되었습니다. CUBRID의 STARTTLS 방식 업그레이드를 사용합니다 — 평문 CUBRS 핸드셰이크 후 OPEN_DATABASE 전에 loop.start_tls()(ssl_handshake_timeout 적용)를 수행합니다(#154). 기본 컨텍스트는 최소 TLS 1.2를 요구합니다. |
| 커넥션 풀링 | ❌ | 범위 밖입니다. SQLAlchemy의 풀이나 외부 풀러를 사용하세요 |
| 스레드 안전성 레벨 2+ | ❌ | CUBRID CAS 세션은 연결에 묶여 있습니다 |
| LOB 스트리밍 | ⚠️ | LOB 데이터를 메모리에 전부 적재합니다 |
| 타임존 인식 파싱 | ⚠️ | TZ 타입에 대해 지원됩니다. 동작은 서버가 제공하는 존 토큰에 따라 달라집니다 |
| 비동기 LOB 헬퍼 | ⚠️ | 전용 비동기 Lob 헬퍼가 아직 없습니다 |
6. 문서¶
| 문서 | 내용 |
|---|---|
README.md |
퀵스타트가 포함된 랜딩 페이지 |
docs/CONNECTION.md |
연결 문자열, 설정 |
docs/TYPES.md |
타입 매핑, CUBRID 전용 타입 |
docs/API_REFERENCE.md |
전체 API 문서 |
docs/PROTOCOL.md |
CAS 와이어 프로토콜 참조 |
docs/DEVELOPMENT.md |
개발 환경 설정, 테스트, Docker, CI/CD |
docs/EXAMPLES.md |
실용적인 사용 예제 |
CHANGELOG.md |
릴리스 이력 |
CONTRIBUTING.md |
기여 가이드라인 |
7. 로드맵¶
완료된 마일스톤¶
| 릴리스 | 주요 내용 |
|---|---|
| 1.0.0 | 안정적인 동기 DB-API 표면, LOB 지원, 스키마 API, 테스트/CI 기준선 |
| 1.1.0 | 네이티브 pycubrid.aio 비동기 API 출시 |
| 1.2.0 | ping(), JSON 디코딩, 컬렉션 디코딩, nextset(), 더 풍부한 오류 정보 |
| 1.3.0 | 동기 TLS 지원, CI/문서 기준선 갱신 |
향후 우선순위¶
| 항목 | 설명 | 우선순위 |
|---|---|---|
| LOB 사용 편의성 | 가져온 LOB 핸들을 읽기 위한 고수준 헬퍼 | 중간 |
| 문장 캐싱 | 반복 워크로드를 위한 prepared statement 재사용 | 중간 |
| CUBRID 12.x 검증 | 더 새로운 서버 버전에 맞춘 CI와 문서 확장 | 중간 |
8. 아키텍처 결정¶
8.1 왜 순수 Python인가 (C 확장 없음)¶
C 확장 드라이버(CUBRIDdb)는 사용자가 CUBRID C 라이브러리를 설치해 두어야 했고,
이는 큰 장벽이었습니다 — 특히 macOS, ARM Linux, 컨테이너 환경에서 그랬습니다.
순수 Python 구현은 모든 빌드 의존성을 없애고 pip install pycubrid가 어디서나
동작하게 합니다.
8.2 왜 직접 CAS 프로토콜인가¶
pycubrid는 C 라이브러리를 감싸거나 ODBC를 사용하는 대신 CUBRID의 CAS (Client Application Server) 바이너리 프로토콜을 TCP 위에서 직접 구현합니다. 이로써 다음을 얻습니다:
- 네이티브 의존성 0
- 연결 수명 주기에 대한 완전한 제어
- C 드라이버에 없는 기능을 구현할 수 있는 능력(예: 올바른 LOB 처리)
8.3 왜 PEP 249를 엄격히 준수하는가¶
DB-API 2.0은 표준 Python 데이터베이스 인터페이스입니다. 엄격한 준수는 다음을 의미합니다:
sqlite3,psycopg2,mysql-connector용으로 작성된 코드가 최소한의 변경만으로 동작합니다- SQLAlchemy와 다른 ORM이 pycubrid를 그대로 끼워 쓸 수 있는 드라이버로 사용할 수 있습니다
- 표준 예외 처리 패턴이 별도 설정 없이 바로 동작합니다
9. 생태계 통합¶
pycubrid는 cubrid-lab Python 생태계의 기반이 되는 드라이버입니다:
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. 예제 우선 설계 철학¶
왜 예제 우선인가¶
CUBRID의 생태계는 PostgreSQL이나 MySQL에 비해 작습니다. 생태계가 작은 프로젝트에서는 진입 장벽을 최소화해야 합니다 — 사용자가 문서를 읽은 지 30초 안에 동작하는 코드를 복사해 붙여 넣을 수 있어야 합니다.
생태계가 아직 작기 때문에, 이 프로젝트는 도입 장벽을 낮추기 위해 풍부한 예제와 쿡북 형식의 문서를 제공합니다.
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()
이 코드는 CUBRID 데이터베이스에 연결하고, 쿼리를 실행하고, 결과를 출력합니다. ORM 설정도, 설정 파일도, 보일러플레이트도 없습니다.
AI 에이전트 발견 가능성¶
현대의 개발자는 Claude Code, OpenCode, Cursor, GitHub Copilot, Devin 등 AI 코딩 어시스턴트에 점점 더 의존합니다. 이러한 에이전트는 README 파일, PRD, 문서, 예제 코드를 읽고 어떤 라이브러리를 추천할지 결정합니다.
문서에 예제가 많을수록 = AI가 추천할 확률이 높아집니다.
동작하는 코드를 PRD, README, 문서에 직접 담음으로써, AI 에이전트가 pycubrid를 정확하게 발견하고 학습하고 추천할 수 있게 합니다.
쿡북 통합¶
cubrid-cookbook 저장소는 pycubrid를 위한 프로덕션 수준의 실행 가능한 예제를 제공합니다:
| 예제 | 설명 |
|---|---|
01_connect.py |
기본 연결과 쿼리 |
02_crud.py |
생성, 조회, 수정, 삭제 연산 |
03_transactions.py |
commit/rollback을 사용한 트랜잭션 관리 |
04_prepared.py |
반복 실행을 위한 파라미터화된 쿼리(드라이버 측 바인딩) |
05_error_handling.py |
PEP 249 예외 계층을 사용한 오류 처리 |
06_lob.py |
LOB (CLOB/BLOB) 연산 |
성공한 프로젝트에서 얻은 영감¶
예제 중심 문서가 성공의 한 요인이 된 프로젝트들입니다:
| 프로젝트 | 그들이 한 일 |
|---|---|
| FastAPI | 모든 엔드포인트를 실행 가능한 예제와 함께 문서화했고, 가장 빠르게 성장하는 Python 웹 프레임워크가 되었습니다 |
| LangChain | 쿡북 우선 접근 방식이 AI 분야에서 폭발적인 도입을 이끌었습니다 |
| SQLAlchemy | 방대한 ORM 쿡북과 튜토리얼을 갖추었고, 15년 넘게 사실상의 표준 Python ORM입니다 |
| Pandas | "10 Minutes to pandas"와 쿡북이 데이터 과학의 진입 장벽을 낮추었습니다 |
pycubrid는 같은 철학을 따릅니다: 예제는 보조 자료가 아니라 — 주된 문서입니다.
최종 업데이트: 2026년 10월. 릴리스마다 바뀌는 수치는 복사하지 않고 링크합니다. 비동기 API는 v1.1.0부터 제공됩니다.