From 9e63ba09434573d6bf81bcbaf964dc14228de45c Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Tue, 6 Aug 2019 17:38:44 +0200 Subject: [PATCH] parse additional kwargs internally as flags to avoid bad_any_cast There seem to be somehow multiple py::kwargs classes created in different libraries, because of this the any_cast is failing. To circumvent this we attach them to the MeshingParameters object as flags. --- libsrc/core/python_ngcore.cpp | 74 +++++++++++++++++++++++++++------- libsrc/core/python_ngcore.hpp | 10 +++-- libsrc/meshing/python_mesh.hpp | 9 ++++- libsrc/stlgeom/python_stl.cpp | 10 ++--- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/libsrc/core/python_ngcore.cpp b/libsrc/core/python_ngcore.cpp index a0810ca6..f60e40d3 100644 --- a/libsrc/core/python_ngcore.cpp +++ b/libsrc/core/python_ngcore.cpp @@ -40,7 +40,7 @@ namespace ngcore if (py::isinstance(value)) { - py::list vdl(value); + auto vdl = py::cast(value); if (py::len(vdl) > 0) { if(py::isinstance(vdl[0])) @@ -59,7 +59,7 @@ namespace ngcore if (py::isinstance(value)) { - py::tuple vdt(value); + auto vdt = py::cast(value); if (py::isinstance(value)) flags.SetFlag(s, makeCArray(vdt)); if (py::isinstance(value)) @@ -69,29 +69,32 @@ namespace ngcore } } - Flags CreateFlagsFromKwArgs(py::object pyclass, const py::kwargs& kwargs, py::list info) + Flags CreateFlagsFromKwArgs(const py::kwargs& kwargs, py::object pyclass, py::list info) { static std::shared_ptr logger = GetLogger("Flags"); - auto flags_doc = pyclass.attr("__flags_doc__")(); py::dict flags_dict; if (kwargs.contains("flags")) { - logger->warn("WARNING: using flags as kwarg is deprecated in {}, use the flag arguments as kwargs instead!", - std::string(py::str(pyclass))); + logger->warn("WARNING: using flags as kwarg is deprecated{}, use the flag arguments as kwargs instead!", + pyclass.is_none() ? "" : std::string(" in ") + std::string(py::str(pyclass))); auto addflags = py::cast(kwargs["flags"]); for (auto item : addflags) flags_dict[item.first.cast().c_str()] = item.second; } - for (auto item : kwargs) - if (!flags_doc.contains(item.first.cast().c_str()) && - !(item.first.cast() == "flags")) - logger->warn("WARNING: kwarg '{}' is an undocumented flags option for class {}, maybe there is a typo?", - item.first.cast(), std::string(py::str(pyclass))); - py::dict special; - if(py::hasattr(pyclass,"__special_treated_flags__")) - special = pyclass.attr("__special_treated_flags__")(); + if(!pyclass.is_none()) + { + auto flags_doc = pyclass.attr("__flags_doc__")(); + for (auto item : kwargs) + if (!flags_doc.contains(item.first.cast().c_str()) && + !(item.first.cast() == "flags")) + logger->warn("WARNING: kwarg '{}' is an undocumented flags option for class {}, maybe there is a typo?", + item.first.cast(), std::string(py::str(pyclass))); + + if(py::hasattr(pyclass,"__special_treated_flags__")) + special = pyclass.attr("__special_treated_flags__")(); + } for (auto item : kwargs) { auto name = item.first.cast(); @@ -116,4 +119,47 @@ namespace ngcore return flags; } + py::dict CreateDictFromFlags(const Flags& flags) + { + py::dict d; + std::string key; + for(auto i : Range(flags.GetNFlagsFlags())) + { + auto& f = flags.GetFlagsFlag(i, key); + d[key.c_str()] = CreateDictFromFlags(f); + } + for(auto i : Range(flags.GetNStringListFlags())) + { + auto strlistflag = flags.GetStringListFlag(i, key); + py::list lst; + for(auto& val : *strlistflag) + lst.append(val); + d[key.c_str()] = lst; + } + for(auto i : Range(flags.GetNNumListFlags())) + { + auto numlistflag = flags.GetNumListFlag(i, key); + py::list lst; + for(auto& val : *numlistflag) + lst.append(val); + d[key.c_str()] = lst; + } + for(auto i : Range(flags.GetNStringFlags())) + { + auto val = flags.GetStringFlag(i, key); + d[key.c_str()] = val; + } + for(auto i : Range(flags.GetNNumFlags())) + { + auto val = flags.GetNumFlag(i, key); + d[key.c_str()] = val; + } + for(auto i : Range(flags.GetNDefineFlags())) + { + auto val = flags.GetDefineFlag(i, key); + d[key.c_str()] = val; + } + return d; + } + } // namespace ngcore diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 562467cc..7a2fe5b2 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -16,10 +16,9 @@ namespace ngcore Array makeCArray(const py::object& obj) { Array arr; - arr.SetAllocSize(py::len(obj)); if(py::isinstance(obj)) - for(auto& val : py::cast(obj)) - arr.Append(py::cast(val)); + for(auto& val : py::cast(obj)) + arr.Append(py::cast(val)); else if(py::isinstance(obj)) for(auto& val : py::cast(obj)) arr.Append(py::cast(val)); @@ -30,7 +29,10 @@ namespace ngcore void NGCORE_API SetFlag(Flags &flags, std::string s, py::object value); // Parse python kwargs to flags - Flags NGCORE_API CreateFlagsFromKwArgs(py::object pyclass, const py::kwargs& kwargs, py::list info = py::list()); + Flags NGCORE_API CreateFlagsFromKwArgs(const py::kwargs& kwargs, py::object pyclass = py::none(), + py::list info = py::list()); + // Create python dict from kwargs + py::dict NGCORE_API CreateDictFromFlags(const Flags& flags); // *************** Archiving functionality ************** diff --git a/libsrc/meshing/python_mesh.hpp b/libsrc/meshing/python_mesh.hpp index 2a808509..62a85778 100644 --- a/libsrc/meshing/python_mesh.hpp +++ b/libsrc/meshing/python_mesh.hpp @@ -1,5 +1,9 @@ +#ifndef NETGEN_MESHING_PYTHON_MESH_HPP +#define NETGEN_MESHING_PYTHON_MESH_HPP #include + +#include #include "meshing.hpp" namespace netgen @@ -168,7 +172,10 @@ inline void CreateMPfromKwargs(MeshingParameters& mp, py::kwargs kwargs, bool th { if(throw_if_not_all_parsed) throw Exception(string("Not all kwargs given to GenerateMesh could be parsed:") + string(py::str(kwargs))); - mp.geometrySpecificParameters = kwargs; + mp.geometrySpecificParameters = CreateFlagsFromKwArgs(kwargs); } } } // namespace netgen + +#endif // NETGEN_MESHING_PYTHON_MESH_HPP + diff --git a/libsrc/stlgeom/python_stl.cpp b/libsrc/stlgeom/python_stl.cpp index 180b5e56..33df2fc8 100644 --- a/libsrc/stlgeom/python_stl.cpp +++ b/libsrc/stlgeom/python_stl.cpp @@ -32,7 +32,7 @@ edgecornerangle: float = )delimiter"; -void CreateSTLParametersFromKwargs(STLParameters& stlparam, py::kwargs kwargs) +void CreateSTLParametersFromKwargs(STLParameters& stlparam, py::dict kwargs) { if(kwargs.contains("yangle")) stlparam.yangle = py::cast(kwargs.attr("pop")("yangle")); @@ -198,14 +198,14 @@ DLL_HEADER void ExportSTL(py::module & m) STLParameters stlparam; if(pars) { - if(pars->geometrySpecificParameters.has_value() && - (pars->geometrySpecificParameters.type() == typeid(py::kwargs))) + try { - auto mp_kwargs = any_cast(pars->geometrySpecificParameters); - py::print("geometry specific kwargs:", mp_kwargs); + auto mp_flags = any_cast(pars->geometrySpecificParameters); + auto mp_kwargs = CreateDictFromFlags(mp_flags); CreateSTLParametersFromKwargs(stlparam, mp_kwargs); pars->geometrySpecificParameters.reset(); } + catch(std::bad_any_cast) {} mp = *pars; } CreateSTLParametersFromKwargs(stlparam, kwargs);