44from itertools import groupby
55from math import isinf , isnan
66
7- from hy import _initialize_env_var
7+ from hy . compat import PY3_14
88from hy .errors import HyWrapperError
99
10+ if PY3_14 :
11+ from string .templatelib import Interpolation , Template
12+
1013PRETTY = True
1114
1215
@@ -464,22 +467,28 @@ class FComponent(Sequence):
464467 format spec (if any).
465468 """
466469
467- _extra_kwargs = ("conversion" ,)
470+ _extra_kwargs = ("conversion" , "expression" , "is_tstring" )
468471
469- def __new__ (cls , s = None , conversion = None ):
472+ def __new__ (cls , s = None , conversion = None , expression = None , is_tstring = False ):
470473 value = super ().__new__ (cls , s )
471474 value .conversion = conversion
475+ value .expression = expression
476+ value .is_tstring = is_tstring
472477 return value
473478
474479 def replace (self , other , recursive = True ):
475480 super ().replace (other , recursive )
476- if hasattr (other , "conversion" ):
477- self .conversion = other .conversion
481+ for attr in self ._extra_kwargs :
482+ if hasattr (other , attr ):
483+ setattr (self , attr , getattr (other , attr ))
478484 return self
479485
480486 def __repr__ (self ):
481487 return "hy.models.FComponent({})" .format (
482- super (Object , self ).__repr__ () + ", conversion=" + repr (self .conversion )
488+ (super (Object , self ).__repr__ ()
489+ + ", conversion=" + repr (self .conversion )
490+ + ", expression=" + repr (self .expression )
491+ + ", is_tstring=" + repr (self .is_tstring ))
483492 )
484493
485494
@@ -498,11 +507,12 @@ class FString(Sequence):
498507 and :class:`hy.models.FComponent`. The design mimics :class:`ast.JoinedStr`.
499508
500509 :ivar brackets: As in :class:`hy.models.String`.
510+ :ivar is_tstring: Whether this represents a template string rather than a format string.
501511 """
502512
503- _extra_kwargs = ("brackets" ,)
513+ _extra_kwargs = ("brackets" , "is_tstring" )
504514
505- def __new__ (cls , s = None , brackets = None ):
515+ def __new__ (cls , s = None , brackets = None , is_tstring = False ):
506516 value = super ().__new__ (
507517 cls ,
508518 # Join adjacent string nodes for the sake of equality
@@ -519,6 +529,7 @@ def __new__(cls, s=None, brackets=None):
519529 if brackets is not None and _string_in_node (f"]{ brackets } ]" , value ):
520530 raise ValueError (f"Syntactically illegal bracket string: { s !r} " )
521531 value .brackets = brackets
532+ value .is_tstring = is_tstring
522533 return value
523534
524535 def __repr__ (self ):
@@ -528,13 +539,19 @@ def __str__(self):
528539 return self ._suffixize (super ().__str__ ())
529540
530541 def _suffixize (self , x ):
531- if self .brackets is None :
542+ if self .brackets is None and not self . is_tstring :
532543 return x
533- return "{}{}brackets={!r})" .format (
534- x [:- 1 ], # Clip off the final close paren
535- "" if x [- 2 ] == "(" else ", " ,
536- self .brackets ,
537- )
544+ args = []
545+ if self .brackets is not None :
546+ args .append (f"brackets={ self .brackets !r} " )
547+ if PY3_14 and self .is_tstring :
548+ args .append (f"is_tstring={ self .is_tstring !r} " )
549+ s = x [:- 1 ] # Clip off the final close paren
550+ if s [- 1 ] != "(" :
551+ s += ", "
552+ s += ", " .join (args )
553+ s += ")"
554+ return s
538555
539556
540557class List (Sequence ):
@@ -562,9 +579,19 @@ def lambda_to_return(l):
562579
563580
564581_wrappers [FComponent ] = recwrap (FComponent )
582+ if PY3_14 :
583+ _wrappers [Interpolation ] = lambda interp : FComponent (
584+ [as_model (interp .value ), as_model (interp .format_spec )],
585+ conversion = interp .conversion ,
586+ expression = interp .expression ,
587+ is_tstring = True )
565588_wrappers [FString ] = lambda fstr : FString (
566- (as_model (x ) for x in fstr ), brackets = fstr .brackets
589+ (as_model (x ) for x in fstr ),
590+ brackets = fstr .brackets ,
591+ is_tstring = fstr .is_tstring ,
567592)
593+ if PY3_14 :
594+ _wrappers [Template ] = recwrap (lambda els : FString (els , is_tstring = True ))
568595_wrappers [List ] = recwrap (List )
569596_wrappers [list ] = recwrap (List )
570597
0 commit comments