| 51 | } |
| 52 | |
| 53 | std::string attrString(const py::object& obj, const char* name, const std::string& fallback) { |
| 54 | if (!py::hasattr(obj, name)) { |
| 55 | return fallback; |
| 56 | } |
| 57 | py::object v = obj.attr(name); |
| 58 | if (v.is_none()) { |
| 59 | return fallback; |
| 60 | } |
| 61 | return py::str(v).cast<std::string>(); |
| 62 | } |
| 63 | |
| 64 | // One live Python filter: owns the module namespace (keepalive) and the instance |
| 65 | // object. All py-object touches happen under the GIL. |