You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Restore pylint: ruff is not a drop-in replacement #289
People are welcome to add ruff, but it's not a replacement for pylint. To replace pylint we'll need to replace some custom pylint plugins + all its type checking.
While working on this story I started shaping a strategy for running ruff and pylint together across our Python repos, so they complement each other instead of overlapping. This is an agentically brainstormed plan; feedback is appreciated.
Use ruff as the first-class tool
Ruff is the default linter and formatter. It is fast, auto-fixes most findings, and owns everything mechanical: style, imports, modern syntax, comprehensions, bugbear, Django checks, and unused imports. When ruff and pylint cover the same check, ruff wins and pylint's version is disabled.
Use pylint where it shines
Keep pylint for the checks ruff cannot do, because they need whole-program or type-aware analysis:
Where both tools cover a check, keep it in ruff and disable pylint's version:
Unused imports: ruff F401 is auto-fixable, so pylint unused-import is disabled. Package re-exports declare __all__, which ruff recognizes.
Carry the shared config in edx-lint
edx-lint ships the canonical pylintrc for Open edX repos. Encode the ruff and pylint split there so every repo inherits the same setup instead of re-deriving it.
Example: edx-platform
edx-platform runs both tools this way, with ruff as the primary gate and pylint for its semantic and plugin checks. It is migrating toward ruff as the first-class tool across staged PRs. Some of its choices are scale-driven and are not part of this baseline:
It suppressed thousands of existing findings with # noqa instead of fixing them, because a mass fix was infeasible. A smaller repo should fix them.
It ignores E722, E731, E741, and E721 to keep the migration an equivalent swap. A smaller repo should keep these on.
Where this repo deviates
Line length stays with pylint (C0301) rather than ruff (E501), against the ruff-wins rule, because pylint ignores trailing comments and URLs while ruff does not.
Deviating is fine with a solid reason
Treat this as a default, not a rule:
A fully type-annotated repo checked by mypy can drop pylint's type checks.
A repo may hand line length to ruff (E501) when it does not need pylint's trailing-comment handling.
Move a check to ruff once ruff gains an equivalent that only pylint provides today.
Keep a scale-driven suppression, like edx-platform's, when fixing every existing finding is not yet practical.
edx-lint ships the canonical pylintrc for Open edX repos. Encode the ruff and pylint split there so every repo inherits the same setup instead of re-deriving it.
That sounds great. When you encode this into edx-lint, I would mark it as a BREAKING CHANGE with a major version bump, because repos which don't use ruff yet will not be ready for the slimmed-out pylint rules.
Activity
feat: integrate pylint into the quality checks
build: integrate pylint into the quality checks
farhan commentedon Aug 31, 2026
Note
Generated with help of Claude after thorough brainstorming & spelunking
@feanil @kdmccormick @openedx/axim-aximprovements
While working on this story I started shaping a strategy for running ruff and pylint together across our Python repos, so they complement each other instead of overlapping. This is an agentically brainstormed plan; feedback is appreciated.
Use ruff as the first-class tool
Ruff is the default linter and formatter. It is fast, auto-fixes most findings, and owns everything mechanical: style, imports, modern syntax, comprehensions, bugbear, Django checks, and unused imports. When ruff and pylint cover the same check, ruff wins and pylint's version is disabled.
Use pylint where it shines
Keep pylint for the checks ruff cannot do, because they need whole-program or type-aware analysis:
no-member,undefined-variable, andused-before-assignment.feature-toggle-needs-docandillegal-waffle-usage.duplicate-code.too-many-*.Give ruff preference on overlap
Where both tools cover a check, keep it in ruff and disable pylint's version:
F401is auto-fixable, so pylintunused-importis disabled. Package re-exports declare__all__, which ruff recognizes.Carry the shared config in edx-lint
edx-lint ships the canonical
pylintrcfor Open edX repos. Encode the ruff and pylint split there so every repo inherits the same setup instead of re-deriving it.Example: edx-platform
edx-platform runs both tools this way, with ruff as the primary gate and pylint for its semantic and plugin checks. It is migrating toward ruff as the first-class tool across staged PRs. Some of its choices are scale-driven and are not part of this baseline:
# noqainstead of fixing them, because a mass fix was infeasible. A smaller repo should fix them.E722,E731,E741, andE721to keep the migration an equivalent swap. A smaller repo should keep these on.Where this repo deviates
C0301) rather than ruff (E501), against the ruff-wins rule, because pylint ignores trailing comments and URLs while ruff does not.Deviating is fine with a solid reason
Treat this as a default, not a rule:
E501) when it does not need pylint's trailing-comment handling.feanil commentedon Sep 3, 2026
This generally makes sense to me and seems like a good approach.
kdmccormick commentedon Sep 14, 2026
@farhan Great writeup 🚀
That sounds great. When you encode this into edx-lint, I would mark it as a BREAKING CHANGE with a major version bump, because repos which don't use ruff yet will not be ready for the slimmed-out pylint rules.