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
Implement Pylint #970
Comments
|
Need to figure out what the right "check code" approach is here. We could just start to put these under |
|
I vote for |
|
I'll work on |
|
I would suggest |
|
Would absolutely love to see this happen. I know flake8 intentionally decided not to implement e.g. I expect you've already considered this, and really hope this won't stop ruff from implementing it, but just wanted to raise it. |
|
@relsunkaev |
|
@MartinBernstorff - Definitely. The multi-file stuff will come, just not as quickly. |
|
Not sure if it should be separate issue, but looking at missing-function-docstring rule (C0116), pylint's version of it is different. It only requires that a function has docstring some in class hierarchy and does not require over-ridden methods to have a docstring. As an example, class Foo:
def validate(self):
"""Doc."""
...
class Bar(Foo):
def validate(self):
...gives no errors in pylint even though second validate is missing docstring being pylint allows inheriting one. This is very useful when implementing interface and the docstring would really be same for all things that subclass. |
|
I'd like to get |
|
Relevant source for defining a |
|
A while ago I set out to find all the pylint codes make redundant by type checking. Unfortunately that code got lost to the sands of time. You might consider skipping those as type checking tools are very sophisticated, if you can do the effort of compiling that list |
|
I've also thought very long and hard about the fact that pylint appears very sophisticated when it comes to types because it builds on Ideally ruff (or any modern linter) is type-aware to be as helpful as possible, but that requires either:
|
|
For what it's worth, the type awareness of pylint is the killer feature that keeps us using it in our project despite how painfully slow it is. Our first-party code is almost fully typed, and mypy is generally good at catching typing issues. We've found multiple instances where pylint caught an issue that mypy missed however - usually in third-party code with missing or incomplete type definitions, but occasionally also in our own code when mypy doesn't notice (eg due to the presence of |
|
Out of curiosity, have you tried pyright? It claims to have inference support for codebases that aren't fully typed. |
|
Mypy has a check_untyped_defs which sounds equivalent, and we use that. We currently rely on mypy's no_strict_optional which pyright has no equivalent to, so pyright is not currently usable on our codebase. |
This PR adds [Pylint `R2004`](https://pylint.pycqa.org/en/latest/user_guide/messages/refactor/magic-value-comparison.html#magic-value-comparison-r2004) Feel free to suggest changes and additions, I have tried to maintain parity with the Pylint implementation [`magic_value.py`](https://github.com/PyCQA/pylint/blob/main/pylint/extensions/magic_value.py) See #970
|
Yeah, I need to do a pass over this issue to make it more useful / actionable based on @antonagestam's excellent analysis. |
|
@charliermarsh while pylint and mypy lints may have significant overlap, do note that mypy can only effectively catch these problems if the given code is properly type hinted. pylint however works with zero type hints. Using both mypy and ruff for example, can probably cover the vast majority of pylint issues, but that would only work for users that have fully type checked code. |
|
Mypy does infer types when the code isn’t type annotated, although not to the extent where it would output warnings like Pylint does without them. I think that problem can be alleviated by running Mypy in strict mode, and probably disallowing dynamic typing. |
|
@Igetin The problem here is that any variables coming from function parameters will never be inferred or checked, for example. all mypy will say is that "the type is not known". mypy without type hints is really not that useful. |
|
Rules
are all implemented as |
…string-slots` (`PLC0205`) (#5399) ## Summary Implement Pylint rule `single-string-used-for-slots` (`C0205`) as `single-string-slots` (`PLC0205`). This rule checks for single strings being assigned to `__slots__`. For example ```python class Foo: __slots__: str = "bar" def __init__(self, bar: str) -> None: self.bar = bar ``` should be ```python class Foo: __slots__: tuple[str, ...] = ("bar",) def __init__(self, bar: str) -> None: self.bar = bar ``` Related to #970. Includes documentation. ## Test Plan `cargo test`
## Summary Completes the documentation for the `flake8-logging-format` rules. Related to #2646. I included both the `flake8-logging-format` recommendation to use the `extra` keyword and the Pylint recommendation to pass format values as parameters so that formatting is done lazily, as #970 suggests the Pylint logging rules are covered by this ruleset. Using lazy formatting via parameters is probably more common than avoiding formatting entirely in favour of the `extra` argument, regardless. ## Test Plan `python scripts/check_docs_formatted.py`
## Summary Implement Pylint `typevar-name-mismatch` (`C0132`) as `type-param-name-mismatch` (`PLC0132`). Includes documentation. Related to #970. The Pylint implementation checks only `TypeVar`, but this PR checks `TypeVarTuple`, `ParamSpec`, and `NewType` as well. This seems to better represent the Pylint rule's [intended behaviour](pylint-dev/pylint#5224). Full disclosure: I am not a fan of the translated name and think it should probably be different. ## Test Plan `cargo test`
## Summary Implement Pylint `typevar-double-variance` (`C0131`) as `type-bivariance` (`PLC0131`). Includes documentation. Related to #970. Renamed the rule to be more clear (it's not immediately obvious what 'double' means, IMO). The Pylint implementation checks only `TypeVar`, but this PR checks `ParamSpec` as well. ## Test Plan Added tests. `cargo test`
Based on <astral-sh/ruff#970> there are still some missing pylint rules so it doesn't seem like we're ready to get rid of pylint yet, but having ruff check them first will help fail faster and prepare us for the eventual day we can drop it entirely.
Based on <astral-sh/ruff#970> there are still some missing pylint rules so it doesn't seem like we're ready to get rid of pylint yet, but having ruff check them first will help fail faster and prepare us for the eventual day we can drop it entirely.
Based on <astral-sh/ruff#970> there are still some missing pylint rules so it doesn't seem like we're ready to get rid of pylint yet, but having ruff check them first will help fail faster and prepare us for the eventual day we can drop it entirely.
…`) (#5651) ## Summary Implement Pylint `typevar-name-incorrect-variance` (`C0105`) as `type-name-incorrect-variance` (`PLC0105`). Includes documentation. Related to #970. The Pylint implementation checks only `TypeVar`, but this PR checks `ParamSpec` as well. ## Test Plan Added test fixture. `cargo test`
## Summary Implement Pylint rule [`consider-using-in` (`R1714`)](https://pylint.pycqa.org/en/latest/user_guide/messages/refactor/consider-using-in.html) as `repeated-equality-comparison-target` (`PLR1714`). This rule checks for expressions that can be re-written as a membership test for better readability and performance. For example, ```python foo == "bar" or foo == "baz" or foo == "qux" ``` should be rewritten as ```python foo in {"bar", "baz", "qux"} ``` Related to #970. Includes documentation. ### Implementation quirks The implementation does not work with Yoda conditions (e.g., `"a" == foo` instead of `foo == "a"`). The Pylint version does. I couldn't find a way of supporting Yoda-style conditions without it being inefficient, so didn't (I don't think people write Yoda conditions any way). ## Test Plan Added fixture. `cargo test`
|
|
## Summary Implement Pylint rule [`consider-using-in` (`R1714`)](https://pylint.pycqa.org/en/latest/user_guide/messages/refactor/consider-using-in.html) as `repeated-equality-comparison-target` (`PLR1714`). This rule checks for expressions that can be re-written as a membership test for better readability and performance. For example, ```python foo == "bar" or foo == "baz" or foo == "qux" ``` should be rewritten as ```python foo in {"bar", "baz", "qux"} ``` Related to #970. Includes documentation. ### Implementation quirks The implementation does not work with Yoda conditions (e.g., `"a" == foo` instead of `foo == "a"`). The Pylint version does. I couldn't find a way of supporting Yoda-style conditions without it being inefficient, so didn't (I don't think people write Yoda conditions any way). ## Test Plan Added fixture. `cargo test`
Error
abstract-class-instantiated/E0110access-member-before-definition/E0203assigning-non-slot/E0237assignment-from-no-return/E1111assignment-from-none/E1128await-outside-async/E1142(PLE1142)bad-configuration-section/E0014bad-except-order/E0701bad-exception-cause/E0705bad-format-character/E1300bad-plugin-value/E0013bad-reversed-sequence/E0111bad-str-strip-call/E1310(PLE1310)bad-string-format-type/E1307(PLE1307)bad-super-call/E1003bidirectional-unicode/E2502(PLE2502)broken-collections-callable/E6005broken-noreturn/E6004catching-non-exception/E0712class-variable-slots-conflict/E0242continue-in-finally/E0116(PLE0116)dict-iter-missing-items/E1141duplicate-argument-name/E0108duplicate-bases/E0241(PLE0241)format-needs-mapping/E1303(F502)function-redefined/E0102(F811)import-error/E0401inconsistent-mro/E0240inherit-non-class/E0239init-is-generator/E0100invalid-all-format/E0605(PLE0605)invalid-all-object/E0604(PLE0604)invalid-bool-returned/E0304invalid-bytes-returned/E0308invalid-character-backspace/E2510(PLE2510)invalid-character-carriage-return/E2511invalid-character-esc/E2513(PLE2513)invalid-character-nul/E2514(PLE2514)invalid-character-sub/E2512(PLE2512)invalid-character-zero-width-space/E2515(PLE2515)invalid-class-object/E0243invalid-enum-extension/E0244invalid-envvar-value/E1507invalid-format-returned/E0311invalid-getnewargs-ex-returned/E0313invalid-getnewargs-returned/E0312invalid-hash-returned/E0309invalid-index-returned/E0305invalid-length-hint-returned/E0310invalid-length-returned/E0303invalid-metaclass/E1139invalid-repr-returned/E0306invalid-sequence-index/E1126invalid-slice-index/E1127invalid-slice-step/E1144invalid-slots/E0238invalid-slots-object/E0236invalid-star-assignment-target/E0113invalid-str-returned/E0307invalid-unary-operand-type/E1130invalid-unicode-codec/E2501logging-format-truncated/E1201logging-too-few-args/E1206(PLE1206)logging-too-many-args/E1205(PLE1205)logging-unsupported-format/E1200method-hidden/E0202misplaced-bare-raise/E0704misplaced-format-function/E0119missing-format-string-key/E1304(F524)missing-kwoa/E1125mixed-format-string/E1302(F506)modified-iterating-dict/E4702modified-iterating-set/E4703no-member/E1101no-method-argument/E0211(N805)no-name-in-module/E0611no-self-argument/E0213(N805)no-value-for-parameter/E1120non-iterator-returned/E0301nonexistent-operator/E0107(B002)nonlocal-and-global/E0115nonlocal-without-binding/E0117(PLE0117)not-a-mapping/E1134not-an-iterable/E1133not-async-context-manager/E1701not-callable/E1102not-context-manager/E1129not-in-loop/E0103(F701,F702)notimplemented-raised/E0711(F901)potential-index-error/E0643raising-bad-type/E0702raising-non-exception/E0710redundant-keyword-arg/E1124relative-beyond-top-level/E0402repeated-keyword/E1132return-arg-in-generator/E0106return-in-init/E0101(PLE0101)return-outside-function/E0104(F706)singledispatch-method/E1519singledispatchmethod-function/E1520star-needs-assignment-target/E0114syntax-error/E0001(E999)too-few-format-args/E1306(F524)too-many-format-args/E1305(F522)too-many-function-args/E1121too-many-star-expressions/E0112(F622)truncated-format-string/E1301(F501)undefined-all-variable/E0603(F822)undefined-variable/E0602(F821)unexpected-keyword-arg/E1123unexpected-special-method-signature/E0302unhashable-member/E1143unpacking-non-sequence/E0633unsubscriptable-object/E1136unsupported-assignment-operation/E1137unsupported-binary-operation/E1131unsupported-delete-operation/E1138unsupported-membership-test/E1135used-before-assignment/E0601used-prior-global-declaration/E0118(PLE0118)yield-inside-async-function/E1700(PLE1700)yield-outside-function/E0105(F704)Warning
abstract-method/W0223anomalous-backslash-in-string/W1401(W605)anomalous-unicode-escape-in-string/W1402arguments-differ/W0221arguments-out-of-order/W1114arguments-renamed/W0237assert-on-string-literal/W0129(PLW0129)assert-on-tuple/W0199(F631)attribute-defined-outside-init/W0201bad-builtin/W0141bad-dunder-name/W3201bad-format-string/W1302bad-format-string-key/W1300bad-indentation/W0311bad-open-mode/W1501bad-staticmethod-argument/W0211bad-thread-instantiation/W1506bare-except/W0702(E722)binary-op-exception/W0711(PLW0711)boolean-datetime/W1502broad-exception-caught/W0718broad-exception-raised/W0719cell-var-from-loop/W0640(B023)comparison-with-callable/W0143confusing-with-statement/W0124consider-ternary-expression/W0160(SIM108)dangerous-default-value/W0102(B006)deprecated-argument/W4903deprecated-class/W4904deprecated-decorator/W4905deprecated-method/W4902deprecated-module/W4901deprecated-typing-alias/W6001differing-param-doc/W9017differing-type-doc/W9018duplicate-except/W0705(B014)duplicate-key/W0109(F601)duplicate-string-formatting-argument/W1308duplicate-value/W0130eq-without-hash/W1641eval-used/W0123(PGH001)exec-used/W0122(S102)expression-not-assigned/W0106(B018)f-string-without-interpolation/W1309(F541)fixme/W0511(FIX001,FIX002,FIX003,FIX004)forgotten-debug-statement/W1515(T100)format-combined-specification/W1305(F525)format-string-without-interpolation/W1310global-at-module-level/W0604global-statement/W0603(PLW0603)global-variable-not-assigned/W0602(PLW0602)global-variable-undefined/W0601implicit-str-concat/W1404(ISC001)import-self/W0406(PLW0406)inconsistent-quotes/W1405(Q000)invalid-envvar-default/W1508(PLW1508)invalid-format-index/W1307invalid-overridden-method/W0236isinstance-second-argument-not-valid-type/W1116keyword-arg-before-vararg/W1113(B026)logging-format-interpolation/W1202(G)logging-fstring-interpolation/W1203(G)logging-not-lazy/W1201(G)lost-exception/W0150(B012)method-cache-max-size-none/W1518misplaced-future/W0410(F404)missing-any-param-doc/W9021missing-format-argument-key/W1303(F524)missing-format-attribute/W1306missing-param-doc/W9015missing-parentheses-for-call-in-test/W0126missing-raises-doc/W9006missing-return-doc/W9011missing-return-type-doc/W9012missing-timeout/W3101missing-type-doc/W9016missing-yield-doc/W9013missing-yield-type-doc/W9014modified-iterating-list/W4701multiple-constructor-doc/W9005named-expr-without-context/W0131(PLW0131)nan-comparison/W0177nested-min-max/W3301non-ascii-file-name/W2402non-parent-init-called/W0233non-str-assignment-to-dunder-name/W1115overlapping-except/W0714overridden-final-method/W0239pointless-statement/W0104(B018)pointless-string-statement/W0105possibly-unused-variable/W0641preferred-module/W0407protected-access/W0212raise-missing-from/W0707(TRY200)raising-format-tuple/W0715redeclared-assigned-name/W0128redefined-builtin/W0622(A001)redefined-loop-name/W2901(PLW2901)redefined-outer-name/W0621redefined-slots-in-subclass/W0244redundant-returns-doc/W9008redundant-u-string-prefix/W1406redundant-unittest-assert/W1503redundant-yields-doc/W9010reimported/W0404self-assigning-variable/W0127self-cls-assignment/W0642shallow-copy-environ/W1507signature-differs/W0222subclassed-final-class/W0240subprocess-popen-preexec-fn/W1509subprocess-run-check/W1510super-init-not-called/W0231super-without-brackets/W0245too-many-try-statements/W0717try-except-raise/W0706(TRY302)unbalanced-dict-unpacking/W0644unbalanced-tuple-unpacking/W0632undefined-loop-variable/W0631unknown-option-value/W0012unnecessary-ellipsis/W2301unnecessary-lambda/W0108unnecessary-pass/W0107unnecessary-semicolon/W0301(E703)unreachable/W0101unspecified-encoding/W1514unused-argument/W0613(ARG001)unused-format-string-argument/W1304(F507)unused-format-string-key/W1301(F504)unused-import/W0611(F401)unused-private-member/W0238unused-variable/W0612(F841)unused-wildcard-import/W0614useless-else-on-loop/W0120(PLW0120)useless-param-doc/W9019useless-parent-delegation/W0246useless-type-doc/W9020useless-with-lock/W2101using-constant-test/W0125using-f-string-in-unsupported-version/W2601using-final-decorator-in-unsupported-version/W2602while-used/W0149wildcard-import/W0401(F403)wrong-exception-operation/W0716Convention
bad-classmethod-argument/C0202(`N804)bad-docstring-quotes/C0198(Q002)bad-file-encoding/C2503bad-mcs-classmethod-argument/C0204bad-mcs-method-argument/C0203compare-to-empty-string/C1901(PLC1901)compare-to-zero/C2001consider-iterating-dictionary/C0201(SIM118)consider-using-any-or-all/C0501(SIM110,SIM111)consider-using-dict-items/C0206consider-using-enumerate/C0200consider-using-f-string/C0209dict-init-mutate/C3401disallowed-name/C0104docstring-first-line-empty/C0199(D210)empty-docstring/C0112(D419)import-outside-toplevel/C0415import-private-name/C2701invalid-characters-in-docstring/C0403invalid-name/C0103(N815)line-too-long/C0301(E501)misplaced-comparison-constant/C2201(SIM300)missing-class-docstring/C0115(D101)missing-final-newline/C0304(W292)missing-function-docstring/C0116(D103)missing-module-docstring/C0114(D100)mixed-line-endings/C0327multiple-imports/C0410(E401)multiple-statements/C0321(E701,E702)non-ascii-module-import/C2403non-ascii-name/C2401single-string-used-for-slots/C0205(PLC0205)singleton-comparison/C0121(E711,E712)superfluous-parens/C0325(UP034)too-many-lines/C0302trailing-newlines/C0305trailing-whitespace/C0303typevar-double-variance/C0131(PLC0131)typevar-name-incorrect-variance/C0105(PLC0105)typevar-name-mismatch/C0132(PLC0132)unexpected-line-ending-format/C0328ungrouped-imports/C0412(I001)unidiomatic-typecheck/C0123(E721)unnecessary-direct-lambda-call/C3002unnecessary-dunder-call/C2801unnecessary-lambda-assignment/C3001unneeded-not/C0113(SIM208)use-implicit-booleaness-not-comparison/C1803use-implicit-booleaness-not-len/C1802use-maxsplit-arg/C0207use-sequence-for-iteration/C0208(PLC0208)useless-import-alias/C0414(PLC0414)wrong-import-order/C0411(I001)wrong-import-position/C0413(E402)wrong-spelling-in-comment/C0401wrong-spelling-in-docstring/C0402Refactor
chained-comparison/R1716comparison-of-constants/R0133(PLR0133)comparison-with-itself/R0124(PLR0124)condition-evals-to-constant/R1727confusing-consecutive-elif/R5601consider-alternative-union-syntax/R6003(UP007)consider-merging-isinstance/R1701(PLR1701)consider-swap-variables/R1712consider-using-alias/R6002(UP006)consider-using-assignment-expr/R6103consider-using-augmented-assign/R6104consider-using-dict-comprehension/R1717(C402)consider-using-from-import/R0402consider-using-generator/R1728(C417)consider-using-get/R1715(SIM401)consider-using-in/R1714consider-using-join/R1713consider-using-max-builtin/R1731consider-using-min-builtin/R1730consider-using-namedtuple-or-dataclass/R6101consider-using-set-comprehension/R1718(C401)consider-using-sys-exit/R1722(PLR1722)consider-using-ternary/R1706(SIM108)consider-using-tuple/R6102consider-using-with/R1732cyclic-import/R0401duplicate-code/R0801else-if-used/R5501(PLR5501)empty-comment/R2044inconsistent-return-statements/R1710(RET501,RET502)literal-comparison/R0123(F632)magic-value-comparison/R2004(PLR2004)no-classmethod-decorator/R0202no-else-break/R1723(RET508)no-else-continue/R1724(RET507)no-else-raise/R1720(RET506)no-else-return/R1705(RET505)no-self-use/R6301no-staticmethod-decorator/R0203property-with-parameters/R0206(PLR0206)redefined-argument-from-local/R1704redefined-variable-type/R0204simplifiable-condition/R1726simplifiable-if-expression/R1719simplifiable-if-statement/R1703simplify-boolean-expression/R1709stop-iteration-return/R1708super-with-arguments/R1725(UP008)too-complex/R1260(C901)too-few-public-methods/R0903too-many-ancestors/R0901too-many-arguments/R0913too-many-boolean-expressions/R0916too-many-branches/R0912(PLR0912)too-many-instance-attributes/R0902too-many-locals/R0914too-many-nested-blocks/R1702too-many-public-methods/R0904too-many-return-statements/R0911(PLR0911)too-many-statements/R0915(PLR0915)trailing-comma-tuple/R1707(COM818)unnecessary-comprehension/R1721unnecessary-dict-index-lookup/R1733unnecessary-list-index-lookup/R1736use-a-generator/R1729(C417)use-dict-literal/R1735(C406)use-list-literal/R1734(C405)use-set-for-membership/R6201useless-object-inheritance/R0205(UP004)useless-option-value/R0022useless-return/R1711(PLR1711)The text was updated successfully, but these errors were encountered: