NewsDeveloper ToolsPython

Ruff v0.16.0: 413 Default Rules Break Unpinned Python Pipelines

Ruff v0.16.0 shipped on July 23, 2026, and it immediately broke CI pipelines across the Python ecosystem. The default ruleset expanded from 59 to 413 rules — a 7x jump — and any team that didn’t pin their Ruff version discovered this via a failing build rather than a release note. Simon Willison found out the hard way: running v0.16.0 against sqlite-utils surfaced 1,618 errors on code that had passed linting the day before. Your codebase likely has some too.

What Changed in Ruff v0.16.0: 354 New Rules, No Warning

Ruff’s default ruleset hadn’t been touched since v0.1.0. The tool defaulted to the conservative ["E4", "E7", "E9", "F"] set — core pyflakes and pycodestyle rules. Effective July 23, that baseline now includes 413 rules across 34 categories. The most impactful additions: flake8-bugbear (29 rules catching mutable defaults and unsafe attribute operations), pyupgrade (42 rules modernizing type hints like Optional[X]X | None), Pylint (67 rules for conventions and complexity), and flake8-simplify (21 rules eliminating redundant conditional patterns). Datetime timezone checks add 17 more.

As pydevtools puts it: “Your code didn’t change; Ruff enabled 354 additional rules by default.” That’s the actual situation. CI passes on Monday, fails on Tuesday, codebase untouched. For teams running ruff>=latest or auto-updating dev tools, v0.16.0 is a silent breaking change.

What To Do Right Now

Two choices. If you want to preserve pre-0.16 behavior and deal with this on your own timeline, one config line restores it:

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]

If you’d rather embrace the expanded defaults — and the new rules do catch real issues — adopt gradually by category, not all 354 violations at once:

# See what pyupgrade rules fire
ruff check --select UP .

# Auto-fix safe violations
ruff check --fix --select UP .

One trap: if your existing config has extend-select = ["UP"], removing it after upgrading would drop rules beyond the new defaults, not just return to baseline. Audit your configuration before making changes in either direction.

Related: OpenAI Acquires Astral: What Happens to uv and ruff?

Rules Worth Disabling Immediately

Not all 354 new rules are equally useful. Several have generated pushback in the GitHub feedback discussion. RET504 (unnecessary-assign) flags verbose assignments before return — sometimes intentional for readability. BLE001 (blind-except) catches broad except Exception blocks, but these are legitimate when wrapping unpredictable third-party libraries. SIM115 enforces with open() context managers, breaking Django’s FileResponse pattern. PERF401 pushes list comprehensions over explicit loops — a bad default for codebases where junior developers need to read and modify the code.

The practical move: run ruff check --statistics to see which rules fire most, then add targeted ignores. Don’t disable entire categories — review per-rule so you don’t discard genuinely useful catches.

The Other New Features

The rule expansion overshadows some genuinely useful additions. ruff format now processes Python code blocks inside Markdown files by default. The new # ruff: ignore[CODE] and # ruff: file-ignore[CODE] comment syntax is cleaner than # noqa, especially for file-wide suppression. CI output now shows fix diffs inline during ruff check, eliminating the need for a separate --diff pass. These improvements would be the headline in a quieter release.

Key Takeaways

  • Ruff v0.16.0 expands defaults from 59 to 413 rules — a 7x increase that silently breaks any project that auto-updates without version pinning
  • Restore old behavior immediately with select = ["E4", "E7", "E9", "F"] in your pyproject.toml if you’re not ready to migrate
  • For controlled migration, adopt new rule categories one at a time using ruff check --select [CATEGORY] .
  • RET504, BLE001, SIM115, and PERF401 are the rules most likely to produce false positives in existing codebases — review before enforcing
  • The new Markdown formatting and ruff: ignore syntax are worth adopting regardless of which ruleset you run
ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to cover latest tech news, controversies, and summarizing them into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *

    More in:News