diff options
author | snermolaev <snermolaev@yandex-team.com> | 2025-04-14 06:15:42 +0300 |
---|---|---|
committer | snermolaev <snermolaev@yandex-team.com> | 2025-04-14 06:28:07 +0300 |
commit | 76887f61431dc5999139a8d72882449ca1503660 (patch) | |
tree | b43f61cd54ca09511f92e812bc782d2d8c849374 /library/python/runtime_py3/test/subinterpreter/stdout_interceptor.cpp | |
parent | 8a826652922c8304490262de6bbb69eb1a9b5751 (diff) | |
download | ydb-76887f61431dc5999139a8d72882449ca1503660.tar.gz |
Subinterpretor compatible __res module
Cython is not yet subinterpreter compatible. There are no ETA when cython is going to support subinterpreters.
This PR removes cython from hermetic python imoprt hooks in order to make them subinterpretr-compatible.
commit_hash:1b067c37f55a4f1d9a6172df7009c75231cc1e25
Diffstat (limited to 'library/python/runtime_py3/test/subinterpreter/stdout_interceptor.cpp')
-rw-r--r-- | library/python/runtime_py3/test/subinterpreter/stdout_interceptor.cpp | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/library/python/runtime_py3/test/subinterpreter/stdout_interceptor.cpp b/library/python/runtime_py3/test/subinterpreter/stdout_interceptor.cpp new file mode 100644 index 00000000000..3cd4b69d012 --- /dev/null +++ b/library/python/runtime_py3/test/subinterpreter/stdout_interceptor.cpp @@ -0,0 +1,77 @@ +#include "stdout_interceptor.h" + +#include <util/stream/output.h> + +namespace { + +struct TOStreamWrapper { + PyObject_HEAD + IOutputStream* Stm = nullptr; +}; + +PyObject* Write(TOStreamWrapper *self, PyObject *const *args, Py_ssize_t nargs) noexcept { + try { + Py_buffer view; + for (Py_ssize_t i = 0; i < nargs; ++i) { + PyObject* buf = args[i]; + if (PyUnicode_Check(args[i])) { + buf = PyUnicode_AsUTF8String(buf); + if (!buf) { + return nullptr; + } + } + + if (PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE | PyBUF_C_CONTIGUOUS) == -1) { + return nullptr; + } + self->Stm->Write(reinterpret_cast<const char*>(view.buf), view.len); + PyBuffer_Release(&view); + } + + return Py_None; + } catch(const std::exception& err) { + PyErr_SetString(PyExc_IOError, err.what()); + } catch (...) { + PyErr_SetString(PyExc_RuntimeError, "Unhandled C++ exception of unknown type"); + } + return nullptr; +} + +PyMethodDef TOStreamWrapperMethods[] = { + {"write", reinterpret_cast<PyCFunction>(Write), METH_FASTCALL, PyDoc_STR("write buffer to wrapped C++ stream")}, + {} +}; + +PyTypeObject TOStreamWrapperType { + .ob_base = PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "testwrap.OStream", + .tp_basicsize = sizeof(TOStreamWrapper), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = PyDoc_STR("C++ IOStream wrapper"), + .tp_methods = TOStreamWrapperMethods, + .tp_new = PyType_GenericNew, +}; + +} + +TPyStdoutInterceptor::TPyStdoutInterceptor(IOutputStream& redirectionStream) noexcept + : RealStdout_{PySys_GetObject("stdout")} +{ + Py_INCREF(RealStdout_); + + PyObject* redirect = TOStreamWrapperType.tp_alloc(&TOStreamWrapperType, 0); + reinterpret_cast<TOStreamWrapper*>(redirect)->Stm = &redirectionStream; + + PySys_SetObject("stdout", redirect); + Py_DECREF(redirect); +} + +TPyStdoutInterceptor::~TPyStdoutInterceptor() noexcept { + PySys_SetObject("stdout", RealStdout_); + Py_DECREF(RealStdout_); +} + +bool TPyStdoutInterceptor::SetupInterceptionSupport() noexcept { + return PyType_Ready(&TOStreamWrapperType) == 0; +} |