@@ -233,7 +233,75 @@ public static IntPtr tp_str(IntPtr ob)
233233 }
234234 try
235235 {
236+ //As per python doc:
237+ //The return value must be a string object. If a class defines __repr__() but not __str__(),
238+ //then __repr__() is also used when an “informal” string representation of instances of that
239+ //class is required.
240+ //In C#, everything provides ToString(), so the check here will be whether the type explicitly
241+ //provides ToString() or if it is language provided (i.e. the fully qualified type name as a string)
242+
243+ //First check which type in the object hierarchy provides ToString()
244+ //ToString has two "official" overloads so loop over GetMethods to get the one without parameters
245+ var instType = co . inst . GetType ( ) ;
246+ foreach ( var method in instType . GetMethods ( ) )
247+ {
248+
249+ //TODO this could probably be done more cleanly with Linq
250+ if ( ! method . IsPublic ) continue ; //skip private/protected methods
251+ if ( method . Name != "ToString" ) continue ; //only look for ToString
252+ if ( method . DeclaringType == typeof ( object ) ) continue ; //ignore default from object
253+ if ( method . GetParameters ( ) . Length != 0 ) continue ; //ignore Formatter overload of ToString
254+
255+ //match! something other than object provides a parameter-less overload of ToString
256+ return Runtime . PyString_FromString ( co . inst . ToString ( ) ) ;
257+ }
258+
259+ //If the object defines __repr__, call it.
260+ System . Reflection . MethodInfo reprMethodInfo = instType . GetMethod ( "__repr__" ) ;
261+ if ( reprMethodInfo != null && reprMethodInfo . IsPublic )
262+ {
263+ var reprString = reprMethodInfo . Invoke ( co . inst , null ) as string ;
264+ return Runtime . PyString_FromString ( reprString ) ;
265+ }
266+
267+ //otherwise fallback to object's ToString() implementation
236268 return Runtime . PyString_FromString ( co . inst . ToString ( ) ) ;
269+
270+ }
271+ catch ( Exception e )
272+ {
273+ if ( e . InnerException != null )
274+ {
275+ e = e . InnerException ;
276+ }
277+ Exceptions . SetError ( e ) ;
278+ return IntPtr . Zero ;
279+ }
280+ }
281+
282+ public static IntPtr tp_repr ( IntPtr ob )
283+ {
284+ var co = GetManagedObject ( ob ) as CLRObject ;
285+ if ( co == null )
286+ {
287+ return Exceptions . RaiseTypeError ( "invalid object" ) ;
288+ }
289+ try
290+ {
291+ //if __repr__ is defined, use it
292+ var instType = co . inst . GetType ( ) ;
293+ System . Reflection . MethodInfo methodInfo = instType . GetMethod ( "__repr__" ) ;
294+ if ( methodInfo != null && methodInfo . IsPublic )
295+ {
296+ var reprString = methodInfo . Invoke ( co . inst , null ) as string ;
297+ return Runtime . PyString_FromString ( reprString ) ;
298+ }
299+
300+ //otherwise use the standard object.__repr__(inst)
301+ IntPtr args = Runtime . PyTuple_New ( 1 ) ;
302+ Runtime . PyTuple_SetItem ( args , 0 , ob ) ;
303+ IntPtr reprFunc = Runtime . PyObject_GetAttrString ( Runtime . PyBaseObjectType , "__repr__" ) ;
304+ return Runtime . PyObject_Call ( reprFunc , args , IntPtr . Zero ) ;
237305 }
238306 catch ( Exception e )
239307 {
0 commit comments