@@ -62,6 +62,8 @@ using sofapython3::PythonEnvironment;
6262#include < SofaPython3/Sofa/Core/Binding_NodeIterator.h>
6363#include < SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h>
6464
65+ #include < SofaPython3/SpellingSuggestionHelper.h>
66+
6567using sofa::core::objectmodel::BaseObjectDescription;
6668
6769#include < queue>
@@ -72,30 +74,11 @@ namespace py { using namespace pybind11; }
7274
7375using sofa::simulation::Node;
7476
75- namespace sofapython3 {
76-
77-
78- template <class Iterable , class UnaryOperation , class PickingFunction >
79- void fillVectorOfStringFrom (const Iterable& v, const UnaryOperation& op, const PickingFunction func)
77+ namespace sofapython3
8078{
81- std::transform (v.begin (), v.end (), op, func);
82- }
8379
84- template <class Iterable >
85- std::ostream& emitSpellingMessage (std::ostream& ostream, const std::string& message, const Iterable& iterable, const std::string& name, sofa::Size numEntries=5 , double thresold=0.6 )
80+ namespace
8681{
87- std::vector<std::string> possibleNames;
88- fillVectorOfStringFrom (iterable, std::back_inserter (possibleNames), [](const typename Iterable::value_type d) { return d->getName (); });
89-
90- auto spellingSuggestions = getClosestMatch (name, possibleNames, numEntries, thresold);
91- if (!spellingSuggestions.empty ())
92- {
93- for (auto & [name, score] : spellingSuggestions)
94- ostream << message << " '" << name << " ' (" << std::to_string ((int )(100 *score))+" % match)" << msgendl;
95- }
96- return ostream;
97- }
98-
9982bool checkParamUsage (BaseObjectDescription& desc, const Base* base)
10083{
10184 std::vector<std::tuple<std::string, std::string>> paramErrors;
@@ -115,10 +98,8 @@ bool checkParamUsage(BaseObjectDescription& desc, const Base* base)
11598 std::vector<std::string> possibleNames;
11699 if (base)
117100 {
118- for (auto & data : base->getDataFields ())
119- possibleNames.emplace_back (data->getName ());
120- for (auto & link : base->getLinks ())
121- possibleNames.emplace_back (link->getName ());
101+ fillVectorOfStringFrom (base->getDataFields (), std::back_inserter (possibleNames), [](const BaseData* d){return d->getName ();});
102+ fillVectorOfStringFrom (base->getLinks (), std::back_inserter (possibleNames), [](const BaseLink* l){return l->getName ();});
122103 }
123104
124105 for (auto & [name, value] : paramErrors)
@@ -223,7 +204,7 @@ py::object getObject(Node &n, const std::string &name, const py::kwargs& kwargs)
223204 msg_deprecated (&n) << " Calling the method getObject() with extra arguments is not supported anymore."
224205 << " To remove this message please refer to the documentation of the getObject method"
225206 << msgendl
226- << PythonEnvironment::getPythonCallingPointString () ;
207+ << PythonEnvironment::getPythonCallingPointString () ;
227208 }
228209
229210 BaseObject *object = n.getObject (name);
@@ -442,67 +423,70 @@ py::object removeChildByName(Node& n, const std::string name)
442423std::unique_ptr<NodeIterator> property_children (Node* node)
443424{
444425 return std::make_unique<NodeIterator>(node,
445- [](Node* n) -> size_t { return n->child .size (); },
446- [](Node* n, unsigned int index) -> Base::SPtr { return n->child [index]; },
447- [](const Node* n, const std::string& name) { return n->getChild (name); },
448- [](Node* n, unsigned int index) { n->removeChild (n->child [index]); }
449- );
426+ [](Node* n) -> size_t { return n->child .size (); },
427+ [](Node* n, unsigned int index) -> Base::SPtr { return n->child [index]; },
428+ [](const Node* n, const std::string& name) { return n->getChild (name); },
429+ [](Node* n, unsigned int index) { n->removeChild (n->child [index]); }
430+ );
450431}
451432
452433std::unique_ptr<NodeIterator> property_parents (Node* node)
453434{
454435 return std::make_unique<NodeIterator>(node,
455- [](Node* n) -> size_t { return n->getNbParents (); },
456- [](Node* n, unsigned int index) -> Node::SPtr {
457- auto p = n->getParents ();
458- return static_cast <Node*>(p[index]);
459- },
460- [](const Node* n, const std::string& name) -> sofa::core::Base* {
461- const auto & parents = n->getParents ();
462- return *std::find_if (parents.begin (),
463- parents.end (),
464- [name](BaseNode* child){ return child->getName () == name; });
465- },
466- [](Node*, unsigned int ) {
467- throw std::runtime_error (" Removing a parent is not a supported operation. Please detach the node from the corresponding graph node." );
468- });
436+ [](Node* n) -> size_t { return n->getNbParents (); },
437+ [](Node* n, unsigned int index) -> Node::SPtr {
438+ auto p = n->getParents ();
439+ return static_cast <Node*>(p[index]);
440+ },
441+ [](const Node* n, const std::string& name) -> sofa::core::Base* {
442+ const auto & parents = n->getParents ();
443+ return *std::find_if (parents.begin (),
444+ parents.end (),
445+ [name](BaseNode* child){ return child->getName () == name; });
446+ },
447+ [](Node*, unsigned int ) {
448+ throw std::runtime_error (" Removing a parent is not a supported operation. Please detach the node from the corresponding graph node." );
449+ });
469450}
470451
471452std::unique_ptr<NodeIterator> property_objects (Node* node)
472453{
473454 return std::make_unique<NodeIterator>(node,
474- [](Node* n) -> size_t { return n->object .size (); },
475- [](Node* n, unsigned int index) -> Base::SPtr { return (n->object [index]);},
476- [](const Node* n, const std::string& name) { return n->getObject (name); },
477- [](Node* n, unsigned int index) { n->removeObject (n->object [index]);}
478- );
455+ [](Node* n) -> size_t { return n->object .size (); },
456+ [](Node* n, unsigned int index) -> Base::SPtr { return (n->object [index]);},
457+ [](const Node* n, const std::string& name) { return n->getObject (name); },
458+ [](Node* n, unsigned int index) { n->removeObject (n->object [index]);}
459+ );
479460}
480461
481- py::object __getattr__ (Node& self , const std::string& name)
462+ py::object __getattr__ (py::object pyself , const std::string& name)
482463{
464+ Node* selfnode = py::cast<Node*>(pyself);
483465 // / Search in the object lists
484- BaseObject *object = self. getObject (name);
466+ BaseObject *object = selfnode-> getObject (name);
485467 if (object)
486468 return PythonFactory::toPython (object);
487469
488470 // / Search in the child lists
489- Node *child = self. getChild (name);
471+ Node *child = selfnode-> getChild (name);
490472 if (child)
491473 return PythonFactory::toPython (child);
492474
493475 // / Search in the data & link lists
494- py::object result = BindingBase::GetAttr (&self , name, false );
476+ py::object result = BindingBase::GetAttr (selfnode , name, false );
495477 if (!result.is_none ())
496478 return result;
497479
498- Node* selfnode = &self;
499-
500480 std::stringstream tmp;
501481 emitSpellingMessage (tmp, " - The data field named " , selfnode->getDataFields (), name, 2 , 0.8 );
502482 emitSpellingMessage (tmp, " - The link named " , selfnode->getDataFields (), name, 2 , 0.8 );
503483 emitSpellingMessage (tmp, " - The object named " , selfnode->getNodeObjects (), name, 2 , 0.8 );
504484 emitSpellingMessage (tmp, " - The child node named " , selfnode->getChildren (), name, 2 , 0.8 );
505485
486+ // Also provide spelling hints on python functions.
487+ emitSpellingMessage (tmp, " - The python attribute named " , py::cast<py::dict>(py::type::of (pyself).attr (" __dict__" )), name, 5 , 0.8 ,
488+ [](const std::pair<py::handle, py::handle>& kv) { return py::cast<std::string>(std::get<0 >(kv)); });
489+
506490 std::stringstream message;
507491 message << " Unable to find attribute: " +name;
508492 if (!tmp.str ().empty ())
@@ -613,6 +597,8 @@ void sendEvent(Node* self, py::object pyUserData, char* eventName)
613597 self->propagateEvent (sofa::core::execparams::defaultInstance (), &event);
614598}
615599
600+ }
601+
616602void moduleAddNode (py::module &m) {
617603 // / Register the complete parent-child relationship between Base and Node to the pybind11
618604 // / typing system.
0 commit comments