Каркас Python-пакета `cuframes`: - python/pyproject.toml — scikit-build-core конфиг - python/CMakeLists.txt — pybind11 module через FetchContent - python/src/_native.cpp — module entry, error таксономия, enum mirrors (PixelFormat, SubscriberMode), version - python/cuframes/__init__.py — re-export публичного API - python/tests/test_smoke.py — smoke tests без real subscribe - python/README.md — статус + build instructions - CMakeLists.txt — подключение python/ при BUILD_PYTHON_BINDINGS=ON Реальный subscriber/frame wrapper в следующих коммитах (tasks #198-#202). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
// cuframes Python bindings — pybind11 entry point.
|
||||
//
|
||||
// Этот файл — skeleton модуля. Полноценные обёртки subscriber/frame появятся
|
||||
// в следующих коммитах (см. issue gx/cuframes#6, tasks #198-#202).
|
||||
//
|
||||
// Контракт thread-safety: см. docs/python.md (т.б.д. в task #202).
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "cuframes/cuframes.h"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace {
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Error taxonomy — Python exceptions, соответствующие cuframes_error_t.
|
||||
//
|
||||
// Принцип: каждая категория ошибок которая требует разной обработки в
|
||||
// downstream'е (reconnect vs retry vs fatal) → отдельный exception class.
|
||||
// Это решает требование из architect review: «detector должен уметь
|
||||
// reconnect-loop по publisher-gone, не падать».
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
struct CuframesExceptions {
|
||||
py::object base;
|
||||
py::object publisher_gone; // CUFRAMES_ERR_DISCONNECTED, _NOT_FOUND
|
||||
py::object frame_timeout; // CUFRAMES_ERR_TIMEOUT, _WOULD_BLOCK
|
||||
py::object device_lost; // CUFRAMES_ERR_CUDA
|
||||
py::object shm_error; // CUFRAMES_ERR_IO
|
||||
py::object protocol_mismatch; // CUFRAMES_ERR_PROTOCOL
|
||||
py::object invalid_argument; // CUFRAMES_ERR_INVALID_ARG
|
||||
py::object out_of_memory; // CUFRAMES_ERR_OUT_OF_MEMORY
|
||||
py::object internal; // CUFRAMES_ERR_INTERNAL, прочее
|
||||
};
|
||||
|
||||
CuframesExceptions g_exc;
|
||||
|
||||
// Маппинг cuframes_error_t → подходящий Python exception class.
|
||||
py::object exception_for(int err) {
|
||||
switch (err) {
|
||||
case CUFRAMES_ERR_NOT_FOUND:
|
||||
case CUFRAMES_ERR_DISCONNECTED:
|
||||
return g_exc.publisher_gone;
|
||||
case CUFRAMES_ERR_TIMEOUT:
|
||||
case CUFRAMES_ERR_WOULD_BLOCK:
|
||||
return g_exc.frame_timeout;
|
||||
case CUFRAMES_ERR_CUDA:
|
||||
return g_exc.device_lost;
|
||||
case CUFRAMES_ERR_IO:
|
||||
return g_exc.shm_error;
|
||||
case CUFRAMES_ERR_PROTOCOL:
|
||||
return g_exc.protocol_mismatch;
|
||||
case CUFRAMES_ERR_INVALID_ARG:
|
||||
return g_exc.invalid_argument;
|
||||
case CUFRAMES_ERR_OUT_OF_MEMORY:
|
||||
return g_exc.out_of_memory;
|
||||
default:
|
||||
return g_exc.internal;
|
||||
}
|
||||
}
|
||||
|
||||
// Бросает подходящий exception если err != CUFRAMES_OK.
|
||||
void check(int err, const char* operation = nullptr) {
|
||||
if (err == CUFRAMES_OK) return;
|
||||
const char* msg = cuframes_strerror(err);
|
||||
std::string what = operation
|
||||
? std::string(operation) + ": " + msg + " (code=" + std::to_string(err) + ")"
|
||||
: std::string(msg) + " (code=" + std::to_string(err) + ")";
|
||||
PyErr_SetString(exception_for(err).ptr(), what.c_str());
|
||||
throw py::error_already_set();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PYBIND11_MODULE(_native, m) {
|
||||
m.doc() = "cuframes — zero-copy CUDA frame sharing (native bindings)";
|
||||
|
||||
// ── Версия ──────────────────────────────────────────────────────────
|
||||
m.def("version_string", []() {
|
||||
return std::string(cuframes_version_string());
|
||||
}, "Runtime version of libcuframes (MAJOR.MINOR.PATCH).");
|
||||
|
||||
m.def("protocol_version", []() {
|
||||
return static_cast<uint32_t>(cuframes_protocol_version());
|
||||
}, "Wire-protocol version. Subscribers с разной версией не подключатся.");
|
||||
|
||||
m.attr("__binding_version__") = CUFRAMES_PY_BINDING_VERSION;
|
||||
|
||||
// ── Error taxonomy ──────────────────────────────────────────────────
|
||||
// Иерархия:
|
||||
// CuframesError (base)
|
||||
// ├── CuframesPublisherGone
|
||||
// ├── CuframesFrameTimeout
|
||||
// ├── CuframesDeviceLost
|
||||
// ├── CuframesShmError
|
||||
// ├── CuframesProtocolMismatch
|
||||
// ├── CuframesInvalidArgument
|
||||
// ├── CuframesOutOfMemory
|
||||
// └── CuframesInternal
|
||||
//
|
||||
// Downstream code может ловить либо конкретный subtype, либо CuframesError
|
||||
// как catch-all.
|
||||
|
||||
g_exc.base = py::exception<std::runtime_error>(m, "CuframesError").attr("__class__");
|
||||
auto make_subexc = [&m](const char* name) {
|
||||
return py::exception<std::runtime_error>(m, name, g_exc.base.ptr()).attr("__class__");
|
||||
};
|
||||
g_exc.publisher_gone = make_subexc("CuframesPublisherGone");
|
||||
g_exc.frame_timeout = make_subexc("CuframesFrameTimeout");
|
||||
g_exc.device_lost = make_subexc("CuframesDeviceLost");
|
||||
g_exc.shm_error = make_subexc("CuframesShmError");
|
||||
g_exc.protocol_mismatch = make_subexc("CuframesProtocolMismatch");
|
||||
g_exc.invalid_argument = make_subexc("CuframesInvalidArgument");
|
||||
g_exc.out_of_memory = make_subexc("CuframesOutOfMemory");
|
||||
g_exc.internal = make_subexc("CuframesInternal");
|
||||
|
||||
// ── Pixel formats (enum mirror) ─────────────────────────────────────
|
||||
py::enum_<cuframes_format_t>(m, "PixelFormat")
|
||||
.value("NV12", CUFRAMES_FORMAT_NV12)
|
||||
.value("YUV420P", CUFRAMES_FORMAT_YUV420P)
|
||||
.value("RGB", CUFRAMES_FORMAT_RGB)
|
||||
.value("BGR", CUFRAMES_FORMAT_BGR)
|
||||
.value("RGBA", CUFRAMES_FORMAT_RGBA)
|
||||
.value("GRAYSCALE", CUFRAMES_FORMAT_GRAYSCALE);
|
||||
|
||||
py::enum_<cuframes_subscriber_mode_t>(m, "SubscriberMode")
|
||||
.value("NEWEST_ONLY", CUFRAMES_MODE_NEWEST_ONLY)
|
||||
.value("STRICT_ORDER", CUFRAMES_MODE_STRICT_ORDER);
|
||||
|
||||
// TODO(task #198): CuframesSubscriber + CuframesFrame classes.
|
||||
// TODO(task #199): DLPack export.
|
||||
// TODO(task #200): Health/stats properties (потребует расширения C API).
|
||||
// TODO(task #201): Per-subscriber CUDA stream + thread-safety contract.
|
||||
}
|
||||
Reference in New Issue
Block a user