惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
Microsoft Security Blog
Microsoft Security Blog
大猫的无限游戏
大猫的无限游戏
B
Blog RSS Feed
MyScale Blog
MyScale Blog
博客园_首页
S
SegmentFault 最新的问题
WordPress大学
WordPress大学
小众软件
小众软件
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
The GitHub Blog
The GitHub Blog
D
Docker
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
F
Fortinet All Blogs
V
V2EX
Last Week in AI
Last Week in AI
Blog — PlanetScale
Blog — PlanetScale
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
雷峰网
雷峰网
博客园 - 叶小钗
月光博客
月光博客
J
Java Code Geeks
量子位
爱范儿
爱范儿
阮一峰的网络日志
阮一峰的网络日志
Martin Fowler
Martin Fowler
H
Help Net Security
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
Latest news
Latest news
Recent Announcements
Recent Announcements
Google DeepMind News
Google DeepMind News
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
The Blog of Author Tim Ferriss
T
Troy Hunt's Blog
B
Blog
T
Tenable Blog
S
Schneier on Security
L
LangChain Blog
L
LINUX DO - 热门话题
博客园 - 司徒正美
I
InfoQ
P
Privacy International News Feed
P
Privacy & Cybersecurity Law Blog

Blog - Astral

Vulnerability and malware checks in uv Open source security at Astral Astral to join OpenAI Ruff v0.15.0 ty: An extremely fast Python type checker and language server Python 3.14 Ruff v0.13.0 Astral OSS Fund: One Year Later pyx: a Python-native package registry, now in Beta An experimental, variant-enabled build of uv uv security advisory: ZIP payload obfuscation Ruff v0.12.0 Ruff v0.10.0 A new home for python-build-standalone Ruff v0.8.0 Ruff v0.7.0 uv: Unified Python packaging Ruff v0.6.0 Announcing the Astral OSS Fund Ruff v0.5.0 Ruff v0.4.5: Ruff's language server is now written in Rust Ruff v0.4.0: a hand-written recursive descent parser for Python Ruff v0.3.0 uv: Python packaging in Rust Ruff v0.2.0 Ruff v0.1.8 Ruff v0.1.5 The Ruff Formatter: An extremely fast, Black-compatible Python formatter Ruff v0.1.0 Ruff v0.0.292 Ruff v0.0.285 Ruff v0.0.283 Ruff v0.0.281 Ruff v0.0.278 Ruff v0.0.276 Announcing Astral, the company behind Ruff
Ruff v0.9.0
micha@astral · 2025-01-09 · via Blog - Astral

Ruff v0.9.0 is available now! Install it from PyPI, or your package manager of choice:

uv pip install --upgrade ruff

As a reminder: Ruff is an extremely fast Python linter and formatter, written in Rust. Ruff can be used to replace Black, Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, and more, all while executing tens or hundreds of times faster than any individual tool.

With a new year comes a new Ruff minor release! Among other changes, this release brings with it a new style guide for the Ruff formatter, seven lint rule stabilizations, and two stabilized lint rule autofixes.

The Ruff 2025 style guide #

This release ships a new style guide for the Ruff formatter. Significant changes include:

  • Interpolated expressions inside f-strings are now formatted
  • Single-line implicitly concatenated strings are now avoided where possible
  • Improved compatibility with Black’s style guide

For a detailed list of all style changes, head to the release page.

F-String formatting #

With the new style guide, Ruff now formats expressions interpolated inside f-string curly braces:

--- 2024
+++ 2025

     return {
         "statusCode": 200,
-        "body": json.dumps({"message": f"{layer_method()+5}"}),
+        "body": json.dumps({"message": f"{layer_method() + 5}"}),
     }

Otherwise, however, Ruff now formats the f-string like any other regular string:

  • F-string quotes are now normalized according to your project's configuration. Quotes will still be left untouched, however, if normalizing them would result in an invalid f-string or would require escaping more quotes in the f-string’s literal parts.
  • Unnecessary escapes are now removed from inside f-strings. For example, \' will be replaced with ' if the f-string uses " for its outer quotes.
--- 2024
+++ 2025

  assert (dag_id in actual_found_dag_ids) == should_be_found, (
-     f'dag \'{dag_id}\' should {"" if should_be_found else "not "}'
+     f"dag '{dag_id}' should {'' if should_be_found else 'not '}"
      f"have been found after processing dag '{expected_dag.dag_id}'"
  )

Lastly, Ruff now looks at the interpolated expressions (the parts inside {} curly braces) in an f-string to see whether it might be acceptable to split the f-string over multiple lines. If any interpolated expression in the f-string contains a line break (either using a multiline expression or a comment inside the braces), Ruff will now sometimes add other line breaks to the f-string if it would help wrap the string to your project's maximum line length.

# Source
f"Unsupported serializer {serializer!r}. Expected one of {', '.join(map(repr, _SERIALIZERS))}"

# Add a line break manually to inform Ruff to split the f-string...
f"Unsupported serializer {
    serializer!r}. Expected one of {', '.join(map(repr, _SERIALIZERS))}"

# 2025 style guide: Ruff now splits the f-string as it does not fit the line length limit,
# and it sees from the line break that this would be acceptable
f"Unsupported serializer {serializer!r}. Expected one of {
    ', '.join(map(repr, _SERIALIZERS))
}"

For more details on how Ruff now formats f-strings, see the documentation.

Fewer single-line implicitly concatenated strings #

Implicitly concatenated strings can be a convenient way to breaking long strings into multiple shorter literals. However, they are also easily overlooked and can sometimes reduce readability, especially when the concatenated literals are placed next to each other on a single line.

With the new style guide, Ruff merges the implicitly concatenated strings if they all fit on a single line:

--- 2024
+++ 2025

  raise argparse.ArgumentTypeError(
-     f"The value of `--max-history {max_history}` " f"is not a positive integer."
+     f"The value of `--max-history {max_history}` is not a positive integer."
  )

All implicitly concatenated strings receive this treatment, except:

  • Triple-quoted strings ('''string''')
  • Raw strings (r"string")
  • Some rare combinations of f-strings with debug texts containing quotes or format specifiers containing quotes (e.g. f'{1=: "abcd \'\'}' or f'{x=:a{y:{z:"abcd"}}}')

For strings that can’t be automatically joined, Ruff now preserves whether the implicitly concatenated string literals are formatted over multiple lines or on a single line.

# Source
single_line = r'^time data "a" doesn\\'t match format "%H:%M:%S". ' f"{PARSING_ERR_MSG}$"
multi_line = (
    r'^time data "a" doesn\\'t match format "%H:%M:%S". '
    f"{PARSING_ERR_MSG}$"
)

# 2024 style guide: the multiline implicitly concatenated string was converted
# to a single-line implicitly concatenated string
single_line = r'^time data "a" doesn\\'t match format "%H:%M:%S". ' f"{PARSING_ERR_MSG}$"
multi_line = r'^time data "a" doesn\\'t match format "%H:%M:%S". ' f"{PARSING_ERR_MSG}$"

# 2025 style guide: neither string can be easily joined
# to remove the implicit concatenation,
# so both are left as they are in the source
single_line = r'^time data "a" doesn\\'t match format "%H:%M:%S". ' f"{PARSING_ERR_MSG}$"
multi_line = (
    r'^time data "a" doesn\\'t match format "%H:%M:%S". '
    f"{PARSING_ERR_MSG}$"
)

Preserving the source formatting for these cases means that the longstanding formatter incompatibility with our ISC001 rule is now resolved. Users will no longer see a warning if they have both the formatter and this lint rule enabled in their Ruff configuration.

Prefer wrapping the assertion message #

If an assert statement is too long to fit onto a single line, Ruff has two possible choices. It could either split the expression (the first part of the statement) over multiple lines, or it could split the assertion message (the part of the statement following the comma).

Previously, Ruff preferred breaking the assert statement’s expression when it encountered an assert statement longer than the maximum line length. This had the advantage that it often avoided the need for additional parentheses around the assertion message. Nonetheless, the Ruff 2025 style guide prefers to parenthesize the assertion message rather than breaking the assertion expression over multiple lines. We think that the assertion expression is the most important part of an assert statement; keeping it on a single line where possible outweighs other considerations and improves readability:

--- 2024
+++ 2025

- assert (match_opt1 is not None) or (
-     match_opt2 is not None
- ), "Cannot find paper abstract section!"
+ assert (match_opt1 is not None) or (match_opt2 is not None), (
+     "Cannot find paper abstract section!"
+ )

This new formatting aligns with Ruff's assignment formatting, where it prefers splitting the value on the right-hand side of an assignment before it will resort to parenthesizing the assignment's targets on the left-hand side.

Fewer parenthesized return annotations #

Previously, Ruff often added parentheses around multiline or subscript return-type annotations when a function declaration exceeded the maximum line length. Ruff now avoids adding parentheses in cases where the return type comes with its own set of parentheses or is known to be multiline.

--- 2024
+++ 2025

- def _register_filesystems() -> (
-     Mapping[
-         str,
-         Callable[[str | None, Properties], AbstractFileSystem]
-         | Callable[[str | None], AbstractFileSystem],
-     ]
- ):
+ def _register_filesystems() -> Mapping[
+     str,
+     Callable[[str | None, Properties], AbstractFileSystem]
+     | Callable[[str | None], AbstractFileSystem],
+ ]:
      scheme_to_fs = _BUILTIN_SCHEME_TO_FS.copy()

The new formatting now aligns more closely with Black’s return-type annotation formatting.

Automatically parenthesized if guards in match case statements #

Previous versions of Ruff never added parentheses to if guards in case clauses of match statements. Unnecessary parentheses, meanwhile, were left untouched. The former could result in formatting that was hard to read due to case patterns being unnecessarily split over multiple lines. The latter could result in unnecessarily parenthesized if guards with a large amount of visual noise.

Ruff now automatically parenthesizes an if guard when a case line goes beyond its maximum allowed length according to your project's configuration. This has the added effect that the if guards are broken before the case pattern, improving readability:

--- 2024
+++ 2025

  # Options: line-length = 60

  match command.split():
-     case [
-         "go",
-         direction,
-     ] if direction in current_room.exits:
+     case ["go", direction] if (
+             direction in current_room.exits
+     ):
          current_room = current_room.neighbor(direction)
      case ["go", _]:
          print("Sorry, you can't go that way")
-     case ["wait", _] if (current_room.waiting_room):
+     case ["wait", _] if current_room.waiting_room:
          pass

Rule stabilizations #

The following rules have been stabilized and are no longer in preview:

Other behavior stabilizations #

The following rules now have improved autofix behavior that was previously only available in preview mode:

And finally, Ruff v0.9 stabilizes several other behaviors that were previously only available to users who opted into preview:

Thank you! #

Thank you to everyone that provided feedback regarding the formatter and other changes included in Ruff's --preview mode, and especially, to our contributors. It's an honor building Ruff with you!


View the full changelog on GitHub.

Read more about Astral — the company behind Ruff.

Thanks to Alex Waygood and Dhruv Manilawala, who both contributed to this blog post.