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

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
S
Schneier on Security
I
InfoQ
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The GitHub Blog
The GitHub Blog
S
Security @ Cisco Blogs
O
OpenAI News
W
WeLiveSecurity
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
人人都是产品经理
人人都是产品经理
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
NISL@THU
NISL@THU
T
Tailwind CSS Blog
V
Visual Studio Blog
PCI Perspectives
PCI Perspectives
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
D
DataBreaches.Net
B
Blog RSS Feed
N
News and Events Feed by Topic
N
News and Events Feed by Topic
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
腾讯CDC
Latest news
Latest news
V
Vulnerabilities – Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
V
V2EX
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Register - Security
The Register - Security
Help Net Security
Help Net Security

Blog - Astral

Ruff v0.16.0 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.