| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "pybind11/pybind11.h" |
| #include "pybind11/stl.h" |
| #include "utils/pybind_util.h" |
| |
| #include "graphar/api/high_level_reader.h" |
| #include "graphar/api/high_level_writer.h" |
| #include "graphar/graph_info.h" |
| #include "graphar/types.h" |
| #include "graphar/version_parser.h" |
| |
| #define STRINGIFY(x) #x |
| #define MACRO_STRINGIFY(x) STRINGIFY(x) |
| |
| namespace py = pybind11; |
| |
| // Changed from PYBIND11_MODULE to a regular function |
| extern "C" void bind_high_level_api(pybind11::module_& m) { |
| // Bind Vertex class |
| auto vertex = py::class_<graphar::Vertex, std::shared_ptr<graphar::Vertex>>( |
| m, "Vertex"); |
| vertex.def("id", &graphar::Vertex::id) |
| .def("property", |
| [](const graphar::Vertex& self, const std::string& property) { |
| // We need to handle different property types |
| // For now, let's support common types used in examples |
| try { |
| return py::cast(self.property<int64_t>(property).value()); |
| } catch (...) { |
| try { |
| return py::cast(self.property<std::string>(property).value()); |
| } catch (...) { |
| throw std::runtime_error( |
| "Unsupported property type or property not found"); |
| } |
| } |
| }) |
| .def("IsValid", &graphar::Vertex::IsValid); |
| |
| // Bind Edge class |
| auto edge = |
| py::class_<graphar::Edge, std::shared_ptr<graphar::Edge>>(m, "Edge"); |
| edge.def("source", &graphar::Edge::source) |
| .def("destination", &graphar::Edge::destination) |
| .def("property", |
| [](const graphar::Edge& self, const std::string& property) { |
| // We need to handle different property types |
| // For now, let's support common types used in examples |
| try { |
| return py::cast(self.property<std::string>(property).value()); |
| } catch (...) { |
| try { |
| return py::cast(self.property<int64_t>(property).value()); |
| } catch (...) { |
| throw std::runtime_error( |
| "Unsupported property type or property not found"); |
| } |
| } |
| }) |
| .def("IsValid", &graphar::Edge::IsValid); |
| |
| // Bind VertexIter class |
| auto vertex_iter = |
| py::class_<graphar::VertexIter, std::shared_ptr<graphar::VertexIter>>( |
| m, "VertexIter"); |
| vertex_iter |
| .def("__iter__", |
| [](graphar::VertexIter& it) -> graphar::VertexIter& { return it; }) |
| .def("__next__", |
| [](graphar::VertexIter& it) { |
| // TODO: Implement proper end checking |
| auto vertex = *it; |
| ++it; |
| return vertex; |
| }) |
| .def("id", &graphar::VertexIter::id) |
| .def("property", |
| [](graphar::VertexIter& self, const std::string& property) { |
| // We need to handle different property types |
| // For now, let's support common types used in examples |
| try { |
| return py::cast(self.property<int64_t>(property).value()); |
| } catch (...) { |
| try { |
| return py::cast(self.property<std::string>(property).value()); |
| } catch (...) { |
| throw std::runtime_error( |
| "Unsupported property type or property not found"); |
| } |
| } |
| }); |
| |
| // Bind VerticesCollection class |
| auto vertices_collection = |
| py::class_<graphar::VerticesCollection, |
| std::shared_ptr<graphar::VerticesCollection>>( |
| m, "VerticesCollection"); |
| vertices_collection |
| .def( |
| "__iter__", |
| [](graphar::VerticesCollection& self) { |
| return py::make_iterator(self.begin(), self.end()); |
| }, |
| py::keep_alive<0, |
| 1>()) // Keep collection alive while iterator is used |
| .def("begin", &graphar::VerticesCollection::begin) |
| .def("end", &graphar::VerticesCollection::end) |
| .def("find", &graphar::VerticesCollection::find) |
| .def("size", &graphar::VerticesCollection::size) |
| .def_static( |
| "Make", [](const std::shared_ptr<graphar::GraphInfo>& graph_info, |
| const std::string& type) { |
| auto result = graphar::VerticesCollection::Make(graph_info, type); |
| return ThrowOrReturn(result); |
| }); |
| |
| // Bind EdgeIter class |
| auto edge_iter = |
| py::class_<graphar::EdgeIter, std::shared_ptr<graphar::EdgeIter>>( |
| m, "EdgeIter"); |
| edge_iter |
| .def("__iter__", |
| [](graphar::EdgeIter& it) -> graphar::EdgeIter& { return it; }) |
| .def("__next__", |
| [](graphar::EdgeIter& it) { |
| // TODO: Implement proper end checking |
| auto edge = *it; |
| ++it; |
| return edge; |
| }) |
| .def("source", &graphar::EdgeIter::source) |
| .def("destination", &graphar::EdgeIter::destination) |
| .def("property", |
| [](graphar::EdgeIter& self, const std::string& property) { |
| // We need to handle different property types |
| // For now, let's support common types used in examples |
| try { |
| return py::cast(self.property<std::string>(property).value()); |
| } catch (...) { |
| try { |
| return py::cast(self.property<int64_t>(property).value()); |
| } catch (...) { |
| throw std::runtime_error( |
| "Unsupported property type or property not found"); |
| } |
| } |
| }); |
| |
| // Bind EdgesCollection class |
| auto edges_collection = py::class_<graphar::EdgesCollection, |
| std::shared_ptr<graphar::EdgesCollection>>( |
| m, "EdgesCollection"); |
| edges_collection |
| .def( |
| "__iter__", |
| [](graphar::EdgesCollection& self) { |
| return py::make_iterator(self.begin(), self.end()); |
| }, |
| py::keep_alive<0, |
| 1>()) // Keep collection alive while iterator is used |
| .def("begin", &graphar::EdgesCollection::begin) |
| .def("end", &graphar::EdgesCollection::end) |
| .def("size", &graphar::EdgesCollection::size) |
| .def("find_src", &graphar::EdgesCollection::find_src) |
| .def("find_dst", &graphar::EdgesCollection::find_dst) |
| .def_static( |
| "Make", |
| [](const std::shared_ptr<graphar::GraphInfo>& graph_info, |
| const std::string& src_type, const std::string& edge_type, |
| const std::string& dst_type, graphar::AdjListType adj_list_type) { |
| auto result = graphar::EdgesCollection::Make( |
| graph_info, src_type, edge_type, dst_type, adj_list_type); |
| return ThrowOrReturn(result); |
| }); |
| |
| // Bind builder::Vertex class |
| auto builder_vertex = |
| py::class_<graphar::builder::Vertex, |
| std::shared_ptr<graphar::builder::Vertex>>(m, "BuilderVertex"); |
| builder_vertex.def(py::init<>()) |
| .def(py::init<graphar::IdType>()) |
| .def("GetId", &graphar::builder::Vertex::GetId) |
| .def("SetId", &graphar::builder::Vertex::SetId) |
| .def("Empty", &graphar::builder::Vertex::Empty) |
| .def("AddProperty", |
| [](graphar::builder::Vertex& self, const std::string& name, |
| const py::object& val) { |
| // Convert Python object to std::any |
| if (py::isinstance<py::int_>(val)) { |
| self.AddProperty(name, py::cast<int64_t>(val)); |
| } else if (py::isinstance<py::str>(val)) { |
| self.AddProperty(name, py::cast<std::string>(val)); |
| } else if (py::isinstance<py::list>(val)) { |
| // Handle list properties |
| py::list py_list = val.cast<py::list>(); |
| std::vector<std::string> string_list; |
| for (auto item : py_list) { |
| string_list.push_back(py::str(item).cast<std::string>()); |
| } |
| self.AddProperty(graphar::Cardinality::LIST, name, string_list); |
| } else { |
| throw std::runtime_error("Unsupported property type"); |
| } |
| }) |
| .def("GetProperty", |
| [](const graphar::builder::Vertex& self, |
| const std::string& property) { |
| const auto& prop = self.GetProperty(property); |
| // Try to cast to common types |
| try { |
| return py::cast(std::any_cast<int64_t>(prop)); |
| } catch (...) { |
| try { |
| return py::cast(std::any_cast<std::string>(prop)); |
| } catch (...) { |
| throw std::runtime_error("Unsupported property type"); |
| } |
| } |
| }) |
| .def("GetProperties", &graphar::builder::Vertex::GetProperties) |
| .def("ContainProperty", &graphar::builder::Vertex::ContainProperty); |
| |
| // WRITER |
| // Bind WriterOptions class |
| // TODO add csv_option_builder parquet_option_builder orc_option_builder |
| auto writer_options = |
| py::class_<graphar::WriterOptions, |
| std::shared_ptr<graphar::WriterOptions>>(m, "WriterOptions"); |
| // Bind builder::VerticesBuilder class |
| auto vertices_builder = |
| py::class_<graphar::builder::VerticesBuilder, |
| std::shared_ptr<graphar::builder::VerticesBuilder>>( |
| m, "VerticesBuilder"); |
| vertices_builder.def("Clear", &graphar::builder::VerticesBuilder::Clear) |
| .def("SetWriterOptions", |
| &graphar::builder::VerticesBuilder::SetWriterOptions) |
| .def("GetWriterOptions", |
| &graphar::builder::VerticesBuilder::GetWriterOptions) |
| .def("SetValidateLevel", |
| &graphar::builder::VerticesBuilder::SetValidateLevel) |
| .def("GetValidateLevel", |
| &graphar::builder::VerticesBuilder::GetValidateLevel) |
| .def( |
| "AddVertex", |
| [](graphar::builder::VerticesBuilder& self, |
| graphar::builder::Vertex& v, graphar::IdType index, |
| const graphar::ValidateLevel& validate_level) { |
| return CheckStatus(self.AddVertex(v, index, validate_level)); |
| }, |
| py::arg("v"), py::arg("index") = -1, |
| py::arg("validate_level") = graphar::ValidateLevel::default_validate) |
| .def("GetNum", &graphar::builder::VerticesBuilder::GetNum) |
| .def("Dump", [](graphar::builder::VerticesBuilder& self) { |
| return CheckStatus(self.Dump()); |
| }); |
| |
| // Static factory methods for VerticesBuilder |
| vertices_builder.def_static( |
| "Make", |
| [](const std::shared_ptr<graphar::VertexInfo>& vertex_info, |
| const std::string& prefix, |
| std::shared_ptr<graphar::WriterOptions> writer_options, |
| graphar::IdType start_vertex_index, |
| const graphar::ValidateLevel& validate_level) { |
| auto result = graphar::builder::VerticesBuilder::Make( |
| vertex_info, prefix, writer_options, start_vertex_index, |
| validate_level); |
| return ThrowOrReturn(result); |
| }, |
| py::arg("vertex_info"), py::arg("prefix"), |
| py::arg("writer_options") = nullptr, py::arg("start_vertex_index") = 0, |
| py::arg("validate_level") = graphar::ValidateLevel::no_validate); |
| |
| vertices_builder.def_static( |
| "Make", |
| [](const std::shared_ptr<graphar::GraphInfo>& graph_info, |
| const std::string& type, |
| std::shared_ptr<graphar::WriterOptions> writer_options, |
| graphar::IdType start_vertex_index, |
| const graphar::ValidateLevel& validate_level) { |
| auto result = graphar::builder::VerticesBuilder::Make( |
| graph_info, type, writer_options, start_vertex_index, |
| validate_level); |
| return ThrowOrReturn(result); |
| }, |
| py::arg("graph_info"), py::arg("type"), |
| py::arg("writer_options") = nullptr, py::arg("start_vertex_index") = 0, |
| py::arg("validate_level") = graphar::ValidateLevel::no_validate); |
| vertices_builder.def_static( |
| "Make", |
| [](const std::shared_ptr<graphar::VertexInfo>& vertex_info, |
| const std::string& prefix, graphar::IdType start_vertex_index) { |
| auto result = graphar::builder::VerticesBuilder::Make( |
| vertex_info, prefix, start_vertex_index); |
| return ThrowOrReturn(result); |
| }, |
| py::arg("vertex_info"), py::arg("prefix"), |
| py::arg("start_vertex_index") = 0); |
| |
| // Bind builder::Edge class |
| auto builder_edge = |
| py::class_<graphar::builder::Edge, |
| std::shared_ptr<graphar::builder::Edge>>(m, "BuilderEdge"); |
| builder_edge.def(py::init<graphar::IdType, graphar::IdType>()) |
| .def("Empty", &graphar::builder::Edge::Empty) |
| .def("GetSource", &graphar::builder::Edge::GetSource) |
| .def("GetDestination", &graphar::builder::Edge::GetDestination) |
| .def("AddProperty", |
| [](graphar::builder::Edge& self, const std::string& name, |
| const py::object& val) { |
| // Convert Python object to std::any |
| if (py::isinstance<py::int_>(val)) { |
| self.AddProperty(name, py::cast<int64_t>(val)); |
| } else if (py::isinstance<py::str>(val)) { |
| self.AddProperty(name, py::cast<std::string>(val)); |
| } else { |
| throw std::runtime_error("Unsupported property type"); |
| } |
| }) |
| .def("GetProperty", |
| [](const graphar::builder::Edge& self, const std::string& property) { |
| const auto& prop = self.GetProperty(property); |
| // Try to cast to common types |
| try { |
| return py::cast(std::any_cast<std::string>(prop)); |
| } catch (...) { |
| try { |
| return py::cast(std::any_cast<int64_t>(prop)); |
| } catch (...) { |
| throw std::runtime_error("Unsupported property type"); |
| } |
| } |
| }) |
| .def("GetProperties", &graphar::builder::Edge::GetProperties) |
| .def("ContainProperty", &graphar::builder::Edge::ContainProperty); |
| |
| // Bind builder::EdgesBuilder class |
| auto edges_builder = |
| py::class_<graphar::builder::EdgesBuilder, |
| std::shared_ptr<graphar::builder::EdgesBuilder>>( |
| m, "EdgesBuilder"); |
| edges_builder |
| .def("SetValidateLevel", |
| &graphar::builder::EdgesBuilder::SetValidateLevel) |
| .def("SetWriterOptions", |
| &graphar::builder::EdgesBuilder::SetWriterOptions) |
| .def("GetWriterOptions", |
| &graphar::builder::EdgesBuilder::GetWriterOptions) |
| .def("GetValidateLevel", |
| &graphar::builder::EdgesBuilder::GetValidateLevel) |
| .def("Clear", &graphar::builder::EdgesBuilder::Clear) |
| .def( |
| "AddEdge", |
| [](graphar::builder::EdgesBuilder& self, |
| const graphar::builder::Edge& e, |
| const graphar::ValidateLevel& validate_level) { |
| return CheckStatus(self.AddEdge(e, validate_level)); |
| }, |
| py::arg("e"), |
| py::arg("validate_level") = graphar::ValidateLevel::default_validate) |
| .def("GetNum", &graphar::builder::EdgesBuilder::GetNum) |
| .def("Dump", [](graphar::builder::EdgesBuilder& self) { |
| return CheckStatus(self.Dump()); |
| }); |
| |
| // Static factory methods for EdgesBuilder |
| edges_builder.def_static( |
| "Make", |
| [](const std::shared_ptr<graphar::EdgeInfo>& edge_info, |
| const std::string& prefix, graphar::AdjListType adj_list_type, |
| graphar::IdType num_vertices, |
| std::shared_ptr<graphar::WriterOptions> writer_options, |
| const graphar::ValidateLevel& validate_level) { |
| auto result = graphar::builder::EdgesBuilder::Make( |
| edge_info, prefix, adj_list_type, num_vertices, writer_options, |
| validate_level); |
| return ThrowOrReturn(result); |
| }, |
| py::arg("edge_info"), py::arg("prefix"), py::arg("adj_list_type"), |
| py::arg("num_vertices"), py::arg("writer_options") = nullptr, |
| py::arg("validate_level") = graphar::ValidateLevel::no_validate); |
| |
| edges_builder.def_static( |
| "Make", |
| [](const std::shared_ptr<graphar::GraphInfo>& graph_info, |
| const std::string& src_type, const std::string& edge_type, |
| const std::string& dst_type, const graphar::AdjListType& adj_list_type, |
| graphar::IdType num_vertices, |
| std::shared_ptr<graphar::WriterOptions> writer_options, |
| const graphar::ValidateLevel& validate_level) { |
| auto result = graphar::builder::EdgesBuilder::Make( |
| graph_info, src_type, edge_type, dst_type, adj_list_type, |
| num_vertices, writer_options, validate_level); |
| return ThrowOrReturn(result); |
| }, |
| py::arg("graph_info"), py::arg("src_type"), py::arg("edge_type"), |
| py::arg("dst_type"), py::arg("adj_list_type"), py::arg("num_vertices"), |
| py::arg("writer_options") = nullptr, |
| py::arg("validate_level") = graphar::ValidateLevel::no_validate); |
| } // namespace graphar |