Skip to content

Commit 7d81799

Browse files
committed
Preliminarily support Redis ChunkStore in Python, remove exceptions from PyBind11 submodules
1 parent c94e6c8 commit 7d81799

File tree

20 files changed

+281
-188
lines changed

20 files changed

+281
-188
lines changed

CMakeLists.txt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,12 @@ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src/cppack)
7979

8080
include(FetchContent)
8181
set(BUILD_TESTING_BACKUP ${BUILD_TESTING})
82-
set(BUILD_TESTING OFF)
8382
set(USE_SYSTEM_ABSEIL_BACKUP ${USE_SYSTEM_ABSEIL})
8483
set(USE_SYSTEM_PYBIND_BACKUP ${USE_SYSTEM_PYBIND})
84+
set(BUILD_TESTING OFF)
8585
set(USE_SYSTEM_ABSEIL ON)
8686
set(USE_SYSTEM_PYBIND ON)
87-
FetchContent_Declare(
88-
pybind11_abseil
89-
GIT_REPOSITORY https://github.com/pybind/pybind11_abseil.git
90-
GIT_TAG master
91-
)
92-
FetchContent_MakeAvailable(pybind11_abseil)
87+
add_subdirectory(${EGLT_THIRD_PARTY_ROOT}/pybind11_abseil)
9388
set(BUILD_TESTING ${BUILD_TESTING_BACKUP})
9489
set(USE_SYSTEM_ABSEIL ${USE_SYSTEM_ABSEIL_BACKUP})
9590
set(USE_SYSTEM_PYBIND ${USE_SYSTEM_PYBIND_BACKUP})

build_pybindings_for_dev.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ repo_root=$(pwd)
77
echo "Building project..."
88
cd build
99
CC=clang CXX=clang++ cmake --build . --parallel "${nproc}" --target evergreen_pybind11
10+
CC=clang CXX=clang++ cmake --build . --parallel "${nproc}" --target pybind11_abseil
1011

1112
echo "Moving compiled files to Python code directory..."
1213
cd "$repo_root"
1314
mv build/src/evergreen_pybind11*.so py/evergreen/
15+
mv build/src/pybind11_abseil_module/pybind11_abseil*.so py/evergreen/
1416
rm -rf install
1517

1618
if [[ "$1" == "--only-rebuild-pybind11" ]]; then

py/evergreen/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from evergreen import stream as eg_stream
1010
from evergreen import data
1111
from evergreen import pydantic_helpers
12+
from evergreen import redis
1213
from evergreen import utils
1314
from evergreen import webrtc
1415
from evergreen import websockets

py/evergreen/redis.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from evergreen.evergreen_pybind11 import redis as redis_pybind11
2+
3+
Redis = redis_pybind11.Redis
4+
ChunkStore = redis_pybind11.ChunkStore

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ add_subdirectory(eglt/redis)
4949
add_subdirectory(eglt/service)
5050
add_subdirectory(eglt/stores)
5151
add_subdirectory(eglt/util)
52+
add_subdirectory(pybind11_abseil_module)
5253

5354
# ------------------------------------------------------------------
5455

src/eglt/actions/actions_pybind11.cc

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,11 @@ void BindAction(py::handle scope, std::string_view name) {
110110
return std::make_shared<Action>(std::move(schema), id);
111111
}))
112112
.def("run",
113-
[](const std::shared_ptr<Action>& action) {
114-
if (const absl::Status status = action->Run(); !status.ok()) {
115-
throw std::runtime_error(status.ToString());
116-
}
117-
})
113+
[](const std::shared_ptr<Action>& action) { return action->Run(); })
118114
.def(
119115
"call",
120116
[](const std::shared_ptr<Action>& action) {
121-
if (const absl::Status status = action->Call(); !status.ok()) {
122-
throw py::value_error(status.ToString());
123-
}
117+
return action->Call();
124118
},
125119
py::call_guard<py::gil_scoped_release>())
126120
.def(

src/eglt/data/data_pybind11.cc

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@
1818
#include <string_view>
1919
#include <vector>
2020

21+
#include <pybind11/pybind11.h>
22+
#include <pybind11_abseil/status_caster.h>
23+
#include <pybind11_abseil/statusor_caster.h>
24+
2125
#include "eglt/data/eg_structs.h"
2226
#include "eglt/data/serialization.h"
2327
#include "eglt/pybind11_headers.h"
28+
#include "eglt/util/status_macros.h"
2429
#include "eglt/util/utils_pybind11.h"
2530

2631
namespace eglt::pybindings {
@@ -187,20 +192,24 @@ void BindSerializerRegistry(py::handle scope, std::string_view name) {
187192
py::class_<SerializerRegistry, std::shared_ptr<SerializerRegistry>>(
188193
scope, std::string(name).c_str());
189194
registry.def(MakeSameObjectRefConstructor<SerializerRegistry>());
195+
190196
registry.def(
191197
py::init([]() { return std::make_shared<SerializerRegistry>(); }));
198+
192199
registry.def_property_readonly(
193200
"_mimetype_to_type", [](const std::shared_ptr<SerializerRegistry>& self) {
194201
return GetMimetypeToTypeDict(self.get());
195202
});
203+
196204
registry.def_property_readonly(
197205
"_type_to_mimetype", [](const std::shared_ptr<SerializerRegistry>& self) {
198206
return GetTypeToMimetypeDict(self.get());
199207
});
208+
200209
registry.def(
201210
"serialize",
202211
[](const std::shared_ptr<SerializerRegistry>& self, py::handle value,
203-
std::string_view mimetype) -> py::bytes {
212+
std::string_view mimetype) -> absl::StatusOr<py::bytes> {
204213
auto mimetype_str = std::string(mimetype);
205214
if (mimetype_str.empty()) {
206215
auto type_to_mimetype = GetTypeToMimetypeDict(self.get());
@@ -218,38 +227,28 @@ void BindSerializerRegistry(py::handle scope, std::string_view name) {
218227
py::gil_scoped_release release_gil;
219228
serialized = self->Serialize(value, mimetype_str);
220229
if (!serialized.ok()) {
221-
auto cpp_any = CastPyObjectToAny(std::move(value), mimetype_str);
222-
if (!cpp_any.ok()) {
223-
throw py::value_error(
224-
absl::StrCat("Failed to convert value to std::any: ",
225-
cpp_any.status().message()));
226-
}
227-
228-
serialized = self->Serialize(*std::move(cpp_any), mimetype_str);
230+
ASSIGN_OR_RETURN(std::any cpp_any,
231+
CastPyObjectToAny(std::move(value), mimetype_str));
232+
serialized = self->Serialize(std::move(cpp_any), mimetype_str);
229233
}
230234
}
231-
if (!serialized.ok()) {
232-
throw py::value_error(absl::StrCat("Failed to serialize value: ",
233-
serialized.status().message()));
234-
}
235+
RETURN_IF_ERROR(serialized.status());
235236
return py::bytes(std::move(*serialized));
236237
},
237238
py::arg("value"), py::arg_v("mimetype", ""));
239+
238240
registry.def(
239241
"deserialize",
240242
[](const std::shared_ptr<SerializerRegistry>& self, py::bytes data,
241-
std::string_view mimetype) -> py::object {
243+
std::string_view mimetype) -> absl::StatusOr<py::object> {
242244
absl::StatusOr<std::any> deserialized;
243245
{
244246
py::gil_scoped_release release_gil;
245247
deserialized = self->Deserialize(std::move(data), mimetype);
246248
}
247-
if (!deserialized.ok()) {
248-
throw py::value_error(absl::StrCat("Failed to deserialize data: ",
249-
deserialized.status().message()));
250-
}
249+
RETURN_IF_ERROR(deserialized.status());
251250
if (std::any_cast<py::object>(&*deserialized) == nullptr) {
252-
throw py::type_error(
251+
return absl::InvalidArgumentError(
253252
absl::StrCat("Deserialized object is not a py::object, but a ",
254253
deserialized->type().name(),
255254
". Cannot convert to py::object because it's not "
@@ -259,14 +258,15 @@ void BindSerializerRegistry(py::handle scope, std::string_view name) {
259258
return std::any_cast<py::object>(*std::move(deserialized));
260259
},
261260
py::arg("data"), py::arg_v("mimetype", ""));
261+
262262
registry.def(
263263
"register_serializer",
264264
[](const std::shared_ptr<SerializerRegistry>& self,
265265
std::string_view mimetype, const py::function& serializer,
266266
const py::object& obj_type = py::none()) {
267267
if (!obj_type.is_none()) {
268268
if (!py::isinstance<py::type>(obj_type)) {
269-
throw py::type_error(
269+
return absl::InvalidArgumentError(
270270
"obj_type must be a type, not an instance or other object.");
271271
}
272272
// Register the mimetype with the type.
@@ -276,6 +276,7 @@ void BindSerializerRegistry(py::handle scope, std::string_view name) {
276276
}
277277
self->RegisterSerializer(std::string(mimetype),
278278
PySerializerToCppSerializer(serializer));
279+
return absl::OkStatus();
279280
},
280281
py::arg("mimetype"), py::arg("serializer"),
281282
py::arg_v("obj_type", py::none()), py::keep_alive<1, 3>());
@@ -286,9 +287,8 @@ void BindSerializerRegistry(py::handle scope, std::string_view name) {
286287
const py::object& obj_type = py::none()) {
287288
if (!obj_type.is_none()) {
288289
if (!py::isinstance<py::type>(obj_type)) {
289-
throw py::type_error(
290-
"obj_type must be a type, not an instance or other "
291-
"object.");
290+
return absl::InvalidArgumentError(
291+
"obj_type must be a type, not an instance or other object.");
292292
}
293293
// Register the mimetype with the type.
294294
auto mimetype_str = std::string(mimetype);
@@ -298,6 +298,7 @@ void BindSerializerRegistry(py::handle scope, std::string_view name) {
298298
self->RegisterDeserializer(
299299
std::string(mimetype),
300300
PyDeserializerToCppDeserializer(deserializer));
301+
return absl::OkStatus();
301302
},
302303
py::keep_alive<1, 3>());
303304
registry.def("__del__", [](const std::shared_ptr<SerializerRegistry>& self) {
@@ -326,25 +327,27 @@ py::module_ MakeDataModule(py::module_ scope, std::string_view module_name) {
326327
data.def(
327328
"to_bytes",
328329
[](py::handle obj, std::string_view mimetype = "",
329-
SerializerRegistry* registry = nullptr) -> py::bytes {
330-
return pybindings::PyToChunk(std::move(obj), mimetype, registry).data;
330+
SerializerRegistry* registry = nullptr) -> absl::StatusOr<py::bytes> {
331+
ASSIGN_OR_RETURN(Chunk chunk, pybindings::PyToChunk(
332+
std::move(obj), mimetype, registry));
333+
return std::move(chunk.data);
331334
},
332335
py::arg("obj"), py::arg_v("mimetype", ""),
333336
py::arg_v("registry", nullptr));
334337

335338
data.def(
336339
"to_chunk",
337340
[](py::handle obj, std::string_view mimetype = "",
338-
SerializerRegistry* registry = nullptr) {
339-
return pybindings::PyToChunk(std::move(obj), mimetype, registry);
341+
SerializerRegistry* registry = nullptr) -> absl::StatusOr<Chunk> {
342+
return pybindings::PyToChunk(obj, mimetype, registry);
340343
},
341344
py::arg("obj"), py::arg_v("mimetype", ""),
342345
py::arg_v("registry", nullptr));
343346

344347
data.def(
345348
"from_chunk",
346349
[](Chunk chunk, std::string_view mimetype = "",
347-
const SerializerRegistry* registry = nullptr) -> py::object {
350+
const SerializerRegistry* registry = nullptr) {
348351
return pybindings::PyFromChunk(std::move(chunk), mimetype, registry);
349352
},
350353
py::arg("chunk"), py::arg_v("mimetype", ""),

src/eglt/data/data_pybind11.h

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
#include <string_view>
1919

2020
#include <pybind11/pybind11.h>
21+
#include <pybind11_abseil/status_caster.h>
22+
#include <pybind11_abseil/statusor_caster.h>
2123

2224
#include "eglt/data/serialization.h"
25+
#include "eglt/util/status_macros.h"
2326

2427
namespace eglt {
2528
namespace py = ::pybind11;
@@ -238,8 +241,9 @@ inline absl::Status EgltAssignInto(pybind11::handle obj, std::string* dest) {
238241

239242
namespace eglt::pybindings {
240243

241-
inline Chunk PyToChunk(py::handle obj, std::string_view mimetype = "",
242-
SerializerRegistry* registry = nullptr) {
244+
inline absl::StatusOr<Chunk> PyToChunk(py::handle obj,
245+
std::string_view mimetype = "",
246+
SerializerRegistry* registry = nullptr) {
243247
auto mimetype_str = std::string(mimetype);
244248

245249
if (registry == nullptr) {
@@ -260,16 +264,10 @@ inline Chunk PyToChunk(py::handle obj, std::string_view mimetype = "",
260264
}
261265

262266
if (mimetype_str.empty()) {
263-
absl::StatusOr<Chunk> chunk;
264267
{
265268
py::gil_scoped_release release; // Release GIL for serialization.
266-
chunk = ConvertTo<Chunk>(std::move(obj));
269+
return ConvertTo<Chunk>(obj);
267270
}
268-
if (!chunk.ok()) {
269-
throw py::value_error(absl::StrCat("Failed to convert object to Chunk: ",
270-
chunk.status().message()));
271-
}
272-
return *std::move(chunk);
273271
}
274272

275273
absl::StatusOr<Chunk> serialized_chunk;
@@ -279,33 +277,30 @@ inline Chunk PyToChunk(py::handle obj, std::string_view mimetype = "",
279277
if (!serialized_chunk.ok()) {
280278
serialized_chunk =
281279
ToChunk(ConvertToOrDie<std::any>(pybindings::PySerializationArgs{
282-
.object = std::move(obj), .mimetype = mimetype_str}),
280+
.object = obj, .mimetype = mimetype_str}),
283281
mimetype_str, registry);
284282
}
285283
}
286284

287-
if (!serialized_chunk.ok()) {
288-
throw py::value_error(std::string(serialized_chunk.status().message()));
289-
}
285+
RETURN_IF_ERROR(serialized_chunk.status());
290286
return *std::move(serialized_chunk);
291287
}
292288

293-
inline py::object PyFromChunk(Chunk chunk, std::string_view mimetype = "",
294-
const SerializerRegistry* registry = nullptr) {
289+
inline absl::StatusOr<py::object> PyFromChunk(
290+
Chunk chunk, std::string_view mimetype = "",
291+
const SerializerRegistry* registry = nullptr) {
295292
absl::StatusOr<std::any> obj;
296293
{
297294
py::gil_scoped_release release; // Release GIL for deserialization.
298295
obj = FromChunk(std::move(chunk), mimetype, registry);
299296
}
300-
if (!obj.ok()) {
301-
throw py::value_error(absl::StrCat("Failed to convert Chunk to object: ",
302-
obj.status().message()));
303-
}
297+
RETURN_IF_ERROR(obj.status());
304298

305299
if (std::any_cast<py::object>(&*obj) == nullptr) {
306-
throw py::type_error(absl::StrCat(
300+
return absl::InvalidArgumentError(absl::StrCat(
307301
"Deserialized object is not a py::object, but a ", obj->type().name(),
308-
". Cannot convert to py::object because it's not implemented yet."));
302+
". Cannot convert to py::object because it's not "
303+
"implemented yet."));
309304
}
310305

311306
return std::any_cast<py::object>(*std::move(obj));

src/eglt/evergreen_pybind11.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <pybind11/detail/common.h>
1919
#include <pybind11/pybind11.h>
2020
#include <pybind11/pytypes.h>
21+
#include <pybind11_abseil/check_status_module_imported.h>
2122

2223
#include "eglt/actions/actions_pybind11.h"
2324
#include "eglt/data/data_pybind11.h"
@@ -33,6 +34,12 @@ namespace eglt {
3334
/// @private
3435
PYBIND11_MODULE(evergreen_pybind11, m) {
3536
absl::InstallFailureSignalHandler({});
37+
if (!pybind11::google::internal::IsStatusModuleImported()) {
38+
py::module_::import("evergreen.pybind11_abseil.status");
39+
// importing under a custom path/name, so just in case check that the
40+
// library understands our import.
41+
py::google::internal::CheckStatusModuleImported();
42+
}
3643

3744
py::module_ data = pybindings::MakeDataModule(m, "data");
3845

0 commit comments

Comments
 (0)