1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Linq ;
3
4
using System . Reflection ;
4
5
5
6
namespace Python . Runtime
@@ -65,6 +66,65 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx)
65
66
return mb . pyHandle ;
66
67
}
67
68
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
+ public int Compare ( Type a , Type b ) {
122
+ if ( a == b ) return 0 ;
123
+ if ( a . IsSubclassOf ( b ) ) return 1 ;
124
+ if ( b . IsSubclassOf ( a ) ) return - 1 ;
125
+ throw new NotSupportedException ( ) ;
126
+ }
127
+ }
68
128
69
129
/// <summary>
70
130
/// MethodBinding __getattribute__ implementation.
@@ -91,6 +151,15 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
91
151
case "Overloads" :
92
152
var om = new OverloadMapper ( self . m , self . target ) ;
93
153
return om . pyHandle ;
154
+ case "__signature__" when Runtime . InspectModule is not null :
155
+ var sig = self . Signature ;
156
+ if ( sig is null )
157
+ {
158
+ return Runtime . PyObject_GenericGetAttr ( ob , key ) ;
159
+ }
160
+ return sig . NewReferenceOrNull ( ) . DangerousMoveToPointerOrNull ( ) ;
161
+ case "__name__" :
162
+ return self . m . GetName ( ) . DangerousMoveToPointerOrNull ( ) ;
94
163
default :
95
164
return Runtime . PyObject_GenericGetAttr ( ob , key ) ;
96
165
}
0 commit comments