@@ -119,6 +119,73 @@ class cpp_function : public function {
119119 return new detail::function_record ();
120120 }
121121
122+ template <typename ContainerHandle, typename StringifierUnary>
123+ static std::string join (ContainerHandle container, StringifierUnary&& f, std::string sep = " , " ) {
124+ std::string joined;
125+ for (auto element : container) {
126+ joined += f (element) + sep;
127+ }
128+ if (!joined.empty ()) {
129+ joined.erase (joined.size () - sep.size ());
130+ }
131+ return joined;
132+ }
133+
134+ // Generate a literal expression for default function argument values
135+ static std::string compose_literal (pybind11::handle h) {
136+ auto typehandle = type::handle_of (h);
137+ if (detail::get_internals ().registered_types_py .count (Py_TYPE (h.ptr ())) > 0 ) {
138+ if (hasattr (typehandle, " __members__" ) && hasattr (h, " name" )) {
139+ // Bound enum type, can be fully represented
140+ auto descr = typehandle.attr (" __module__" ).cast <std::string>();
141+ descr += " ." + typehandle.attr (" __qualname__" ).cast <std::string>();
142+ descr += " ." + h.attr (" name" ).cast <std::string>();
143+ return descr;
144+ }
145+
146+ // Use ellipsis expression instead of repr to ensure syntactic validity
147+ return " ..." ;
148+ }
149+
150+ if (isinstance<dict>(h)) {
151+ std::string literal = " {" ;
152+ literal += join (
153+ reinterpret_borrow<dict>(h),
154+ [](const std::pair<handle, handle>& v) { return compose_literal (v.first ) + " : " + compose_literal (v.second ); }
155+ );
156+ literal += " }" ;
157+ return literal;
158+ }
159+
160+ if (isinstance<list>(h)) {
161+ std::string literal = " [" ;
162+ literal += join (reinterpret_borrow<list>(h), &compose_literal);
163+ literal += " ]" ;
164+ return literal;
165+ }
166+
167+ if (isinstance<tuple>(h)) {
168+ std::string literal = " (" ;
169+ literal += join (reinterpret_borrow<tuple>(h), &compose_literal);
170+ literal += " )" ;
171+ return literal;
172+ }
173+
174+ if (isinstance<set>(h)) {
175+ auto v = reinterpret_borrow<set>(h);
176+ if (v.empty ()) {
177+ return " set()" ;
178+ }
179+ std::string literal = " {" ;
180+ literal += join (v, &compose_literal);
181+ literal += " }" ;
182+ return literal;
183+ }
184+
185+ // All other types should be terminal and well-represented by repr
186+ return repr (h).cast <std::string>();
187+ }
188+
122189 // / Special internal constructor for functors, lambda functions, etc.
123190 template <typename Func, typename Return, typename ... Args, typename ... Extra>
124191 void initialize (Func &&f, Return (*)(Args...), const Extra&... extra) {
@@ -235,8 +302,10 @@ class cpp_function : public function {
235302 a.name = strdup (a.name );
236303 if (a.descr )
237304 a.descr = strdup (a.descr );
238- else if (a.value )
239- a.descr = strdup (repr (a.value ).cast <std::string>().c_str ());
305+ else if (a.value ) {
306+ std::string literal = compose_literal (a.value );
307+ a.descr = strdup (literal.c_str ());
308+ }
240309 }
241310
242311 rec->is_constructor = !strcmp (rec->name , " __init__" ) || !strcmp (rec->name , " __setstate__" );
0 commit comments