11using System ;
22using System . Collections . Generic ;
3+ using System . Linq ;
34using System . Reflection ;
45
56namespace Python . Runtime
@@ -65,6 +66,67 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx)
6566 return mb . pyHandle ;
6667 }
6768
69+ PyObject Signature
70+ {
71+ get
72+ {
73+ var infos = this . info . Valid ? new [ ] { this . info . Value } : this . m . info ;
74+ Type type = infos . Select ( i => i . DeclaringType )
75+ . OrderByDescending ( t => t , new TypeSpecificityComparer ( ) )
76+ . First ( ) ;
77+ infos = infos . Where ( info => info . DeclaringType == type ) . ToArray ( ) ;
78+ // this is a primitive version
79+ // the overload with the maximum number of parameters should be used
80+ MethodInfo primary = infos . OrderByDescending ( i => i . GetParameters ( ) . Length ) . First ( ) ;
81+ var primaryParameters = primary . GetParameters ( ) ;
82+ PyObject signatureClass = Runtime . InspectModule . GetAttr ( "Signature" ) ;
83+ var primaryReturn = primary . ReturnParameter ;
84+
85+ using var parameters = new PyList ( ) ;
86+ using var parameterClass = primaryParameters . Length > 0 ? Runtime . InspectModule . GetAttr ( "Parameter" ) : null ;
87+ using var positionalOrKeyword = parameterClass ? . GetAttr ( "POSITIONAL_OR_KEYWORD" ) ;
88+ for ( int i = 0 ; i < primaryParameters . Length ; i ++ )
89+ {
90+ var parameter = primaryParameters [ i ] ;
91+ var alternatives = infos . Select ( info =>
92+ {
93+ ParameterInfo [ ] altParamters = info . GetParameters ( ) ;
94+ return i < altParamters . Length ? altParamters [ i ] : null ;
95+ } ) . Where ( p => p != null ) ;
96+ using var defaultValue = alternatives
97+ . Select ( alternative => alternative . DefaultValue != DBNull . Value ? alternative . DefaultValue . ToPython ( ) : null )
98+ . FirstOrDefault ( v => v != null ) ?? parameterClass . GetAttr ( "empty" ) ;
99+
100+ if ( alternatives . Any ( alternative => alternative . Name != parameter . Name ) )
101+ {
102+ return signatureClass . Invoke ( ) ;
103+ }
104+
105+ using var args = new PyTuple ( new [ ] { parameter . Name . ToPython ( ) , positionalOrKeyword } ) ;
106+ using var kw = new PyDict ( ) ;
107+ if ( defaultValue is not null )
108+ {
109+ kw [ "default" ] = defaultValue ;
110+ }
111+ using var parameterInfo = parameterClass . Invoke ( args : args , kw : kw ) ;
112+ parameters . Append ( parameterInfo ) ;
113+ }
114+
115+ // TODO: add return annotation
116+ return signatureClass . Invoke ( parameters ) ;
117+ }
118+ }
119+
120+ struct TypeSpecificityComparer : IComparer < Type >
121+ {
122+ public int Compare ( Type a , Type b )
123+ {
124+ if ( a == b ) return 0 ;
125+ if ( a . IsSubclassOf ( b ) ) return 1 ;
126+ if ( b . IsSubclassOf ( a ) ) return - 1 ;
127+ throw new NotSupportedException ( ) ;
128+ }
129+ }
68130
69131 /// <summary>
70132 /// MethodBinding __getattribute__ implementation.
@@ -91,6 +153,15 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
91153 case "Overloads" :
92154 var om = new OverloadMapper ( self . m , self . target ) ;
93155 return om . pyHandle ;
156+ case "__signature__" when Runtime . InspectModule is not null :
157+ var sig = self . Signature ;
158+ if ( sig is null )
159+ {
160+ return Runtime . PyObject_GenericGetAttr ( ob , key ) ;
161+ }
162+ return sig . NewReferenceOrNull ( ) . DangerousMoveToPointerOrNull ( ) ;
163+ case "__name__" :
164+ return self . m . GetName ( ) . DangerousMoveToPointerOrNull ( ) ;
94165 default :
95166 return Runtime . PyObject_GenericGetAttr ( ob , key ) ;
96167 }
0 commit comments