For those who don’t know what Ruff is (like me, 5 minutes ago), here’s what the GitHub project describes it as:
> An extremely fast Python linter, written in Rust.
Pro-tip to announcement authors: it’s helpful when there’s a one-sentence description of the project at the top of a post/article for newcomers who aren’t familiar with the project.
I love Ruff. It's amazing. It's blindingly fast. I dig it.
But. v0.1.0 comes with a breaking change: the old `--output` option is now named `--output-format`, and it was only deprecated 3 weeks ago in version 0.0.291 (https://github.com/astral-sh/ruff/releases/tag/v0.0.291). That's bound to break some CI pipelines, and definitely breaks the python-lsp-ruff language server plugin. If you use the latter, I have a PR at https://github.com/python-lsp/python-lsp-ruff/pull/48 that will get you running again for now.
To be super clear, the Ruff team doesn't owe it to anyone to make the command line stable. This is a little inconvenient, but that's our problem, not theirs. They've made an amazing free tool we can all use. Still, it's something you'll need to know about and deal with.
Edit: “our” as in “us end users”. I’m also just an end user of python-lsp-ruff and not associated with it. I realized on re-reading that it might sound like I’m one of its developers. Nope!
If they're using semver, having a major version number of zero means that any change can be breaking. Additionally, while it's not part of the semver spec, to me having the minor version be zero as well is an even bigger indicator that nothing is stable.
Sounds like they'll be using the cargo variant of semver where changing the leading digit is a breaking change with a common expectation that fewer leading digits implies "better" for varying metrics of "better" (fewer breaking changes, more production ready, etc).
Agree with this as both someone who depends on projects that introduce breaking changes, and as an author of libraries that follow this convention.
Introducing breaking changes can be a hard decision to make, especially knowing that downstream consumers might disagree and their things might break, but the version numbers let you know that it's still unstable and introduced breaking changes.
This announcement post specifically addresses this: v0.1.0 introduces a new versioning policy [0], where patch versions (v0.1.1) are guaranteed to no longer break "stable" features, while minor versions (v0.2.0) can. At some point I'd assume they plan on stabilizing it such that even minor versions don't break stable features, but as a sibling notes, using v0 as a project's major version is usually intended to communicate that you shouldn't count on things staying stable.
Yep. Again, I’m not complaining. It broke a thing I use, so I fixed the thing.
However, it’s something that pretty much all Ruff users to know about. Some projects look at their big x.y.Z number and decide to bump y or x to say “hey, it’s been long enough, let’s call it a new version”. This isn’t one of those cases.
I can’t overstate how much I agree with the Ruff team in not being afraid to break things at this point. They have a very promising new tool, but it is very early. They are still very much learning the space and best way to produce their product.
It would be an absolute tragedy if they felt compelled to maintain backwards compatibility for philosophical reasons at this stage, if they felt it constrained the capability or usability of their product.
As of right now, pylsp has some nice features that ruff doesn’t cover yet, like the jedi, rope, and black stuff. The editor I’m currently using doesn’t easily — at all? — support multiple servers at once. Today, that means it’s easiest for me to use it as a plugin under pylsp.
I read this comment on the train to work today. First thing that happened at work was that somebody had disabled the linting stage because of exactly this error.
> We also released an alpha version of our Black-compatible code formatter.
Interesting that Ruff has replaced so many linters, and now going for formatter next. One tool to rule them all!
Extra interesting that Ruff appears to provide more knobs than Black, which will likely be a big plus for those not happy with how opinionated Black is.
For teams, I'm not sure the knobs are a good thing. Sounds like it will just be another source of infinite bikeshedding arguments. I am a big fan of "set up Black and forget about it", even if I dislike some things it does (like the space after the colon in one-sided slices).
For every bikeshedder there are those of us who just set it to the defaults and disable one or two rules and call it a day. I run mypy in strict mode and vanilla ruff with only the line length rule adjusted and it’s been great and sensible
No it isn't good (in this case). All the options are pointless aesthetic choices that don't make a difference in correctness or performance, and the time spent tweaking them is far better spent pushing features and fixes.
People will never agree about minor, non-consequential choices, especially choices that are not objectively good or bad. Where these decisions have no effect on the quality of the output of the work (like trivial formatting settings), it's better to pick an arbitrary side, e.g. choose Black's set of decisions, live with them, and focus on actual work.
Yes, and what I am saying is that if people on your team cannot let a trivial, unimportant technical detail go, that is a people problem.
You may have avoided the silly argument about code formatting. But if that tendency lives in your engineers, they will find another nit to pick somewhere else.
In my opinion this is not a problem best solved by technology.
But someone on the team has to take time, no matter how little, to choose which way to go for all these pointless nits. Again, they don't matter, why does anyone on the team have to work on them? Just use Black's settings and move on.
I’ve been meaning to find time to get ruff-lap working on Doom Emacs side by side with pyright. Is anyone who’s already managed to get it working willing to share their config?
One suggestion to the authors - every serious codebase I've ever worked on had their own set of linters and plugins for whatever linter they were using.
How do I extend Ruff? Can I extend Ruff? How do I write plugins and linters? It's Rust in Python and I am generally leery of such things. The fact that it's one tool to do all these things makes believe it's because the tool is inflexible so it must be able to do all these things.
Looks very cool, but I don't feel like I've had many problems with tool speed. Is this actually better than all of those listed tools in terms of features? I feel like I might just end up using all of them.
Same. The difference between ruff and, say, pylint, is night and day. The tools it replaces are amazing in their own right. However, having ruff and a language server point out problems the moment I type them is wonderful.
Just curious, how are you using black? I would expect it to take 3-5 seconds for 10k LoC, but how frequently do you need to format that much code to notice 3-5 seconds at all?
Ruff isn't quite at feature priority with the tools it's replacing (although it's close). The main benefits to using ruff is that it's great enough to run regularly locally without being noticable, even on large codebases and it provides tool chain consolidation (although the latter can be achieved with other tools like pants). The speed difference is more noticable in monorepos. If you instead have many smaller repos it probably makes sense to just implement the original tools
The speed difference sneaks up on you - Ruff is so fast there’s usually no perceptible delay but then you use flake8 + isort + pyupgrade and you realize how much you’d gotten used to the minor but noticeable delays.
For me, the big win is having a single tool instead of a dozen - like when the last flake8 update happened we had to play plug-in Jenga until everything updated, you have different configuration files for flake8, isort, pyupgrade, pylint, bandit, etc. and inconsistent support for pyproject.toml or ignoring things, etc. None of that is a big problem but it’s nice for it just to be gone entirely.
I'll be ecstatic when the inevitable rust-backed python typechecker arrives, python type checking has been excruciatingly slow in the various places I've used it. Ruff is a great start though!
Have you seen Pyre[0]? Not Rust, OCaml, and pretty fast. Made by a team at Meta and open sourced on GitHub. If you use python-lsp, I wrote an extension[1] to enable integration (though I haven't tested it recently, been programming in rust; it is mostly a "for me" extension).
That looks cool, thanks for posting it. I notice that you have a contributing section <https://github.com/cricalix/python-lsp-pyre#contributing> but no obvious licensing information (I checked some files, too, in case the license was in the file headers)
I was an early adopter of Ruff, what sold me wasn't even the performance win, but the advantage of having a single configuration file without third-party plugins, making it much easier to run the linter in my editor, CLI, pre-commit hooks, and CI without any fuss.
The speed of the tool and its development pace astound me.
If the authors/maintainers are lurking here: know that you're doing an amazing job.
This is also my question. I think ruff is a great tool. I love it and use it on all my new projects. It is an insanely fast and enjoyable tool in a Python world where tools are frequently very slow and a pain to use. But how are you going to make money as a linting tool?
I will say that seeing from afar Charlie has been hiring some very smart people. Not sure how it will turn out but hopefully something good will come of it.
> In the future, we’ll build and sell services on top of our tools — but the tools themselves will remain free and open-source.
> Our plan is to provide paid services that are better and easier to use than the alternatives by integrating our open-source offerings directly. Our goal is for these services to be as impactful as Ruff itself — but you may choose not to use them. Either way, Ruff will remain free and open-source, just as it is today.
I'm impressed by Ruff. I heard about it a while ago and just assumed I wouldn't be able to use it because it's not just flake8 I like, but a bunch of third-party flake8-* plugin packages too.
50 comments
[ 2.8 ms ] story [ 75.2 ms ] thread> An extremely fast Python linter, written in Rust.
Pro-tip to announcement authors: it’s helpful when there’s a one-sentence description of the project at the top of a post/article for newcomers who aren’t familiar with the project.
But. v0.1.0 comes with a breaking change: the old `--output` option is now named `--output-format`, and it was only deprecated 3 weeks ago in version 0.0.291 (https://github.com/astral-sh/ruff/releases/tag/v0.0.291). That's bound to break some CI pipelines, and definitely breaks the python-lsp-ruff language server plugin. If you use the latter, I have a PR at https://github.com/python-lsp/python-lsp-ruff/pull/48 that will get you running again for now.
To be super clear, the Ruff team doesn't owe it to anyone to make the command line stable. This is a little inconvenient, but that's our problem, not theirs. They've made an amazing free tool we can all use. Still, it's something you'll need to know about and deal with.
Edit: “our” as in “us end users”. I’m also just an end user of python-lsp-ruff and not associated with it. I realized on re-reading that it might sound like I’m one of its developers. Nope!
Introducing breaking changes can be a hard decision to make, especially knowing that downstream consumers might disagree and their things might break, but the version numbers let you know that it's still unstable and introduced breaking changes.
[0] https://astral.sh/blog/ruff-v0.1.0#ruffs-versioning-policy
However, it’s something that pretty much all Ruff users to know about. Some projects look at their big x.y.Z number and decide to bump y or x to say “hey, it’s been long enough, let’s call it a new version”. This isn’t one of those cases.
It would be an absolute tragedy if they felt compelled to maintain backwards compatibility for philosophical reasons at this stage, if they felt it constrained the capability or usability of their product.
(of course I should have pinned versions...)
Interesting that Ruff has replaced so many linters, and now going for formatter next. One tool to rule them all!
Extra interesting that Ruff appears to provide more knobs than Black, which will likely be a big plus for those not happy with how opinionated Black is.
https://github.com/astral-sh/ruff/discussions/7310#discussio...
You may have avoided the silly argument about code formatting. But if that tendency lives in your engineers, they will find another nit to pick somewhere else.
In my opinion this is not a problem best solved by technology.
How do I extend Ruff? Can I extend Ruff? How do I write plugins and linters? It's Rust in Python and I am generally leery of such things. The fact that it's one tool to do all these things makes believe it's because the tool is inflexible so it must be able to do all these things.
I think the philosophy right now is to treat it like Black, but I'm not going to speak for the authors or maintainers, it's just my opinion.
For me, the big win is having a single tool instead of a dozen - like when the last flake8 update happened we had to play plug-in Jenga until everything updated, you have different configuration files for flake8, isort, pyupgrade, pylint, bandit, etc. and inconsistent support for pyproject.toml or ignoring things, etc. None of that is a big problem but it’s nice for it just to be gone entirely.
0: https://pyre-check.org/
1: https://github.com/cricalix/python-lsp-pyre
Not sure how good it is.
The speed of the tool and its development pace astound me.
If the authors/maintainers are lurking here: know that you're doing an amazing job.
I will say that seeing from afar Charlie has been hiring some very smart people. Not sure how it will turn out but hopefully something good will come of it.
> In the future, we’ll build and sell services on top of our tools — but the tools themselves will remain free and open-source.
> Our plan is to provide paid services that are better and easier to use than the alternatives by integrating our open-source offerings directly. Our goal is for these services to be as impactful as Ruff itself — but you may choose not to use them. Either way, Ruff will remain free and open-source, just as it is today.
It's there in their announcement post.
https://astral.sh/blog/announcing-astral-the-company-behind-...
What are the paid alternative services they are talking about?
Turns out Ruff went and reimplemented the majority of those I use, from scratch. https://docs.astral.sh/ruff/faq/#how-does-ruff-compare-to-fl...