@@ -4796,59 +4796,77 @@ def bad_node(self, node):
4796
4796
if bad :
4797
4797
fail ("Unsupported expression as default value: " + repr (default ))
4798
4798
4799
- expr = module .body [0 ].value
4800
- # mild hack: explicitly support NULL as a default value
4801
- if isinstance (expr , ast .Name ) and expr .id == 'NULL' :
4802
- value = NULL
4803
- py_default = '<unrepresentable>'
4804
- c_default = "NULL"
4805
- elif (isinstance (expr , ast .BinOp ) or
4806
- (isinstance (expr , ast .UnaryOp ) and
4807
- not (isinstance (expr .operand , ast .Constant ) and
4808
- type (expr .operand .value ) in {int , float , complex })
4809
- )):
4799
+ def get_c_default (
4800
+ default : str , default_kind : str , expr : ast .expr | None = None
4801
+ ) -> str :
4810
4802
c_default = kwargs .get ("c_default" )
4811
4803
if not (isinstance (c_default , str ) and c_default ):
4812
- fail ("When you specify an expression (" + repr (default ) + ") as your default value,\n you MUST specify a valid c_default." + ast .dump (expr ))
4813
- py_default = default
4814
- value = unknown
4815
- elif isinstance (expr , ast .Attribute ):
4816
- a = []
4817
- n = expr
4818
- while isinstance (n , ast .Attribute ):
4819
- a .append (n .attr )
4820
- n = n .value
4821
- if not isinstance (n , ast .Name ):
4822
- fail ("Unsupported default value " + repr (default ) + " (looked like a Python constant)" )
4823
- a .append (n .id )
4824
- py_default = "." .join (reversed (a ))
4825
-
4826
- c_default = kwargs .get ("c_default" )
4827
- if not (isinstance (c_default , str ) and c_default ):
4828
- fail ("When you specify a named constant (" + repr (py_default ) + ") as your default value,\n you MUST specify a valid c_default." )
4829
-
4830
- try :
4831
- value = eval (py_default )
4832
- except NameError :
4804
+ msg = (
4805
+ f"When you specify { default_kind } ({ default !r} ) "
4806
+ f"as your default value,\n "
4807
+ f"you MUST specify a valid c_default."
4808
+ )
4809
+ if expr :
4810
+ msg += f"\n { ast .dump (expr )} "
4811
+ fail (msg )
4812
+ return c_default
4813
+
4814
+ def is_numeric (node : ast .expr ) -> bool :
4815
+ match node :
4816
+ case ast .Constant (value = value ):
4817
+ return type (value ) in {int , float , complex }
4818
+ case _:
4819
+ return False
4820
+
4821
+ match expr := module .body [0 ].value :
4822
+ # mild hack: explicitly support NULL as a default value
4823
+ case ast .Name ('NULL' ):
4824
+ value = NULL
4825
+ py_default = '<unrepresentable>'
4826
+ c_default = "NULL"
4827
+ case ast .BinOp ():
4828
+ c_default = get_c_default (default , 'an expression' , expr )
4829
+ py_default = default
4833
4830
value = unknown
4834
- else :
4835
- value = ast .literal_eval (expr )
4836
- py_default = repr (value )
4837
- if isinstance (value , (bool , None .__class__ )):
4838
- c_default = "Py_" + py_default
4839
- elif isinstance (value , str ):
4840
- c_default = c_repr (value )
4841
- else :
4842
- c_default = py_default
4831
+ case ast .UnaryOp (operand = operand ) if is_numeric (operand ):
4832
+ c_default = get_c_default (default , 'an expression' , expr )
4833
+ py_default = default
4834
+ value = unknown
4835
+ case ast .Attribute ():
4836
+ a = []
4837
+ n = expr
4838
+ while isinstance (n , ast .Attribute ):
4839
+ a .append (n .attr )
4840
+ n = n .value
4841
+ if not isinstance (n , ast .Name ):
4842
+ fail (
4843
+ f"Unsupported default value { default !r} (looked like a Python constant)"
4844
+ )
4845
+ a .append (n .id )
4846
+ py_default = "." .join (reversed (a ))
4847
+ c_default = get_c_default (default , 'a named constant' )
4848
+
4849
+ try :
4850
+ value = eval (py_default )
4851
+ except NameError :
4852
+ value = unknown
4853
+ case _:
4854
+ value = ast .literal_eval (expr )
4855
+ py_default = repr (value )
4856
+ match value :
4857
+ case True | False | None :
4858
+ c_default = f"Py_{ py_default } "
4859
+ case str ():
4860
+ c_default = c_repr (value )
4861
+ case _:
4862
+ c_default = py_default
4843
4863
4844
4864
except SyntaxError as e :
4845
- fail ("Syntax error: " + repr ( e .text ) )
4865
+ fail (f "Syntax error: { e .text !r } " )
4846
4866
except (ValueError , AttributeError ):
4847
4867
value = unknown
4848
- c_default = kwargs .get ("c_default" )
4849
4868
py_default = default
4850
- if not (isinstance (c_default , str ) and c_default ):
4851
- fail ("When you specify a named constant (" + repr (py_default ) + ") as your default value,\n you MUST specify a valid c_default." )
4869
+ c_default = get_c_default (py_default , 'a named constant' )
4852
4870
4853
4871
kwargs .setdefault ('c_default' , c_default )
4854
4872
kwargs .setdefault ('py_default' , py_default )
@@ -4899,29 +4917,32 @@ def bad_node(self, node):
4899
4917
4900
4918
names = [k .name for k in self .function .parameters .values ()]
4901
4919
if parameter_name in names [1 :]:
4902
- fail ("You can't have two parameters named " + repr ( parameter_name ) + " !" )
4920
+ fail (f "You can't have two parameters named { parameter_name !r } !" )
4903
4921
elif names and parameter_name == names [0 ] and c_name is None :
4904
4922
fail (f"Parameter '{ parameter_name } ' requires a custom C name" )
4905
4923
4906
4924
key = f"{ parameter_name } _as_{ c_name } " if c_name else parameter_name
4907
4925
self .function .parameters [key ] = p
4908
4926
4909
- def parse_converter (self , annotation ):
4910
- if (isinstance (annotation , ast .Constant ) and
4911
- type (annotation .value ) is str ):
4912
- return annotation .value , True , {}
4913
-
4914
- if isinstance (annotation , ast .Name ):
4915
- return annotation .id , False , {}
4916
-
4917
- if not isinstance (annotation , ast .Call ):
4918
- fail ("Annotations must be either a name, a function call, or a string." )
4919
-
4920
- name = annotation .func .id
4921
- symbols = globals ()
4922
-
4923
- kwargs = {node .arg : eval_ast_expr (node .value , symbols ) for node in annotation .keywords }
4924
- return name , False , kwargs
4927
+ def parse_converter (
4928
+ self , annotation : ast .AST
4929
+ ) -> tuple [str , bool , dict [str | None , object ]]:
4930
+ match annotation :
4931
+ case ast .Constant (value = str () as value ):
4932
+ return value , True , {}
4933
+ case ast .Name (id ):
4934
+ return id , False , {}
4935
+ case ast .Call (func = ast .Name (name )):
4936
+ symbols = globals ()
4937
+ kwargs = {
4938
+ node .arg : eval_ast_expr (node .value , symbols )
4939
+ for node in annotation .keywords
4940
+ }
4941
+ return name , False , kwargs
4942
+ case _:
4943
+ fail (
4944
+ "Annotations must be either a name, a function call, or a string."
4945
+ )
4925
4946
4926
4947
def parse_special_symbol (self , symbol ):
4927
4948
if symbol == '*' :
0 commit comments