| 212 | } |
| 213 | |
| 214 | Expected<std::unique_ptr<FilterInstance>> createInstance( |
| 215 | const FilterClass& klass, const std::string& params_json) override { |
| 216 | ensureInterpreter(); |
| 217 | py::gil_scoped_acquire gil; |
| 218 | try { |
| 219 | auto ns = std::make_shared<py::object>(py::dict()); |
| 220 | py::exec(klass.source, *ns); |
| 221 | py::dict& nsd = reinterpret_cast<py::dict&>(*ns); |
| 222 | if (!nsd.contains("T")) { |
| 223 | return PJ::unexpected("Python filter module must define a top-level class named 'T'"); |
| 224 | } |
| 225 | py::object cls = nsd["T"]; |
| 226 | py::object params; |
| 227 | if (params_json.empty() || params_json == "{}") { |
| 228 | params = py::dict(); |
| 229 | } else { |
| 230 | params = py::module_::import("json").attr("loads")(params_json); |
| 231 | } |
| 232 | if (!py::hasattr(cls, "create")) { |
| 233 | return PJ::unexpected("Python filter class 'T' must define a static create(params)"); |
| 234 | } |
| 235 | py::object instance = cls.attr("create")(params); |
| 236 | if (!py::hasattr(instance, "calculate")) { |
| 237 | return PJ::unexpected("the object returned by T.create() must have a calculate(self, time, value) method"); |
| 238 | } |
| 239 | return std::unique_ptr<FilterInstance>( |
| 240 | std::make_unique<PythonFilterInstance>(std::move(ns), std::move(instance))); |
| 241 | } catch (const py::error_already_set& e) { |
| 242 | return PJ::unexpected(std::string("Python error: ") + e.what()); |
| 243 | } catch (const std::exception& e) { |
| 244 | return PJ::unexpected(std::string("Python error: ") + e.what()); |
| 245 | } |
| 246 | } |
| 247 | }; |
| 248 | |
| 249 | } // namespace |
nothing calls this directly
no test coverage detected