32 #include "../util/pybind_dict_utils.h" 33 #include "../util/type_casters.h" 35 #include <libxml/tree.h> 45 dict(dict), parent(parent), prefix(prefix), _exists(exists)
60 if (it.second !=
empty()) {
65 for (
auto le : it.second) {
82 pybind11::handle elem;
83 if (!
try_get(
dict, property, elem) || elem.is_none()) {
88 pybind11::str str(elem);
98 pybind11::handle elem;
99 if (!
try_get(
dict, property, elem) || elem.is_none()) {
103 if (py::isinstance<py::str>(elem)) {
107 }
else if (py::isinstance<py::iterable>(elem)) {
108 for (
auto part : elem) {
114 std::ostringstream os;
115 os <<
"Unsupported value for property entry at ";
117 os <<
property <<
": Expected string or iterable of string, but got ";
118 auto childType = py::str(elem.get_type());
119 os << childType.cast<std::string>();
120 throw std::invalid_argument(os.str());
130 pybind11::handle elem;
131 if (!
try_get(
dict, property, elem) || elem.is_none()) {
136 out = elem.cast<
double>();
146 pybind11::handle elem;
147 if (!
try_get(
dict, property, elem) || elem.is_none()) {
152 out = elem.cast<
int>();
162 pybind11::handle elem;
163 if (!
try_get(
dict, property, elem) || elem.is_none()) {
168 py::detail::make_caster<MatNd> caster;
169 py::detail::load_type(caster, elem);
170 out = MatNd_clone(py::detail::cast_op<MatNd*>(caster));
184 std::string prefixStr =
prefix;
186 auto iter =
children.find(prefixStr);
191 pybind11::object child;
194 exists =
try_get(
dict, prefix, child) && !child.is_none();
198 child = pybind11::dict();
200 else if (!pybind11::isinstance<pybind11::dict>(child)) {
202 std::ostringstream os;
203 os <<
"Unsupported value for child property entry at ";
205 os << prefix <<
": Expected dict, but got ";
206 auto childType = pybind11::str(child.get_type());
207 os << childType.cast<std::string>();
208 throw std::invalid_argument(os.str());
225 const char* property,
226 const std::string& value)
228 dict[property] = value;
235 dict[property] = value;
242 dict[property] = value;
249 dict[property] = value;
257 dict[property] = pybind11::cast(value, pybind11::return_value_policy::copy);
278 std::string prefixStr =
prefix;
287 pybind11::object child;
290 exists =
try_get(
dict, prefix, child) && !child.is_none();
294 if (pybind11::isinstance<pybind11::dict>(child)) {
298 else if (pybind11::isinstance<pybind11::iterable>(child)) {
301 for (
auto elem : child) {
302 if (pybind11::isinstance<pybind11::dict>(elem)) {
303 std::ostringstream itemPrefix;
304 itemPrefix << prefix <<
"[" << i <<
"]";
306 list.push_back(
new PropertySourceDict(pybind11::reinterpret_borrow<pybind11::dict>(elem),
this,
307 itemPrefix.str().c_str(),
true));
311 std::ostringstream os;
312 os <<
"Unsupported element for child property entry at ";
314 os << prefix <<
"[" << i <<
"]" <<
": Expected dict, but got ";
315 auto childType = pybind11::str(child.get_type());
316 os << childType.cast<std::string>();
317 throw std::invalid_argument(os.str());
324 std::ostringstream os;
325 os <<
"Unsupported value for child list property entry at ";
327 os << prefix <<
": Expected list of dict or dict, but got ";
328 auto childType = pybind11::str(child.get_type());
329 os << childType.cast<std::string>();
330 throw std::invalid_argument(os.str());
340 py::object copymod = py::module::import(
"copy");
341 py::dict cpdict = copymod.attr(
"deepcopy")(
dict);
348 std::ostringstream os;
350 for (
auto ele : iterable) {
352 os << py::cast<std::string>(py::str(ele)) <<
' ';
354 std::string result = os.str();
356 if (!result.empty()) {
357 result.erase(result.end() - 1);
362 static xmlNodePtr
dict2xml(
const py::dict& data, xmlDocPtr doc,
const char* nodeName)
364 xmlNodePtr node = xmlNewDocNode(doc, NULL, BAD_CAST nodeName, NULL);
366 for (
auto entry : data) {
367 auto key = py::cast<std::string>(entry.first);
368 auto value = entry.second;
370 std::string valueStr;
372 if (py::isinstance<py::dict>(value)) {
374 xmlNodePtr subNode =
dict2xml(py::reinterpret_borrow<py::dict>(value), doc, key.c_str());
375 xmlAddChild(node, subNode);
378 else if (py::isinstance<py::str>(value)) {
380 valueStr = py::cast<std::string>(value);
382 else if (py::isinstance<py::array>(value)) {
388 else if (py::isinstance<py::iterable>(value)) {
391 auto it = value.begin();
393 if (it == value.end())
continue;
396 if (std::all_of(it, value.end(), [](py::handle ele) {
397 return py::isinstance<py::dict>(ele);
400 for (
auto ele : value) {
401 xmlNodePtr subNode =
dict2xml(py::reinterpret_borrow<py::dict>(ele), doc, key.c_str());
402 xmlAddChild(node, subNode);
411 valueStr = py::cast<std::string>(py::str(value));
414 xmlSetProp(node, BAD_CAST key.c_str(), BAD_CAST valueStr.c_str());
423 std::unique_ptr<xmlDoc, void (*)(xmlDocPtr)> doc(xmlNewDoc(NULL), xmlFreeDoc);
426 xmlNodePtr rootNode =
dict2xml(
dict, doc.get(), rootNodeName);
427 xmlDocSetRootElement(doc.get(), rootNode);
430 xmlIndentTreeOutput = 1;
431 xmlSaveFormatFile(fileName, doc.get(), 1);
virtual void saveXML(const char *fileName, const char *rootNodeName)
virtual PropertySink * getChild(const char *prefix)
static std::string spaceJoinedString(py::handle iterable)
static xmlNodePtr dict2xml(const py::dict &data, xmlDocPtr doc, const char *nodeName)
virtual PropertySink * clone() const
PropertySourceDict * parent
virtual ~PropertySourceDict()
T get_cast(const py::dict &dict, const char *key, T default_, bool noneIsEmpty=true)
void appendPrefix(std::ostream &)
virtual const std::vector< PropertySource * > & getChildList(const char *prefix)
static PropertySource * empty()
PropertySourceDict(pybind11::dict dict, PropertySourceDict *parent, const char *prefix, bool exists)
virtual bool getProperty(std::string &out, const char *property)
std::map< std::string, PropertySourceDict * > children
bool try_get(const py::dict &dict, const char *key, T &var)
std::map< std::string, std::vector< PropertySource * > > listChildren
virtual bool getPropertyBool(const char *property, bool def=false)
virtual void setProperty(const char *property, const std::string &value)