Skip to content

Releases: astral-sh/ruff

v0.4.1

19 Apr 12:32
0ff25a5
Compare
Choose a tag to compare

Changes

Preview features

  • [pylint] Implement invalid-hash-returned (PLE0309) (#10961)
  • [pylint] Implement invalid-index-returned (PLE0305) (#10962)

Bug fixes

  • [pylint] Allow NoReturn-like functions for __str__, __len__, etc. (PLE0307) (#11017)
  • Parser: Use empty range when there's "gap" in token source (#11032)
  • [ruff] Ignore stub functions in unused-async (RUF029) (#11026)
  • Parser: Expect indented case block instead of match stmt (#11033)

Contributors

v0.4.0

18 Apr 19:53
e751b4e
Compare
Choose a tag to compare

Changes

A new, hand-written parser

Ruff's new parser is >2x faster, which translates to a 20-40% speedup for all linting and formatting invocations. There's a lot to say about this exciting change, so check out the blog post for more details!

See #10036 for implementation details.

A new language server in Rust

With this release, we also want to highlight our new language server. ruff server is a Rust-powered language server that comes built-in with Ruff. It can be used with any editor that supports the Language Server Protocol (LSP). It uses a multi-threaded, lock-free architecture inspired by rust-analyzer and it will open the door for a lot of exciting features. It’s also faster than our previous Python-based language server -- but you probably guessed that already.

ruff server is only in alpha, but it has a lot of features that you can try out today:

  • Lints Python files automatically and shows quick-fixes when available
  • Formats Python files, with support for range formatting
  • Comes with commands for quickly performing actions: ruff.applyAutofix, ruff.applyFormat, and ruff.applyOrganizeImports
  • Supports source.fixAll and source.organizeImports source actions
  • Automatically reloads your project configuration when you change it

To setup ruff server with your editor, refer to the README.md.

Preview features

  • [pycodestyle] Do not trigger E3 rules on defs following a function/method with a dummy body (#10704)
  • [pylint] Implement invalid-bytes-returned (E0308) (#10959)
  • [pylint] Implement invalid-length-returned (E0303) (#10963)
  • [pylint] Implement self-cls-assignment (W0642) (#9267)
  • [pylint] Omit stubs from invalid-bool and invalid-str-return-type (#11008)
  • [ruff] New rule unused-async (RUF029) to detect unneeded async keywords on functions (#9966)

Rule changes

  • [flake8-bandit] Allow urllib.request.urlopen calls with static Request argument (S310) (#10964)
  • [flake8-bugbear] Treat raise NotImplemented-only bodies as stub functions (B006) (#10990)
  • [flake8-slots] Respect same-file Enum subclasses (SLOT000) (#11006)
  • [pylint] Support inverted comparisons (PLR1730) (#10920)

Linter

  • Improve handling of builtin symbols in linter rules (#10919)
  • Improve display of rules in --show-settings (#11003)
  • Improve inference capabilities of the BuiltinTypeChecker (#10976)
  • Resolve classes and functions relative to script name (#10965)
  • Improve performance of RuleTable::any_enabled (#10971)

Server

This section is devoted to updates for our new language server, written in Rust.

  • Enable ruff-specific source actions (#10916)
  • Refreshes diagnostics for open files when file configuration is changed (#10988)
  • Important errors are now shown as popups (#10951)
  • Introduce settings for directly configuring the linter and formatter (#10984)
  • Resolve configuration for each document individually (#10950)
  • Write a setup guide for Neovim (#10987)

Configuration

  • Add RUFF_OUTPUT_FILE environment variable support (#10992)

Bug fixes

  • Avoid non-augmented-assignment for reversed, non-commutative operators (PLR6104) (#10909)
  • Limit commutative non-augmented-assignments to primitive data types (PLR6104) (#10912)
  • Respect per-file-ignores for RUF100 on blanket # noqa (#10908)
  • Consider if expression for parenthesized with items parsing (#11010)
  • Consider binary expr for parenthesized with items parsing (#11012)
  • Reset FOR_TARGET context for all kinds of parentheses (#11009)

Contributors

v0.3.7

12 Apr 03:55
2e37cf6
Compare
Choose a tag to compare

Changes

Preview features

  • [flake8-bugbear] Implement loop-iterator-mutation (B909) (#9578)
  • [pylint] Implement rule to prefer augmented assignment (PLR6104) (#9932)

Bug fixes

  • Avoid TOCTOU errors in cache initialization (#10884)
  • [pylint] Recode nan-comparison rule to W0177 (#10894)
  • [pylint] Reverse min-max logic in if-stmt-min-max (#10890)

Contributors

v0.3.6

11 Apr 16:29
4e8a846
Compare
Choose a tag to compare

Changes

Preview features

  • [pylint] Implement bad-staticmethod-argument (PLW0211) (#10781)
  • [pylint] Implement if-stmt-min-max (PLR1730, PLR1731) (#10002)
  • [pyupgrade] Replace str,Enum multiple inheritance with StrEnum UP042 (#10713)
  • [refurb] Implement if-expr-instead-of-or-operator (FURB110) (#10687)
  • [refurb] Implement int-on-sliced-str (FURB166) (#10650)
  • [refurb] Implement write-whole-file (FURB103) (#10802)
  • [refurb] Support itemgetter in reimplemented-operator (FURB118) (#10526)
  • [flake8_comprehensions] Add sum/min/max to unnecessary comprehension check (C419) (#10759)

Rule changes

  • [pydocstyle] Require capitalizing docstrings where the first sentence is a single word (D403) (#10776)
  • [pycodestyle] Ignore annotated lambdas in class scopes (E731) (#10720)
  • [flake8-pyi] Various improvements to PYI034 (#10807)
  • [flake8-slots] Flag subclasses of call-based typing.NamedTuples as well as subclasses of collections.namedtuple() (SLOT002) (#10808)
  • [pyflakes] Allow forward references in class bases in stub files (F821) (#10779)
  • [pygrep-hooks] Improve blanket-noqa error message (PGH004) (#10851)

CLI

  • Support FORCE_COLOR env var (#10839)

Configuration

  • Support negated patterns in [extend-]per-file-ignores (#10852)

Bug fixes

  • [flake8-import-conventions] Accept non-aliased (but correct) import in unconventional-import-alias (ICN001) (#10729)
  • [flake8-quotes] Add semantic model flag when inside f-string replacement field (#10766)
  • [pep8-naming] Recursively resolve TypeDicts for N815 violations (#10719)
  • [flake8-quotes] Respect Q00* ignores in flake8-quotes rules (#10728)
  • [flake8-simplify] Show negated condition in needless-bool diagnostics (SIM103) (#10854)
  • [ruff] Use within-scope shadowed bindings in asyncio-dangling-task (RUF006) (#10793)
  • [flake8-pytest-style] Fix single-tuple conversion in pytest-parametrize-values-wrong-type (PT007) (#10862)
  • [flake8-return] Ignore assignments to annotated variables in unnecessary-assign (RET504) (#10741)
  • [refurb] Do not allow any keyword arguments for read-whole-file in rb mode (FURB101) (#10803)
  • [pylint] Don't recommend decorating staticmethods with @singledispatch (PLE1519, PLE1520) (#10637)
  • [pydocstyle] Use section name range for all section-related docstring diagnostics (#10740)
  • Respect # noqa directives on __all__ openers (#10798)

Contributors

v0.3.5

01 Apr 17:41
200ebee
Compare
Choose a tag to compare

Changes

Preview features

  • [pylint] Implement modified-iterating-set (E4703) (#10473)
  • [refurb] Implement for-loop-set-mutations (FURB142) (#10583)
  • [refurb] Implement unnecessary-from-float (FURB164) (#10647)
  • [refurb] Implement verbose-decimal-constructor (FURB157) (#10533)

Rule changes

  • [flake8-comprehensions] Handled special case for C401 which also matches C416 (#10596)
  • [flake8-pyi] Mark unaliased-collections-abc-set-import fix as "safe" for more cases in stub files (PYI025) (#10547)
  • [numpy] Add row_stack to NumPy 2.0 migration rule (#10646)
  • [pycodestyle] Allow cell magics before an import (E402) (#10545)
  • [pycodestyle] Avoid blank line rules for the first logical line in cell (#10291)

Configuration

  • Respected nested namespace packages (#10541)
  • [flake8-boolean-trap] Add setting for user defined allowed boolean trap (#10531)

Bug fixes

  • Correctly handle references in __all__ definitions when renaming symbols in autofixes (#10527)
  • Track ranges of names inside __all__ definitions (#10525)
  • [flake8-bugbear] Avoid false positive for usage after continue (B031) (#10539)
  • [flake8-copyright] Accept commas in default copyright pattern (#9498)
  • [flake8-datetimez] Allow f-strings with %z for DTZ007 (#10651)
  • [flake8-pytest-style] Fix PT014 autofix for last item in list (#10532)
  • [flake8-quotes] Ignore Q000, Q001 when string is inside forward ref (#10585)
  • [isort] Always place non-relative imports after relative imports (#10669)
  • [isort] Respect Unicode characters in import sorting (#10529)
  • [pyflakes] Fix F821 false negatives when from __future__ import annotations is active (attempt 2) (#10524)
  • [pyflakes] Make unnecessary-lambda an always-unsafe fix (#10668)
  • [pylint] Fixed false-positive on the rule PLW1641 (eq-without-hash) (#10566)
  • [ruff] Fix panic in unused # noqa removal with multi-byte space (RUF100) (#10682)

Documentation

  • Add PR title format to CONTRIBUTING.md (#10665)
  • Fix list markup to include blank lines required (#10591)
  • Put flake8-logging next to the other flake8 plugins in registry (#10587)
  • [flake8-bandit] Update warning message for rule S305 to address insecure block cipher mode use (#10602)
  • [flake8-bugbear] Document use of anonymous assignment in useless-expression (#10551)
  • [flake8-datetimez] Clarify error messages and docs for DTZ rules (#10621)
  • [pycodestyle] Use same before vs. after numbers for space-around-operator (#10640)
  • [ruff] Change quadratic-list-summation docs to use iadd consistently (#10666)

Contributors

v0.3.4

23 Mar 13:29
5062572
Compare
Choose a tag to compare

Changes

Preview features

  • [flake8-simplify] Detect implicit else cases in needless-bool (SIM103) (#10414)
  • [pylint] Implement nan-comparison (PLW0117) (#10401)
  • [pylint] Implement nonlocal-and-global (E115) (#10407)
  • [pylint] Implement singledispatchmethod-function (PLE5120) (#10428)
  • [refurb] Implement list-reverse-copy (FURB187) (#10212)

Rule changes

  • [flake8-pytest-style] Add automatic fix for pytest-parametrize-values-wrong-type (PT007) (#10461)
  • [pycodestyle] Allow SPDX license headers to exceed the line length (E501) (#10481)

Formatter

  • Fix unstable formatting for trailing subscript end-of-line comment (#10492)

Bug fixes

  • Avoid code comment detection in PEP 723 script tags (#10464)
  • Avoid incorrect tuple transformation in single-element case (C409) (#10491)
  • Bug fix: Prevent fully defined links name from being reformatted (#10442)
  • Consider raw source code for W605 (#10480)
  • Docs: Link inline settings when not part of options section (#10499)
  • Don't treat annotations as redefinitions in .pyi files (#10512)
  • Fix E231 bug: Inconsistent catch compared to pycodestyle, such as when dict nested in list (#10469)
  • Fix pylint upstream categories not showing in docs (#10441)
  • Add missing Options references to blank line docs (#10498)
  • 'Revert "F821: Fix false negatives in .py files when from __future__ import annotations is active (#10362)"' (#10513)
  • Apply NFKC normalization to unicode identifiers in the lexer (#10412)
  • Avoid failures due to non-deterministic binding ordering (#10478)
  • [flake8-bugbear] Allow tuples of exceptions (B030) (#10437)
  • [flake8-quotes] Avoid syntax errors due to invalid quotes (Q000, Q002) (#10199)

Contributors

v0.3.3

15 Mar 18:13
608df9a
Compare
Choose a tag to compare

Changes

Preview features

  • [flake8-bandit]: Implement S610 rule (#10316)
  • [pycodestyle] Implement blank-line-at-end-of-file (W391) (#10243)
  • [pycodestyle] Implement redundant-backslash (E502) (#10292)
  • [pylint] - implement redeclared-assigned-name (W0128) (#9268)

Rule changes

  • [flake8_comprehensions] Handled special case for C400 which also matches C416 (#10419)
  • [flake8-bandit] Implement upstream updates for S311, S324 and S605 (#10313)
  • [pyflakes] Remove F401 fix for __init__ imports by default and allow opt-in to unsafe fix (#10365)
  • [pylint] Implement invalid-bool-return-type (E304) (#10377)
  • [pylint] Include builtin warnings in useless-exception-statement (PLW0133) (#10394)

CLI

  • Add message on success to ruff check (#8631)

Bug fixes

  • [PIE970] Allow trailing ellipsis in typing.TYPE_CHECKING (#10413)
  • Avoid TRIO115 if the argument is a variable (#10376)
  • [F811] Avoid removing shadowed imports that point to different symbols (#10387)
  • Fix F821 and F822 false positives in .pyi files (#10341)
  • Fix F821 false negatives in .py files when from __future__ import annotations is active (#10362)
  • Fix case where Indexer fails to identify continuation preceded by newline #10351 (#10354)
  • Sort hash maps in Settings display (#10370)
  • Track conditional deletions in the semantic model (#10415)
  • [C413] Wrap expressions in parentheses when negating (#10346)
  • [pycodestyle] Do not ignore lines before the first logical line in blank lines rules. (#10382)
  • [pycodestyle] Do not trigger E225 and E275 when the next token is a ')' (#10315)
  • [pylint] Avoid false-positive slot non-assignment for __dict__ (PLE0237) (#10348)
  • Gate f-string struct size test for Rustc < 1.76 (#10371)

Documentation

  • Use ruff.toml format in README (#10393)
  • [RUF008] Make it clearer that a mutable default in a dataclass is only valid if it is typed as a ClassVar (#10395)
  • [pylint] Extend docs and test in invalid-str-return-type (E307) (#10400)
  • Remove . from check and format commands (#10217)

Contributors

v0.3.2

09 Mar 01:24
a892fc7
Compare
Choose a tag to compare

Changes

Preview features

  • Improve single-with item formatting for Python 3.8 or older (#10276)

Rule changes

  • [pyupgrade] Allow fixes for f-string rule regardless of line length (UP032) (#10263)
  • [pycodestyle] Include actual conditions in E712 diagnostics (#10254)

Bug fixes

  • Fix trailing kwargs end of line comment after slash (#10297)
  • Fix unstable with items formatting (#10274)
  • Avoid repeating function calls in f-string conversions (#10265)
  • Fix E203 false positive for slices in format strings (#10280)
  • Fix incorrect Parameter range for *args and **kwargs (#10283)
  • Treat typing.Annotated subscripts as type definitions (#10285)

Contributors

v0.3.1

06 Mar 22:47
b9264a5
Compare
Choose a tag to compare

Changes

Preview features

  • [pycodestyle] Fix E301 not triggering on decorated methods. (#10117)
  • [pycodestyle] Respect isort settings in blank line rules (E3*) (#10096)
  • [pycodestyle] Make blank lines in typing stub files optional (E3*) (#10098)
  • [pylint] Implement singledispatch-method (E1519) (#10140)
  • [pylint] Implement useless-exception-statement (W0133) (#10176)

Rule changes

  • [flake8-debugger] Check for use of debugpy and ptvsd debug modules (#10177) (#10194)
  • [pyupgrade] Generate diagnostic for all valid f-string conversions regardless of line length (UP032) (#10238)
  • [pep8_naming] Add fixes for N804 and N805 (#10215)

CLI

  • Colorize the output of ruff format --diff (#10110)
  • Make --config and --isolated global flags (#10150)
  • Correctly expand tildes and environment variables in paths passed to --config (#10219)

Configuration

  • Accept a PEP 440 version specifier for required-version (#10216)
  • Implement isort's default-section setting (#10149)

Bug fixes

  • Remove trailing space from CapWords message (#10220)
  • Respect external codes in file-level exemptions (#10203)
  • [flake8-raise] Avoid false-positives for parens-on-raise with future.exception() (RSE102) (#10206)
  • [pylint] Add fix for unary expressions in PLC2801 (#9587)
  • [ruff] Fix RUF028 not allowing # fmt: skip on match cases (#10178)

Contributors

v0.3.0

29 Feb 15:30
b53118e
Compare
Choose a tag to compare

This release introduces the new Ruff formatter 2024.2 style and adds a new lint rule to
detect invalid formatter suppression comments.

Changes

Preview features

  • [flake8-bandit] Remove suspicious-lxml-import (S410) (#10154)
  • [pycodestyle] Allow os.environ modifications between imports (E402) (#10066)
  • [pycodestyle] Don't warn about a single whitespace character before a comma in a tuple (E203) (#10094)

Rule changes

  • [eradicate] Detect commented out case statements (ERA001) (#10055)
  • [eradicate] Detect single-line code for try:, except:, etc. (ERA001) (#10057)
  • [flake8-boolean-trap] Allow boolean positionals in __post_init__ (#10027)
  • [flake8-copyright] Allow © in copyright notices (#10065)
  • [isort]: Use one blank line after imports in typing stub files (#9971)
  • [pylint] New Rule dict-iter-missing-items (PLE1141) (#9845)
  • [pylint] Ignore sys.version and sys.platform (PLR1714) (#10054)
  • [pyupgrade] Detect literals with unary operators (UP018) (#10060)
  • [ruff] Expand rule for list(iterable).pop(0) idiom (RUF015) (#10148)

Formatter

This release introduces the Ruff 2024.2 style, stabilizing the following changes:

  • Prefer splitting the assignment's value over the target or type annotation (#8943)
  • Remove blank lines before class docstrings (#9154)
  • Wrap multiple context managers in with parentheses when targeting Python 3.9 or newer (#9222)
  • Add a blank line after nested classes with a dummy body (...) in typing stub files (#9155)
  • Reduce vertical spacing for classes and functions with a dummy (...) body (#7440, #9240)
  • Add a blank line after the module docstring (#8283)
  • Parenthesize long type hints in assignments (#9210)
  • Preserve indent for single multiline-string call-expressions (#9673)
  • Normalize hex escape and unicode escape sequences (#9280)
  • Format module docstrings (#9725)

CLI

  • Explicitly disallow extend as part of a --config flag (#10135)
  • Remove build from the default exclusion list (#10093)
  • Deprecate ruff <path>, ruff --explain, ruff --clean, and ruff --generate-shell-completion in favor of ruff check <path>, ruff rule, ruff clean, and ruff generate-shell-completion (#10169)
  • Remove the deprecated CLI option --format from ruff rule and ruff linter (#10170)

Bug fixes

  • [flake8-bugbear] Avoid adding default initializers to stubs (B006) (#10152)
  • [flake8-type-checking] Respect runtime-required decorators for function signatures (#10091)
  • [pycodestyle] Mark fixes overlapping with a multiline string as unsafe (W293) (#10049)
  • [pydocstyle] Trim whitespace when removing blank lines after section (D413) (#10162)
  • [pylint] Delete entire statement, including semicolons (PLR0203) (#10074)
  • [ruff] Avoid f-string false positives in gettext calls (RUF027) (#10118)
  • Fix ruff crashing on PowerPC systems because of too small page size (#10080)

Performance

  • Add cold attribute to less likely printer queue branches in the formatter (#10121)
  • Skip unnecessary string normalization in the formatter (#10116)

Documentation

  • Remove "Beta" Label from formatter documentation (#10144)
  • line-length option: fix link to pycodestyle.max-line-length (#10136)

Contributors