@@ -5126,8 +5126,7 @@ def state_dsl_start(self, line: str) -> None:
5126
5126
5127
5127
self .next (self .state_modulename_name , line )
5128
5128
5129
- @staticmethod
5130
- def parse_function_names (line : str ) -> FunctionNames :
5129
+ def parse_function_names (self , line : str ) -> FunctionNames :
5131
5130
left , as_ , right = line .partition (' as ' )
5132
5131
full_name = left .strip ()
5133
5132
c_basename = right .strip ()
@@ -5142,28 +5141,101 @@ def parse_function_names(line: str) -> FunctionNames:
5142
5141
fail (f"Illegal function name: { full_name !r} " )
5143
5142
if not is_legal_c_identifier (c_basename ):
5144
5143
fail (f"Illegal C basename: { c_basename !r} " )
5145
- return FunctionNames (full_name = full_name , c_basename = c_basename )
5144
+ names = FunctionNames (full_name = full_name , c_basename = c_basename )
5145
+ self .normalize_function_kind (names .full_name )
5146
+ return names
5146
5147
5147
- def update_function_kind (self , fullname : str ) -> None :
5148
+ def normalize_function_kind (self , fullname : str ) -> None :
5149
+ # Fetch the method name and possibly class.
5148
5150
fields = fullname .split ('.' )
5149
5151
name = fields .pop ()
5150
5152
_ , cls = self .clinic ._module_and_class (fields )
5153
+
5154
+ # Check special method requirements.
5151
5155
if name in unsupported_special_methods :
5152
5156
fail (f"{ name !r} is a special method and cannot be converted to Argument Clinic!" )
5153
-
5157
+ if name == '__init__' and (self .kind is not CALLABLE or not cls ):
5158
+ fail (f"{ name !r} must be a normal method; got '{ self .kind } '!" )
5159
+ if name == '__new__' and (self .kind is not CLASS_METHOD or not cls ):
5160
+ fail ("'__new__' must be a class method!" )
5161
+ if self .kind in {GETTER , SETTER } and not cls :
5162
+ fail ("@getter and @setter must be methods" )
5163
+
5164
+ # Normalise self.kind.
5154
5165
if name == '__new__' :
5155
- if (self .kind is CLASS_METHOD ) and cls :
5156
- self .kind = METHOD_NEW
5157
- else :
5158
- fail ("'__new__' must be a class method!" )
5166
+ self .kind = METHOD_NEW
5159
5167
elif name == '__init__' :
5160
- if (self .kind is CALLABLE ) and cls :
5161
- self .kind = METHOD_INIT
5168
+ self .kind = METHOD_INIT
5169
+
5170
+ def resolve_return_converter (
5171
+ self , full_name : str , forced_converter : str
5172
+ ) -> CReturnConverter :
5173
+ if forced_converter :
5174
+ if self .kind in {GETTER , SETTER }:
5175
+ fail (f"@{ self .kind .name .lower ()} method cannot define a return type" )
5176
+ ast_input = f"def x() -> { forced_converter } : pass"
5177
+ try :
5178
+ module_node = ast .parse (ast_input )
5179
+ except SyntaxError :
5180
+ fail (f"Badly formed annotation for { full_name !r} : { forced_converter !r} " )
5181
+ function_node = module_node .body [0 ]
5182
+ assert isinstance (function_node , ast .FunctionDef )
5183
+ try :
5184
+ name , legacy , kwargs = self .parse_converter (function_node .returns )
5185
+ if legacy :
5186
+ fail (f"Legacy converter { name !r} not allowed as a return converter" )
5187
+ if name not in return_converters :
5188
+ fail (f"No available return converter called { name !r} " )
5189
+ return return_converters [name ](** kwargs )
5190
+ except ValueError :
5191
+ fail (f"Badly formed annotation for { full_name !r} : { forced_converter !r} " )
5192
+
5193
+ if self .kind is METHOD_INIT :
5194
+ return init_return_converter ()
5195
+ return CReturnConverter ()
5196
+
5197
+ def parse_cloned_function (self , names : FunctionNames , existing : str ) -> None :
5198
+ full_name , c_basename = names
5199
+ fields = [x .strip () for x in existing .split ('.' )]
5200
+ function_name = fields .pop ()
5201
+ module , cls = self .clinic ._module_and_class (fields )
5202
+ parent = cls or module
5203
+
5204
+ for existing_function in parent .functions :
5205
+ if existing_function .name == function_name :
5206
+ break
5207
+ else :
5208
+ print (f"{ cls = } , { module = } , { existing = } " , file = sys .stderr )
5209
+ print (f"{ (cls or module ).functions = } " , file = sys .stderr )
5210
+ fail (f"Couldn't find existing function { existing !r} !" )
5211
+
5212
+ fields = [x .strip () for x in full_name .split ('.' )]
5213
+ function_name = fields .pop ()
5214
+ module , cls = self .clinic ._module_and_class (fields )
5215
+
5216
+ overrides : dict [str , Any ] = {
5217
+ "name" : function_name ,
5218
+ "full_name" : full_name ,
5219
+ "module" : module ,
5220
+ "cls" : cls ,
5221
+ "c_basename" : c_basename ,
5222
+ "docstring" : "" ,
5223
+ }
5224
+ if not (existing_function .kind is self .kind and
5225
+ existing_function .coexist == self .coexist ):
5226
+ # Allow __new__ or __init__ methods.
5227
+ if existing_function .kind .new_or_init :
5228
+ overrides ["kind" ] = self .kind
5229
+ # Future enhancement: allow custom return converters
5230
+ overrides ["return_converter" ] = CReturnConverter ()
5162
5231
else :
5163
- fail (
5164
- "'__init__' must be a normal method; "
5165
- f"got '{ self .kind } '!"
5166
- )
5232
+ fail ("'kind' of function and cloned function don't match! "
5233
+ "(@classmethod/@staticmethod/@coexist)" )
5234
+ function = existing_function .copy (** overrides )
5235
+ self .function = function
5236
+ self .block .signatures .append (function )
5237
+ (cls or module ).functions .append (function )
5238
+ self .next (self .state_function_docstring )
5167
5239
5168
5240
def state_modulename_name (self , line : str ) -> None :
5169
5241
# looking for declaration, which establishes the leftmost column
@@ -5188,111 +5260,56 @@ def state_modulename_name(self, line: str) -> None:
5188
5260
# are we cloning?
5189
5261
before , equals , existing = line .rpartition ('=' )
5190
5262
if equals :
5191
- full_name , c_basename = self .parse_function_names (before )
5192
5263
existing = existing .strip ()
5193
5264
if is_legal_py_identifier (existing ):
5194
5265
# we're cloning!
5195
- fields = [x .strip () for x in existing .split ('.' )]
5196
- function_name = fields .pop ()
5197
- module , cls = self .clinic ._module_and_class (fields )
5198
-
5199
- for existing_function in (cls or module ).functions :
5200
- if existing_function .name == function_name :
5201
- break
5202
- else :
5203
- print (f"{ cls = } , { module = } , { existing = } " , file = sys .stderr )
5204
- print (f"{ (cls or module ).functions = } " , file = sys .stderr )
5205
- fail (f"Couldn't find existing function { existing !r} !" )
5206
-
5207
- fields = [x .strip () for x in full_name .split ('.' )]
5208
- function_name = fields .pop ()
5209
- module , cls = self .clinic ._module_and_class (fields )
5210
-
5211
- self .update_function_kind (full_name )
5212
- overrides : dict [str , Any ] = {
5213
- "name" : function_name ,
5214
- "full_name" : full_name ,
5215
- "module" : module ,
5216
- "cls" : cls ,
5217
- "c_basename" : c_basename ,
5218
- "docstring" : "" ,
5219
- }
5220
- if not (existing_function .kind is self .kind and
5221
- existing_function .coexist == self .coexist ):
5222
- # Allow __new__ or __init__ methods.
5223
- if existing_function .kind .new_or_init :
5224
- overrides ["kind" ] = self .kind
5225
- # Future enhancement: allow custom return converters
5226
- overrides ["return_converter" ] = CReturnConverter ()
5227
- else :
5228
- fail ("'kind' of function and cloned function don't match! "
5229
- "(@classmethod/@staticmethod/@coexist)" )
5230
- function = existing_function .copy (** overrides )
5231
- self .function = function
5232
- self .block .signatures .append (function )
5233
- (cls or module ).functions .append (function )
5234
- self .next (self .state_function_docstring )
5235
- return
5266
+ names = self .parse_function_names (before )
5267
+ return self .parse_cloned_function (names , existing )
5236
5268
5237
5269
line , _ , returns = line .partition ('->' )
5238
5270
returns = returns .strip ()
5239
5271
full_name , c_basename = self .parse_function_names (line )
5240
-
5241
- return_converter = None
5242
- if returns :
5243
- if self .kind in {GETTER , SETTER }:
5244
- fail (f"@{ self .kind .name .lower ()} method cannot define a return type" )
5245
- ast_input = f"def x() -> { returns } : pass"
5246
- try :
5247
- module_node = ast .parse (ast_input )
5248
- except SyntaxError :
5249
- fail (f"Badly formed annotation for { full_name !r} : { returns !r} " )
5250
- function_node = module_node .body [0 ]
5251
- assert isinstance (function_node , ast .FunctionDef )
5252
- try :
5253
- name , legacy , kwargs = self .parse_converter (function_node .returns )
5254
- if legacy :
5255
- fail (f"Legacy converter { name !r} not allowed as a return converter" )
5256
- if name not in return_converters :
5257
- fail (f"No available return converter called { name !r} " )
5258
- return_converter = return_converters [name ](** kwargs )
5259
- except ValueError :
5260
- fail (f"Badly formed annotation for { full_name !r} : { returns !r} " )
5272
+ return_converter = self .resolve_return_converter (full_name , returns )
5261
5273
5262
5274
fields = [x .strip () for x in full_name .split ('.' )]
5263
5275
function_name = fields .pop ()
5264
5276
module , cls = self .clinic ._module_and_class (fields )
5265
5277
5266
- if self .kind in {GETTER , SETTER }:
5267
- if not cls :
5268
- fail ("@getter and @setter must be methods" )
5269
-
5270
- self .update_function_kind (full_name )
5271
- if self .kind is METHOD_INIT and not return_converter :
5272
- return_converter = init_return_converter ()
5273
-
5274
- if not return_converter :
5275
- return_converter = CReturnConverter ()
5276
-
5277
- self .function = Function (name = function_name , full_name = full_name , module = module , cls = cls , c_basename = c_basename ,
5278
- return_converter = return_converter , kind = self .kind , coexist = self .coexist ,
5279
- critical_section = self .critical_section ,
5280
- target_critical_section = self .target_critical_section )
5281
- self .block .signatures .append (self .function )
5282
-
5283
- # insert a self converter automatically
5284
- type , name = correct_name_for_self (self .function )
5285
- kwargs = {}
5286
- if cls and type == "PyObject *" :
5287
- kwargs ['type' ] = cls .typedef
5288
- sc = self .function .self_converter = self_converter (name , name , self .function , ** kwargs )
5289
- p_self = Parameter (name , inspect .Parameter .POSITIONAL_ONLY ,
5290
- function = self .function , converter = sc )
5291
- self .function .parameters [name ] = p_self
5292
-
5293
- (cls or module ).functions .append (self .function )
5278
+ func = Function (
5279
+ name = function_name ,
5280
+ full_name = full_name ,
5281
+ module = module ,
5282
+ cls = cls ,
5283
+ c_basename = c_basename ,
5284
+ return_converter = return_converter ,
5285
+ kind = self .kind ,
5286
+ coexist = self .coexist ,
5287
+ critical_section = self .critical_section ,
5288
+ target_critical_section = self .target_critical_section
5289
+ )
5290
+ self .add_function (func )
5291
+
5294
5292
self .next (self .state_parameters_start )
5295
5293
5294
+ def add_function (self , func : Function ) -> None :
5295
+ # Insert a self converter automatically.
5296
+ tp , name = correct_name_for_self (func )
5297
+ if func .cls and tp == "PyObject *" :
5298
+ func .self_converter = self_converter (name , name , func ,
5299
+ type = func .cls .typedef )
5300
+ else :
5301
+ func .self_converter = self_converter (name , name , func )
5302
+ func .parameters [name ] = Parameter (
5303
+ name ,
5304
+ inspect .Parameter .POSITIONAL_ONLY ,
5305
+ function = func ,
5306
+ converter = func .self_converter
5307
+ )
5308
+
5309
+ self .block .signatures .append (func )
5310
+ self .function = func
5311
+ (func .cls or func .module ).functions .append (func )
5312
+
5296
5313
# Now entering the parameters section. The rules, formally stated:
5297
5314
#
5298
5315
# * All lines must be indented with spaces only.
0 commit comments