Skip to content

Commit 06c863f

Browse files
1borgypawamoy
authored andcommitted
fix: Add support for PEP 750 template strings
1 parent bf98d7d commit 06c863f

File tree

4 files changed

+65
-1
lines changed

4 files changed

+65
-1
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: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,18 @@
33
from __future__ import annotations
44

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

89
import pytest
910

10-
from griffe import Expr, ExprName, module_vtree, relative_to_absolute, temporary_visited_module
11+
from griffe import (
12+
Expr,
13+
ExprName,
14+
module_vtree,
15+
relative_to_absolute,
16+
temporary_visited_module,
17+
)
1118

1219
syntax_examples = [
1320
# Operations.
@@ -51,6 +58,8 @@
5158
"call(something=something)",
5259
# Strings.
5360
"f'a {round(key, 2)} {z}'",
61+
# YORE: EOL 3.13: Replace line with `"t'a {round(key, 2)} {z}'",`.
62+
*(["t'a {round(key, 2)} {z}'"] if sys.version_info >= (3, 14) else []),
5463
# Slices.
5564
"o[x]",
5665
"o[x, y]",

0 commit comments

Comments
 (0)