Skip to content

Commit 6d4581a

Browse files
committed
feat(formatter): check if expression contains await
1 parent ee3acbb commit 6d4581a

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

logfire/_internal/ast_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def rewrite_function(self, node: ast.FunctionDef | ast.AsyncFunctionDef, qualnam
106106

107107
return ast.fix_missing_locations(
108108
ast.copy_location(
109-
type(node)( # type: ignore
109+
type(node)(
110110
name=node.name,
111111
args=node.args,
112112
body=new_body,

logfire/_internal/formatter.py

+15
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,21 @@ def compile_formatted_value(node: ast.FormattedValue, ex_source: executing.Sourc
354354
3. Another code object which formats the value.
355355
"""
356356
source = get_node_source_text(node.value, ex_source)
357+
358+
# Check if the expression contains await before attempting to compile
359+
try:
360+
parsed = ast.parse(source, mode='eval')
361+
for sub_node in ast.walk(parsed):
362+
if isinstance(sub_node, ast.Await):
363+
# Signal that we can't compile this
364+
raise KnownFormattingError(
365+
f'Cannot evaluate await expression in f-string: {source}. Pre-evaluate the expression before logging.'
366+
)
367+
except SyntaxError:
368+
# For other syntax errors during parsing, let the compile step handle it
369+
# as it might provide better error messages
370+
pass
371+
357372
value_code = compile(source, '<fvalue1>', 'eval')
358373
expr = ast.Expression(
359374
ast.JoinedStr(

tests/test_formatter.py

+29
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,32 @@ def test_internal_exception_formatting(caplog: pytest.LogCaptureFixture):
178178
assert len(caplog.records) == 1
179179
assert caplog.records[0].message.startswith('Caught an internal error in Logfire.')
180180
assert str(caplog.records[0].exc_info[1]) == 'bad scrubber' # type: ignore
181+
182+
183+
def test_await_in_fstring():
184+
"""Test that await expressions in f-strings are rejected with a clear error message."""
185+
# Create a simple AST node with an Await expression
186+
import ast
187+
188+
# Create a FormattedValue node containing an Await expression
189+
await_expr = ast.Await(value=ast.Name(id='coro', ctx=ast.Load()))
190+
node = ast.FormattedValue(value=await_expr, conversion=-1, format_spec=None)
191+
192+
# Create a minimal mock of executing.Source
193+
class MockSource:
194+
text = "f'{await coro}'"
195+
196+
@staticmethod
197+
def get_text(node: ast.AST) -> str:
198+
return 'await coro'
199+
200+
mock_source = MockSource()
201+
202+
# Test that using compile_formatted_value raises the right error
203+
from logfire._internal.formatter import KnownFormattingError, compile_formatted_value
204+
205+
with pytest.raises(KnownFormattingError) as exc_info:
206+
compile_formatted_value(node, mock_source)
207+
208+
assert 'Cannot evaluate await expression in f-string' in str(exc_info.value)
209+
assert 'Pre-evaluate the expression before logging' in str(exc_info.value)

0 commit comments

Comments
 (0)