diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 0558ab5cca1ee..4aae32aa031eb 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -1,5 +1,56 @@ # Breaking Changes +## 0.3.0 + +### Ruff 2024.2 style + +The formatter now formats code according to the Ruff 2024.2 style guide. Read the [changelog](./CHANGELOG.md#030) for a detailed list of stabilized style changes. + +### `isort`: Use one blank line after imports in typing stub files ([#9971](https://github.com/astral-sh/ruff/pull/9971)) + +Previously, Ruff used one or two blank lines (or the number configured by `isort.lines-after-imports`) after imports in typing stub files (`.pyi` files). +The [typing style guide for stubs](https://typing.readthedocs.io/en/latest/source/stubs.html#style-guide) recommends using at most 1 blank line for grouping. +As of this release, `isort` now always uses one blank line after imports in stub files, the same as the formatter. + +### `build` is no longer excluded by default ([#10093](https://github.com/astral-sh/ruff/pull/10093)) + +Ruff maintains a list of directories and files that are excluded by default. This list now consists of the following patterns: + +- `.bzr` +- `.direnv` +- `.eggs` +- `.git` +- `.git-rewrite` +- `.hg` +- `.ipynb_checkpoints` +- `.mypy_cache` +- `.nox` +- `.pants.d` +- `.pyenv` +- `.pytest_cache` +- `.pytype` +- `.ruff_cache` +- `.svn` +- `.tox` +- `.venv` +- `.vscode` +- `__pypackages__` +- `_build` +- `buck-out` +- `dist` +- `node_modules` +- `site-packages` +- `venv` + +Previously, the `build` directory was included in this list. However, the `build` directory tends to be a not-unpopular directory +name, and excluding it by default caused confusion. Ruff now no longer excludes `build` except if it is excluded by a `.gitignore` file +or because it is listed in `extend-exclude`. + +### `--format` is no longer a valid `rule` or `linter` command option + +Previously, `ruff rule` and `ruff linter` accepted the `--format ` option as an alias for `--output-format`. Ruff no longer +supports this alias. Please use `ruff rule --output-format ` and `ruff linter --output-format ` instead. + ## 0.1.9 ### `site-packages` is now excluded by default ([#5513](https://github.com/astral-sh/ruff/pull/5513)) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7846a900aab2c..a22b673ac90c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,70 @@ # Changelog +## 0.3.0 + +This release introduces the new Ruff formatter 2024.2 style and adds a new lint rule to +detect invalid formatter suppression comments. + +### Preview features + +- \[`flake8-bandit`\] Remove suspicious-lxml-import (`S410`) ([#10154](https://github.com/astral-sh/ruff/pull/10154)) +- \[`pycodestyle`\] Allow `os.environ` modifications between imports (`E402`) ([#10066](https://github.com/astral-sh/ruff/pull/10066)) +- \[`pycodestyle`\] Don't warn about a single whitespace character before a comma in a tuple (`E203`) ([#10094](https://github.com/astral-sh/ruff/pull/10094)) + +### Rule changes + +- \[`eradicate`\] Detect commented out `case` statements (`ERA001`) ([#10055](https://github.com/astral-sh/ruff/pull/10055)) +- \[`eradicate`\] Detect single-line code for `try:`, `except:`, etc. (`ERA001`) ([#10057](https://github.com/astral-sh/ruff/pull/10057)) +- \[`flake8-boolean-trap`\] Allow boolean positionals in `__post_init__` ([#10027](https://github.com/astral-sh/ruff/pull/10027)) +- \[`flake8-copyright`\] Allow © in copyright notices ([#10065](https://github.com/astral-sh/ruff/pull/10065)) +- \[`isort`\]: Use one blank line after imports in typing stub files ([#9971](https://github.com/astral-sh/ruff/pull/9971)) +- \[`pylint`\] New Rule `dict-iter-missing-items` (`PLE1141`) ([#9845](https://github.com/astral-sh/ruff/pull/9845)) +- \[`pylint`\] Ignore `sys.version` and `sys.platform` (`PLR1714`) ([#10054](https://github.com/astral-sh/ruff/pull/10054)) +- \[`pyupgrade`\] Detect literals with unary operators (`UP018`) ([#10060](https://github.com/astral-sh/ruff/pull/10060)) +- \[`ruff`\] Expand rule for `list(iterable).pop(0)` idiom (`RUF015`) ([#10148](https://github.com/astral-sh/ruff/pull/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](https://github.com/astral-sh/ruff/pull/8943)) +- Remove blank lines before class docstrings ([#9154](https://github.com/astral-sh/ruff/pull/9154)) +- Wrap multiple context managers in `with` parentheses when targeting Python 3.9 or newer ([#9222](https://github.com/astral-sh/ruff/pull/9222)) +- Add a blank line after nested classes with a dummy body (`...`) in typing stub files ([#9155](https://github.com/astral-sh/ruff/pull/9155)) +- Reduce vertical spacing for classes and functions with a dummy (`...`) body ([#7440](https://github.com/astral-sh/ruff/issues/7440), [#9240](https://github.com/astral-sh/ruff/pull/9240)) +- Add a blank line after the module docstring ([#8283](https://github.com/astral-sh/ruff/pull/8283)) +- Parenthesize long type hints in assignments ([#9210](https://github.com/astral-sh/ruff/pull/9210)) +- Preserve indent for single multiline-string call-expressions ([#9673](https://github.com/astral-sh/ruff/pull/9637)) +- Normalize hex escape and unicode escape sequences ([#9280](https://github.com/astral-sh/ruff/pull/9280)) +- Format module docstrings ([#9725](https://github.com/astral-sh/ruff/pull/9725)) + +### CLI + +- Explicitly disallow `extend` as part of a `--config` flag ([#10135](https://github.com/astral-sh/ruff/pull/10135)) +- Remove `build` from the default exclusion list ([#10093](https://github.com/astral-sh/ruff/pull/10093)) +- Deprecate `ruff `, `ruff --explain`, `ruff --clean`, and `ruff --generate-shell-completion` in favor of `ruff check `, `ruff rule`, `ruff clean`, and `ruff generate-shell-completion` ([#10169](https://github.com/astral-sh/ruff/pull/10169)) +- Remove the deprecated CLI option `--format` from `ruff rule` and `ruff linter` ([#10170](https://github.com/astral-sh/ruff/pull/10170)) + +### Bug fixes + +- \[`flake8-bugbear`\] Avoid adding default initializers to stubs (`B006`) ([#10152](https://github.com/astral-sh/ruff/pull/10152)) +- \[`flake8-type-checking`\] Respect runtime-required decorators for function signatures ([#10091](https://github.com/astral-sh/ruff/pull/10091)) +- \[`pycodestyle`\] Mark fixes overlapping with a multiline string as unsafe (`W293`) ([#10049](https://github.com/astral-sh/ruff/pull/10049)) +- \[`pydocstyle`\] Trim whitespace when removing blank lines after section (`D413`) ([#10162](https://github.com/astral-sh/ruff/pull/10162)) +- \[`pylint`\] Delete entire statement, including semicolons (`PLR0203`) ([#10074](https://github.com/astral-sh/ruff/pull/10074)) +- \[`ruff`\] Avoid f-string false positives in `gettext` calls (`RUF027`) ([#10118](https://github.com/astral-sh/ruff/pull/10118)) +- Fix `ruff` crashing on PowerPC systems because of too small page size ([#10080](https://github.com/astral-sh/ruff/pull/10080)) + +### Performance + +- Add cold attribute to less likely printer queue branches in the formatter ([#10121](https://github.com/astral-sh/ruff/pull/10121)) +- Skip unnecessary string normalization in the formatter ([#10116](https://github.com/astral-sh/ruff/pull/10116)) + +### Documentation + +- Remove "Beta" Label from formatter documentation ([#10144](https://github.com/astral-sh/ruff/pull/10144)) +- `line-length` option: fix link to `pycodestyle.max-line-length` ([#10136](https://github.com/astral-sh/ruff/pull/10136)) + ## 0.2.2 Highlights include: diff --git a/Cargo.lock b/Cargo.lock index 4fba4c76c532f..2db6a93508f71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1950,7 +1950,7 @@ dependencies = [ [[package]] name = "ruff" -version = "0.2.2" +version = "0.3.0" dependencies = [ "anyhow", "argfile", @@ -2111,7 +2111,7 @@ dependencies = [ [[package]] name = "ruff_linter" -version = "0.2.2" +version = "0.3.0" dependencies = [ "aho-corasick", "annotate-snippets 0.9.2", @@ -2365,7 +2365,7 @@ dependencies = [ [[package]] name = "ruff_shrinking" -version = "0.2.2" +version = "0.3.0" dependencies = [ "anyhow", "clap", diff --git a/README.md b/README.md index a903e927ea1b2..66ea87ae3dde0 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.2.2 + rev: v0.3.0 hooks: # Run the linter. - id: ruff diff --git a/crates/ruff/Cargo.toml b/crates/ruff/Cargo.toml index 13dd5e31d9d56..43f31ff524c0f 100644 --- a/crates/ruff/Cargo.toml +++ b/crates/ruff/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff" -version = "0.2.2" +version = "0.3.0" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_linter/Cargo.toml b/crates/ruff_linter/Cargo.toml index 6800145786fdd..53cd3a79b8ad9 100644 --- a/crates/ruff_linter/Cargo.toml +++ b/crates/ruff_linter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_linter" -version = "0.2.2" +version = "0.3.0" publish = false authors = { workspace = true } edition = { workspace = true } diff --git a/crates/ruff_python_formatter/README.md b/crates/ruff_python_formatter/README.md index 9a11c23cee9b7..7eab0dc590727 100644 --- a/crates/ruff_python_formatter/README.md +++ b/crates/ruff_python_formatter/README.md @@ -208,37 +208,167 @@ on both `first()` and `second()`: ] ``` -#### Line width vs. line length +#### Parenthesizing long nested-expressions + +Black 24 and newer parenthesizes long conditional expressions and type annotations in function parameters: + +```python +# Black +[ + "____________________________", + "foo", + "bar", + ( + "baz" + if some_really_looooooooong_variable + else "some other looooooooooooooong value" + ), +] + +def foo( + i: int, + x: ( + Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong + ), + *, + s: str, +) -> None: + pass + +# Ruff +[ + "____________________________", + "foo", + "bar", + "baz" if some_really_looooooooong_variable else "some other looooooooooooooong value" +] -Ruff uses the Unicode width of a line to determine if a line fits. Black's stable style uses -character width, while Black's preview style uses Unicode width for strings ([#3445](https://github.com/psf/black/pull/3445)), -and character width for all other tokens. Ruff's behavior is closer to Black's preview style than -Black's stable style, although Ruff _also_ uses Unicode width for identifiers and comments. +def foo( + i: int, + x: Loooooooooooooooooooooooong + | Looooooooooooooooong + | Looooooooooooooooooooong + | Looooooong, + *, + s: str, +) -> None: + pass +``` + +We agree that Ruff's formatting (that matches Black's 23) is hard to read and needs improvement. But we aren't convinced that parenthesizing long nested expressions is the best solution, especially when considering expression formatting holistically. That's why we want to defer the decision until we've explored alternative nested expression formatting styles. See [psf/Black#4123](https://github.com/psf/black/issues/4123) for an in-depth explanation of our concerns and an outline of possible alternatives. -#### Walruses in slice expressions +#### Call expressions with a single multiline string argument -Black avoids inserting space around `:=` operators within slices. For example, the following adheres -to Black stable style: +Unlike Black, Ruff preserves the indentation of a single multiline-string argument in a call expression: ```python # Input -x[y:=1] +call( + """" + A multiline + string + """ +) + +dedent("""" + A multiline + string +""") # Black -x[y:=1] +call( + """" + A multiline + string + """ +) + +dedent( + """" + A multiline + string +""" +) + + +# Ruff +call( + """" + A multiline + string + """ +) + +dedent("""" + A multiline + string +""") ``` -Ruff will instead add space around the `:=` operator: +Black intended to ship a similar style change as part of the 2024 style that always removes the indent. It turned out that this change was too disruptive to justify the cases where it improved formatting. Ruff introduced the new heuristic of preserving the indent. We believe it's a good compromise that improves formatting but minimizes disruption for users. + +#### Blank lines at the start of a block + +Black 24 and newer allows blank lines at the start of a block, where Ruff always removes them: + +```python +# Black +if x: + + a = 123 + +# Ruff +if x: + a = 123 +``` + +Currently, we are concerned that allowing blank lines at the start of a block leads [to unintentional blank lines when refactoring or moving code](https://github.com/astral-sh/ruff/issues/8893#issuecomment-1867259744). However, we will consider adopting Black's formatting at a later point with an improved heuristic. The style change is tracked in [#9745](https://github.com/astral-sh/ruff/issues/9745). + +#### Hex codes and Unicode sequences + +Ruff normalizes hex codes and Unicode sequences in strings ([#9280](https://github.com/astral-sh/ruff/pull/9280)). Black intended to ship this change as part of the 2024 style but accidentally didn't. + +```python +# Black +a = "\x1B" +b = "\u200B" +c = "\U0001F977" +d = "\N{CYRILLIC small LETTER BYELORUSSIAN-UKRAINIAN I}" + +# Ruff +a = "\x1b" +b = "\u200b" +c = "\U0001f977" +d = "\N{CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I}" +``` + +#### Module docstrings + +Ruff formats module docstrings similar to class or function docstrings, whereas Black does not. ```python # Input -x[y:=1] +"""Module docstring + +""" + +# Black +"""Module docstring + +""" # Ruff -x[y := 1] +"""Module docstring""" + ``` -This will likely be incorporated into Black's preview style ([#3823](https://github.com/psf/black/pull/3823)). +#### Line width vs. line length + +Ruff uses the Unicode width of a line to determine if a line fits. Black uses Unicode width for strings, +and character width for all other tokens. Ruff _also_ uses Unicode width for identifiers and comments. #### `global` and `nonlocal` names are broken across multiple lines by continuations @@ -606,44 +736,3 @@ df.drop(columns=["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]).drop_duplicates(a).rename } ).to_csv(path / "aaaaaa.csv", index=False).other(a) ``` - -#### Expressions with (non-pragma) trailing comments are split more often ([#7823](https://github.com/astral-sh/ruff/issues/7823)) - -Both Ruff and Black will break the following expression over multiple lines, since it then allows -the expression to fit within the configured line width: - -```python -# Input -some_long_variable_name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - -# Black -some_long_variable_name = ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -) - -# Ruff -some_long_variable_name = ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -) -``` - -However, if the expression ends in a trailing comment, Black will avoid wrapping the expression -in some cases, while Ruff will wrap as long as it allows the expanded lines to fit within the line -length limit: - -```python -# Input -some_long_variable_name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # a trailing comment - -# Black -some_long_variable_name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" # a trailing comment - -# Ruff -some_long_variable_name = ( - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -) # a trailing comment -``` - -Doing so leads to fewer overlong lines while retaining the comment's intent. As pragma comments -(like `# noqa` and `# type: ignore`) are ignored when computing line width, this behavior only -applies to non-pragma comments. diff --git a/crates/ruff_shrinking/Cargo.toml b/crates/ruff_shrinking/Cargo.toml index f760d4f14f22f..ad6bf18edc5d2 100644 --- a/crates/ruff_shrinking/Cargo.toml +++ b/crates/ruff_shrinking/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ruff_shrinking" -version = "0.2.2" +version = "0.3.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/docs/integrations.md b/docs/integrations.md index dfe11f4ccbf51..382621b3ebdb0 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -14,7 +14,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.2.2 + rev: v0.3.0 hooks: # Run the linter. - id: ruff @@ -27,7 +27,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook: ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.2.2 + rev: v0.3.0 hooks: # Run the linter. - id: ruff @@ -41,7 +41,7 @@ To run the hooks over Jupyter Notebooks too, add `jupyter` to the list of allowe ```yaml - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.2.2 + rev: v0.3.0 hooks: # Run the linter. - id: ruff diff --git a/docs/versioning.md b/docs/versioning.md index afd76c947c259..5d5414885d929 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -9,30 +9,38 @@ Ruff uses a custom versioning scheme that uses the **minor** version number for - A deprecated option or feature is removed - Configuration changes in a backwards incompatible way - This _may_ occur in minor version changes until `1.0.0`, however it should generally be avoided. -- A rule is promoted to stable - Support for a new file type is promoted to stable - Support for an end-of-life Python version is dropped -- The behavior of a stable rule is changed - - The scope of a stable rule is significantly increased - - The intent of the rule changes - - Does not include bug fixes that follow the original intent of the rule -- Stable rules are added to the default set -- Stable rules are removed from the default set -- A safe fix for a rule is promoted to stable +- Linter: + - A rule is promoted to stable + - The behavior of a stable rule is changed + - The scope of a stable rule is significantly increased + - The intent of the rule changes + - Does not include bug fixes that follow the original intent of the rule + - Stable rules are added to the default set + - Stable rules are removed from the default set + - A safe fix for a rule is promoted to stable +- Formatter: + - The stable style changed **Patch** version increases will occur when: - Bugs are fixed, _including behavior changes that fix bugs_ -- An unsafe fix for a rule is added -- A safe fix for a rule is added in preview -- The scope of a rule is increased in preview -- A fix’s applicability is demoted -- A new configuration option is added -- A rule is added in preview -- The behavior of a preview rule is changed +- A new configuration option is added in a backwards compatible way (no formatting changes or new lint errors) - Support for a new Python version is added - Support for a new file type is added in preview - An option or feature is deprecated +- Linter: + - An unsafe fix for a rule is added + - A safe fix for a rule is added in preview + - The scope of a rule is increased in preview + - A fix’s applicability is demoted + - A rule is added in preview + - The behavior of a preview rule is changed +- Formatter: + - The stable style changed to prevent invalid syntax, changes to the program's semantics, or removal of comments + - The preview style changed + ## Preview mode diff --git a/pyproject.toml b/pyproject.toml index 86597f5e1b01a..67c64a53eb153 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "ruff" -version = "0.2.2" +version = "0.3.0" description = "An extremely fast Python linter and code formatter, written in Rust." authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }] readme = "README.md" diff --git a/scripts/benchmarks/pyproject.toml b/scripts/benchmarks/pyproject.toml index 45ec7fb3ccbcb..146bbcd7b0ad2 100644 --- a/scripts/benchmarks/pyproject.toml +++ b/scripts/benchmarks/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "scripts" -version = "0.2.2" +version = "0.3.0" description = "" authors = ["Charles Marsh "]