11"""Helpers for introspecting and wrapping annotations."""
22
3- import ast
43import builtins
54import enum
65import functools
2019]
2120
2221
22+ class _LazyImporter :
23+ def __getattr__ (self , name ):
24+ if name == "ast" :
25+ import ast
26+ setattr (self , "ast" , ast )
27+ return ast
28+ elif name == "_Stringifier" :
29+ from ._stringifier import _Stringifier
30+ setattr (self , "_Stringifier" , _Stringifier )
31+ return _Stringifier
32+ else :
33+ raise AttributeError (
34+ f"{ self .__class__ .__name__ !r} object has no attribute { name !r} "
35+ )
36+
37+
2338class Format (enum .IntEnum ):
2439 VALUE = 1
2540 VALUE_WITH_FAKE_GLOBALS = 2
@@ -29,6 +44,7 @@ class Format(enum.IntEnum):
2944
3045_Union = None
3146_sentinel = object ()
47+ _laz = _LazyImporter ()
3248
3349# Slots shared by ForwardRef and _Stringifier. The __forward__ names must be
3450# preserved for compatibility with the old typing.ForwardRef class. The remaining
@@ -205,7 +221,7 @@ def __forward_arg__(self):
205221 if self .__arg__ is not None :
206222 return self .__arg__
207223 if self .__ast_node__ is not None :
208- self .__arg__ = ast .unparse (self .__ast_node__ )
224+ self .__arg__ = _laz . ast .unparse (self .__ast_node__ )
209225 return self .__arg__
210226 raise AssertionError (
211227 "Attempted to access '__forward_arg__' on an uninitialized ForwardRef"
@@ -265,206 +281,6 @@ def __repr__(self):
265281 return f"ForwardRef({ self .__forward_arg__ !r} { module_repr } )"
266282
267283
268- class _Stringifier :
269- # Must match the slots on ForwardRef, so we can turn an instance of one into an
270- # instance of the other in place.
271- __slots__ = _SLOTS
272-
273- def __init__ (
274- self ,
275- node ,
276- globals = None ,
277- owner = None ,
278- is_class = False ,
279- cell = None ,
280- * ,
281- stringifier_dict ,
282- ):
283- # Either an AST node or a simple str (for the common case where a ForwardRef
284- # represent a single name).
285- assert isinstance (node , (ast .AST , str ))
286- self .__arg__ = None
287- self .__forward_evaluated__ = False
288- self .__forward_value__ = None
289- self .__forward_is_argument__ = False
290- self .__forward_is_class__ = is_class
291- self .__forward_module__ = None
292- self .__code__ = None
293- self .__ast_node__ = node
294- self .__globals__ = globals
295- self .__cell__ = cell
296- self .__owner__ = owner
297- self .__stringifier_dict__ = stringifier_dict
298-
299- def __convert_to_ast (self , other ):
300- if isinstance (other , _Stringifier ):
301- if isinstance (other .__ast_node__ , str ):
302- return ast .Name (id = other .__ast_node__ )
303- return other .__ast_node__
304- elif isinstance (other , slice ):
305- return ast .Slice (
306- lower = (
307- self .__convert_to_ast (other .start )
308- if other .start is not None
309- else None
310- ),
311- upper = (
312- self .__convert_to_ast (other .stop )
313- if other .stop is not None
314- else None
315- ),
316- step = (
317- self .__convert_to_ast (other .step )
318- if other .step is not None
319- else None
320- ),
321- )
322- else :
323- return ast .Constant (value = other )
324-
325- def __get_ast (self ):
326- node = self .__ast_node__
327- if isinstance (node , str ):
328- return ast .Name (id = node )
329- return node
330-
331- def __make_new (self , node ):
332- stringifier = _Stringifier (
333- node ,
334- self .__globals__ ,
335- self .__owner__ ,
336- self .__forward_is_class__ ,
337- stringifier_dict = self .__stringifier_dict__ ,
338- )
339- self .__stringifier_dict__ .stringifiers .append (stringifier )
340- return stringifier
341-
342- # Must implement this since we set __eq__. We hash by identity so that
343- # stringifiers in dict keys are kept separate.
344- def __hash__ (self ):
345- return id (self )
346-
347- def __getitem__ (self , other ):
348- # Special case, to avoid stringifying references to class-scoped variables
349- # as '__classdict__["x"]'.
350- if self .__ast_node__ == "__classdict__" :
351- raise KeyError
352- if isinstance (other , tuple ):
353- elts = [self .__convert_to_ast (elt ) for elt in other ]
354- other = ast .Tuple (elts )
355- else :
356- other = self .__convert_to_ast (other )
357- assert isinstance (other , ast .AST ), repr (other )
358- return self .__make_new (ast .Subscript (self .__get_ast (), other ))
359-
360- def __getattr__ (self , attr ):
361- return self .__make_new (ast .Attribute (self .__get_ast (), attr ))
362-
363- def __call__ (self , * args , ** kwargs ):
364- return self .__make_new (
365- ast .Call (
366- self .__get_ast (),
367- [self .__convert_to_ast (arg ) for arg in args ],
368- [
369- ast .keyword (key , self .__convert_to_ast (value ))
370- for key , value in kwargs .items ()
371- ],
372- )
373- )
374-
375- def __iter__ (self ):
376- yield self .__make_new (ast .Starred (self .__get_ast ()))
377-
378- def __repr__ (self ):
379- if isinstance (self .__ast_node__ , str ):
380- return self .__ast_node__
381- return ast .unparse (self .__ast_node__ )
382-
383- def __format__ (self , format_spec ):
384- raise TypeError ("Cannot stringify annotation containing string formatting" )
385-
386- def _make_binop (op : ast .AST ):
387- def binop (self , other ):
388- return self .__make_new (
389- ast .BinOp (self .__get_ast (), op , self .__convert_to_ast (other ))
390- )
391-
392- return binop
393-
394- __add__ = _make_binop (ast .Add ())
395- __sub__ = _make_binop (ast .Sub ())
396- __mul__ = _make_binop (ast .Mult ())
397- __matmul__ = _make_binop (ast .MatMult ())
398- __truediv__ = _make_binop (ast .Div ())
399- __mod__ = _make_binop (ast .Mod ())
400- __lshift__ = _make_binop (ast .LShift ())
401- __rshift__ = _make_binop (ast .RShift ())
402- __or__ = _make_binop (ast .BitOr ())
403- __xor__ = _make_binop (ast .BitXor ())
404- __and__ = _make_binop (ast .BitAnd ())
405- __floordiv__ = _make_binop (ast .FloorDiv ())
406- __pow__ = _make_binop (ast .Pow ())
407-
408- del _make_binop
409-
410- def _make_rbinop (op : ast .AST ):
411- def rbinop (self , other ):
412- return self .__make_new (
413- ast .BinOp (self .__convert_to_ast (other ), op , self .__get_ast ())
414- )
415-
416- return rbinop
417-
418- __radd__ = _make_rbinop (ast .Add ())
419- __rsub__ = _make_rbinop (ast .Sub ())
420- __rmul__ = _make_rbinop (ast .Mult ())
421- __rmatmul__ = _make_rbinop (ast .MatMult ())
422- __rtruediv__ = _make_rbinop (ast .Div ())
423- __rmod__ = _make_rbinop (ast .Mod ())
424- __rlshift__ = _make_rbinop (ast .LShift ())
425- __rrshift__ = _make_rbinop (ast .RShift ())
426- __ror__ = _make_rbinop (ast .BitOr ())
427- __rxor__ = _make_rbinop (ast .BitXor ())
428- __rand__ = _make_rbinop (ast .BitAnd ())
429- __rfloordiv__ = _make_rbinop (ast .FloorDiv ())
430- __rpow__ = _make_rbinop (ast .Pow ())
431-
432- del _make_rbinop
433-
434- def _make_compare (op ):
435- def compare (self , other ):
436- return self .__make_new (
437- ast .Compare (
438- left = self .__get_ast (),
439- ops = [op ],
440- comparators = [self .__convert_to_ast (other )],
441- )
442- )
443-
444- return compare
445-
446- __lt__ = _make_compare (ast .Lt ())
447- __le__ = _make_compare (ast .LtE ())
448- __eq__ = _make_compare (ast .Eq ())
449- __ne__ = _make_compare (ast .NotEq ())
450- __gt__ = _make_compare (ast .Gt ())
451- __ge__ = _make_compare (ast .GtE ())
452-
453- del _make_compare
454-
455- def _make_unary_op (op ):
456- def unary_op (self ):
457- return self .__make_new (ast .UnaryOp (op , self .__get_ast ()))
458-
459- return unary_op
460-
461- __invert__ = _make_unary_op (ast .Invert ())
462- __pos__ = _make_unary_op (ast .UAdd ())
463- __neg__ = _make_unary_op (ast .USub ())
464-
465- del _make_unary_op
466-
467-
468284class _StringifierDict (dict ):
469285 def __init__ (self , namespace , globals = None , owner = None , is_class = False ):
470286 super ().__init__ (namespace )
@@ -475,7 +291,7 @@ def __init__(self, namespace, globals=None, owner=None, is_class=False):
475291 self .stringifiers = []
476292
477293 def __missing__ (self , key ):
478- fwdref = _Stringifier (
294+ fwdref = _laz . _Stringifier (
479295 key ,
480296 globals = self .globals ,
481297 owner = self .owner ,
@@ -537,7 +353,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
537353 name = freevars [i ]
538354 else :
539355 name = "__cell__"
540- fwdref = _Stringifier (name , stringifier_dict = globals )
356+ fwdref = _laz . _Stringifier (name , stringifier_dict = globals )
541357 new_closure .append (types .CellType (fwdref ))
542358 closure = tuple (new_closure )
543359 else :
@@ -588,7 +404,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
588404 name = freevars [i ]
589405 else :
590406 name = "__cell__"
591- fwdref = _Stringifier (
407+ fwdref = _laz . _Stringifier (
592408 name ,
593409 cell = cell ,
594410 owner = owner ,
0 commit comments