Skip to content

feat: extend f-string rules to t-strings (#3613) - #3702

Open
raza-khan0108 wants to merge 12 commits into
wemake-services:masterfrom
raza-khan0108:feat/issue-3613-tstrings
Open

feat: extend f-string rules to t-strings (#3613)#3702
raza-khan0108 wants to merge 12 commits into
wemake-services:masterfrom
raza-khan0108:feat/issue-3613-tstrings

Conversation

@raza-khan0108

Copy link
Copy Markdown

Extend style rules for f-strings to t-strings (Python 3.14+)

Checklist

  • I have double checked that there are no unrelated changes in this pull request (old patches, accidental config files, etc)
  • I have created at least one test case for the changes I have made
  • I have updated the documentation for the changes I have made
  • I have added my changes to the CHANGELOG.md

Related issues


Summary of Changes

Python 3.14 introduces Template Strings (t-strings) via PEP 750. Since t-strings share formatting and interpolation syntax with f-strings, this PR extends our existing formatted string style rules to cover t-strings as well.

1. AST Compatibility Shims (compat/nodes.py)

  • Added conditional shims for ast.TemplateStr and ast.Interpolation. On Python versions < 3.14, these fallback to safe stub classes inheriting from ast.expr so type checking and AST traversal work cleanly across all Python versions without raising AttributeError.

2. AST Visitor Extensions (visitors/ast/)

  • builtins.py: Added visit_TemplateStr handler and generalized _check_complex_formatted_string to inspect both ast.JoinedStr and nodes.TemplateStr, enforcing complexity restrictions (WPS237) on t-string interpolation expressions.
  • complexity/jones.py: Added TemplateStr and Interpolation to ignored node types so internal formatting nodes do not inflate inline Jones line complexity scores.
  • complexity/overuses.py: Updated _check_string_constant to ignore string constants nested inside nodes.TemplateStr.
  • operators.py: Added TemplateStr to string classes for math operator checking.

3. Tokenize Visitor Extensions (visitors/tokenize/)

  • primitives.py: Added visit_tstring_start handler and updated _multiline_fstring_pattern regex to match f and t string prefixes ((?:[ft]r?|r[ft])(['"])), enforcing triple-quote requirements for multiline formatted strings (WPS479).
  • comments.py: Added visit_tstring_start handler and updated _comment_in_fstring regex to forbid inline comments inside t-string expressions (WPS480).

4. Violation Documentation (violations/)

  • Updated violation descriptions and docstrings for WPS237 (TooComplexFormattedStringViolation), WPS479 (MultilineFormattedStringViolation), and WPS480 (CommentInFormattedStringViolation) to explicitly state they forbid complex expressions, multiline quotes, and inline comments in both f-strings and t-strings.

5. Automated Testing (tests/)

  • Added unit test cases covering simple and complex t-string usages across AST and tokenize visitors in test_formatted_string.py, test_mulitiline_formatted_string312.py, and test_comment_in_formatted_string312.py.
  • Guarded all new t-string tests with @pytest.mark.skipif(sys.version_info < (3, 14), reason='t-strings are only in Python 3.14+').

🙏 Please, if you or your company is finding wemake-python-styleguide valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/wemake-python-styleguide. As a thank you, your profile/company logo will be added to our main README which receives hundreds of unique visitors per day.

Copilot AI review requested due to automatic review settings July 5, 2026 10:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

"""Used to define `TemplateStr` nodes in `python3.14+`."""

values: list[ast.expr]
values: list[ast.expr] # noqa: WPS110

@Khabib73 Khabib73 Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


@final
class WrongFormatStringVisitor(base.BaseNodeVisitor):
class WrongFormatStringVisitor(base.BaseNodeVisitor): # noqa: WPS214

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

Comment thread wemake_python_styleguide/visitors/ast/builtins.py Outdated
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (13912d3) to head (f959320).
⚠️ Report is 34 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##            master     #3702    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files          369       371     +2     
  Lines        12425     12556   +131     
  Branches       858       870    +12     
==========================================
+ Hits         12425     12556   +131     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@yangfan-yf-yf yangfan-yf-yf left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 3.10–3.13 jobs are failing only because the new Python 3.14-only paths reduce total coverage below the repository's required 100% threshold.

The job output identifies the skipped t-string test bodies in test_formatted_string.py (lines 280–285 and 302–307), plus the new visit_tstring_start methods in comments.py and primitives.py. Those methods cannot execute before Python 3.14, while the existing version-specific coverage convention already uses covdefaults pragmas such as # pragma: >=3.12 cover.

Please mark the t-string-only test functions and the two visit_tstring_start methods with the corresponding # pragma: >=3.14 cover condition (or use an equivalent existing version-gated test layout). That keeps the 3.14 execution covered while excluding paths that older interpreters cannot reach. The 3.14 job already passes; this should restore the 3.10–3.13 matrix without weakening the coverage requirement.

@raza-khan0108

raza-khan0108 commented Jul 26, 2026

Copy link
Copy Markdown
Author

Added # pragma: >=3.14 cover annotations to the Python 3.14-only visit_tstring_start visitor methods (comments.py, primitives.py) and all t-string test function definitions (test_formatted_string.py, test_comment_in_formatted_string312.py, and test_mulitiline_formatted_string312.py).

This excludes these 3.14-only execution paths on Python 3.10–3.13 while keeping 100% coverage requirement intact on 3.14+.

Comment thread tests/test_visitors/test_ast/test_builtins/test_strings/test_formatted_string.py Outdated
Comment thread wemake_python_styleguide/violations/best_practices.py
@raza-khan0108

raza-khan0108 commented Jul 26, 2026

Copy link
Copy Markdown
Author

Updated the testing suite and violation documentation:

  1. Parameterized Template Strings:

    • Refactored all string templates in test_formatted_string.py to use {0} prefix placeholders.
    • Parameterized test functions with prefix ('f' and 't', with 't' skipped for Python < 3.14).
    • Removed redundant standalone test_simple_t_string and test_complex_t_string functions since all simple and complex cases are now automatically tested for both f and t strings.
  2. Violation Docstrings Note:

    • Added notes to TooComplexFormattedStringViolation, MultilineFormattedStringViolation, and CommentInFormattedStringViolation indicating that t-strings are only checked on python3.14+.

"foo = t'test {a} # testing'",
],
)
def test_correct_t_string_comments( # pragma: >=3.14 cover

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here we should do the same with PREFIXES parametrization :)

assert_errors(visitor, [MultilineFormattedStringViolation])


@pytest.mark.skipif(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here :)

@@ -19,11 +20,15 @@ def is_doc_string(node: ast.AST) -> bool:


def has_fstring_conversion(component: ast.AST) -> bool:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be renamed, it is not about fstring only anymore.

"""Performs check for t-strings."""
self._check_fstring_is_multi_lined(token)

def _check_fstring_is_multi_lined(self, token: tokenize.TokenInfo) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should also be renamed, _check_fstring_is_multi_lined name is not correct anymore, it is not just about fstring now

Don't write comments inside formatted strings.

Example::

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't forget to update the versionchanged entries for all violations that were changed :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extend the rules for f-strings to t-strings

5 participants