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