Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ruleset Suggestion: wemake-python-styleguide #3845

Open
kytta opened this issue Apr 1, 2023 · 15 comments
Open

Ruleset Suggestion: wemake-python-styleguide #3845

kytta opened this issue Apr 1, 2023 · 15 comments
Labels
needs-decision Awaiting a decision from a maintainer plugin Implementing a known but unsupported plugin

Comments

@kytta
Copy link

kytta commented Apr 1, 2023

wemake-python-styleguide is a Flake8-based style guide that depends on many other Flake8 plugins (AFAICT all implemented by Ruff), but it also ships lots of custom Flake8 rules. Is there an interest to implement those? As a bonus, the rule naming format is already Ruff-friendly (three letters, three numbers, sorted into categories)

UPDATE 2023-04-19: I have finally got to work on the list a bit more. Here are the rules that I think would make sense to implement in Ruff.

WPS1xx — Naming

Some of those are already covered by pep8-naming (N), but some are missing.

  • WPS100 — Forbid blacklisted (= not expressive enough) module names (like utils)
  • WPS101 — Forbid magic names (except some whitelisted ones). covered by N807
  • WPS102 — Forbid module names that do not match our pattern. covered by N999
  • WPS110 — Forbid blacklisted variable names. (similar to WPS100)
  • WPS111 — Forbid short variable or module names (1-2 characters).
  • WPS112 — Forbid private name pattern. (e.g. __collect_coverage())
    • potentially fixable (__collect_coverage()_collect_coverage())
  • WPS113 — Forbid using the same alias as the original name in imports. covered by PLC0414
  • WPS114 — Forbid names with underscored numbers pattern. (wrong: iso_123_456)
  • WPS115 — Require snake_case for naming class attributes. Similar to N806
    • potentially fixable (VARIABLE_NAMEvariable_name)
  • WPS116 — Forbid using more than one consecutive underscore in variable names.
    • potentially fixable (variable__namevariable_name)
  • WPS117 — Forbid naming variables self, cls, or mcs.
  • WPS118 — Forbid long variable or module names. (default: over 45 characters)
  • WPS119 — Forbid Unicode names. Only allow ASCII.
  • WPS120 — Forbid trailing _ for names that do not need it. (variables that don't actually shadow any builtins)
    • potentially fixable (variable_name_variable_name)
  • WPS121 — Forbid using variables that are marked as unused. Either don't use or rename
    • potentially fixable (_variable_namevariable_name)
  • WPS122 — Forbid explicit unused variables. Either use or don't define
    • potentially fixable (_ = my_function()my_function())
  • WPS123 — Forbid unused variables with multiple underscores.
    • potentially fixable (__, var_name = my_function()_, var_name = my_function())
  • WPS124 — Forbid variable or module names which could be difficult to read. (e.g. Memo0Output)
  • WPS125 — Forbid variable or module names which shadow builtin names. covered by flake8-builtins (A)
WPS2xx — Complexity

Unlike mccabe (C90), WPS also relies on other metrics, like Jones complexity and cognitive complexity (as proposed by G. Ann Campbell). Some violations are covered by Pylint (PLR).

  • WPS200 — Forbid modules with complex lines. (median Jones Complexity of module > 12)

  • WPS201 — Forbid modules with too many (12+) imports.

  • WPS202 — Forbid too many (7+) classes and functions in a single module.

  • WPS203 — Forbid modules with too many (50+) imported names.

  • WPS204 — Forbid overused expressions in a module, function or method. (expression referenced over 4 times in function / over 7 times in module)

  • WPS210 — Forbid too many (5+) local variables in the unit of code.

  • WPS211 — Forbid too many arguments for a function or method. covered by PLR0913

  • WPS212 — Forbid placing too many return statements in a function. covered by PLR0911

  • WPS213 — Forbid putting too many expressions in a single function. covered by PLR0915

  • WPS214 — Forbid too many methods (7) in a single class.

  • WPS215 — Restrict the maximum number of base classes (3).

  • WPS216 — Restrict the maximum number of decorators (5).

  • WPS217 — Forbid placing too many (5+) await expressions in a function.

  • WPS218 — Forbid placing too many (5+) assert statements into a function.

  • WPS219 — Forbid consecutive expressions with too deep (4+) access level. (e.g. self.attr.inner.wrapper.method.call() — 5 levels deep)

  • [WPS220] — Forbid nesting blocks too deep.

    • kinda covered by C901?
  • WPS221 — Forbid complex (Jones Complexity > 14) lines.

  • WPS222 — Forbid conditions with too many (4+) logical operators.

  • WPS223 — Forbid too many (3+) elif branches.

  • WPS224 — Forbid too many for statements within a comprehension.

  • WPS225 — Forbid too many (3+) except cases in a single try clause.

  • WPS226 — Forbid the overuse (3+ usages) of string literals.

  • WPS227 — Forbid returning or yielding tuples that are too long.

  • WPS228 — Forbid compare expressions that are too long (4+ items).

  • WPS229 — Forbid try blocks with bodies that are too long (over 1 line).

  • WPS230 — Forbid instances with too many (6+) public attributes.

  • WPS231 — Forbid functions with too much (12+) cognitive complexity.

  • WPS232 — Forbid modules with average cognitive complexity that is too high (8+).

  • WPS233 — Forbid call chains that are too long (3+).

  • WPS234 — Forbid overly complex annotations (3+ levels).

  • WPS235 — Forbid from ... import ... with too many (8+) imported names.

  • WPS236 — Forbid using too many (4+) variables to unpack a tuple.

  • WPS237 — Forbids f-strings that are too complex.

    A complex format string is defined as use of any formatted value that is not:

    • the value of a variable
    • the value of a collection through lookup with a variable, number, or string as the key
    • the return value of a procedure call without arguments
  • WPS238 — Forbids too many (3+) raise statements in a function.

WPS3xx — Consistency

A lot of those are very opinionated and some have to do with code style. Implement with caution :)

  • WPS300 — Forbid imports relative to the current folder. covered by TID252

  • WPS301 — Forbid imports like import os.path (dotted raw imports).

  • WPS302 — Forbid u string prefix. covered by UP025

  • WPS303 — Forbid underscores (_) in numbers.

  • WPS304 — Forbid partial floats like .05 or 23..

  • WPS305 — Forbid f-strings.

  • WPS306 — Forbid writing classes without base classes. Use object as implicit base class.

  • WPS307 — Forbid multiple if statements inside list comprehensions.

  • WPS308 — Forbid comparing between two literals. covered by PLR0133

  • WPS309 — Forbid comparisons where the argument doesn't come first. covered by SIM300

  • WPS310 — Forbid uppercase X, O, B, and E in numbers.

  • WPS311 — Forbid comparisons with multiple in checks.

  • WPS312 — Forbid comparisons of a variable to itself.

  • WPS313 — Enforce separation of parenthesis from keywords with spaces. covered by E275

  • WPS314 — Forbid using if statements that use invalid (= always true or always false) conditionals. (if True:)

  • WPS315 — Forbid extra object in parent classes list.

  • WPS316 — Forbid multiple assignment targets for context managers.

  • WPS317 — Forbid incorrect indentation for parameters. covered by E122

  • WPS318 — Forbid extra indentation. covered by E117

  • WPS319 — Forbid brackets in the wrong position.

  • WPS320 — Forbid multi-line function type annotations.

  • WPS321 — Forbid uppercase string modifiers.

  • WPS322 — Forbid triple quotes for singleline strings.

  • WPS323 — Forbid % formatting on strings.

  • WPS324 — Enforce consistent return statements. covered by RET502

  • WPS325 — Enforce consistent yield statements.

  • WPS326 — Forbid implicit string concatenation. covered by ISC001

  • WPS327 — Forbid meaningless continue in loops.

  • WPS328 — Forbid meaningless nodes. (like an immediately broken loop)

  • WPS329 — Forbid meaningless (= immediately reraised) except cases.

  • WPS330 — Forbid unnecessary operators in your code.

  • WPS331 — Forbid local variables that are only used in return statements.

  • WPS332 — Forbid walrus operator.

  • WPS333 — Forbid implicit complex comparison expressions.

  • WPS334 — Forbid reversed order complex comparison expressions.

    • potentially fixable: a > b > c -> c < b < a
  • WPS335 — Forbid wrong for loop iter targets. Use either variables or literal tuples, not literal sets/dicts/lists

  • WPS336 — Forbid explicit string concatanation in favour of .format() method.

  • WPS337 — Forbid multiline conditions.

  • WPS338 — Forbid incorrect order of methods inside a class.

    We follow “Newspaper order” where the most important things come first.

    • init_subclass
    • new
    • init
    • call
    • await
    • public and magic methods
    • protected methods
    • private methods (we discourage using them)
  • WPS339 — Forbid meaningless (traling, leading) zeros.

  • WPS340 — Forbid redundant + signs in the exponent.

  • WPS341 — Forbid lowercase letters in hex numbers.

  • WPS342 — Forbid \\ escape sequences inside regular strings. Use raw strings.

  • WPS343 — Forbid uppercase complex number suffix.

  • WPS344 — Forbid explicit division (or modulo) by zero.

  • WPS345 — Forbid meaningless math operations with 0 and 1.

  • WPS346 — Forbid double minus operations.

  • WPS347 — Forbid imports that may cause confusion outside of the module.

    Names that we forbid to import:

    • Common names like dumps and loads
    • Names starting with to_ and from_
    • Too short names like Q or F, but we are fine with _
  • WPS348 — Forbid starting lines with a dot.

  • WPS349 — Forbid redundant components in a subscript's slice.

  • WPS350 — Enforce using augmented assign (x += 1 instead of x = x + 1) pattern.

  • WPS351 — Forbid unnecessary literals in your code.

    • somewhat covered by C405, C406, C408
  • WPS352 — Forbid multiline loops.

  • WPS353 — Forbid yield from with several nodes. (see WPS335)

  • WPS354 — Forbid consecutive yield expressions. Use yield from

  • WPS355 — Forbid useless blank lines before and after brackets.

  • WPS356 — Forbid unnecessary iterable unpacking.

  • WPS357 — Forbid using \r (carriage return) in line breaks.

  • WPS358 — Forbid using float zeros: 0.0. Cast explicitly.

  • WPS359 — Forbids to unpack iterable objects to lists.

  • WPS360 — Forbid the use of raw strings when there is no backslash in the string.

  • WPS361 — Forbids inconsistent newlines in comprehensions. Either all or nothing.

  • WPS362 — Forbid assignment to a subscript slice.

WPS4xx — Best practices
  • WPS400 — Restrict various control (such as magic) comments.

    • forbids noqa without violation number and type: comments
    • noqa covered by PGH004
  • WPS401 — Forbid empty doc comments (#:).

  • WPS402 — Forbid too many (10+) # noqa comments.

  • WPS403 — Forbid too many (5+) # pragma: no cover comments.

  • WPS404 — Forbid complex defaults.

  • WPS405 — Forbid anything other than ast.Name to define loop variables.

  • WPS406 — Forbid anything other than ast.Name to define contexts.

  • WPS407 — Forbid mutable constants on a module level.

  • WPS408 — Forbid using the same logical conditions in one expression. (e.g. if x or x)

  • WPS409 — Forbid heterogeneous operators in one comparison. (e.g. if x > y == 5)

  • WPS410 — Forbid some module-level variables.

    We discourage using module variables like __author__, because code should not contain any metadata.

  • WPS411 — Forbid empty modules.

  • WPS412 — Forbid logic inside __init__ module.

  • WPS413 — Forbid __getattr__ and __dir__ module magic methods.

  • WPS414 — Forbid tuple unpacking with side-effects.

  • WPS415 — Forbid the same exception class in multiple except blocks.

  • WPS416 — Forbid yield keyword inside comprehensions.

  • WPS417 — Forbid duplicate items in hashes (set or dict literals).

    • potetially fixable for sets: remove duplicate items from set literal
  • WPS418 — Forbid exceptions inherited from BaseException.

    • potetially fixable: replace BaseException -> Exception
  • WPS419 — Forbid multiple returning paths with try / except case.

  • WPS420 — Forbid some python keywords (del, pass, global, nonlocal).

  • WPS421 — Forbid calling some built-in functions. (list)

  • WPS422 — Forbid old __future__ imports. covered by UP

  • WPS423 — Forbid NotImplemented exception.

  • WPS424 — Forbid BaseException exception.

  • WPS425 — Forbid booleans as non-keyword parameters. covered by PBT

  • WPS426 — Forbid lambda inside loops.

  • WPS427 — Forbid unreachable code.

  • WPS428 — Forbid statements that do nothing.

  • WPS429 — Forbid multiple assignments on the same line.

  • WPS430 — Forbid nested functions.

  • WPS431 — Forbid nested classes.

  • WPS432 — Forbid magic numbers.

    • covered by PLR2004 for comparisons, but not for arithmetic operations
  • WPS433 — Forbid imports nested in functions.

  • WPS434 — Forbid assigning a variable to itself.

  • WPS435 — Forbid multiplying lists.

  • WPS436 — Forbid importing protected modules.

  • WPS437 — Forbid protected attributes and methods.

  • WPS438 — Forbid raising StopIteration inside generators.

  • WPS439 — Forbid Unicode escape sequences in binary strings.

  • WPS440 — Forbid overlapping local and block variables.

  • WPS441 — Forbid control variables after the block body.

  • WPS442 — Forbid shadowing variables from outer scopes.

  • WPS443 — Forbid explicit unhashable types of asset items and dict keys.

  • WPS444 — Forbid explicit falsely-evaluated conditions with several keywords. (e.g. while False: ...

  • WPS445 — Forbid incorrectly named keywords in double-starred dicts. (e.g. f(**{'4': '2'}) is incorrect, as it would expand to f(4=2))

  • WPS446 — Forbid approximate constants (like pi, e, etc.).

  • WPS447 — Forbid using the alphabet as a string. Use constants from string

  • WPS448 — Forbid incorrect order of except. From most precise to less

  • WPS449 — Forbid float dictionary keys.

  • WPS450 — Forbid importing protected objects from modules.

  • WPS451 — Forbid positional only or / arguments.

  • WPS452 — Forbid break and continue in a finally block.

  • WPS453 — Forbid executing a file with shebang incorrectly set. covered by EXE

  • WPS454 — Forbid raising Exception or BaseException. covered by TRY002

  • WPS455 — Forbids using non-trivial expressions as a parameter for except.

  • WPS456 — Forbids using float("NaN") construct to generate NaN. Use math.nan

  • WPS457 — Forbids use of infinite while True: loops.

  • WPS458 — Forbids to import from already imported modules.

  • WPS459 — Forbids comparisons with float and complex.

  • WPS460 — Forbids to have single element destructuring.

  • WPS461 — Forbids to use specific inline ignore (= noqa) violations.

  • WPS462 — Frobids direct usage of multiline strings. Assign to a variable first

  • WPS463 — Forbids to have functions starting with get_ without returning a value.

  • WPS464 — Forbid empty comments.

  • WPS465 — Forbid comparisons between bitwise and boolean expressions.

  • WPS466 — Forbid using complex grammar for using decorators. (like @some.decorator['method'] + other)

  • WPS467 — Forbid using a bare raise keyword outside of except.

  • WPS468 — Forbid using a placeholder (_) with enumerate.

  • WPS469 — Forbid raising an exception from itself.

  • WPS470 — Forbid kwarg unpacking in class definition.

  • WPS471 — Forbid consecutive slices.

    • potentially fixable: merge slices [1:][:2] -> [1:3]
  • WPS472 — Forbid getting first element using unpacking.

  • WPS473 — Limit empty lines in functions or methods body.

WPS5xx — Refactoring
  • WPS500 — Forbid else without break in a loop. covered by PLW0120
  • WPS501 — Forbid finally in try block without except block.
  • WPS502 — Forbid simplifiable if conditions. (e.g. x = True if y else False) covered by SIM210
  • WPS503 — Forbid useless else cases in returning functions. covered by RET506
  • WPS504 — Forbid negated conditions together with else clause.
  • WPS505 — Forbid nested try blocks.
  • WPS506 — Forbid useless proxy lambda expressions.
  • WPS507 — Forbid unpythonic (not using __bool__) zero-length compare.
  • WPS508 — Forbid not with compare expressions.
  • WPS509 — Forbid nesting ternary expressions in certain places.
  • WPS510 — Forbid in with static containers except set.
  • WPS511 — Forbid multiple isinstance calls on the same variable. covered by PLR1701 and SIM101
  • WPS512 — Forbid multiple isinstance calls with single-item tuples.
  • WPS513 — Forbid implicit elif conditions. covered by SIM114
  • WPS514 — Forbid multiple equality comparisons with the same variable.
  • WPS515 — Forbid open() without a context manager. covered by SIM115
  • WPS516 — Forbid comparing types with type() function.
  • WPS517 — Forbid useless (constant) starred expressions.
  • WPS518 — Forbid implicit enumerate() calls.
  • WPS519 — Forbid implicit sum() calls.
  • WPS520 — Forbid comparing with explicit falsy constants.
  • WPS521 — Forbid comparing values with constants using is or is not.
  • WPS522 — Forbid implicit primitives in the form of lambda functions.
  • WPS523 — Forbid unpythonic variable swaps.
  • WPS524 — Forbid misrefactored self assignment.
  • WPS525 — Forbid comparisons where in is compared with single item container.
  • WPS526 — Forbid yield inside for loop instead of yield from. covered by UP028
  • WPS527 — Require tuples as arguments for certain functions.
  • WPS528 — Enforce .items() iterator.
  • WPS529 — Enforce .get() dict method.
  • WPS530 — Forbid implicit negative indexes.
  • WPS531 — Forbid if statements that simply return booleans in functions or methods. covered by SIM103
  • WPS532 — Forbid ast.Is in ast.Compare.ops when it's size is not zero.
WPS6xx — OOP
  • WPS600 — Forbid subclassing lowercase builtins.
  • WPS601 — Forbid shadowing class level attributes with instance level attributes.
  • WPS602 — Forbid @staticmethod decorator.
  • WPS603 — Forbid certain magic methods. See also WPS420
  • WPS604 — Forbid incorrect nodes (e.g. loops) inside class definitions.
  • WPS605 — Forbid methods without any arguments.
  • WPS606 — Forbid anything other than a class as a base class.
  • WPS607 — Forbid incorrect __slots__ definition. (e.g. not a tuple, with duplicates, ...)
  • WPS608 — Forbid super() with parameters or outside of methods.
    • partially covered by UP008
  • WPS609 — Forbid directly calling certain magic attributes and methods.
  • WPS610 — Forbid certain async magic methods.
  • WPS611 — Forbid yield inside of certain magic methods.
  • WPS612 — Forbid useless overwritten methods.
  • WPS613 — Forbid super() with incorrect method or property access.
  • WPS614 — Forbids descriptors in regular functions.
  • WPS615 — Forbids to use getters and setters in objects.
  • WPS616 — Calling super() in buggy context (= inside comprehensions).
@charliermarsh charliermarsh added the plugin Implementing a known but unsupported plugin label Apr 1, 2023
@vadim-su
Copy link
Contributor

It will be great to get the possibility to add wemake-python-styleguide rules 😅

@kytta
Copy link
Author

kytta commented Apr 19, 2023

Alright, I think I managed to move every WPS rule into the issue body. I tried my best to mark already implemented stuff as completed and also mark those rules that may potentially be fixable. I hope I didn't miss any!

@kytta kytta mentioned this issue Apr 19, 2023
6 tasks
@Day0Dreamer
Copy link

Given how @sobolevn is reluctant to give attention to the "wemake-python-styleguide", I feel also the strong need to have the ruleset be taken over to ruff.

@sobolevn
Copy link
Contributor

sobolevn commented May 3, 2023

What do you mean by "is reluctant to give attention"?

@Day0Dreamer
Copy link

Day0Dreamer commented May 3, 2023

@sobolevn apologies if I'm mistaken and for having this conversation here. I don't really know of a place to talk about this which would receive a response.

Please refer to wemake-services/wemake-python-styleguide#2514 for contents

On account of absence of your input in the thread, or significant releases, I am lead to think : The styleguide is an abandonware.

I gather you have been silent on threads about PR that intend to migrate from flake8 version 4.0 (released in 2021) to version 6.0 (released 2023) ? New flake8 is much snappier it looks like!

Meanwhile, I have spent 3 days marrying the Version 0.17.0
of Sep 27, 2022 of the wemake-python-styleguide. Ended up with

  • creating a .flake8 file, because pyproject.toml is an option only in more recent releases;
  • ignoring all the errors ruff has A, ARG, B, C, DTZ, E, EM, F, FBT, I, ICN, ISC, N, PLC, PLE, PLR, PLW, Q, RUF, S, T, TID, UP, YTT;
  • pip uninstalled following packages flake8-eradicate flake8-bandit flake8-bugbear flake8-commas flake8-comprehensions flake8-debugger flake8-docstrings flake8-isort mccabe isort pydocstyle darglint

In the end I'd be happy okay with quickchecking ruff + WPS via flake8.

It is already a shame, that we still need slow flake8 in order to run wemake-python-styleguide. The new cool --watch flag ruff has is also very useful.

@vadim-su
Copy link
Contributor

vadim-su commented May 5, 2023

image
🤯 240 points

@Corfucinas
Copy link

The only reason I don't migrate to ruff is that it's missing the rules from wemake-python-styleguide.

As soon as it is integrated, I'm in

@Pixel-Minions
Copy link

Same, having WPS would be amazing! I really love Ruff and its speed, but the WPS rules are the best, the quality of the code from my previous company that used them was really high.

@strmwalker
Copy link

@charliermarsh gentle ping
I suggest to introduce WPS to ruff with complexity violations (docs), because implementing all rules from WPS is an impossible task for a single person, and WPS2xx rules are the most useful ones in wemake-python-styleguide. I already implemented some of the rules, and if you think WPS is worth to be a part of ruff, I am willing to contribute the rest.

@simon-liebehenschel
Copy link

🤯 240 points

@suharnikov Yes, a list is long, but let's keep in mind that some amount of rules are not necessary to migrate because some of them are already completely or partially covered by the existing Ruff and non-Ruff rules + Mypy/Pyright.

Also, some rules are opinionated and forbid a valid Python code. For example:

  • WPS602 — Forbid @staticmethod decorator.
  • WPS332 Found walrus operator

The final TO-DO list will be much shorter.

I will try to do not miss any PR to try an unreleased Ruff version and report false-positives.

@sobolevn
Copy link
Contributor

@AIGeneratedUsername keep in mind, that all rules work as a complex. If you drop some of them (based on some subjective criteria), you will lose a lot of benefits.

@vadim-su
Copy link
Contributor

Fully agree with @sobolevn. It's a complex set of rules to make code more readable and robust.

@AIGeneratedUsername
About WPS602 and WPS332:

  • WPS602 - Based on the history context static methods should not exist in Python:sweat_smile:
  • WPS332 - Walrus operator has limited use cases and a detrimental effect on code readability. I know only one (ok, mb two) case when this operator can be helpful and I prefer to avoid it to maintain the overall consistency of code.

@apatrushev
Copy link

Related to #8022

@vadim-su
Copy link
Contributor

Hello guys, any updates?

@serjflint
Copy link

Hello guys, any updates?

Hello. Afaik it requires #1774. Better ask there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-decision Awaiting a decision from a maintainer plugin Implementing a known but unsupported plugin
Projects
None yet
Development

No branches or pull requests