Action Engine
Loading...
Searching...
No Matches
data_pybind11.h
1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef ACTIONENGINE_PYBIND11_ACTIONENGINE_DATA_H_
16#define ACTIONENGINE_PYBIND11_ACTIONENGINE_DATA_H_
17
18#include <string_view>
19
20#include <pybind11/pybind11.h>
21#include <pybind11/stl.h>
22#include <pybind11/stl_bind.h>
23#include <pybind11_abseil/status_caster.h>
24#include <pybind11_abseil/statusor_caster.h>
25
26#include "actionengine/data/serialization.h"
28#include "actionengine/util/status_macros.h"
29
30PYBIND11_MAKE_OPAQUE(std::vector<act::Port>);
31PYBIND11_MAKE_OPAQUE(std::vector<act::NodeFragment>);
32PYBIND11_MAKE_OPAQUE(std::vector<act::ActionMessage>);
33
34namespace act {
35namespace py = ::pybind11;
36
37namespace pybindings {
38
39void EnsureMimetypeAssociations(SerializerRegistry* registry);
40
41py::dict GetMimetypeToTypeDict(SerializerRegistry* registry);
42
43py::dict GetTypeToMimetypeDict(SerializerRegistry* registry);
44
45py::dict GetGlobalTypeToMimetype();
46
47struct PySerializationArgs {
48 py::handle object;
49 std::string_view mimetype;
50};
51
52template <typename T>
53concept PyObjectEgltConvertsTo = requires(py::handle obj) {
54 {EgltAssignInto(std::move(obj), std::declval<T*>())}
55 ->std::same_as<absl::Status>;
56};
57
58using PyObjectToStdAnyCaster =
59 std::function<absl::StatusOr<std::any>(py::handle)>;
60
61template <typename T>
62PyObjectToStdAnyCaster MakeDefaultPyObjectToStdAnyCaster() {
63 return [](py::handle obj) -> absl::StatusOr<std::any> {
64 if (obj.is_none()) {
65 return absl::InvalidArgumentError(
66 "Cannot convert None to a C++ type. Please provide a valid object.");
67 }
68
69 try {
70 auto pybind11_conversion = py::cast<T>(obj);
71 return std::any(std::move(pybind11_conversion));
72 } catch (const py::cast_error& e) {
73 return absl::InvalidArgumentError(absl::StrCat(
74 "Failed to cast object to ", typeid(T).name(), ": ", e.what()));
75 }
76 };
77}
78
79template <typename T>
80PyObjectToStdAnyCaster MakeDefaultPyObjectToStdAnyCaster()
81 requires(PyObjectEgltConvertsTo<T>) {
82 return [](py::handle obj) -> absl::StatusOr<std::any> {
83 if (obj.is_none()) {
84 return absl::InvalidArgumentError(
85 "Cannot convert None to a C++ type. Please provide a valid object.");
86 }
87
88 auto act_provided_conversion = act::ConvertTo<T>(obj);
89 if (act_provided_conversion.ok()) {
90 return std::any(std::move(*act_provided_conversion));
91 }
92
93 try {
94 auto pybind11_conversion = py::cast<T>(std::move(obj));
95 return std::any(std::move(pybind11_conversion));
96 } catch (const py::cast_error& e) {
97 return absl::InvalidArgumentError(absl::StrCat(
98 "Failed to cast object to ", typeid(T).name(), ": ", e.what()));
99 }
100 };
101}
102
103absl::flat_hash_map<std::string, PyObjectToStdAnyCaster>&
104GetCastersForMimetypes();
105
106absl::StatusOr<std::any> CastPyObjectToAny(py::handle obj,
107 std::string_view mimetype = "");
108
109absl::Status EgltAssignInto(PySerializationArgs args, std::any* dest);
110
111} // namespace pybindings
112} // namespace act
113
114namespace act {
115absl::Status EgltAssignInto(const py::handle& obj, Chunk* chunk);
116} // namespace act
117
118namespace pybind11 {
119absl::Status EgltAssignInto(pybind11::handle obj, std::string* dest);
120} // namespace pybind11
121
122namespace act::pybindings {
123
124absl::StatusOr<Chunk> PyToChunk(py::handle obj, std::string_view mimetype = "",
125 SerializerRegistry* registry = nullptr);
126
127absl::StatusOr<py::object> PyFromChunk(
128 Chunk chunk, std::string_view mimetype = "",
129 const SerializerRegistry* registry = nullptr);
130
131namespace py = pybind11;
132
133void BindChunkMetadata(py::handle scope,
134 std::string_view name = "ChunkMetadata");
135
136void BindChunk(py::handle scope, std::string_view name = "Chunk");
137
138void BindNodeFragment(py::handle scope, std::string_view name = "NodeFragment");
139
140void BindPort(py::handle scope, std::string_view name = "Port");
141
142void BindActionMessage(py::handle scope,
143 std::string_view name = "ActionMessage");
144
145void BindWireMessage(py::handle scope, std::string_view name = "WireMessage");
146
147void BindSerializerRegistry(py::handle scope,
148 std::string_view name = "SerializerRegistry");
149
150py::module_ MakeDataModule(py::module_ scope,
151 std::string_view module_name = "data");
152} // namespace act::pybindings
153
154#endif // ACTIONENGINE_PYBIND11_ACTIONENGINE_DATA_H_
Definition types.h:104
ActionEngine data structures used to implement actions and nodes (data streams).