Skip to content

Commit 59266a9

Browse files
authored
feat: Add support for PEP 750 template strings
PR-440: #440
1 parent bf98d7d commit 59266a9

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

docs/reference/api/expressions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060

6161
::: griffe.ExprIfExp
6262

63+
::: griffe.ExprInterpolation
64+
6365
::: griffe.ExprJoinedStr
6466

6567
::: griffe.ExprKeyword
@@ -88,6 +90,8 @@
8890

8991
::: griffe.ExprSubscript
9092

93+
::: griffe.ExprTemplateStr
94+
9195
::: griffe.ExprTuple
9296

9397
::: griffe.ExprUnaryOp

packages/griffelib/src/griffe/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@
289289
ExprFormatted,
290290
ExprGeneratorExp,
291291
ExprIfExp,
292+
ExprInterpolation,
292293
ExprJoinedStr,
293294
ExprKeyword,
294295
ExprLambda,
@@ -301,6 +302,7 @@
301302
ExprSetComp,
302303
ExprSlice,
303304
ExprSubscript,
305+
ExprTemplateStr,
304306
ExprTuple,
305307
ExprUnaryOp,
306308
ExprVarKeyword,
@@ -443,6 +445,7 @@
443445
"ExprFormatted",
444446
"ExprGeneratorExp",
445447
"ExprIfExp",
448+
"ExprInterpolation",
446449
"ExprJoinedStr",
447450
"ExprKeyword",
448451
"ExprLambda",
@@ -455,6 +458,7 @@
455458
"ExprSetComp",
456459
"ExprSlice",
457460
"ExprSubscript",
461+
"ExprTemplateStr",
458462
"ExprTuple",
459463
"ExprUnaryOp",
460464
"ExprVarKeyword",

packages/griffelib/src/griffe/_internal/expressions.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from __future__ import annotations
88

99
import ast
10+
import sys
1011
from dataclasses import dataclass
1112
from dataclasses import fields as getfields
1213
from enum import IntEnum, auto
@@ -532,6 +533,20 @@ def iterate(self, *, flat: bool = True) -> Iterator[str | Expr]:
532533
yield from _yield(self.orelse, flat=flat, outer_precedence=precedence, is_left=False)
533534

534535

536+
@dataclass(eq=True, slots=True)
537+
class ExprInterpolation(Expr):
538+
"""Template string interpolation like `{name}`."""
539+
540+
value: str | Expr
541+
"""Interpolated value."""
542+
543+
def iterate(self, *, flat: bool = True) -> Iterator[str | Expr]:
544+
yield "{"
545+
# Prevent parentheses from being added, avoiding `{(1 + 1)}`
546+
yield from _yield(self.value, flat=flat, outer_precedence=_OperatorPrecedence.NONE)
547+
yield "}"
548+
549+
535550
@dataclass(eq=True, slots=True)
536551
class ExprJoinedStr(Expr):
537552
"""Joined strings like `f"a {b} c"`."""
@@ -915,6 +930,19 @@ def canonical_path(self) -> str:
915930
return self.left.canonical_path
916931

917932

933+
@dataclass(eq=True, slots=True)
934+
class ExprTemplateStr(Expr):
935+
"""Template strings like `t"a {name}"`."""
936+
937+
values: Sequence[str | Expr]
938+
"""Joined values."""
939+
940+
def iterate(self, *, flat: bool = True) -> Iterator[str | Expr]:
941+
yield "t'"
942+
yield from _join(self.values, "", flat=flat)
943+
yield "'"
944+
945+
918946
@dataclass(eq=True, slots=True)
919947
class ExprTuple(Expr):
920948
"""Tuples like `(0, 1, 2)`."""
@@ -1369,6 +1397,25 @@ def __call__(self, node: Any, parent: Module | Class, **kwargs: Any) -> Expr: ..
13691397
ast.YieldFrom: _build_yield_from,
13701398
}
13711399

1400+
if sys.version_info >= (3, 14):
1401+
1402+
def _build_interpolation(node: ast.Interpolation, parent: Module | Class, **kwargs: Any) -> Expr:
1403+
return ExprInterpolation(_build(node.value, parent, **kwargs))
1404+
1405+
def _build_templatestr(
1406+
node: ast.TemplateStr,
1407+
parent: Module | Class,
1408+
**kwargs: Any,
1409+
) -> Expr:
1410+
return ExprTemplateStr([_build(value, parent, in_joined_str=True, **kwargs) for value in node.values])
1411+
1412+
_node_map.update(
1413+
{
1414+
ast.Interpolation: _build_interpolation,
1415+
ast.TemplateStr: _build_templatestr,
1416+
},
1417+
)
1418+
13721419

13731420
def _build(node: ast.AST, parent: Module | Class, /, **kwargs: Any) -> Expr:
13741421
return _node_map[type(node)](node, parent, **kwargs)

tests/test_nodes.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import logging
6+
import sys
67
from ast import PyCF_ONLY_AST
78

89
import pytest
@@ -51,6 +52,8 @@
5152
"call(something=something)",
5253
# Strings.
5354
"f'a {round(key, 2)} {z}'",
55+
# YORE: EOL 3.13: Replace line with `"t'a {round(key, 2)} {z}'",`.
56+
*(["t'a {round(key, 2)} {z}'"] if sys.version_info >= (3, 14) else []),
5457
# Slices.
5558
"o[x]",
5659
"o[x, y]",

0 commit comments

Comments
 (0)