56
56
from libclinic .block_parser import Block , BlockParser
57
57
from libclinic .crenderdata import CRenderData , Include , TemplateDict
58
58
from libclinic .converter import (
59
- CConverter , CConverterClassT ,
59
+ CConverter , CConverterClassT , ConverterType ,
60
60
converters , legacy_converters )
61
61
62
62
@@ -1988,13 +1988,38 @@ def parse_file(
1988
1988
libclinic .write_file (output , cooked )
1989
1989
1990
1990
1991
+ @functools .cache
1992
+ def _create_parser_base_namespace () -> dict [str , Any ]:
1993
+ ns = dict (
1994
+ CConverter = CConverter ,
1995
+ CReturnConverter = CReturnConverter ,
1996
+ buffer = buffer ,
1997
+ robuffer = robuffer ,
1998
+ rwbuffer = rwbuffer ,
1999
+ unspecified = unspecified ,
2000
+ NoneType = NoneType ,
2001
+ )
2002
+ for name , converter in converters .items ():
2003
+ ns [f'{ name } _converter' ] = converter
2004
+ for name , return_converter in return_converters .items ():
2005
+ ns [f'{ name } _return_converter' ] = return_converter
2006
+ return ns
2007
+
2008
+
2009
+ def create_parser_namespace () -> dict [str , Any ]:
2010
+ base_namespace = _create_parser_base_namespace ()
2011
+ return base_namespace .copy ()
2012
+
2013
+
2014
+
1991
2015
class PythonParser :
1992
2016
def __init__ (self , clinic : Clinic ) -> None :
1993
2017
pass
1994
2018
1995
2019
def parse (self , block : Block ) -> None :
2020
+ namespace = create_parser_namespace ()
1996
2021
with contextlib .redirect_stdout (io .StringIO ()) as s :
1997
- exec (block .input )
2022
+ exec (block .input , namespace )
1998
2023
block .output = s .getvalue ()
1999
2024
2000
2025
@@ -3443,7 +3468,6 @@ class float_return_converter(double_return_converter):
3443
3468
3444
3469
def eval_ast_expr (
3445
3470
node : ast .expr ,
3446
- globals : dict [str , Any ],
3447
3471
* ,
3448
3472
filename : str = '-'
3449
3473
) -> Any :
@@ -3460,8 +3484,9 @@ def eval_ast_expr(
3460
3484
node = node .value
3461
3485
3462
3486
expr = ast .Expression (node )
3487
+ namespace = create_parser_namespace ()
3463
3488
co = compile (expr , filename , 'eval' )
3464
- fn = FunctionType (co , globals )
3489
+ fn = FunctionType (co , namespace )
3465
3490
return fn ()
3466
3491
3467
3492
@@ -4463,12 +4488,11 @@ def parse_converter(
4463
4488
case ast .Name (name ):
4464
4489
return name , False , {}
4465
4490
case ast .Call (func = ast .Name (name )):
4466
- symbols = globals ()
4467
4491
kwargs : ConverterArgs = {}
4468
4492
for node in annotation .keywords :
4469
4493
if not isinstance (node .arg , str ):
4470
4494
fail ("Cannot use a kwarg splat in a function-call annotation" )
4471
- kwargs [node .arg ] = eval_ast_expr (node .value , symbols )
4495
+ kwargs [node .arg ] = eval_ast_expr (node .value )
4472
4496
return name , False , kwargs
4473
4497
case _:
4474
4498
fail (
@@ -4984,25 +5008,21 @@ def run_clinic(parser: argparse.ArgumentParser, ns: argparse.Namespace) -> None:
4984
5008
parser .error (
4985
5009
"can't specify --converters and a filename at the same time"
4986
5010
)
4987
- converters : list [tuple [str , str ]] = []
4988
- return_converters : list [tuple [str , str ]] = []
4989
- ignored = set ("""
4990
- add_c_converter
4991
- add_c_return_converter
4992
- add_default_legacy_c_converter
4993
- add_legacy_c_converter
4994
- """ .strip ().split ())
4995
- module = globals ()
4996
- for name in module :
4997
- for suffix , ids in (
4998
- ("_return_converter" , return_converters ),
4999
- ("_converter" , converters ),
5000
- ):
5001
- if name in ignored :
5002
- continue
5003
- if name .endswith (suffix ):
5004
- ids .append ((name , name .removesuffix (suffix )))
5005
- break
<
2D0F
/code>
5011
+ AnyConverterType = ConverterType | ReturnConverterType
5012
+ converter_list : list [tuple [str , AnyConverterType ]] = []
5013
+ return_converter_list : list [tuple [str , AnyConverterType ]] = []
5014
+
5015
+ for name , converter in converters .items ():
5016
+ converter_list .append ((
5017
+ name ,
5018
+ converter ,
5019
+ ))
5020
+ for name , return_converter in return_converters .items ():
5021
+ return_converter_list .append ((
5022
+ name ,
5023
+ return_converter
5024
+ ))
5025
+
5006
5026
print ()
5007
5027
5008
5028
print ("Legacy converters:" )
@@ -5012,15 +5032,17 @@ def run_clinic(parser: argparse.ArgumentParser, ns: argparse.Namespace) -> None:
5012
5032
print ()
5013
5033
5014
5034
for title , attribute , ids in (
5015
- ("Converters" , 'converter_init' , converters ),
5016
- ("Return converters" , 'return_converter_init' , return_converters ),
5035
+ ("Converters" , 'converter_init' , converter_list ),
5036
+ ("Return converters" , 'return_converter_init' , return_converter_list ),
5017
5037
):
5018
5038
print (title + ":" )
5039
+
5040
+ ids .sort (key = lambda item : item [0 ].lower ())
5019
5041
longest = - 1
5020
- for name , short_name in ids :
5021
- longest = max (longest , len (short_name ))
5022
- for name , short_name in sorted ( ids , key = lambda x : x [ 1 ]. lower ()):
5023
- cls = module [ name ]
5042
+ for name , _ in ids :
5043
+ longest = max (longest , len (name ))
5044
+
5045
+ for name , cls in ids :
5024
5046
callable = getattr (cls , attribute , None )
5025
5047
if not callable :
5026
5048
continue
@@ -5033,7 +5055,7 @@ def run_clinic(parser: argparse.ArgumentParser, ns: argparse.Namespace) -> None:
5033
5055
else :
5034
5056
s = parameter_name
5035
5057
parameters .append (s )
5036
- print (' {}({})' .format (short_name , ', ' .join (parameters )))
5058
+ print (' {}({})' .format (name , ', ' .join (parameters )))
5037
5059
print ()
5038
5060
print ("All converters also accept (c_default=None, py_default=None, annotation=None)." )
5039
5061
print ("All return converters also accept (py_default=None)." )
0 commit comments