Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.refactron.dev/llms.txt

Use this file to discover all available pages before exploring further.

Transform ID: format_to_fstring Language: Python

What it does

Rewrites legacy string-formatting expressions to PEP 498 f-strings. Both the % operator ("hello %s" % name) and str.format() calls ("hello {}".format(name)) are converted in place. The % operator is handled by Refactron’s own printf-grammar converter, which covers the full conversion grammar — %s, %r, %d, %x / %o / %e / %g, width and precision specifiers, and literal %% — not just plain %s. str.format() calls go through LibCST’s ConvertFormatStringCommand.

Detector pattern

The detector at src/analyze/detectors/python/old-string-format.ts finds BinaryOperator(left=String, op='%', right=...) and Call(func=Attribute(value=String, attr='format'), ...) nodes, anchoring each finding on the operator (not the opening quote, which on a multi-line literal can sit many lines above).

Preconditions

  1. The expression is one of the two recognised forms above.
  2. The substituted values are safe to inline as f-string fields — an argument containing a backslash, a brace, or a quote matching the literal’s is conservatively skipped, as are mapping %(name)s specifiers and dynamic * width/precision.
  3. The string literal is not an existing f-string.

Before / after

def greet(name):
    # Old percent-formatting style.
    return "hello %s" % name


def format_value(x):
    # Old str.format style.
    return "value is {}".format(x)

Edge cases handled

  • Both % and .format() styles in the same file.
  • Returns null (no change) for plain strings without format operators.
  • Survives complex .format() patterns that the underlying ConvertFormatStringCommand cannot handle — the file is left unchanged rather than crashed.

Edge cases NOT handled (skip via precondition)

  • Nested .format() calls inside dict/list literals (per ADR-006, complex shapes may be skipped by LibCST’s converter).
  • Format strings with chained attribute access in the substitution slot (e.g. "{}".format(a.b.c)).
  • Conditional formats (format called via getattr or aliased).
When the underlying converter cannot safely produce an equivalent f-string, the transform reports preconditions but leaves the source untouched — it never emits a half-converted file.