diff --git a/src/interfaces/python/swig_typemaps.i b/src/interfaces/python/swig_typemaps.i index db7818f5cf1..59289e9c9f7 100644 --- a/src/interfaces/python/swig_typemaps.i +++ b/src/interfaces/python/swig_typemaps.i @@ -1417,7 +1417,7 @@ def _internal_get_param(self, name): except Exception: raise if name in self.parameter_names(): - raise ValueError("The current Python API does not have a getter for '{}'".format(name)) + raise ValueError("The current Python API does not have a getter for '{}' of type '{}'".format(name, self.parameter_type(name))) else: raise KeyError("There is no parameter called '{}' in {}".format(name, self.get_name())) diff --git a/src/interfaces/swig/SGBase.i b/src/interfaces/swig/SGBase.i index 6d1fc470902..7a437e9621f 100644 --- a/src/interfaces/swig/SGBase.i +++ b/src/interfaces/swig/SGBase.i @@ -1,3 +1,9 @@ +/* + * This software is distributed under BSD 3-clause license (see LICENSE file). + * + * Authors: Gil Hoben, Heiko Strathmann, Sergey Lisitsyn + */ + /* base includes required by any module */ %include "stdint.i" %include "std_string.i" @@ -373,12 +379,39 @@ namespace std { %include %include -#ifdef SWIGPYTHON namespace shogun { - %extend CSGObject { + std::vector parameter_names() const { + std::vector result; + for (auto const& each: $self->get_params()) { + result.push_back(each.first); + } + return result; + } + + std::string parameter_type(const std::string& name) const { + auto params = $self->get_params(); + if (params.find(name) != params.end()) { + return params[name].get()->get_value().type(); + } + else { + SG_SERROR("There is no parameter called '%s' in %s", name.c_str(), $self->get_name()); + } + } + + std::string parameter_description(const std::string& name) const { + auto params = $self->get_params(); + if (params.find(name) != params.end()) { + return params[name].get()->get_properties().get_description(); + } + else { + SG_SERROR("There is no parameter called '%s' in %s", name.c_str(), $self->get_name()); + } + } + +#ifdef SWIGPYTHON std::string __str__() const { return $self->to_string(); @@ -485,9 +518,11 @@ namespace shogun } /*int getbuffer(PyObject *obj, Py_buffer *view, int flags) { return 0; }*/ +#endif //SWIGPYTHON } } +#ifdef SWIGPYTHON %pythoncode %{ try: import copy_reg diff --git a/src/shogun/base/SGObject.cpp b/src/shogun/base/SGObject.cpp index 155e8821d92..f8b1e7f1f0c 100644 --- a/src/shogun/base/SGObject.cpp +++ b/src/shogun/base/SGObject.cpp @@ -975,14 +975,16 @@ std::string CSGObject::to_string() const return ss.str(); } -std::vector CSGObject::parameter_names() const +#ifndef SWIG // SWIG should skip this part +std::map> CSGObject::get_params() const { - std::vector result; - std::transform(self->map.cbegin(), self->map.cend(), std::back_inserter(result), - // FIXME: const auto& each fails on gcc 4.8.4 - [](const std::pair& each) -> std::string { return each.first.name(); }); + std::map> result; + for (auto const& each: self->map) { + result.emplace(each.first.name(), std::make_shared(each.second)); + } return result; } +#endif bool CSGObject::equals(const CSGObject* other) const { @@ -1068,11 +1070,19 @@ CSGObject* CSGObject::get(const std::string& name) if (auto* result = get_sgobject_type_dispatcher(name)) return result; - - SG_ERROR( - "Cannot get parameter %s::%s of type %s as object, not object type.\n", - get_name(), name.c_str(), - self->map[BaseTag(name)].get_value().type().c_str()); + if (self->map.find(BaseTag(name)) != self->map.end()) + { + SG_ERROR( + "Cannot get parameter %s::%s of type %s as object, not a shogun " + "object base type.\n", + get_name(), name.c_str(), + self->map[BaseTag(name)].get_value().type().c_str()); + } + else + { + SG_ERROR( + "There is no parameter '%s' in %s.\n", name.c_str(), get_name()); + } return nullptr; } diff --git a/src/shogun/base/SGObject.h b/src/shogun/base/SGObject.h index 7c9cb97ad89..cae68ddc15c 100644 --- a/src/shogun/base/SGObject.h +++ b/src/shogun/base/SGObject.h @@ -28,6 +28,7 @@ #include #include +#include /** \namespace shogun * @brief all of classes and functions are contained in the shogun namespace @@ -79,14 +80,13 @@ template class SGStringList; #define VARARG_IMPL(base, count, ...) VARARG_IMPL2(base, count, __VA_ARGS__) #define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__) -#define SG_ADD3(param, name, description) \ +#define SG_ADD3(param, name, description) \ { \ this->m_parameters->add(param, name, description); \ - this->watch_param( \ - name, param, AnyParameterProperties()); \ + this->watch_param(name, param, AnyParameterProperties(description)); \ } -#define SG_ADD4(param, name, description, param_properties) \ +#define SG_ADD4(param, name, description, param_properties) \ { \ AnyParameterProperties pprop = \ AnyParameterProperties(description, param_properties); \ @@ -533,11 +533,13 @@ class CSGObject */ virtual std::string to_string() const; - /** Returns set of all parameter names of the object. + /** Returns map of parameter names and AnyParameter pairs + * of the object. * */ - std::vector parameter_names() const; - +#ifndef SWIG // SWIG should skip this part + std::map> get_params() const; +#endif /** Specializes a provided object to the specified type. * Throws exception if the object cannot be specialized. * diff --git a/tests/unit/base/SGObjectAll_unittest.cc b/tests/unit/base/SGObjectAll_unittest.cc index 493b8741109..0fd3be8e06a 100644 --- a/tests/unit/base/SGObjectAll_unittest.cc +++ b/tests/unit/base/SGObjectAll_unittest.cc @@ -293,7 +293,12 @@ TEST(SGObjectAll, DISABLED_tag_coverage) std::vector old_names; for (auto i : range(obj->m_parameters->get_num_parameters())) old_names.push_back(obj->m_parameters->get_parameter(i)->m_name); - auto tag_names = obj->parameter_names(); + + std::vector tag_names; + std::transform(obj->get_params().cbegin(), obj->get_params().cend(), std::back_inserter(tag_names), + [](const std::pair>& each) -> std::string { + return each.first; + }); // hack to increase readability of error messages old_names.push_back("_Shogun class: " + class_name);