As a reminder: Ruff is an extremely fast Python linter, written in Rust. Ruff can be used to replace Flake8 (plus dozens of plugins), isort, pydocstyle, pyupgrade, and more, all while executing tens or hundreds of times faster than any individual tool.
Ruff is used in production by tens of thousands of open source projects and major enterprises. In the last year, we've been working to expand Ruff's feature set and improve stability for those that depend on Ruff in their daily workflows.
Today, we're excited to announce that Ruff v0.1.0 is out! This release is focused on stabilization, and includes a new preview mode, the introduction of fix safety levels, and a formal versioning policy.
pip install --upgrade ruff
A growing feature set #
Earlier this year, Charlie looked back on the first 200 releases of Ruff, at which point 376 lint rules were supported. Ruff now supports over 700 rules, with new rules being added in every release. In case you missed it, we've released some exciting features this year:
- Jupyter notebook support
- Python 3.12 f-string syntax support
- Python 3.12 type alias and generics syntax support
- 2-3x performance improvements to our lexer
- Improvements to the Ruff playground
We also released an alpha version of our Black-compatible code formatter. Expect more news on that front soon!
Introducing preview mode #
In v0.0.289, we added a new preview mode to enable the use of unstable features when running Ruff.
Since new rules often benefit from a trial period, we want to be able to release them in a staged manner. Previously, we used a "nursery" rule category to do this, a concept taken from Clippy, Rust's linter.
However, the nursery required opt-in for each rule using their exact code, e.g., if you'd selected
F and we released an unstable rule
F999, you'd need to update your selection to
Requiring opt-in for each rule reduced exposure of new rules and could be tedious for users to
update. Furthermore, as Ruff grows, we want a global concept for use of unstable features — the
nursery concept doesn't scale beyond rule selection.
Preview mode will be used to enable new rules, unstable fixes, and experimental code analysis. Releasing these features — but gating them to users who opt-in — will allow us to collect community feedback and gain confidence that changes are a net-benefit.
Preview mode can be enabled per-invocation with the
--preview flag or by updating your
[tool.ruff] preview = true
Check out the docs for preview mode and give it a try!
Respecting fix safety #
Ruff's ability to automatically fix violations is one of its most powerful features. However, given Python's dynamic nature, it's not always possible to guarantee that a fix is "safe". Since May, we've been labeling a subset of Ruff's fixes as unsafe. When applying safe fixes, the meaning and intent of your code will be retained; when applying unsafe fixes, the meaning could change.
is a rule which checks for potentially unperformant use of
list(...). The fix replaces this
next(iter(...)) which can result in a drastic speedup:
$ python -m timeit "head = list(range(99999999))" 1 loop, best of 5: 1.69 sec per loop $ python -m timeit "head = next(iter(range(99999999)))" 5000000 loops, best of 5: 70.8 nsec per loop
However, when the collection is empty, this fix changes the raised exception from an
$ python -c 'list(range(0))' Traceback (most recent call last): File "<string>", line 1, in <module> IndexError: list index out of range $ python -c 'next(iter(range(0)))' Traceback (most recent call last): File "<string>", line 1, in <module> StopIteration
Since this could break error handling, this fix is categorized as unsafe.
Previously, the safety of a fix was only an internal note, but in v0.1.0, Ruff will only use safe fixes by default to increase confidence when applying fixes and highlight fixes that need additional review.
Unsafe fixes can be enabled by passing the
--unsafe-fixes flag to
# Show unsafe fixes ruff check . --unsafe-fixes # Apply unsafe fixes ruff check . --fix --unsafe-fixes
or by setting
unsafe-fixes in your configuration file:
[tool.ruff] unsafe-fixes = true
When working with Ruff in an IDE (via our LSP), we will no longer apply unsafe fixes with the "Fix all" action. Instead, unsafe fixes can be applied individually with the "Quick fix" action allowing review of each fix. If you opt-in to unsafe fixes, they'll be applied during "Fix all". See the LSP docs for more details.
See the docs for more details on fix safety.
Ruff's versioning policy #
Thus far, Ruff releases have only involved incrementing the patch version number. This versioning scheme suffers from a few core problems:
- There is no documented policy and little room for a meaningful policy
- Rules are added in most releases, resulting in significant new violations for users on upgrade
- Users cannot get bug fix upgrades with confidence that they will not need to do other work
- Ruff is not perceived as stable
With the promotion to v0.1.0, Ruff can adopt a meaningful rules around versioning to ensure that users know what to expect from each release. With the addition of a minor version number, we hope to:
- Reduce the frequency of large changes
- Give rules a period for stabilization before enabling
- Differentiate between breaking and non-breaking releases
- Move towards stronger stability guarantees
With the release of 0.1.0, Ruff includes a full versioning policy. Briefly:
- The minor version will be used for stabilization of preview features, changes to stable behavior, and breaking changes.
- The patch version will be used for bug fixes and any changes to rules or fixes in preview.
Check out the docs for a full description of the policy.
A new home for Ruff's documentation #
Our documentation has moved from beta.ruff.rs/docs to docs.astral.sh. We're excited to remove the beta label and move the documentation under the umbrella of our growing company. All existing links redirect to the new domain, and should continue to work as-before.
Thank you! #
Thousands of community members visit our repository every day, and we continue to be energized by the incredible positivity around Ruff. It's a privilege and joy to build this project in collaboration with our 282 contributors, plus all of those that have engaged with the project along the way, be it on Discord or by filing an Issue. A big thank-you to everyone that's participated in this wonderful community.
View the full changelog on GitHub.