/* * Copyright 2025 Google LLC * * Licensed 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. */ #ifndef THIRD_PARTY_CEL_PYTHON_CEL_EXTENSION_H_ #define THIRD_PARTY_CEL_PYTHON_CEL_EXTENSION_H_ #include #include #include "absl/status/status.h" #include "compiler/compiler.h" #include "runtime/runtime_builder.h" #include "runtime/runtime_options.h" #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) // This include causes many issues if included in C++ environments that don't // support exceptions. The include is only needed for pybind11-based extension // implementations, so we can safely skip it in other cases. #include #endif namespace cel_python { // Base class used for pybind11-based extensions. It is not instantiable from // Python. class CelExtension { public: explicit CelExtension(std::string name, std::string alias = "", int version = -1) : name_(std::move(name)), alias_(std::move(alias)), version_(version) {} virtual ~CelExtension() = default; virtual cel::CompilerLibrary GetCompilerLibrary() { return cel::CompilerLibrary(name_, nullptr, nullptr); } virtual absl::Status ConfigureRuntime(cel::RuntimeBuilder& runtime_builder, const cel::RuntimeOptions& opts) { return absl::OkStatus(); } std::string name() const { return name_; } std::string alias() const { return alias_; } int version() const { return version_; } private: std::string name_; std::string alias_; int version_; }; #define CEL_MODULE_NAME "cel_expr_python.cel" // Macro for defining a pybind11 module for a CEL extension. The macro takes two // arguments: the name of the module and the name of the extension class. It // must be used after the extension class is defined. // // The extension class must implement the `CelExtension` interface defined // above and provide a public default constructor. // // Example: // // class SampleCelExtension : public cel_python::CelExtension { // ... // }; // // CEL_EXTENSION_MODULE(sample_cel_ext, SampleCelExtension); // #define CEL_EXTENSION_MODULE(module_name, class_name) \ PYBIND11_MODULE(module_name, m, pybind11::mod_gil_not_used()) { \ pybind11::module_::import(CEL_MODULE_NAME); \ pybind11::class_(m, #class_name) \ .def(pybind11::init<>()); \ } #define CEL_VERSIONED_EXTENSION_MODULE(module_name, class_name) \ PYBIND11_MODULE(module_name, m, pybind11::mod_gil_not_used()) { \ pybind11::module_::import(CEL_MODULE_NAME); \ pybind11::class_(m, #class_name) \ .def(pybind11::init<>()) \ .def(pybind11::init(), pybind11::arg("version")); \ } } // namespace cel_python #endif // THIRD_PARTY_CEL_PYTHON_CEL_EXTENSION_H_