88
99#include " pycolmap/log_exceptions.h"
1010
11+ #include < exception>
1112#include < memory>
1213#include < regex>
1314#include < sstream>
@@ -33,17 +34,16 @@ const Eigen::IOFormat vec_fmt(Eigen::StreamPrecision,
3334
3435template <typename T>
3536inline T pyStringToEnum (const py::enum_<T>& enm, const std::string& value) {
36- auto values = enm.attr (" __members__" ).template cast <py::dict>();
37- auto strVal = py::str (value);
38- if (values.contains (strVal )) {
39- return T (values[strVal ].template cast <T>());
37+ const auto values = enm.attr (" __members__" ).template cast <py::dict>();
38+ const auto str_val = py::str (value);
39+ if (values.contains (str_val )) {
40+ return T (values[str_val ].template cast <T>());
4041 }
41- std::string msg =
42+ const std::string msg =
4243 " Invalid string value " + value + " for enum " +
4344 std::string (enm.attr (" __name__" ).template cast <std::string>());
4445 THROW_EXCEPTION (std::out_of_range, msg.c_str ());
45- T t;
46- return t;
46+ return T ();
4747}
4848
4949template <typename T>
@@ -54,25 +54,31 @@ inline void AddStringToEnumConstructor(py::enum_<T>& enm) {
5454 py::implicitly_convertible<std::string, T>();
5555}
5656
57- inline void UpdateFromDict (py::object& self, py::dict& dict) {
58- for (auto & it : dict) {
57+ inline void UpdateFromDict (py::object& self, const py::dict& dict) {
58+ for (const auto & it : dict) {
59+ if (!py::isinstance<py::str>(it.first )) {
60+ const std::string msg = " Dictionary key is not a string: " +
61+ py::str (it.first ).template cast <std::string>();
62+ THROW_EXCEPTION (std::invalid_argument, msg.c_str ());
63+ }
64+ const py::str name = py::reinterpret_borrow<py::str>(it.first );
65+ const py::handle& value = it.second ;
66+ const auto attr = self.attr (name);
5967 try {
60- if (py::hasattr (self. attr (it. first ) , " mergedict" )) {
61- self. attr (it. first ). attr (" mergedict" ).attr (" __call__" )(it. second );
68+ if (py::hasattr (attr, " mergedict" ) && py::isinstance<py::dict>(value )) {
69+ attr. attr (" mergedict" ).attr (" __call__" )(value );
6270 } else {
63- self.attr (it. first ) = it. second ;
71+ self.attr (name ) = value ;
6472 }
6573 } catch (const py::error_already_set& ex) {
6674 if (ex.matches (PyExc_TypeError)) {
6775 // If fail we try bases of the class
68- py::list bases = self.attr (it.first )
69- .attr (" __class__" )
70- .attr (" __bases__" )
71- .cast <py::list>();
76+ const py::list bases =
77+ attr.attr (" __class__" ).attr (" __bases__" ).cast <py::list>();
7278 bool success_on_base = false ;
7379 for (auto & base : bases) {
7480 try {
75- self.attr (it. first ) = base (it. second );
81+ self.attr (name ) = base (value );
7682 success_on_base = true ;
7783 break ;
7884 } catch (const py::error_already_set&) {
@@ -86,31 +92,27 @@ inline void UpdateFromDict(py::object& self, py::dict& dict) {
8692 ss << self.attr (" __class__" )
8793 .attr (" __name__" )
8894 .template cast <std::string>()
89- << " ." << py::str (it.first ).template cast <std::string>()
90- << " : Could not convert "
91- << py::type::of (it.second .cast <py::object>())
92- .attr (" __name__" )
93- .template cast <std::string>()
94- << " : " << py::str (it.second ).template cast <std::string>() << " to '"
95- << py::type::of (self.attr (it.first ))
95+ << " ." << name.template cast <std::string>() << " : Could not convert "
96+ << py::type::of (value.cast <py::object>())
9697 .attr (" __name__" )
9798 .template cast <std::string>()
99+ << " : " << py::str (value).template cast <std::string>() << " to '"
100+ << py::type::of (attr).attr (" __name__" ).template cast <std::string>()
98101 << " '." ;
99102 // We write the err message to give info even if exceptions
100103 // is catched outside, e.g. in function overload resolve
101104 LOG (ERROR) << " Internal TypeError: " << ss.str ();
102105 throw (py::type_error (std::string (" Failed to merge dict into class: " ) +
103106 " Could not assign " +
104- py::str (it. first ) .template cast <std::string>()));
107+ name .template cast <std::string>()));
105108 } else if (ex.matches (PyExc_AttributeError) &&
106109 py::str (ex.value ()).cast <std::string>() ==
107110 std::string (" can't set attribute" )) {
108111 std::stringstream ss;
109112 ss << self.attr (" __class__" )
110113 .attr (" __name__" )
111114 .template cast <std::string>()
112- << " ." << py::str (it.first ).template cast <std::string>()
113- << " defined readonly." ;
115+ << " ." << name.template cast <std::string>() << " defined readonly." ;
114116 throw py::attribute_error (ss.str ());
115117 } else if (ex.matches (PyExc_AttributeError)) {
116118 LOG (ERROR) << " Internal AttributeError: "
@@ -125,33 +127,32 @@ inline void UpdateFromDict(py::object& self, py::dict& dict) {
125127 }
126128}
127129
130+ bool AttributeIsFunction (const std::string& name, const py::object& attribute) {
131+ return (name.find (" __" ) == 0 || name.rfind (" __" ) != std::string::npos ||
132+ py::hasattr (attribute, " __func__" ) ||
133+ py::hasattr (attribute, " __call__" ));
134+ }
135+
128136template <typename T, typename ... options>
129137inline py::dict ConvertToDict (const T& self) {
130- auto pyself = py::cast (self);
138+ const auto pyself = py::cast (self);
131139 py::dict dict;
132- for (auto & handle : pyself.attr (" __dir__" )()) {
133- std::string attribute = py::str (handle);
134- auto member = pyself.attr (attribute.c_str ());
135- if (attribute.find (" __" ) != 0 &&
136- attribute.rfind (" __" ) == std::string::npos &&
137- !py::hasattr (member, " __func__" )) {
138- if (py::hasattr (member, " todict" )) {
139- dict[attribute.c_str ()] =
140- member.attr (" todict" ).attr (" __call__" )().template cast <py::dict>();
141- } else {
142- dict[attribute.c_str ()] = member;
143- }
140+ for (const auto & handle : pyself.attr (" __dir__" )()) {
141+ const py::str name = py::reinterpret_borrow<py::str>(handle);
142+ const auto attribute = pyself.attr (name);
143+ if (AttributeIsFunction (name, attribute)) {
144+ continue ;
145+ }
146+ if (py::hasattr (attribute, " todict" )) {
147+ dict[name] =
148+ attribute.attr (" todict" ).attr (" __call__" )().template cast <py::dict>();
149+ } else {
150+ dict[name] = attribute;
144151 }
145152 }
146153 return dict;
147154}
148155
149- bool AttributeIsFunction (const std::string& name, const py::object& attribute) {
150- return (name.find (" __" ) == 0 || name.rfind (" __" ) != std::string::npos ||
151- py::hasattr (attribute, " __func__" ) ||
152- py::hasattr (attribute, " __call__" ));
153- }
154-
155156template <typename T, typename ... options>
156157inline std::string CreateSummary (const T& self, bool write_type) {
157158 std::stringstream ss;
@@ -161,38 +162,38 @@ inline std::string CreateSummary(const T& self, bool write_type) {
161162 ss << pyself.attr (" __class__" ).attr (" __name__" ).template cast <std::string>()
162163 << " :" ;
163164 for (auto & handle : pyself.attr (" __dir__" )()) {
164- std::string attribute = py::str (handle);
165- py::object member ;
165+ const py::str name = py::reinterpret_borrow<py:: str> (handle);
166+ py::object attribute ;
166167 try {
167- member = pyself.attr (attribute. c_str () );
168+ attribute = pyself.attr (name );
168169 } catch (const std::exception& e) {
169170 // Some properties are not valid for some uninitialized objects.
170171 continue ;
171172 }
172- if (AttributeIsFunction (attribute, member )) {
173+ if (AttributeIsFunction (name, attribute )) {
173174 continue ;
174175 }
175176 ss << " \n " ;
176177 if (!after_subsummary) {
177178 ss << prefix;
178179 }
179- ss << attribute;
180- if (py::hasattr (member , " summary" )) {
181- std::string summ = member .attr (" summary" )
180+ ss << attribute. template cast <std::string>() ;
181+ if (py::hasattr (attribute , " summary" )) {
182+ std::string summ = attribute .attr (" summary" )
182183 .attr (" __call__" )(write_type)
183184 .template cast <std::string>();
184185 summ = std::regex_replace (summ, std::regex (" \n " ), " \n " + prefix);
185186 ss << " : " << summ;
186187 } else {
187188 if (write_type) {
188189 const std::string type_str =
189- py::str (py::type::of (member ).attr (" __name__" ));
190+ py::str (py::type::of (attribute ).attr (" __name__" ));
190191 ss << " : " << type_str;
191192 after_subsummary = true ;
192193 }
193- std::string value = py::str (member );
194- if (value.length () > 80 && py::hasattr (member , " __len__" )) {
195- const int length = member .attr (" __len__" )().template cast <int >();
194+ std::string value = py::str (attribute );
195+ if (value.length () > 80 && py::hasattr (attribute , " __len__" )) {
196+ const int length = attribute .attr (" __len__" )().template cast <int >();
196197 value = StringPrintf (
197198 " %c ... %d elements ... %c" , value.front (), length, value.back ());
198199 }
0 commit comments