@@ -38,6 +38,7 @@ class Format(enum.IntEnum):
38
38
"__weakref__" ,
39
39
"__arg__" ,
40
40
"__globals__" ,
41
+ "__extra_names__" ,
41
42
"__code__" ,
42
43
"__ast_node__" ,
43
44
"__cell__" ,
@@ -82,6 +83,7 @@ def __init__(
82
83
# is created through __class__ assignment on a _Stringifier object.
83
84
self .__globals__ = None
84
85
self .__cell__ = None
86
+ self .__extra_names__ = None
85
87
# These are initially None but serve as a cache and may be set to a non-None
86
88
# value later.
87
89
self .__code__ = None
@@ -151,6 +153,8 @@ def evaluate(self, *, globals=None, locals=None, type_params=None, owner=None):
151
153
if not self .__forward_is_class__ or param_name not in globals :
152
154
globals [param_name ] = param
153
155
locals .pop (param_name , None )
156
+ if self .__extra_names__ :
157
+ locals = {** locals , ** self .__extra_names__ }
154
158
155
159
arg = self .__forward_arg__
156
160
if arg .isidentifier () and not keyword .iskeyword (arg ):
@@ -274,6 +278,7 @@ def __init__(
274
278
cell = None ,
275
279
* ,
276
280
stringifier_dict ,
281
+ extra_names = None ,
277
282
):
278
283
# Either an AST node or a simple str (for the common case where a ForwardRef
279
284
# represent a single name).
@@ -285,49 +290,61 @@ def __init__(
285
290
self .__code__ = None
286
291
self .__ast_node__ = node
287
292
self .__globals__ = globals
293
+ self .__extra_names__ = extra_names
288
294
self .__cell__ = cell
289
295
self .__owner__ = owner
290
296
self .__stringifier_dict__ = stringifier_dict
291
297
292
298
def __convert_to_ast (self , other ):
293
299
if isinstance (other , _Stringifier ):
294
300
if isinstance (other .__ast_node__ , str ):
295
- return ast .Name (id = other .__ast_node__ )
296
- return other .__ast_node__
297
- elif isinstance (other , slice ):
301
+ return ast .Name (id = other .__ast_node__ ), other .__extra_names__
302
+ return other .__ast_node__ , other .__extra_names__
303
+ elif other is None or type (other ) in (str , int , float , bool , complex ):
304
+ return ast .Constant (value = other ), None
305
+ else :
306
+ name = self .__stringifier_dict__ .create_unique_name ()
307
+ return ast .Name (id = name ), {name : other }
308
+
309
+ def __convert_to_ast_getitem (self , other ):
310
+ if isinstance (other , slice ):
311
+ extra_names = {}
312
+
313
+ def conv (obj ):
314
+ if obj is None :
315
+ return None
316
+ new_obj , new_extra_names = self .__convert_to_ast (obj )
317
+ if new_extra_names is not None :
318
+ extra_names .update (new_extra_names )
319
+ return new_obj
320
+
298
321
return ast .Slice (
299
- lower = (
300
- self .__convert_to_ast (other .start )
301
- if other .start is not None
302
- else None
303
- ),
304
- upper = (
305
- self .__convert_to_ast (other .stop )
306
- if other .stop is not None
307
- else None
308
- ),
309
- step = (
310
- self .__convert_to_ast (other .step )
311
- if other .step is not None
312
- else None
313
- ),
314
- )
322
+ lower = conv (other .start ),
323
+ upper = conv (other .stop ),
324
+ step = conv (other .step ),
325
+ ), extra_names
315
326
else :
316
- return ast . Constant ( value = other )
327
+ return self . __convert_to_ast ( other )
317
328
318
329
def __get_ast (self ):
319
330
node = self .__ast_node__
320
331
if isinstance (node , str ):
321
332
return ast .Name (id = node )
322
333
return node
323
334
324
- def __make_new (self , node ):
335
+ def __make_new (self , node , extra_names = None ):
336
+ new_extra_names = {}
337
+ if self .__extra_names__ is not None :
338
+ new_extra_names .update (self .__extra_names__ )
339
+ if extra_names is not None :
340
+ new_extra_names .update (extra_names )
325
341
stringifier = _Stringifier (
326
342
node ,
327
343
self .__globals__ ,
328
344
self .__owner__ ,
329
345
self .__forward_is_class__ ,
330
346
stringifier_dict = self .__stringifier_dict__ ,
347
+ extra_names = new_extra_names ,
331
348
)
332
349
self .__stringifier_dict__ .stringifiers .append (stringifier )
333
350
return stringifier
@@ -343,27 +360,37 @@ def __getitem__(self, other):
343
360
if self .__ast_node__ == "__classdict__" :
344
361
raise KeyError
345
362
if isinstance (other , tuple ):
346
- elts = [self .__convert_to_ast (elt ) for elt in other ]
363
+ extra_names = {}
364
+ elts = []
365
+ for elt in other :
366
+ new_elt , new_extra_names = self .__convert_to_ast_getitem (elt )
367
+ if new_extra_names is not None :
368
+ extra_names .update (new_extra_names )
369
+ elts .append (new_elt )
347
370
other = ast .Tuple (elts )
348
371
else :
349
- other = self .__convert_to_ast (other )
372
+ other , extra_names = self .__convert_to_ast_getitem (other )
350
373
assert isinstance (other , ast .AST ), repr (other )
351
- return self .__make_new (ast .Subscript (self .__get_ast (), other ))
374
+ return self .__make_new (ast .Subscript (self .__get_ast (), other ), extra_names )
352
375
353
376
def __getattr__ (self , attr ):
354
377
return self .__make_new (ast .Attribute (self .__get_ast (), attr ))
355
378
356
379
def __call__ (self , * args , ** kwargs ):
357
- return self .__make_new (
358
- ast .Call (
359
- self .__get_ast (),
360
- [self .__convert_to_ast (arg ) for arg in args ],
361
- [
362
- ast .keyword (key , self .__convert_to_ast (value ))
363
- for key , value in kwargs .items ()
364
- ],
365
- )
366
- )
380
+ extra_names = {}
381
+ ast_args = []
382
+ for arg in args :
383
+ new_arg , new_extra_names = self .__convert_to_ast (arg )
384
+ if new_extra_names is not None :
385
+ extra_names .update (new_extra_names )
386
+ ast_args .append (new_arg )
387
+ ast_kwargs = []
388
+ for key , value in kwargs .items ():
389
+ new_value , new_extra_names = self .__convert_to_ast (value )
390
+ if new_extra_names is not None :
391
+ extra_names .update (new_extra_names )
392
+ ast_kwargs .append (ast .keyword (key , new_value ))
393
+ return self .__make_new (ast .Call (self .__get_ast (), ast_args , ast_kwargs ), extra_names )
367
394
368
395
def __iter__ (self ):
369
396
yield self .__make_new (ast .Starred (self .__get_ast ()))
@@ -378,8 +405,9 @@ def __format__(self, format_spec):
378
405
379
406
def _make_binop (op : ast .AST ):
380
407
def binop (self , other ):
408
+ rhs , extra_names = self .__convert_to_ast (other )
381
409
return self .__make_new (
382
- ast .BinOp (self .__get_ast (), op , self . __convert_to_ast ( other ))
410
+ ast .BinOp (self .__get_ast (), op , rhs ), extra_names
383
411
)
384
412
385
413
return binop
@@ -392,25 +420,19 @@ def binop(self, other):
392
420
__mod__ = _make_binop (ast .Mod ())
393
421
__lshift__ = _make_binop (ast .LShift ())
394
422
__rshift__ = _make_binop (ast .RShift ())
423
+ __or__ = _make_binop (ast .BitOr ())
395
424
__xor__ = _make_binop (ast .BitXor ())
396
425
__and__ = _make_binop (ast .BitAnd ())
397
426
__floordiv__ = _make_binop (ast .FloorDiv ())
398
427
__pow__ = _make_binop (ast .Pow ())
399
428
400
- def __or__ (self , other ):
401
- if self .__stringifier_dict__ .create_unions :
402
- return types .UnionType [self , other ]
403
-
404
- return self .__make_new (
405
- ast .BinOp (self .__get_ast (), ast .BitOr (), self .__convert_to_ast (other ))
406
- )
407
-
408
429
del _make_binop
409
430
410
431
def _make_rbinop (op : ast .AST ):
411
432
def rbinop (self , other ):
433
+ new_other , extra_names = self .__convert_to_ast (other )
412
434
return self .__make_new (
413
- ast .BinOp (self . __convert_to_ast ( other ) , op , self .__get_ast ())
435
+ ast .BinOp (new_other , op , self .__get_ast ()), extra_names
414
436
)
415
437
416
438
return rbinop
@@ -423,29 +445,24 @@ def rbinop(self, other):
423
445
__rmod__ = _make_rbinop (ast .Mod ())
424
446
__rlshift__ = _make_rbinop (ast .LShift ())
425
447
__rrshift__ = _make_rbinop (ast .RShift ())
448
+ __ror__ = _make_rbinop (ast .BitOr ())
426
449
__rxor__ = _make_rbinop (ast .BitXor ())
427
450
__rand__ = _make_rbinop (ast .BitAnd ())
428
451
__rfloordiv__ = _make_rbinop (ast .FloorDiv ())
429
452
__rpow__ = _make_rbinop (ast .Pow ())
430
453
431
- def __ror__ (self , other ):
432
- if self .__stringifier_dict__ .create_unions :
433
- return types .UnionType [other , self ]
434
-
435
- return self .__make_new (
436
- ast .BinOp (self .__convert_to_ast (other ), ast .BitOr (), self .__get_ast ())
437
- )
438
-
439
454
del _make_rbinop
440
455
441
456
def _make_compare (op ):
442
457
def compare (self , other ):
458
+ rhs , extra_names = self .__convert_to_ast (other )
443
459
return self .__make_new (
444
460
ast .Compare (
445
461
left = self .__get_ast (),
446
462
ops = [op ],
447
- comparators = [self .__convert_to_ast (other )],
448
- )
463
+ comparators = [rhs ],
464
+ ),
465
+ extra_names ,
449
466
)
450
467
451
468
return compare
@@ -479,8 +496,9 @@ def __init__(self, namespace, globals=None, owner=None, is_class=False, create_u
479
496
self .globals = globals
480
497
self .owner = owner
481
498
self .is_class = is_class
482
- self .create_unions = create_unions
499
+ self .create_unions = False
483
500
self .stringifiers = []
501
+ self .next_id = 1
484
502
485
503
def __missing__ (self , key ):
486
504
fwdref = _Stringifier (
@@ -493,6 +511,11 @@ def __missing__(self, key):
493
511
self .stringifiers .append (fwdref )
494
512
return fwdref
495
513
514
+ def create_unique_name (self ):
515
+ name = f"__annotationlib_name_{ self .next_id } __"
516
+ self .next_id += 1
517
+ return name
518
+
496
519
497
520
def call_evaluate_function (evaluate , format , * , owner = None ):
498
521
"""Call an evaluate function. Evaluate functions are normally generated for
@@ -559,9 +582,9 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
559
582
)
560
583
annos = func (Format .VALUE_WITH_FAKE_GLOBALS )
561
584
if _is_evaluate :
562
- return annos if isinstance ( annos , str ) else repr (annos )
585
+ return _stringify_single (annos )
563
586
return {
564
- key : val if isinstance ( val , str ) else repr (val )
587
+ key : _stringify_single (val )
565
588
for key , val in annos .items ()
566
589
}
567
590
elif format == Format .FORWARDREF :
@@ -640,6 +663,16 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
640
663
raise ValueError (f"Invalid format: { format !r} " )
641
664
642
665
666
+ def _stringify_single (anno ):
667
+ if anno is ...:
668
+ return "..."
669
+ # We have to handle str specially to support PEP 563 stringified annotations.
670
+ elif isinstance (anno , str ):
671
+ return anno
672
+ else :
673
+ return repr (anno )
674
+
675
+
643
676
def get_annotate_function (obj ):
644
677
"""Get the __annotate__ function for an object.
645
678
0 commit comments