Hey devs This is a heads up that we are gradually rolling out ruff checks on the openedx-platform master branch.
Already, pycodestyle has been disabled. ruff check now does all the basic style checks.
Also, import sorting is now enforced with ruff. We recently did a big sweep PR to fix all the imports. (If you had a PR open before, you might see a lot of merge conflicts now–sorry! To deal with this, I recommend running ruff format and squashing it into your commit before rebasing.)
We’re currently working on switching most things that pylint checks over to ruff. You’ll notice that, in order to disable checks on certain lines, you’ll need to to use # noqa codes instead of # pylint-disable codes. We expect that we’ll still run pylint in the end, but only for the Open-edX-specific custom checks that we’ve developed. This should be a much smaller set of checks and they’ll probably run very quickly.
When we’re done, this should make all of our static analysis checks much faster to run, both locally and on PRs Furthermore, you’ll find that the majority of linting failures can be resolved automatically with ruff format and ruff check --fix instead of having to fiddle with newlines and unused import statements by hand.
We expect that we’ll still run pylint in the end, but only for the Open-edX-specific custom checks that we’ve developed. This should be a much smaller set of checks and they’ll probably run very quickly.
pylint maintainer here, the big cost in pylint is in the ast parsing and rebuilding that is done once (except for very specific checks like cyclic-import or duplicate-code that are costly in themselves), if you run pylint for your pylint plugins you might as well run pylint checks that aren’t in ruff for marginal cost.
That’s helpful to know, thanks. And thanks for all the work you’ve done that’s helped keep bugs out of our code for so many years.
It’s less about the wall-clock time that one run of pylint takes, and more about the expected time developers will spend iteratively running pylint in order to get their checks to pass. The more checks we have in pylint, the more often developers will need look at pylint output, manually make the fixes, and then run pylint again to see if their fixes worked. I’m hoping that the remaining pylint checks we have are ones which developers will very rarely violate, so that the guidance to our devs can be “only run pylint on targeted files if your PR build fails” rather than “run pylint on everything before committing”.
On PRs, pylint is already fast enough that it’s not the limiting check.
After some research, we’ve decided to keep pylint for the time being. We’ll run ruff first in CI (instead of pycodestyle) which will catch all the low-hanging, auto-fixable stuff, but continuing to run pylint will protect us against various type errors in our un-annotated code.
pylint’s type checking (e.g. signature mismatch detection from 3rd-party library updates, as in fix: Drop constraints for cryptography and pact-python · openedx/openedx-platform@3017e2d · GitHub) provides value that ruff cannot replicate. Dropping pylint down to only plugin-specific checks would lose that coverage. Longer-term this could be revisited alongside a proper mypy or similar type-checking migration, but that’s out of scope for the current ruff migration.