Skip to content

Commit 2d62f4e

Browse files
Merge pull request #321 from sofa-framework/revert-314-pr-add-difflib-support
Revert "[Sofa.Core] Add spelling suggestion to addObject & addChild"
2 parents 4077999 + 921e809 commit 2d62f4e

5 files changed

Lines changed: 54 additions & 204 deletions

File tree

Plugin/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ set(HEADER_FILES
55
${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/initModule.h
66
${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/PythonEnvironment.h
77
${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/SceneLoaderPY3.h
8-
${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/SpellingSuggestionHelper.h
98

109
${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/DataCache.h
1110
${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/DataHelper.h

Plugin/src/SofaPython3/SpellingSuggestionHelper.h

Lines changed: 0 additions & 55 deletions
This file was deleted.

Plugin/src/SofaPython3/config.h.in

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,3 @@
5555
#else
5656
#define SOFAPYTHON3_BIND_ATTRIBUTE_ERROR() namespace pybind11 { PYBIND11_RUNTIME_EXCEPTION(attribute_error, PyExc_AttributeError) }
5757
#endif // PYBIND11_SOFA_VERSION >= 20801
58-
59-
#if PYBIND11_SOFA_VERSION >= 20801
60-
#define SOFAPYTHON3_ADD_PYBIND_TYPE_FOR_OLD_VERSION()
61-
#else
62-
#define SOFAPYTHON3_ADD_PYBIND_TYPE_FOR_OLD_VERSION() namespace pybind11 { \
63-
class type : public pybind11::object { \
64-
public: \
65-
PYBIND11_OBJECT(type, pybind11::object, PyType_Check) \
66-
static pybind11::handle handle_of(pybind11::handle h) { return handle((PyObject*) Py_TYPE(h.ptr())); } \
67-
static type of(pybind11::handle h) { return type(type::handle_of(h), borrowed_t{}); } \
68-
template<typename T> static handle handle_of(); \
69-
template<typename T> static type of() {return type(type::handle_of<T>(), borrowed_t{}); } \
70-
}; \
71-
}
72-
#endif // PYBIND11_SOFA_VERSION >= 20801

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp

Lines changed: 6 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
* Contact information: contact@sofa-framework.org *
1919
******************************************************************************/
2020

21-
#include "SofaPython3/SpellingSuggestionHelper.h"
2221
#include <pybind11/pybind11.h>
2322

2423
#include <pybind11/numpy.h>
@@ -45,9 +44,7 @@ using sofa::simulation::Node;
4544

4645
#include <SofaPython3/DataHelper.h>
4746

48-
// These two lines are there to handle deprecated version of pybind.
4947
SOFAPYTHON3_BIND_ATTRIBUTE_ERROR()
50-
SOFAPYTHON3_ADD_PYBIND_TYPE_FOR_OLD_VERSION()
5148

5249
/// Makes an alias for the pybind11 namespace to increase readability.
5350
namespace py { using namespace pybind11; }
@@ -342,39 +339,15 @@ py::list BindingBase::__dir__(Base* self)
342339
return list;
343340
}
344341

345-
py::object BindingBase::__getattr__(py::object self, const std::string& attributeName)
342+
py::object BindingBase::__getattr__(py::object self, const std::string& s)
346343
{
347-
// Search for attribute s.
348-
py::object res = BindingBase::GetAttr( py::cast<Base*>(self), attributeName, false );
349-
350-
// If there is one, then return it
351-
if( !res.is_none() )
352-
return res;
353-
354-
// If there is none, then search into the python dictionnary
355-
if( py::hasattr(self.attr("__dict__"), attributeName.c_str()) )
356-
return self.attr("__dict__")[attributeName.c_str()];
357-
358-
// If we reach this line, this indicate that no attribute was found. Maybe it is a misspelling
359-
// so let's build misspelling hints for the user.
360-
Base* selfbase = py::cast<Base*>(self);
361-
std::stringstream tmp;
362-
emitSpellingMessage(tmp, " - The data field named ", selfbase->getDataFields(), attributeName, 2, 0.6);
363-
emitSpellingMessage(tmp, " - The link named ", selfbase->getLinks(), attributeName, 2, 0.6);
364-
365-
// Also provide spelling hints on python functions.
366-
emitSpellingMessage(tmp, " - The python attribute named ", py::cast<py::dict>(py::type::of(self).attr("__dict__")), attributeName, 5, 0.8,
367-
[](const std::pair<py::handle, py::handle>& kv) { return py::cast<std::string>(std::get<0>(kv)); });
368-
369-
std::stringstream message;
370-
message << "Unable to find attribute: "+attributeName;
371-
if(!tmp.str().empty())
344+
py::object res = BindingBase::GetAttr( py::cast<Base*>(self), s, false );
345+
if( res.is_none() )
372346
{
373-
message << msgendl;
374-
message << " You possibly wanted to access: " << msgendl;
375-
message << tmp.rdbuf();
347+
return self.attr("__dict__")[s.c_str()];
376348
}
377-
throw py::attribute_error(message.str());
349+
350+
return res;
378351
}
379352

380353
void BindingBase::__setattr__(py::object self, const std::string& s, py::object value)

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp

Lines changed: 48 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
*******************************************************************************
1818
* Contact information: contact@sofa-framework.org *
1919
******************************************************************************/
20+
21+
2022
/// Neede to have automatic conversion from pybind types to stl container.
2123
#include <pybind11/stl.h>
22-
#include <pybind11/numpy.h>
24+
#include <pybind11/eval.h>
2325

2426
#include <sofa/simulation/Simulation.h>
2527
#include <sofa/core/ComponentNameHelper.h>
@@ -33,9 +35,6 @@ namespace simpleapi = sofa::simpleapi;
3335
#include <sofa/helper/logging/Messaging.h>
3436
using sofa::helper::logging::Message;
3537

36-
#include <sofa/helper/DiffLib.h>
37-
using sofa::helper::getClosestMatch;
38-
3938
#include <sofa/simulation/graph/DAGNode.h>
4039
using sofa::core::ExecParams;
4140

@@ -60,67 +59,41 @@ using sofapython3::PythonEnvironment;
6059
#include <SofaPython3/Sofa/Core/Binding_NodeIterator.h>
6160
#include <SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h>
6261

63-
#include <SofaPython3/SpellingSuggestionHelper.h>
64-
6562
using sofa::core::objectmodel::BaseObjectDescription;
6663

6764
#include <queue>
6865
#include <sofa/core/objectmodel/Link.h>
6966

70-
// These two lines are there to handle deprecated version of pybind.
71-
SOFAPYTHON3_BIND_ATTRIBUTE_ERROR()
72-
SOFAPYTHON3_ADD_PYBIND_TYPE_FOR_OLD_VERSION()
73-
7467
/// Makes an alias for the pybind11 namespace to increase readability.
7568
namespace py { using namespace pybind11; }
7669

7770
using sofa::simulation::Node;
7871

79-
namespace sofapython3
80-
{
72+
namespace sofapython3 {
8173

82-
namespace
83-
{
84-
bool checkParamUsage(BaseObjectDescription& desc, const Base* base)
74+
bool checkParamUsage(BaseObjectDescription& desc)
8575
{
86-
std::vector<std::tuple<std::string, std::string>> paramErrors;
76+
bool hasFailure = false;
77+
std::stringstream tmp;
78+
tmp <<"Unknown Attribute(s): " << msgendl;
8779
for( auto& it : desc.getAttributeMap() )
8880
{
8981
if (!it.second.isAccessed())
9082
{
91-
paramErrors.emplace_back(std::make_tuple(it.first, it.second));
83+
hasFailure = true;
84+
tmp << " - \""<<it.first <<"\" with value: \"" <<std::string(it.second) << msgendl;
9285
}
9386
}
94-
95-
if(!paramErrors.empty() || !desc.getErrors().empty())
87+
if(!desc.getErrors().empty())
88+
{
89+
hasFailure = true;
90+
tmp << desc.getErrors()[0];
91+
}
92+
if(hasFailure)
9693
{
97-
std::stringstream tmp;
98-
tmp << "Unknown Attribute(s): " << msgendl;
99-
100-
std::vector<std::string> possibleNames;
101-
if(base)
102-
{
103-
fillVectorOfStringFrom(base->getDataFields(), std::back_inserter(possibleNames), [](const BaseData* d){return d->getName();});
104-
fillVectorOfStringFrom(base->getLinks(), std::back_inserter(possibleNames), [](const BaseLink* l){return l->getName();});
105-
}
106-
107-
for(auto& [name, value] : paramErrors)
108-
{
109-
tmp << " - Unable to set attribute '"<< name <<"' with value: " << value;
110-
const auto& v = getClosestMatch(name, possibleNames);
111-
if(!v.empty())
112-
tmp << ". Possible misspelling of attribute '" << std::get<0>(v[0]) << "' ?";
113-
else
114-
tmp << ".";
115-
tmp << msgendl;
116-
}
117-
118-
if(!desc.getErrors().empty())
119-
tmp << desc.getErrors()[0];
12094
throw py::type_error(tmp.str());
12195
}
122-
123-
return false;
96+
return hasFailure;
12497
}
12598

12699
py::object getItem(Node& self, std::list<std::string>& path)
@@ -206,7 +179,7 @@ py::object getObject(Node &n, const std::string &name, const py::kwargs& kwargs)
206179
msg_deprecated(&n) << "Calling the method getObject() with extra arguments is not supported anymore."
207180
<< "To remove this message please refer to the documentation of the getObject method"
208181
<< msgendl
209-
<< PythonEnvironment::getPythonCallingPointString() ;
182+
<< PythonEnvironment::getPythonCallingPointString() ;
210183
}
211184

212185
BaseObject *object = n.getObject(name);
@@ -274,7 +247,7 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs
274247

275248
setFieldsFromPythonValues(object.get(), kwargs);
276249

277-
checkParamUsage(desc, object.get());
250+
checkParamUsage(desc);
278251

279252
// Convert the logged messages in the object's internal logging into python exception.
280253
// this is not a very fast way to do that...but well...python is slow anyway. And serious
@@ -369,7 +342,7 @@ py::object addChildKwargs(Node* self, const std::string& name, const py::kwargs&
369342
node->setInstanciationSourceFileName(finfo->filename);
370343
node->setInstanciationSourceFilePos(finfo->line);
371344

372-
checkParamUsage(desc, node.get());
345+
checkParamUsage(desc);
373346

374347
for(auto a : kwargs)
375348
{
@@ -425,79 +398,56 @@ py::object removeChildByName(Node& n, const std::string name)
425398
std::unique_ptr<NodeIterator> property_children(Node* node)
426399
{
427400
return std::make_unique<NodeIterator>(node,
428-
[](Node* n) -> size_t { return n->child.size(); },
429-
[](Node* n, unsigned int index) -> Base::SPtr { return n->child[index]; },
430-
[](const Node* n, const std::string& name) { return n->getChild(name); },
431-
[](Node* n, unsigned int index) { n->removeChild(n->child[index]); }
432-
);
401+
[](Node* n) -> size_t { return n->child.size(); },
402+
[](Node* n, unsigned int index) -> Base::SPtr { return n->child[index]; },
403+
[](const Node* n, const std::string& name) { return n->getChild(name); },
404+
[](Node* n, unsigned int index) { n->removeChild(n->child[index]); }
405+
);
433406
}
434407

435408
std::unique_ptr<NodeIterator> property_parents(Node* node)
436409
{
437410
return std::make_unique<NodeIterator>(node,
438-
[](Node* n) -> size_t { return n->getNbParents(); },
439-
[](Node* n, unsigned int index) -> Node::SPtr {
440-
auto p = n->getParents();
441-
return static_cast<Node*>(p[index]);
442-
},
443-
[](const Node* n, const std::string& name) -> sofa::core::Base* {
444-
const auto& parents = n->getParents();
445-
return *std::find_if(parents.begin(),
446-
parents.end(),
447-
[name](BaseNode* child){ return child->getName() == name; });
448-
},
449-
[](Node*, unsigned int) {
450-
throw std::runtime_error("Removing a parent is not a supported operation. Please detach the node from the corresponding graph node.");
451-
});
411+
[](Node* n) -> size_t { return n->getNbParents(); },
412+
[](Node* n, unsigned int index) -> Node::SPtr {
413+
auto p = n->getParents();
414+
return static_cast<Node*>(p[index]);
415+
},
416+
[](const Node* n, const std::string& name) -> sofa::core::Base* {
417+
const auto& parents = n->getParents();
418+
return *std::find_if(parents.begin(),
419+
parents.end(),
420+
[name](BaseNode* child){ return child->getName() == name; });
421+
},
422+
[](Node*, unsigned int) {
423+
throw std::runtime_error("Removing a parent is not a supported operation. Please detach the node from the corresponding graph node.");
424+
});
452425
}
453426

454427
std::unique_ptr<NodeIterator> property_objects(Node* node)
455428
{
456429
return std::make_unique<NodeIterator>(node,
457-
[](Node* n) -> size_t { return n->object.size(); },
458-
[](Node* n, unsigned int index) -> Base::SPtr { return (n->object[index]);},
459-
[](const Node* n, const std::string& name) { return n->getObject(name); },
460-
[](Node* n, unsigned int index) { n->removeObject(n->object[index]);}
461-
);
430+
[](Node* n) -> size_t { return n->object.size(); },
431+
[](Node* n, unsigned int index) -> Base::SPtr { return (n->object[index]);},
432+
[](const Node* n, const std::string& name) { return n->getObject(name); },
433+
[](Node* n, unsigned int index) { n->removeObject(n->object[index]);}
434+
);
462435
}
463436

464-
py::object __getattr__(py::object pyself, const std::string& name)
437+
py::object __getattr__(Node& self, const std::string& name)
465438
{
466-
Node* selfnode = py::cast<Node*>(pyself);
467439
/// Search in the object lists
468-
BaseObject *object = selfnode->getObject(name);
440+
BaseObject *object = self.getObject(name);
469441
if (object)
470442
return PythonFactory::toPython(object);
471443

472444
/// Search in the child lists
473-
Node *child = selfnode->getChild(name);
445+
Node *child = self.getChild(name);
474446
if (child)
475447
return PythonFactory::toPython(child);
476448

477449
/// Search in the data & link lists
478-
py::object result = BindingBase::GetAttr(selfnode, name, false);
479-
if(!result.is_none())
480-
return result;
481-
482-
std::stringstream tmp;
483-
emitSpellingMessage(tmp, " - The data field named ", selfnode->getDataFields(), name, 2, 0.8);
484-
emitSpellingMessage(tmp, " - The link named ", selfnode->getDataFields(), name, 2, 0.8);
485-
emitSpellingMessage(tmp, " - The object named ", selfnode->getNodeObjects(), name, 2, 0.8);
486-
emitSpellingMessage(tmp, " - The child node named ", selfnode->getChildren(), name, 2, 0.8);
487-
488-
// Also provide spelling hints on python functions.
489-
emitSpellingMessage(tmp, " - The python attribute named ", py::cast<py::dict>(py::type::of(pyself).attr("__dict__")), name, 5, 0.8,
490-
[](const std::pair<py::handle, py::handle>& kv) { return py::cast<std::string>(std::get<0>(kv)); });
491-
492-
std::stringstream message;
493-
message << "Unable to find attribute: "+name;
494-
if(!tmp.str().empty())
495-
{
496-
message << msgendl;
497-
message << " You possibly wanted to access: " << msgendl;
498-
message << tmp.rdbuf();
499-
}
500-
throw pybind11::attribute_error(message.str());
450+
return BindingBase::GetAttr(&self, name, true);
501451
}
502452

503453
/// gets an item using its path (path is dot-separated, relative to the object
@@ -599,8 +549,6 @@ void sendEvent(Node* self, py::object pyUserData, char* eventName)
599549
self->propagateEvent(sofa::core::execparams::defaultInstance(), &event);
600550
}
601551

602-
}
603-
604552
void moduleAddNode(py::module &m) {
605553
/// Register the complete parent-child relationship between Base and Node to the pybind11
606554
/// typing system.

0 commit comments

Comments
 (0)