mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
Add optional default_val parameter to GetProp() (#9242)
* SHARED-12256: Add test and change function.
* SHARED-12256: Update to only wrapping changes.
* SHARED-12256: Parameterize tests.
* SHARED-12256: GetPropIfPresent changes.
* Revert "SHARED-12256: GetPropIfPresent changes."
This reverts commit f598f8c161.
* SHARED-12256: Make default the keyword in the boost wrappings.
* SHARED-12256: Overload function instead of using a sentinel.
* SHARED-12256: Extend GetProp changes.
* SHARED-12256: Add entry point for tests and fix tests.
This commit is contained in:
committed by
greg landrum
parent
4b714e973b
commit
709def06a7
@@ -344,6 +344,18 @@ struct atom_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def(
|
||||
"GetProp", GetPyPropOrDefault<Atom>,
|
||||
(python::arg("self"), python::arg("key"),
|
||||
python::arg("autoConvert") = false,
|
||||
python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - autoConvert: if True attempt to convert the property into a python object\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: the property value, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("SetIntProp", AtomSetProp<int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
@@ -369,6 +381,14 @@ struct atom_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetIntProp", GetPropOrDefault<Atom, int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (an int).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an int, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("GetUnsignedProp", GetProp<Atom, unsigned>,
|
||||
python::args("self", "key"),
|
||||
@@ -381,6 +401,14 @@ struct atom_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedProp", GetPropOrDefault<Atom, unsigned>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (an unsigned integer).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an integer, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("SetDoubleProp", AtomSetProp<double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
"Sets an atomic property\n\n"
|
||||
@@ -398,6 +426,14 @@ struct atom_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetDoubleProp", GetPropOrDefault<Atom, double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a double).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a double, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("SetBoolProp", AtomSetProp<bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
@@ -415,6 +451,14 @@ struct atom_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetBoolProp", GetPropOrDefault<Atom, bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a bool).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a bool, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("SetExplicitBitVectProp", AtomSetProp<ExplicitBitVect>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
|
||||
@@ -216,6 +216,18 @@ struct bond_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def(
|
||||
"GetProp", GetPyPropOrDefault<Bond>,
|
||||
(python::arg("self"), python::arg("key"),
|
||||
python::arg("autoConvert") = false,
|
||||
python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - autoConvert: if True attempt to convert the property into a python object\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: the property value, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("SetIntProp", BondSetProp<int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
"Sets a bond property\n\n"
|
||||
@@ -239,6 +251,14 @@ struct bond_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetIntProp", GetPropOrDefault<Bond, int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (an int).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an int, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("GetUnsignedProp", GetProp<Bond, unsigned int>,
|
||||
python::args("self", "key"),
|
||||
@@ -251,6 +271,14 @@ struct bond_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedProp", GetPropOrDefault<Bond, unsigned int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (an unsigned integer).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an integer, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("SetDoubleProp", BondSetProp<double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
@@ -269,6 +297,14 @@ struct bond_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetDoubleProp", GetPropOrDefault<Bond, double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a double).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a double, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("SetBoolProp", BondSetProp<bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("val")),
|
||||
@@ -286,6 +322,14 @@ struct bond_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetBoolProp", GetPropOrDefault<Bond, bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a boolean).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a bool, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
|
||||
.def("HasProp", BondHasProp, python::args("self", "key"),
|
||||
"Queries a Bond to see if a particular property has been "
|
||||
|
||||
@@ -61,6 +61,9 @@ endif(RDK_BUILD_COMPRESSED_SUPPLIERS)
|
||||
add_pytest(pyGraphMolWrap
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rough_test.py)
|
||||
|
||||
add_pytest(pyTestGetPropDefault
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testGetPropDefault.py)
|
||||
|
||||
add_pytest(pyTestConformerWrap
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testConformer.py)
|
||||
|
||||
|
||||
@@ -240,6 +240,18 @@ struct conformer_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def(
|
||||
"GetProp", GetPyPropOrDefault<Conformer>,
|
||||
(python::arg("self"), python::arg("key"),
|
||||
python::arg("autoConvert") = false,
|
||||
python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - autoConvert: if True attempt to convert the property into a python object\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: the property value, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetDoubleProp", GetProp<Conformer, double>,
|
||||
python::args("self", "key"),
|
||||
"Returns the double value of the property if possible.\n\n"
|
||||
@@ -249,6 +261,14 @@ struct conformer_wrapper {
|
||||
" NOTE:\n"
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n")
|
||||
.def("GetDoubleProp", GetPropOrDefault<Conformer, double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the double value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a double, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetIntProp", GetProp<Conformer, int>, python::args("self", "key"),
|
||||
"Returns the integer value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
@@ -257,6 +277,14 @@ struct conformer_wrapper {
|
||||
" NOTE:\n"
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n")
|
||||
.def("GetIntProp", GetPropOrDefault<Conformer, int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the integer value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an integer, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedProp", GetProp<Conformer, unsigned int>,
|
||||
python::args("self", "key"),
|
||||
"Returns the unsigned int value of the property if possible.\n\n"
|
||||
@@ -266,6 +294,14 @@ struct conformer_wrapper {
|
||||
" NOTE:\n"
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n")
|
||||
.def("GetUnsignedProp", GetPropOrDefault<Conformer, unsigned int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the unsigned int value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an unsigned integer, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetBoolProp", GetProp<Conformer, bool>,
|
||||
python::args("self", "key"),
|
||||
"Returns the Bool value of the property if possible.\n\n"
|
||||
@@ -275,6 +311,14 @@ struct conformer_wrapper {
|
||||
" NOTE:\n"
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n")
|
||||
.def("GetBoolProp", GetPropOrDefault<Conformer, bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the Bool value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a bool, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("ClearProp", MolClearProp<Conformer>, python::args("self", "key"),
|
||||
"Removes a property from the conformer.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
|
||||
@@ -757,6 +757,18 @@ struct mol_wrapper {
|
||||
" NOTE:\n"
|
||||
" - If the property has not been set, a KeyError exception will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def(
|
||||
"GetProp", GetPyPropOrDefault<ROMol>,
|
||||
(python::arg("self"), python::arg("key"),
|
||||
python::arg("autoConvert") = false,
|
||||
python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - autoConvert: if True attempt to convert the property into a python object\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: the property value, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetDoubleProp", GetProp<ROMol, double>,
|
||||
python::args("self", "key"),
|
||||
"Returns the double value of the property if possible.\n\n"
|
||||
@@ -767,6 +779,14 @@ struct mol_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetDoubleProp", GetPropOrDefault<ROMol, double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the double value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a double, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetIntProp", GetProp<ROMol, int>, python::args("self", "key"),
|
||||
"Returns the integer value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
@@ -776,6 +796,14 @@ struct mol_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetIntProp", GetPropOrDefault<ROMol, int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the integer value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an integer, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedProp", GetProp<ROMol, unsigned int>,
|
||||
python::args("self", "key"),
|
||||
"Returns the unsigned int value of the property if possible.\n\n"
|
||||
@@ -786,6 +814,14 @@ struct mol_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedProp", GetPropOrDefault<ROMol, unsigned int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the unsigned int value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: an unsigned integer, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetBoolProp", GetProp<ROMol, bool>, python::args("self", "key"),
|
||||
"Returns the Bool value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
@@ -795,6 +831,14 @@ struct mol_wrapper {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetBoolProp", GetPropOrDefault<ROMol, bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"Returns the Bool value of the property if possible.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: a bool, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("ClearProp", MolClearProp<ROMol>, python::args("self", "key"),
|
||||
"Removes a property from the molecule.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
|
||||
@@ -260,26 +260,54 @@ struct sgroup_wrap {
|
||||
" - If the property has not been set, a KeyError exception "
|
||||
"will be raised.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def(
|
||||
"GetProp", GetPyPropOrDefault<SubstanceGroup>,
|
||||
(python::arg("self"), python::arg("key"),
|
||||
python::arg("autoConvert") = false,
|
||||
python::arg("default")),
|
||||
"Returns the value of the property.\n\n"
|
||||
" ARGUMENTS:\n"
|
||||
" - key: the name of the property to return (a string).\n\n"
|
||||
" - autoConvert: if True attempt to convert the property into a python object\n\n"
|
||||
" - default: value to return if the property is not present.\n\n"
|
||||
" RETURNS: the property value, or default if the property is not present.\n",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetIntProp",
|
||||
(int (RDProps::*)(const std::string_view) const) &
|
||||
SubstanceGroup::getProp<int>,
|
||||
python::args("self", "key"),
|
||||
"returns the value of a particular property")
|
||||
.def("GetIntProp", GetPropOrDefault<SubstanceGroup, int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"returns the value of a particular property, or default if not present",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedProp",
|
||||
(unsigned int (RDProps::*)(const std::string_view) const) &
|
||||
SubstanceGroup::getProp<unsigned int>,
|
||||
python::args("self", "key"),
|
||||
"returns the value of a particular property")
|
||||
.def("GetUnsignedProp", GetPropOrDefault<SubstanceGroup, unsigned int>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"returns the value of a particular property, or default if not present",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetDoubleProp",
|
||||
(double (RDProps::*)(const std::string_view) const) &
|
||||
SubstanceGroup::getProp<double>,
|
||||
python::args("self", "key"),
|
||||
"returns the value of a particular property")
|
||||
.def("GetDoubleProp", GetPropOrDefault<SubstanceGroup, double>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"returns the value of a particular property, or default if not present",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetBoolProp",
|
||||
(bool (RDProps::*)(const std::string_view) const) &
|
||||
SubstanceGroup::getProp<bool>,
|
||||
python::args("self", "key"),
|
||||
"returns the value of a particular property")
|
||||
.def("GetBoolProp", GetPropOrDefault<SubstanceGroup, bool>,
|
||||
(python::arg("self"), python::arg("key"), python::arg("default")),
|
||||
"returns the value of a particular property, or default if not present",
|
||||
boost::python::return_value_policy<return_pyobject_passthrough>())
|
||||
.def("GetUnsignedVectProp",
|
||||
(std::vector<unsigned int> (RDProps::*)(const std::string_view)
|
||||
const) &
|
||||
|
||||
@@ -212,30 +212,59 @@ PyObject *GetProp(const RDOb *ob, const std::string &key) {
|
||||
return rawPy(std::move(res));
|
||||
}
|
||||
|
||||
template <class RDOb, class T>
|
||||
PyObject *GetPropOrDefault(const RDOb *ob, const std::string &key,
|
||||
T default_val) {
|
||||
T res;
|
||||
try {
|
||||
if (!ob->getPropIfPresent(key, res)) {
|
||||
return rawPy(std::move(default_val));
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
auto msg = std::string("key `") + key + "` exists but does not result in " +
|
||||
GetTypeName<T>() + " reason: " + e.what();
|
||||
PyErr_SetString(PyExc_ValueError, msg.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
return rawPy(std::move(res));
|
||||
}
|
||||
|
||||
template <class RDOb>
|
||||
python::object autoConvertString(const RDOb *ob, const std::string &key) {
|
||||
int ivalue;
|
||||
double dvalue;
|
||||
std::string svalue;
|
||||
|
||||
if (ob->getPropIfPresent(key, ivalue)) {
|
||||
return python::object(ivalue);
|
||||
} else if (ob->getPropIfPresent(key, dvalue)) {
|
||||
return python::object(dvalue);
|
||||
} else if (ob->getPropIfPresent(key, svalue)) {
|
||||
try {
|
||||
if (ob->getPropIfPresent(key, ivalue)) {
|
||||
return python::object(ivalue);
|
||||
}
|
||||
} catch (const std::bad_any_cast &) {}
|
||||
|
||||
try {
|
||||
if (ob->getPropIfPresent(key, dvalue)) {
|
||||
return python::object(dvalue);
|
||||
}
|
||||
} catch (const std::bad_any_cast &) {}
|
||||
|
||||
if (ob->getPropIfPresent(key, svalue)) {
|
||||
return python::object(svalue);
|
||||
}
|
||||
|
||||
return python::object();
|
||||
}
|
||||
|
||||
// nullptr = raise KeyError; non-null = return *default_val_ptr as fallback
|
||||
template <class RDOb>
|
||||
PyObject *GetPyProp(const RDOb *obj, const std::string &key, bool autoConvert) {
|
||||
PyObject *GetPyPropImpl(const RDOb *obj, const std::string &key,
|
||||
bool autoConvert, python::object *default_val_ptr) {
|
||||
python::object pobj;
|
||||
if (!autoConvert) {
|
||||
std::string res;
|
||||
if (obj->getPropIfPresent(key, res)) {
|
||||
return rawPy(res);
|
||||
} else if (default_val_ptr && !obj->hasProp(key)) {
|
||||
return rawPy(*default_val_ptr);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_KeyError, key.c_str());
|
||||
return nullptr;
|
||||
@@ -256,6 +285,7 @@ PyObject *GetPyProp(const RDOb *obj, const std::string &key, bool autoConvert) {
|
||||
case RDTypeTag::StringTag:
|
||||
if (autoConvert) {
|
||||
pobj = autoConvertString(obj, rdvalue.key);
|
||||
return rawPy(pobj);
|
||||
}
|
||||
return rawPy(from_rdvalue<std::string>(rdvalue.val));
|
||||
case RDTypeTag::FloatTag:
|
||||
@@ -309,10 +339,28 @@ PyObject *GetPyProp(const RDOb *obj, const std::string &key, bool autoConvert) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// We reach here only when autoConvert=true and the key was not returned by
|
||||
// the loop above. Two cases: (a) key not in dict at all — hasProp is false,
|
||||
// return default; (b) key exists as AnyTag (skipped by the loop) — hasProp
|
||||
// is true, raise KeyError as the property cannot be converted.
|
||||
if (default_val_ptr && !obj->hasProp(key)) {
|
||||
return rawPy(*default_val_ptr);
|
||||
}
|
||||
PyErr_SetString(PyExc_KeyError, key.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class RDOb>
|
||||
PyObject *GetPyProp(const RDOb *obj, const std::string &key, bool autoConvert) {
|
||||
return GetPyPropImpl(obj, key, autoConvert, nullptr);
|
||||
}
|
||||
|
||||
template <class RDOb>
|
||||
PyObject *GetPyPropOrDefault(const RDOb *obj, const std::string &key,
|
||||
bool autoConvert, python::object default_val) {
|
||||
return GetPyPropImpl(obj, key, autoConvert, &default_val);
|
||||
}
|
||||
|
||||
// Return policy for functions that directly return a PyObject* and
|
||||
// are fully responsible for setting the Python error state.
|
||||
struct return_pyobject_passthrough {
|
||||
|
||||
169
Code/GraphMol/Wrap/testGetPropDefault.py
Normal file
169
Code/GraphMol/Wrap/testGetPropDefault.py
Normal file
@@ -0,0 +1,169 @@
|
||||
import pytest
|
||||
|
||||
from rdkit import Chem
|
||||
from rdkit.Chem import AllChem
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GetProp with default
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.parametrize("auto_convert", [False, True])
|
||||
@pytest.mark.parametrize("default", [None, "fallback", 0, 0.0])
|
||||
def test_get_prop_with_default_missing(auto_convert, default):
|
||||
"""Default is returned when the property is not set."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
assert m.GetProp("test_prop", autoConvert=auto_convert,
|
||||
default=default) == default
|
||||
|
||||
|
||||
@pytest.mark.parametrize("auto_convert", [False, True])
|
||||
@pytest.mark.parametrize("prop_value, default, unconverted_value", [
|
||||
("value", "fallback", "value"),
|
||||
("value", None, "value"),
|
||||
(42, 0, '42'),
|
||||
(42.0, 0.0, '42'),
|
||||
])
|
||||
def test_get_prop_with_default_present(auto_convert, prop_value, default, unconverted_value):
|
||||
"""The stored property value is returned, not the default."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
if isinstance(prop_value, int):
|
||||
m.SetIntProp("test_prop", prop_value)
|
||||
elif isinstance(prop_value, float):
|
||||
m.SetDoubleProp("test_prop", prop_value)
|
||||
else:
|
||||
m.SetProp("test_prop", prop_value)
|
||||
expected = prop_value if auto_convert else unconverted_value
|
||||
assert m.GetProp("test_prop", autoConvert=auto_convert,
|
||||
default=default) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("auto_convert", [False, True])
|
||||
def test_get_prop_no_default_not_set(auto_convert):
|
||||
"""KeyError is raised when the property is missing and no default is given."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
with pytest.raises(KeyError):
|
||||
m.GetProp("test_prop", autoConvert=auto_convert)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("auto_convert", [False, True])
|
||||
@pytest.mark.parametrize("prop_value, unconverted_value", [
|
||||
("hello", "hello"),
|
||||
(42, "42"),
|
||||
(42.0, "42"),
|
||||
])
|
||||
def test_get_prop_no_default_set(auto_convert, prop_value, unconverted_value):
|
||||
"""GetProp without default returns the stored value normally."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
if isinstance(prop_value, int):
|
||||
m.SetIntProp("test_prop", prop_value)
|
||||
elif isinstance(prop_value, float):
|
||||
m.SetDoubleProp("test_prop", prop_value)
|
||||
else:
|
||||
m.SetProp("test_prop", prop_value)
|
||||
expected = prop_value if auto_convert else unconverted_value
|
||||
assert m.GetProp("test_prop", autoConvert=auto_convert) == expected
|
||||
|
||||
|
||||
def test_get_prop_default_positional():
|
||||
"""default can be supplied positionally as the third argument."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
with pytest.raises(KeyError):
|
||||
m.GetProp("test_prop", True)
|
||||
default_val = m.GetProp("test_prop", True, True)
|
||||
assert default_val is True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GetProp with default on Atom, Bond, Conformer, SubstanceGroup
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_get_prop_default_on_atom():
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
atom = m.GetAtomWithIdx(0)
|
||||
assert atom.GetProp("missing", default="x") == "x"
|
||||
with pytest.raises(KeyError):
|
||||
atom.GetProp("missing")
|
||||
atom.SetProp("p", "v")
|
||||
assert atom.GetProp("p", default="x") == "v"
|
||||
|
||||
|
||||
def test_get_prop_default_on_bond():
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
bond = m.GetBondWithIdx(0)
|
||||
assert bond.GetProp("missing", default="x") == "x"
|
||||
with pytest.raises(KeyError):
|
||||
bond.GetProp("missing")
|
||||
bond.SetProp("p", "v")
|
||||
assert bond.GetProp("p", default="x") == "v"
|
||||
|
||||
|
||||
def test_get_prop_default_on_conformer():
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
AllChem.EmbedMolecule(m, randomSeed=42)
|
||||
conf = m.GetConformer()
|
||||
assert conf.GetProp("missing", default="x") == "x"
|
||||
with pytest.raises(KeyError):
|
||||
conf.GetProp("missing")
|
||||
conf.SetProp("p", "v")
|
||||
assert conf.GetProp("p", default="x") == "v"
|
||||
|
||||
|
||||
def test_get_prop_default_on_substance_group():
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
sg = Chem.CreateMolSubstanceGroup(m, "SRU")
|
||||
assert sg.GetProp("missing", default="x") == "x"
|
||||
with pytest.raises(KeyError):
|
||||
sg.GetProp("missing")
|
||||
sg.SetProp("p", "v")
|
||||
assert sg.GetProp("p", default="x") == "v"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Typed getters with default — Mol
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.parametrize("set_fn, get_fn, val, default", [
|
||||
("SetIntProp", "GetIntProp", 42, 0),
|
||||
("SetDoubleProp", "GetDoubleProp", 3.14, 0.0),
|
||||
("SetBoolProp", "GetBoolProp", True, False),
|
||||
("SetUnsignedProp", "GetUnsignedProp", 7, 0),
|
||||
])
|
||||
def test_typed_getter_with_default_present(set_fn, get_fn, val, default):
|
||||
"""Stored typed value is returned even when a default is provided."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
getattr(m, set_fn)("p", val)
|
||||
assert getattr(m, get_fn)("p", default=default) == val
|
||||
|
||||
|
||||
@pytest.mark.parametrize("get_fn, default", [
|
||||
("GetIntProp", 0),
|
||||
("GetDoubleProp", 0.0),
|
||||
("GetBoolProp", False),
|
||||
("GetUnsignedProp", 0),
|
||||
])
|
||||
def test_typed_getter_with_default_missing(get_fn, default):
|
||||
"""Default is returned when the property is not set."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
assert getattr(m, get_fn)("missing", default=default) == default
|
||||
|
||||
|
||||
@pytest.mark.parametrize("get_fn", ["GetIntProp", "GetDoubleProp", "GetBoolProp", "GetUnsignedProp"])
|
||||
def test_typed_getter_no_default_raises(get_fn):
|
||||
"""Without a default, KeyError is raised for a missing property."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
with pytest.raises(KeyError):
|
||||
getattr(m, get_fn)("missing")
|
||||
|
||||
|
||||
def test_typed_getter_default_wrong_type_raises_value_error():
|
||||
"""GetIntProp(default=x) raises ValueError when the key exists but holds the wrong type."""
|
||||
m = Chem.MolFromSmiles("CC")
|
||||
m.SetDoubleProp("dbl_key", 3.14)
|
||||
with pytest.raises(ValueError):
|
||||
m.GetIntProp("dbl_key", default=0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.exit(pytest.main([__file__]))
|
||||
Reference in New Issue
Block a user