版本发布 8
### Bugfixes - Fixes the false positive `WPS222` for nested conditions, #3630 - Fixes the false positive `WPS529` for dict subscripts in the `else` branch, #3501 ### New Contributors * @frankgoldfish made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3620 **Full Changelog**: https://github.com/wemake-services/wemake-python-styleguide/compare/1.6.1...1.6.2
### Main changes Due to PEP-695, it's now allowed to use `[]` in decorators only for `python3.12+`. ```python @MyClassDecorator[T, V] def some_function(): ... ``` ### Features - Adds `WPS243`: forbids complex `finally` bodies, #3458 - Adds `WPS478`: forbids using non strict slice operations, #1011 - Adds `WPS479`: forbids using multiline fstrings, #3405 - Adds `WPS480`: forbids using comments inside formatted string, #3404 ### Bugfixes - Removes unnecessary `WPS604` and `WPS614` rules from the `noqa.py`, #3420 - Fixes `WPS115` false-positive on `StrEnum`, `IntEnum`, `IntFlag` attributes, #3381 - Fixes `WPS432`, now it ignores magic numbers in `Literal`, #3397 - Fixes `WPS466` for generic type specifications `MyClassDecorator[T]`, #3417 - Fixes `WPS212` to ignore nested classes and functions when counting `return` statements, #3413 - Improves `WPS349` highlighting, #3437 ## New Contributors * @LordGvozd made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3362 * @NikitaSemenovAiforia made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3382 * @wjqsm made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3403 * @mkaraev made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3411 * @joscha made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3421 * @MIXgleb made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3423 * @dgtrv made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3431 * @alexeev-prog made their first contribution in https://github.com/wemake-services/wemake-python-styleguide/pull/3461 **Full Changelog**: https://github.com/wemake-services/wemake-python-styleguide/compare/1.1.0...1.2.0
### Command line utility This version introduces `wps` CLI tool. `wps explain <code>` command can be used to access WPS violation docs (same as on website) but without any internet access. Example output: <img width="788" alt="Снимок экрана 2025-03-25 в 13 33 04" src="https://github.com/user-attachments/assets/a4c9acb7-67b6-4db6-a2ac-2187c1b61b6c" /> ### Features - Adds `WPS476`: forbids to use `await` expressions in `for` loops, #1600 - Adds `WPS477`: forbids `TypeVarTuple` after a `TypeVar` with a default, #3265 ### Bugfixes - Fixes `WPS115` false-positive on `Enum` attributes, #3238 - Removes duplicated `WPS312`, #3239 - Fixes `WPS432`, now it shows literal num, #1402 - Fixes `WPS226`, now it points to the first string literal occurrence, #3267 - Fixes `WPS605` false-positive on `@staticmethod`, #3292 - Fixes `_SELF` name not to trigger `WPS117`, #3310 - Fixes `WPS221` being too strict with f-strings, #3350
### Ruff This release introduces the new main concept: `ruff` compatibility. Now `WPS` is the only `flake8` plugin that is installed. Other things are done by `ruff`. It is faster, it has autofixing, there are lots of rules. Basically, this way `WPS` just gain lots of new rule and plugins almost for free. It is now stricter than ever! `WPS` now officially supports **ALL** `ruff` existing rules. This means that there are no conflicts between two linters. To run `WPS` and `ruff` together, use: ```bash ruff format && ruff check && flake8 --select=WSP . ``` You can copy our configuration from [`pyproject.toml`](https://github.com/wemake-services/wemake-python-styleguide/blob/bca0a1452335619ee5898e2ab657ca6e4a741f5f/pyproject.toml#L103) (for `ruff`) and [`setup.cfg`](https://github.com/wemake-services/wemake-python-styleguide/blob/bca0a1452335619ee5898e2ab657ca6e4a741f5f/setup.cfg#L7) (for `flake8`). ### Black `WPS` can now also be used with `black` with **default** configuration. However, we recommend using `ruff format` instead. ### Speed `WPS` got a lot faster! Because: - We removed a lot of `flake8` plugins - We removed a lot of rules covered by `ruff` Running `0.19.2` (previous version) on https://github.com/dry-python/returns ```bash » time flake8 . flake8 . 20.63s user 2.47s system 469% cpu 4.919 total ``` The same on `1.0.0`: ``` » time flake8 . flake8 . 8.56s user 0.54s system 898% cpu 1.013 total ``` Which is **2.4x** times faster! ### Integrations We also significantly improved all the integrations! `WPS` can now be used as first-class `pre-commit` hook with: ```yaml repos: - repo: https://github.com/wemake-services/wemake-python-styleguide rev: 1.0.0 hooks: - id: wemake-python-styleguide ``` Our [GitHub Action](https://github.com/marketplace/actions/wemake-python-styleguide) also got a lot of new options and fixes. ### Removals - **Breaking**: Drops `python3.9` support - **Breaking**: Drops `nitpick` support - **Breaking**: Drops `flake8-commas`, `flake8-isort`, `flake8-debugger`, `flake8-string-format`, `flake8-quotes`, `flake8-comprehensions`, `flake8-bugbear`, `flake8-docstrings`, `flake8-eradicate`, `flake8-bandit`, `flake8-broken-line`, `flake8-rst-docstrings`, `pep8-naming` support, use `ruff format` and `ruff check` instead - **Breaking**: Drops `darglint` support, because it is unmaintained - **Breaking**: Removes `WPS113`, because is covered by `pylint` linter - **Breaking**: Removes `WPS119`, because is covered by `pylint` linter - **Breaking**: Removes `WPS125`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS302`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS304`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS305`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS306`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS309`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS310`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS313`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS315`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS316`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS317`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS318`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS319`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS320`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS323`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS326`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS329`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS331`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS333`, because is covered by `pylint` linter - **Breaking**: Removes `WPS337`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS340`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS341`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS343`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS348`, because it conflicts with `ruff` formatter - **Breaking**: Removes `WPS351`, because it is covered by `ruff` linter - **Breaking**: Removes `WPS352`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS355`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS360`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS361`, because it is covered by `ruff` formatter - **Breaking**: Removes `WPS415`, because is covered by `ruff` linter - **Breaking**: Removes `WPS417`, because is covered by `ruff` linter - **Breaking**: Removes `WPS419`, because is covered by `ruff` linter - **Breaking**: Removes `WPS423`, because is covered by `ruff` linter - **Breaking**: Removes `WPS424`, because is covered by `ruff` linter - **Breaking**: Removes `WPS425`, because is covered by `ruff` linter - **Breaking**: Removes `WPS428`, because is covered by `ruff` linter - **Breaking**: Removes `WPS433`, because is covered by `pylint` linter - **Breaking**: Removes `WPS434`, because is covered by `pylint` linter - **Breaking**: Removes `WPS436`, because is covered by `pylint` linter - **Breaking**: Removes `WPS437`, because is covered by `ruff` linter - **Breaking**: Removes `WPS440`, because it was buggy and is covered by `mypy`, #3209 - **Breaking**: Removes `WPS442`, because it was buggy and is covered by `mypy`, #3209 - **Breaking**: Removes `WPS450`, because is covered by `pylint` linter - **Breaking**: Removes `WPS452`, because is covered by `ruff` linter - **Breaking**: Removes `WPS454`, because is covered by `ruff` linter - **Breaking**: Removes `WPS456`, because is covered by `ruff` linter - **Breaking**: Removes `WPS465`, because `|` is now heavily used by typing - **Breaking**: Removes `WPS467`, because is covered by `pylint` linter - **Breaking**: Removes `WPS502`, because is covered by `ruff` linter - **Breaking**: Removes `WPS503`, because is covered by `ruff` linter - **Breaking**: Removes `WPS507`, because is covered by `pylint` linter - **Breaking**: Removes `WPS508`, because is covered by `ruff` linter - **Breaking**: Removes `WPS510`, because is covered by `pylint` linter - **Breaking**: Removes `WPS514`, because is covered by `pylint` linter - **Breaking**: Removes `WPS528`, because is covered by `pylint` linter - **Breaking**: Removes `WPS525`, because is covered by `ruff` linter - **Breaking**: Removes `WPS526`, because is covered by `ruff` linter - **Breaking**: Removes `WPS521`, because is covered by `ruff` linter - **Breaking**: Removes `WPS609`, because is covered by `pylint` linter - **Breaking**: Removes `--i-control-code` setting, if you want to disable some violations, just use `# noqa` or `--ignore` with code that you want to exclude, there's no need to create one more way of disabling some specific violations ### Features - Adds official `python3.13` support - Allows any compares in `assert` statements for `WPS520`, #3112 - Allows walrus operator (`:=`) in comprehesions, #3121 - Allows `pass` in `case` bodies, #2642 - Allows subclassing builtins in `WPS600`, when creating an `Enum`, #2506 - Allows using variables after blocks for `WPS441` in `assert` statements, #2543 - Does not count `self`, `cls`, and `mcs` as arguments for `WPS211` complexity check anymore, #2394 - Allows underscores (`_`) with exactly 3 digits after it in `WPS303`, #3120 - Allows class / instance attribute shadowing in `@dataclass`es for `WPS601`, #1926 - Allows any number of instance attributes on `@dataclass`es in `WPS230`, #2448 - Allows any number of function parameters in `@overload` definitions for `WPS211`, #1957 - Allows using multiline strings when placed on separate lines, #3056 - Allows using `hasattr` builtin function, #2228 - Disallows using `is not` and `not in` as negated conditions in `WPS504`, #2617 - Allows all branches in `if/elif/else` to be negated in `WPS504`, #2617 - Adds a new rule to forbid `lambda` assigns to special attributes, #1733 - Adds a new rule to check problematic function params, #1343 - Adds a new rule to detect duplicate conditions in `if`s and `elif`s, #2241 - Adds a new rule to detect duplicate `case` pattens in `match`, #3206 - Adds a new rule to find too many `match` subjects, #3201 - Adds a new rule to detect too many `case` statements, #3202 - Adds a new rule to find too complex `except` with too many exceptions - Adds a new rule to find too many `PEP695` type params - Adds a new rule to find useless ternary expressions, #1706 - Adds a new rule to forbid `raise SystemExit`, use `sys.exit` instead, #1786 - Adds a new rule to forbid extra syntax in `match ...` subjects, #3217 - Adds new `--allowed-module-metadata` and `--forbidden-module-metadata` configuration options for `WPS410`, #3060 - Now `--allowed-domain-names` also affect `WPS11` to allow custom short variable names, #2554 - Adds support to run `wemake-python-styleguide` as a `pre-commit` hook, #2588 - GitHub Action can now use `cwd:` parameter to specify where your configuration file is, #2474 - GitHub Action can now use `fail_workflow:` parameter to not fail the workflow even if the check did find any issues - GitHub Action can now use `filter_mode:` parameter to specify how ReviewDog will filter found violations, see https://github.com/reviewdog/reviewdog#filter-mode #2239 ### Bugfixes - Fixes `WPS217` to allow simple calls in `f` strings, #3150 - Fixes `WPS217` not to raise on empty `f` strings, because `ruff check` handles that now for us - Fixes `OverusedStringViolation` not to include `'...'` string - Removes `astor` package in favour of `ast.unparse` - Fixes `WPS210` to not count nested local variables in nested scopes #3108 - Fixes `IterableUnpackingViolation` with generic types and `TypeVarTuple` - Fixes `WPS469` detecting incorrect names of raised exceptions, #3109 - Fixes unnormalized paths in formatter output - Fixes `WPS221` to ignore PEP695's `TypeAlias` from line complexity checks - Fixes `WPS474` to only count import collisions in the same context, #2962 - Fixes `WPS612` to count defaults in function definitions, #2478 - Fixes several bugs in `WPS322` with multiline strings detection - Fixes several violations not been detected in `case:` statements - Fixes `WPS314` not detecting `match` statements - Fixes `match` + `case` does not increase cognitive complexity ### Misc - Integration with `ondivi` doc for legacy codebases - Fixes a documentation error for the Formatter (Showing statistic) section - Source code is now formatted with `ruff` - Removes deprecated `ast` nodes from code: `ast.Num`, `ast.Bytes`, `ast.Str`, `ast.NamedConstant`, etc
### Bugfixes - Fixes `WrongEmptyLinesCountViolation` crash on `Callable[..., ...]` #2899
This release fixes how `...` is used. For example, it is common to define function stubs / protocols like this: ```python def some_function(): ... ``` Now, `...` will be excluded from several rules. ### Bugfixes - Fixes `TooDeepNestingViolation` not to trigger on `...` in functions and classes - Fixes `StatementHasNoEffectViolation` not to trigger on `...` in functions and classes, when it is the only node
This minor version will be the last release with all the `flake8` plugins. In the future this project will be migrated to be used together with `ruff`. ### Features - Adds official `python3.12` support - **Breaking**: drops `python3.8` support - **Breaking**: Reconsider `object` required base class exception: since `class Klass[_Type]` must not contain `object`, this rule is change to be the opposite: `object` explicit base class must not be used. You can use `ruff` to change all `object`-based types to the new style: `ruff check --select=UP004 --fix .` https://docs.astral.sh/ruff/rules/useless-object-inheritance/ - **Breaking**: allow positional-only parameters, since it is required by `mypy` when using `Concatenate` - Adds support for naming rules for PEP695 type params - Due to how `f`-string are parsed in `python3.12` several token-based violations are not reported anymore for them: `WrongMultilineStringViolation`, `ImplicitRawStringViolation`, `WrongUnicodeEscapeViolation`, `RawStringNotNeededViolation` - `wemake` output formatter now respects `NO_COLOR=1` option to disable text highlighting. See https://no-color.org - Adds `ImportObjectCollisionViolation` to detect the same objects imported under different aliases - Adds `reveal_locals` to the list of forbidden functions - Updates `flake8` to `7.x` ### Bugfixes - Fixes `ForbiddenInlineIgnoreViolation` config parsing. #2590 - Fixes `WrongEmptyLinesCountViolation` for func definitions with ellipsis. #2847 - Fixes `WrongEmptyLinesCountViolation` for multiline implicit string concatination. #2787 - Fixes `ObjectInBaseClassesListViolation`, `UnpythonicGetterSetterViolation`, `ImplicitInConditionViolation`, `RedundantSubscriptViolation`, `TooLongCompareViolation` to include better error details - Fixes `TooDeepNestingViolation` for `TryStar` and `Match` statements - Fixes `TooLongTryBodyViolation` and `TooManyExceptCasesViolation` to work for `TryStar` statements as well - Fixes `UselessNodeViolation` to work with `TryStar` - Fixes `DuplicateExceptionViolation` to work with `TryStar` - Fixes `TryExceptMultipleReturnPathViolation` to work with `TryStar` - Fixes `IncorrectExceptOrderViolation` to work with `TryStar` - Fixes that `MatchStar` was not checked in pattern matching name assignments - Fixes pattern matching support in `BlockAndLocalOverlapViolation` and `OuterScopeShadowingViolation` ### Misc - Updates multiple`flake8-*` dependencies - Fixes multiple typos in docs
### Features - **Breaking**: drops `python3.7` support, because it has almost reached its EOL - Adds `python3.11` support - Bump `flake8` to version `5.x` - Bump `flake8-*` dependencies to newer versions - Added `ChainedIsViolation` #2443 - Added `BuggySuperContextViolation` #2310 ### Bugfixes - Make `generic_visit()` check script properly handle `with` statements. - Allow calling magic methods with the same name as the enclosing method #2381 - Fix WrongEmptyLinesCountViolation false positive #2531 - Fix OpenWithoutContextManagerViolation false positive #2577 ### Misc - Replaced `flakehell` mentions to `flakeheaven` #2409