Compare commits

...

272 Commits

Author SHA1 Message Date
Charlie Marsh
fd7ccb4c9e Bump version to 0.0.263 (#4086) 2023-04-24 23:32:29 -06:00
Evan Rittenhouse
ae6f38344a Unify positional and keyword arguments when checking for missing arguments in docstring (#4067) 2023-04-25 05:32:15 +00:00
Trevor McCulloch
bbf658d4c5 [pylint] Implement PLE0302 unexpected-special-method-signature (#4075) 2023-04-25 04:51:21 +00:00
Jonathan Plasse
1f3b0fd602 Fix SIM222 and SIM223 false positives and auto-fix (#4063) 2023-04-25 04:44:02 +00:00
Dhruv Manilawala
37483f3ac9 Ignore ClassVar annotation for RUF008, RUF009 (#4081) 2023-04-24 23:58:30 +00:00
Zanie Adkins
4d3a1e0581 Add PrefectHQ/prefect to list of ruff users (#4084) 2023-04-24 17:49:12 -06:00
Bartosz Sokorski
9e5f348a17 Add Poetry to the list of projects using Ruff (#4085) 2023-04-24 17:48:35 -06:00
Jonathan Plasse
5e91211e6d Add in_boolean_test to Context (#4072) 2023-04-23 23:18:23 -06:00
Jonathan Plasse
df77595426 Move Truthiness into ruff_python_ast (#4071) 2023-04-24 04:54:31 +00:00
Charlie Marsh
407af6e0ae Avoid infinite-propagation of inline comments when force-splitting imports (#4074) 2023-04-23 22:39:51 -06:00
Dhruv Manilawala
d64146683e Increment priority should be (branch-local, global) (#4070) 2023-04-23 00:04:15 -06:00
Charlie Marsh
0e7914010f Misc. small clean-up of flake8-import-conventions rules (#4069) 2023-04-23 04:57:15 +00:00
Edgar R. M
cfc7d8a2b5 [flake8-import-conventions] Implement new rule ICN003 to ban from ... import ... for selected modules (#4040) 2023-04-23 04:40:36 +00:00
Tom Kuson
f5cd659292 Add docs for tryceratops rules (#4042) 2023-04-23 04:35:56 +00:00
Charlie Marsh
260138b427 Use Context for pep8-naming helpers (#4068) 2023-04-22 18:44:54 -04:00
Jonathan Plasse
2da149fd7e Ignore N815 for TypedDict fields (#4066) 2023-04-22 18:17:14 -04:00
Micha Reiser
e33887718d Use Rust 1.69 (#4065) 2023-04-22 23:04:17 +01:00
Micha Reiser
ba4f4f4672 Upgrade dependencies (#4064) 2023-04-22 18:04:01 +01:00
Pronoy Mandal
b7a57ce120 Update tutorial.md (#4055) 2023-04-21 10:56:31 -06:00
Alan Du
82abbc7234 [flake8-bugbear] Add pytest.raises(Exception) support to B017 (#4052) 2023-04-21 03:43:01 +00:00
Dhruv Manilawala
ba98149022 Avoid RUF008 if field annotation is immutable (#4039) 2023-04-20 16:02:12 -04:00
Dhruv Manilawala
7fd44a3e12 Avoid PYI015 for valid default value without annotation (#4043) 2023-04-20 15:45:47 -04:00
Evan Rittenhouse
6e8d561090 Support --fix in watch mode (#4035) 2023-04-19 23:33:12 -04:00
Jacob Coffee
cb762f4cad Add Astral announcement to README (#4010) 2023-04-19 20:28:45 +00:00
Charlie Marsh
eed6866b7e Add relative-path tests for banned-api (#4033) 2023-04-19 16:04:22 -04:00
Charlie Marsh
25a6bfa9ee Bump version to 0.0.262 (#4032) 2023-04-19 15:49:28 -04:00
Charlie Marsh
b3f8f2a5c1 Remove TODO in handle_node_store (#4031) 2023-04-19 15:28:56 -04:00
Charlie Marsh
cc8b5a543b Ignore stub file assignments to value-requiring targets (#4030) 2023-04-19 15:26:00 -04:00
Charlie Marsh
10d5415bcb Ignore certain flake8-pyi errors within function bodies (#4029) 2023-04-19 15:10:29 -04:00
Charlie Marsh
827cbe7f97 Treat non-future function annotations as required-at-runtime (#4028) 2023-04-19 14:43:55 -04:00
Charlie Marsh
0d84517fbc Use module path resolver for relative autofix (#4027) 2023-04-19 14:43:45 -04:00
Charlie Marsh
7fa1da20fb Support relative imports in banned-api enforcement (#4025) 2023-04-19 14:30:13 -04:00
Francesco Nuzzo
f13a161ead remove unnecessary f-string formatting (#4026) 2023-04-19 18:14:33 +00:00
Charlie Marsh
c4cda301aa Ignore relative imports in banned-api rules (#4024) 2023-04-19 13:30:08 -04:00
Charlie Marsh
13fda30051 Refactor flake8_tidy_imports rules to consistently take Checker (#4023) 2023-04-19 16:42:15 +00:00
Micha Reiser
a3146ab1ca Fix (doc-)line-too-long start location (#4006) 2023-04-19 08:42:28 +02:00
Micha Reiser
c0cf87356e Set non-empty range for indentation diagnostics (#4005) 2023-04-18 16:26:13 +02:00
Andrei Grazhdankov
6c3e4ef441 Add Robyn to user list (#4008) 2023-04-18 09:51:20 -04:00
Charlie Marsh
6c038830a8 Ignore argument assignments when enforcing RET504 (#4004) 2023-04-18 03:22:38 +00:00
Charlie Marsh
064a293b80 Fix defaults for section-order (#4003) 2023-04-18 03:00:17 +00:00
Charlie Marsh
79c47e29ee Avoid short-circuiting when detecting RET rules (#4002) 2023-04-17 22:52:26 -04:00
Charlie Marsh
be87a29a9d Respect typing-modules when evaluating no-return functions (#4001) 2023-04-17 20:25:44 +00:00
Micha Reiser
280dffb5e1 Add parser benchmark (#3990) 2023-04-17 16:43:59 +02:00
Charlie Marsh
336993ea06 Change Alpha trove classifier to Beta (#3995) 2023-04-17 13:55:49 +00:00
Tom Kuson
516cb10000 Add more documentation for flake8-type-checking (#3994) 2023-04-17 09:51:54 -04:00
Charlie Marsh
1cdd5e3424 Remove autofix behavior for uncapitalized-environment-variables (SIM112) (#3988) 2023-04-16 23:19:05 +00:00
Dhruv Manilawala
bd78c6ade2 Preserve type annotations when fixing E731 (#3983) 2023-04-16 23:15:38 +00:00
Dhruv Manilawala
5ce35faa86 Do not consider nested comment as part of code (#3984) 2023-04-16 19:11:01 -04:00
Justin Chu
484b572e6b Add ONNX Runtime to user list (#3982) 2023-04-16 18:21:46 -04:00
Charlie Marsh
81805a45f0 Add some additional users (#3975) 2023-04-14 12:41:22 -04:00
Charlie Marsh
c457752f36 Redirect PIE802 to C419 (#3971) 2023-04-13 22:12:32 -04:00
Charlie Marsh
289289bfd3 Implement unnecessary-literal-within-dict-call (C418) (#3969) 2023-04-14 01:39:35 +00:00
Charlie Marsh
09274307e8 Add multi-edit change to BREAKING_CHANGES.md (#3968) 2023-04-13 23:12:00 +00:00
Charlie Marsh
d8718dcf54 Remove extraneous debug and TODO (#3967) 2023-04-13 18:45:18 -04:00
Charlie Marsh
fb9eeba422 Move user-defined section validation into Settings (#3966) 2023-04-13 22:40:05 +00:00
Paul
2d2630ef07 Implement isort custom sections and ordering (#2419) (#3900) 2023-04-13 21:28:22 +00:00
Charlie Marsh
1f22e035e3 Add 'or if cond' to E712 message (#3962) 2023-04-13 19:02:23 +00:00
Rob Young
a6a7584d79 Implement flake8-bandit shell injection rules (#3924) 2023-04-13 14:45:27 -04:00
Charlie Marsh
ffac4f6ec3 Ignore assert errors (S101) in TYPE_CHECKING blocks (#3960) 2023-04-13 18:20:44 +00:00
Dhruv Manilawala
032a84b167 Check for parenthesis in implicit str concat in PT006 (#3955) 2023-04-13 17:56:18 +00:00
Charlie Marsh
3357aaef4b Add docs for assert rule (S101) (#3959) 2023-04-13 13:43:00 -04:00
Charlie Marsh
d9ed43d112 Clarify some isort differences in FAQ (#3954) 2023-04-13 04:05:28 +00:00
Charlie Marsh
e160a52bfd Raise percent-format upgrade rule (UP031) for hanging modulos (#3953) 2023-04-12 23:59:20 -04:00
Charlie Marsh
9067ae47d1 Allow typing_extensions.TypeVar assignments in .pyi files (#3951) 2023-04-12 17:30:15 -04:00
Charlie Marsh
71e807b3be Add Prefect to user list (#3949) 2023-04-12 12:09:36 -04:00
Charlie Marsh
1e2df07544 Use identifier range for pytest rules (#3948) 2023-04-12 15:28:25 +00:00
USER-5
860841468c [flake8-pyi] Implement duplicate types in unions (PYI016) (#3922) 2023-04-12 04:06:09 +00:00
Charlie Marsh
ed4ecc3255 Remove unused import (#3944) 2023-04-12 03:55:38 +00:00
Charlie Marsh
b999e4b1e2 Allow users to extend the set of included files via include (#3914) 2023-04-11 23:39:43 -04:00
Charlie Marsh
8ce227047d Tidy up some pygrep-hooks rules (#3942) 2023-04-12 03:35:15 +00:00
Daniel Stancl
523515f936 [flake8-import-conventions] Add a rule for BannedImportAlias (#3926) 2023-04-12 03:29:24 +00:00
Charlie Marsh
10da3bc8dd Support pyright: ignore comments (#3941) 2023-04-12 03:10:29 +00:00
Charlie Marsh
eb0dd74040 Avoid adding required imports to stub files (#3940) 2023-04-11 22:31:20 -04:00
Micha Reiser
61200d2171 lint snapshots: Use filename only to avoid platform specific separators (#3930) 2023-04-11 11:40:51 +02:00
Micha Reiser
e8aebee3f6 Pretty print Diagnostics in snapshot tests (#3906) 2023-04-11 09:03:00 +00:00
Micha Reiser
210083bdd8 Order Edits by Locations (#3905) 2023-04-11 08:56:41 +00:00
Micha Reiser
c33c9dc585 Introduce SourceFile to avoid cloning the message filename (#3904) 2023-04-11 08:28:55 +00:00
Micha Reiser
056c212975 Render code frame with context (#3901) 2023-04-11 10:22:11 +02:00
Micha Reiser
381203c084 Store source code on message (#3897) 2023-04-11 07:57:36 +00:00
Micha Reiser
76c47a9a43 Cheap cloneable LineIndex (#3896) 2023-04-11 07:33:40 +00:00
Micha Reiser
9209e57c5a Extract message emitters from Printer (#3895) 2023-04-11 07:24:25 +00:00
Leiser Fernández Gallo
333f1bd9ce Extend SIM105 to match also 'Ellipsis only' bodies in exception handlers (#3925) 2023-04-10 09:55:02 -04:00
Leiser Fernández Gallo
002caadf9e [flake8-simplify] Add autofix for contextlib.suppress (SIM105) (#3915) 2023-04-09 22:45:19 +00:00
Dhruv Manilawala
311ba29d0f Do not skip analysis if *args present for F523 (#3923) 2023-04-09 18:34:52 -04:00
Dhruv Manilawala
237a64d922 Check for arguments in inner/outer call for C414 (#3916) 2023-04-09 18:33:11 -04:00
Moritz Sauter
d4af2dd5cf [ruff] Add checks for mutable defaults in dataclasses (#3877) 2023-04-09 02:46:28 +00:00
Charlie Marsh
a36ce585ce Remove extract_path_names helper (#3920) 2023-04-08 11:14:42 -04:00
Charlie Marsh
29ec6df24f Avoid N802 violations for @override methods (#3912) 2023-04-08 03:11:50 +00:00
Evan Rittenhouse
8b17508ef1 Remove old documentation (#3911) 2023-04-07 22:51:19 -04:00
Evan Rittenhouse
abaf0a198d Ensure that tab characters aren't in multi-line strings before throwing a violation (#3837) 2023-04-06 22:25:40 -04:00
konstin
454c6d9c2f Extended ecosystem check with scraped data (#3858) 2023-04-06 22:39:48 +00:00
konstin
cae5503e34 [pylint] Fix unicode handling in PLE2515 (#3898) 2023-04-06 13:54:52 -04:00
Dhruv Manilawala
34e9786a41 Visit comprehension to detect group name usage/overrides (#3887) 2023-04-05 18:03:11 -04:00
Dhruv Manilawala
5467d45dfa Ignore PLW2901 when using typing cast (#3891) 2023-04-05 18:02:32 -04:00
Charlie Marsh
ac87137c1c Avoid printing docs on cargo dev generate-all (#3890) 2023-04-05 14:18:33 -04:00
Charlie Marsh
e0bccfd2d9 Allow legacy C and T selectors in JSON schema (#3889) 2023-04-05 17:58:36 +00:00
Tom Kuson
7b6e55a2e0 Add documentation for flake8-type-checking (#3886) 2023-04-05 17:30:25 +00:00
brucearctor
5c374b5793 Consistent Style/Levels in Usage (#3884) 2023-04-05 03:06:43 +00:00
Edgar R. M
ffdd0de522 Add Meltano to users (#3883) 2023-04-04 23:05:53 -04:00
Charlie Marsh
5370968839 Add some additional users and alphabetize (#3882) 2023-04-05 02:40:02 +00:00
Charlie Marsh
255b094b33 Bump version to 0.0.261 (#3881) 2023-04-04 22:31:01 -04:00
Dhruv Manilawala
b6155232ac Consider logger candidate from logging module only (#3878) 2023-04-04 19:52:57 +00:00
kyoto7250
390d7dcf39 Supports more cases in SIM112 (#3876) 2023-04-04 15:49:24 -04:00
Charlie Marsh
251340a246 Add LangChain and LlamaIndex (#3879) 2023-04-04 19:36:31 +00:00
Charlie Marsh
d919adc13c Introduce a ruff_python_semantic crate (#3865) 2023-04-04 16:50:47 +00:00
kyoto7250
46bcb1f725 [flake8-simplify] Implement dict-get-with-none-default (SIM910) (#3874) 2023-04-04 03:52:10 +00:00
Dhruv Manilawala
2b21effa77 fixup! Support mutually exclusive branches for B031 (#3844) (#3875) 2023-04-03 23:34:11 -04:00
Chris Chan
10504eb9ed Generate ImportMap from module path to imported dependencies (#3243) 2023-04-04 03:31:37 +00:00
Dhruv Manilawala
76e111c874 Support mutually exclusive branches for B031 (#3844) 2023-04-04 02:33:17 +00:00
brucearctor
e006b922a6 Add documentation for ruff-action (GitHub Action!) (#3857) 2023-04-03 23:47:26 +00:00
Charlie Marsh
60f6a8571a Allow starred arguments in B030 (#3871) 2023-04-03 23:20:34 +00:00
Charlie Marsh
f4173b2a93 Move shadow tracking into Scope directly (#3854) 2023-04-03 15:33:44 -04:00
Charlie Marsh
449e08ed08 Rename autofix::helpers to autofix::actions (#3866) 2023-04-03 13:34:49 -04:00
Charlie Marsh
5625410936 Remove uses_magic_variable_access dependence on Checker (#3864) 2023-04-03 12:22:06 -04:00
Charlie Marsh
3744e9ab3f Remove contains_effect's dependency on Context (#3855) 2023-04-03 12:08:13 -04:00
Nicolas Vuillamy
b52cb93e58 Add thank you in README.md + usage in MegaLinter (#3848) 2023-04-03 15:45:25 +00:00
Nazia Povey
849091d846 When checking module visibility, don't check entire ancestry (#3835) 2023-04-03 11:38:41 -04:00
Ran Benita
d2f2544f6e flake8-pyi: fix PYI015 false positive on assignment of TypeVar & friends (#3861) 2023-04-03 11:28:46 -04:00
Charlie Marsh
25771cd4b9 Use references for Export binding type (#3853) 2023-04-03 15:26:42 +00:00
Charlie Marsh
924bebbb4a Change "indexes" to "indices" in various contexts (#3856) 2023-04-02 23:08:03 +00:00
Charlie Marsh
08e5b3fa61 Make collect_call_path return an Option (#3849) 2023-04-01 22:29:32 -04:00
Charlie Marsh
d822e08111 Move CallPath into its own module (#3847) 2023-04-01 11:25:04 -04:00
Charlie Marsh
2f90157ce2 Move logging resolver into logging.rs (#3843) 2023-04-01 03:50:44 +00:00
Charlie Marsh
88308ef9cc Move Binding structs out of scope.rs (#3842) 2023-03-31 23:49:48 -04:00
Charlie Marsh
6d80c79bac Combine operations.rs and helpers.rs (#3841) 2023-04-01 03:40:34 +00:00
Charlie Marsh
2fbc620ad3 Move __all__ utilities to all.rs (#3840) 2023-04-01 03:31:15 +00:00
Charlie Marsh
27e40e9b31 Remove helpers.rs dependency on Binding (#3839) 2023-04-01 03:19:45 +00:00
Charlie Marsh
b6276e2d95 Move f-string identification into rule module (#3838) 2023-03-31 23:10:11 -04:00
Charlie Marsh
66d72b1c7b Move keyword checks into is_identifier (#3834) 2023-03-31 16:56:33 -04:00
Jonathan Plasse
968c7df770 Fix is_module_name() and improve perf of is_identifier() (#3795) 2023-03-31 15:15:36 -04:00
Jonathan Plasse
fe38597279 Fix SIM222 and SIM223 false positive (#3832) 2023-03-31 14:50:35 -04:00
Jonathan Plasse
f3f9a9f297 Fix pre-commit CI job exit code (#3833) 2023-03-31 14:47:04 -04:00
Micha Reiser
48d8680e71 Ambiguous unicode, only test unicode characters (#3814) 2023-03-31 18:03:00 +01:00
Charlie Marsh
82584ad101 Extend unncessary-generator-any-all to set comprehensions (#3824) 2023-03-31 16:29:25 +00:00
konstin
13e52b1f76 Use cache in cargo udeps CI (#3809) 2023-03-31 11:07:14 -04:00
Charlie Marsh
dfc872c9a0 Track star imports on Scope directly (#3822) 2023-03-31 15:01:12 +00:00
Charlie Marsh
cf7e1ddd08 Remove some usize references (#3819) 2023-03-30 17:35:42 -04:00
Charlie Marsh
9de1f82658 Avoid unnecessary-comprehension-any-all for async generators (#3823) 2023-03-30 18:43:59 +00:00
Charlie Marsh
54ad9397e5 Flag non-Name expressions in duplicate-isinstance-call (#3817) 2023-03-30 12:19:53 -04:00
Jonathan Plasse
29c8b75fd4 Ignore collapsible-if violations for if False: and if True: (#3732) 2023-03-30 15:52:43 +00:00
Charlie Marsh
0b586d5451 Use panic instead of unreachable for invalid arguments (#3816) 2023-03-30 15:40:53 +00:00
Charlie Marsh
01357f62e5 Add import insertion support to autofix capabilities (#3787) 2023-03-30 15:33:46 +00:00
Micha Reiser
d7113d3995 refactor: StateMachine use match statement (#3811) 2023-03-30 15:55:54 +02:00
Madison Swain-Bowden
a142d71e0b Add Openverse to users of ruff in README (#3806) 2023-03-30 09:14:47 -04:00
Charlie Marsh
f79506f5a4 Move some generic structs out of isort (#3788) 2023-03-30 08:58:01 -04:00
Dhruv Manilawala
44ae3237b8 Additional simple magic return types (#3805) 2023-03-30 08:57:49 -04:00
konstin
f4cda31708 Use crates.io version of pep440_rs (#3812)
* Use crates.io version of pep440_rs

* Update Cargo.lock
2023-03-30 12:47:07 +00:00
Charlie Marsh
4328448a2f Use multi-fix semantics for inplace removal (#3804) 2023-03-30 00:16:43 +00:00
Charlie Marsh
88298759ce Misc. follow-up changes to #3802 (#3803) 2023-03-29 19:18:36 -04:00
Charlie Marsh
3c0e789b19 Improve robustness of argument removal for encode calls (#3802) 2023-03-29 23:07:13 +00:00
Charlie Marsh
8601dcc09b Add import name resolution to Context (#3777) 2023-03-29 21:47:50 +00:00
Charlie Marsh
134fdd1609 Remove star-import handling from sys-exit-alias (#3776) 2023-03-29 21:33:50 +00:00
Charlie Marsh
2e6eddc7bd Improve top-of-file insertions for required imports (#3779) 2023-03-29 21:25:39 +00:00
Jonathan Plasse
cb588d1d6d Allow TID252 to fix all valid module paths (#3796) 2023-03-29 15:13:12 -04:00
Charlie Marsh
9d3b8eb67b Bump version to v0.0.260 (#3799) 2023-03-29 14:51:50 -04:00
Charlie Marsh
e1e5532ab1 Add flymake-ruff to docs (#3800) 2023-03-29 18:48:59 +00:00
Andy Freeland
7d962bf80c [flake8-bugbear] Allow pathlib.Path() in B008 (#3794) 2023-03-29 15:42:43 +00:00
Micha Reiser
595cd065f3 Reduce explcit clones (#3793) 2023-03-29 15:15:14 +02:00
Anže Starič
b6f1fed424 [isort]: support submodules in known_(first|third)_party config options (#3768) 2023-03-29 03:53:38 +00:00
Jonathan Plasse
5501fc9572 Exempt return with side effects for TRY300 (#3780) 2023-03-28 19:52:05 -04:00
Charlie Marsh
5977862a60 Enumerate all codes in default configuration example (#3790) 2023-03-28 23:36:22 +00:00
Leiser Fernández Gallo
224e85c6d7 Implement flake8-gettext (#3785) 2023-03-28 23:32:02 +00:00
Charlie Marsh
515e436cfa Clarify order of pre-commit hooks (#3789) 2023-03-28 23:15:36 +00:00
Charlie Marsh
f322bcd2bd Minor nits on reference names (#3786) 2023-03-28 22:18:19 +00:00
Charlie Marsh
22d5b0071d Rename end_of_statement to end_of_last_statement (#3775) 2023-03-28 12:31:06 -04:00
Charlie Marsh
990b378c4d Set parents even in same-line cases (#3773) 2023-03-28 12:09:30 -04:00
Charlie Marsh
e88fbae926 Use import alias locations for pep8-naming import rules (#3772) 2023-03-28 11:41:23 -04:00
Charlie Marsh
81de3a16bc Include with statements in complexity calculation (#3771) 2023-03-28 15:20:22 +00:00
Andy Freeland
bfecf684ce [flake8-bugbear] Add more immutable functions for B008 (#3764) 2023-03-28 10:50:05 -04:00
konstin
756e9956a2 Fix cargo test --doc (#3766) 2023-03-28 11:36:07 +00:00
Micha Reiser
f68c26a506 perf(pycodestyle): Initialize Stylist from tokens (#3757) 2023-03-28 11:53:35 +02:00
Micha Reiser
000394f428 perf(pycodestyle): Introduce TokenKind (#3745) 2023-03-28 11:22:39 +02:00
Micha Reiser
2fdf98ef4e perf(pycodestyle): Refactor checks to iterate over tokens insteadof text (#3736) 2023-03-28 10:37:13 +02:00
Micha Reiser
1d724b1495 perf(pycodestyle): Remove regex captures (#3735) 2023-03-28 09:50:34 +02:00
Micha Reiser
113a8b8fda perf(pycodestyle): Reduce allocations when computing logical lines (#3715) 2023-03-28 09:09:27 +02:00
Charlie Marsh
c3917eab38 Revert "Implement flake8-i18n (#3741)" (#3765) 2023-03-27 21:14:38 +00:00
JBLDSKY
0eb5a22dd1 [flake8-pyi] Implement PYI012 (#3743) 2023-03-27 18:27:24 +00:00
Charlie Marsh
450c6780ff Avoid useless-import alias (C0414) in .pyi files (#3761) 2023-03-27 18:27:03 +00:00
Leiser Fernández Gallo
5cb120327c Implement flake8-i18n (#3741) 2023-03-27 18:03:39 +00:00
trag1c
8dbffb576d Removed unnecessary pipe escape (#3760) 2023-03-27 13:49:47 -04:00
Charlie Marsh
31fff4b10e Disallow some restriction lints (#3754) 2023-03-26 23:20:20 +00:00
Jonathan Plasse
2326335f5c Improve performance of statistics (#3751) 2023-03-26 18:46:44 -04:00
Charlie Marsh
6ed6da3e82 Move fix::FixMode to flags::FixMode (#3753) 2023-03-26 21:40:06 +00:00
Jonathan Plasse
cd75b57036 Sort statistics by count (#3748) 2023-03-26 16:45:35 -04:00
Charlie Marsh
e603382cf0 Allow diagnostics to generate multi-edit fixes (#3709) 2023-03-26 16:45:19 -04:00
Charlie Marsh
32be63fd1e Avoid overlong-line errors for lines that end with URLs (#3663) 2023-03-26 18:17:35 +00:00
Jonathan Plasse
d594179275 Fix SIM222 and SIM223 false negatives (#3740) 2023-03-26 18:09:11 +00:00
Agriya Khetarpal
c0befb4670 Use wild::args() and add wild as a dependency (#3739) 2023-03-26 14:32:45 +00:00
Charlie Marsh
a66481ed28 Rename setter methods on Diagnostic (#3738) 2023-03-26 10:28:30 -04:00
Charlie Marsh
5c7898124f Traverse over nested string type annotations (#3724) 2023-03-25 21:56:09 -04:00
Jonathan Plasse
50a7916e84 [pydocstyle] Implement autofix for D403 (#3731) 2023-03-25 19:21:45 +00:00
Charlie Marsh
6a40a5c5a2 Add a note on src (#3733) 2023-03-25 16:18:34 +00:00
Jonathan Plasse
fec4fa39a7 Improve add_rule.py and add_plugin.py scripts (#3725) 2023-03-25 16:05:39 +00:00
Dhruv Manilawala
2659336ed1 Add support for .log(level, msg) calls in flake8-logging-format (#3726) 2023-03-25 15:55:53 +00:00
Jonathan Plasse
8ac7584756 [flake8-pyi] Implement PYI015 (#3728) 2023-03-25 15:48:11 +00:00
Jonathan Plasse
4a1740a4c4 [flake8-pyi] Add autofix for PYI014 (#3729) 2023-03-25 15:41:11 +00:00
Charlie Marsh
2083134a96 Rename Fix to Edit (#3702) 2023-03-24 19:29:14 -04:00
Charlie Marsh
c721eedc37 Remove 'b lifetime from Checker (#3723) 2023-03-24 21:42:18 +00:00
Dhruv Manilawala
c1d89d8c93 [flake8-bugbear]: Implement rule B031 (#3680) 2023-03-24 17:26:11 -04:00
Jonathan Plasse
b8ae1e0e05 Add pre-commit in CI (#3707) 2023-03-24 17:20:13 -04:00
Dhruv Manilawala
63adf9f5e8 Allow aliased logging module as a logger candidate (#3718) 2023-03-24 17:19:09 -04:00
Micha Reiser
7af83460ce Use unicode-width to determine line-length instead of character count (#3714) 2023-03-24 17:17:05 -04:00
Jonathan Plasse
dc4d7619ee Add Diagnostic.try_amend() to simplify error handling (#3701) 2023-03-24 17:10:11 -04:00
Jonathan Plasse
1bac206995 Revert "Replace logical_lines feature with debug_assertions (#3648)" (#3708) 2023-03-23 23:42:56 -04:00
Jonathan Plasse
efc6e8cb39 Exempt PLR1711 and RET501 if non-None annotation (#3705) 2023-03-24 03:11:58 +00:00
Jonathan Plasse
7f3b748401 Fix Ruff pre-commit hook errors (#3706) 2023-03-23 22:52:24 -04:00
Jonathan Plasse
7da06b9741 Allow simple container literals as default values (#3703) 2023-03-23 22:51:36 -04:00
Charlie Marsh
0f95056f13 Avoid panics for implicitly concatenated forward references (#3700) 2023-03-23 19:13:50 -04:00
Charlie Marsh
028329854b Avoid parsing f-strings in type annotations (#3699) 2023-03-23 18:51:44 -04:00
Charlie Marsh
ba43d6bd0b Avoid parsing ForwardRef contents as type references (#3698) 2023-03-23 18:44:02 -04:00
Charlie Marsh
e8d17d23cb Expand the scope of useless-expression (B018) (#3455) 2023-03-23 18:33:58 -04:00
Jonathan Plasse
aea925a898 Fix SIM118 auto-fix (#3695) 2023-03-23 17:14:56 -04:00
Charlie Marsh
f58345dee3 Bump version to v0.0.259 (#3691) 2023-03-23 14:52:42 -04:00
Charlie Marsh
71c0da27bb Avoid nested loops in missing_whitespace (#3688) 2023-03-23 14:18:59 -04:00
Charlie Marsh
8a2d1a3029 Respect all rule-exemption sources when suppressing parser errors (#3665) 2023-03-23 13:36:48 -04:00
Micha Reiser
6161e56ea4 Fix RuleSet.remove (#3685) 2023-03-23 17:01:37 +00:00
Charlie Marsh
189c9d4683 Add dedicated structs for BindingKind variants (#3672) 2023-03-22 19:08:48 -04:00
Charlie Marsh
615887a7fe Bump version to v0.0.258 (#3671) 2023-03-22 15:02:57 -04:00
Charlie Marsh
07808a58f2 Refactor out common exemption-parsing logic (#3670) 2023-03-22 15:02:07 -04:00
Ran Benita
fe568c08d2 isort: fix bad interaction between force-sort-within-sections and force-to-top (#3645) 2023-03-22 14:00:00 -04:00
Charlie Marsh
7741d43ae5 Allow pairwise diagnostics for zip(..., strict=True) (#3669) 2023-03-22 13:03:43 -04:00
Charlie Marsh
1b3e54231c Flag, but don't fix, unused imports in ModuleNotFoundError blocks (#3658) 2023-03-22 13:03:30 -04:00
Charlie Marsh
3a8e98341b Enable autofix for annotations within 'simple' string literals (#3657) 2023-03-22 12:45:51 -04:00
kyoto7250
8593739f88 Check indentation level when executing E231 (#3668) 2023-03-22 12:32:00 -04:00
Charlie Marsh
242dd3dae1 Rename remaining use-* rules (#3661) 2023-03-22 11:36:01 -04:00
Charlie Marsh
875f61cb62 Rename pathlib rules to match updated naming convention (#3660) 2023-03-22 11:35:45 -04:00
Jonathan Plasse
3ec1ea8ac2 Add cargo-udeps in CI (#3646) 2023-03-22 15:53:12 +01:00
Charlie Marsh
1e45b13958 Remove linked issue from flake8-django (#3664) 2023-03-22 03:26:22 +00:00
Dhruv Manilawala
9e61956711 [flake8-django]: Implement rule DJ012 (#3659) 2023-03-22 03:07:58 +00:00
Jonathan Plasse
5eae3fbbfb Avoid RUF007 fixes for more than two arguments (#3654) 2023-03-21 22:17:31 +00:00
Colin Delahunty
41e38ffa98 [flake8-bandit]: Implement deny-list rules for suspicious member calls (#3239) 2023-03-21 15:11:52 -04:00
Charlie Marsh
27903cdb11 Replace logical_lines feature with debug_assertions (#3648) 2023-03-21 12:16:41 -04:00
Charlie Marsh
3b1709ba1e Avoid attempting infinite open fix with re-bound builtin (#3650) 2023-03-21 15:32:31 +00:00
Dhruv Manilawala
33394e4a69 docs: all flake8-comprehension rules (#3631) 2023-03-21 14:28:19 +00:00
Charlie Marsh
7b9bdc494a Consider same-site fixes to be overlapping (#3638) 2023-03-21 10:09:47 -04:00
James Greenhill
b06ca25421 Add PostHog to users of Ruff in README (#3641) 2023-03-21 10:05:35 -04:00
Jonathan Plasse
c42f8b93d2 Add Swatinem/rust-cache to benchmark-compare job (#3637) 2023-03-21 14:45:09 +01:00
Micha Reiser
f59a22b6e5 Remove unused dependencies (#3644) 2023-03-21 11:02:41 +01:00
Jonathan Plasse
b5edc6dfc9 Add autofix functionality for F523 (#3613) 2023-03-21 03:55:23 +00:00
Charlie Marsh
626169e2ef Avoid raising PEP 604 errors with forward-referenced members (#3640) 2023-03-20 23:49:41 -04:00
Charlie Marsh
e9f359ac5e Convert single-argument %-style format calls (#3600) 2023-03-21 03:35:10 +00:00
Jacob Latonis
318c2c80e2 pylint: Implement binary-op-exception (PLW0711) (#3639) 2023-03-21 03:33:40 +00:00
Jonathan Plasse
92aa3a8178 Use language: system for Rust hooks (#3616) 2023-03-20 22:44:21 -04:00
Jonathan Plasse
22a4ab51f9 Handle UP032 autofix with adjacent keywords (#3636) 2023-03-21 00:17:45 +00:00
Jonathan Plasse
f70a49ed8b Add autofix for magic methods (ANN204) (#3633) 2023-03-20 19:19:20 -04:00
Charlie Marsh
f039bf36a2 Avoid trimming escaped whitespace in D210 (#3635) 2023-03-20 17:17:42 -04:00
Jonathan Plasse
169dd72328 Fix TRY300 false positive (#3634) 2023-03-20 20:55:28 +00:00
Jonathan Plasse
fd39ec4bdd Merge Availability and AutofixKind (#3629) 2023-03-20 16:45:33 +00:00
Charlie Marsh
7c0f17279c Flag PEP 585 and PEP 604 violations in quoted annotations (#3593) 2023-03-20 11:15:44 -04:00
konstin
81d0884974 Add basic jupyter notebook support (#3440)
* Add basic jupyter notebook support behind a feature flag

* Address review comments

* Rename in separate commit to make both git and clippy happy

* cfg(feature = "jupyter_notebook") another test

* Address more review comments

* Address more review comments

* and clippy and windows

* More review comment
2023-03-20 12:06:01 +01:00
Jacob Latonis
a45753f462 [pylint]: Implement assert-on-string-literal (W0129) (#3610) 2023-03-19 23:45:51 -04:00
Zhengbo Wang
b08326162b Doc/CLN: pass pre-commit (#3604) 2023-03-19 19:20:11 +00:00
Dhruv Manilawala
3a65af4dae feat: update C416 with dict comprehension (autofixable) (#3605) 2023-03-19 18:37:28 +00:00
Ville Lindholm
474aa0b196 Fix infinite loop due to rules D207 & W605 (#3609) 2023-03-19 18:29:13 +00:00
Charlie Marsh
4892167217 Avoid panics for implicitly-concatenated docstrings (#3584)
## Summary

In the rare event that a docstring contains an implicit string concatenation, we currently have the potential to panic, because we assume that if a string starts with triple quotes, it _ends_ with triple quotes. But with implicit concatenation, that's not the case: a single `Expr` could start and end with different quote styles, because it can contain multiple string tokens.

Supporting these "properly" is pretty hard. In some cases it's hard to even know what the "right" behavior is. So for now, I'm just detecting and warning, which is better than a panic.

Closes #3543.

Closes #3585.
2023-03-19 14:16:50 -04:00
Micha Reiser
a5494b8541 Bitflag based RuleSet (#3606) 2023-03-19 17:09:06 +01:00
Micha Reiser
9ac9a1c69e Gracefully handle lint panics (#3509) 2023-03-19 17:08:38 +01:00
Rogdham
f06dff8af8 Change broken links in README to beta.ruff.rs (#3607) 2023-03-19 15:17:44 +00:00
Charlie Marsh
fe7443ce2f Use any_enabled in AST checker (#3601) 2023-03-19 10:44:33 -04:00
Henry Schreiner
4bdb2dd362 ci(check_ecosystem): add PyPa/build (#3569) 2023-03-18 19:09:22 -04:00
Henry Schreiner
53a4743631 ci: fix check_ecosystem (#3602) 2023-03-18 19:03:08 -04:00
Charlie Marsh
4ffcd8366a Rename a variety of rules to match updated conventions (#3283) 2023-03-18 17:35:59 -04:00
Charlie Marsh
dfb772c6f1 Avoid removing comment hash for noqa's with trailing content (#3589) 2023-03-18 18:48:52 +00:00
Jonathan Plasse
c21eb06922 Fix D417 false positive (#3596) 2023-03-18 13:14:03 -04:00
Charlie Marsh
16a350c731 Reduce usage of ALL in ecosystem CI (#3590) 2023-03-18 13:13:09 -04:00
Charlie Marsh
fa04861724 Check exclusions prior to resolving pyproject.toml files (#3588) 2023-03-18 13:12:49 -04:00
Micha Reiser
404504ab41 CI Checks: Fix malformed markdown (#3595)
The Benchmark results aren't formatted properly if the ecosystem check finds differences because the ecosystem check doesn't emit a trailing newline.

This PR adds the trailing newline to the ecosystem check script.
2023-03-18 10:04:50 +00:00
Charlie Marsh
621e4353e3 Re-add the list of supported plugins to the README (#3592) 2023-03-17 23:33:37 -04:00
Charlie Marsh
0c4926ff7b Bump version to v0.0.257 (#3591) 2023-03-17 22:34:10 -04:00
tomecki
61653b9f27 [pylint] Implement useless-return (R1711) (#3116) 2023-03-17 18:30:32 -04:00
Charlie Marsh
8dd3959e74 Update output in resources/test/project/README.md (#3587) 2023-03-17 21:51:03 +00:00
Charlie Marsh
50f9db21da Enable ANSI colors on Windows 10 (#3583) 2023-03-17 17:34:39 -04:00
1547 changed files with 84069 additions and 69890 deletions

View File

@@ -26,4 +26,11 @@ rustflags = [
"-Wclippy::print_stdout",
"-Wclippy::print_stderr",
"-Wclippy::dbg_macro",
"-Wclippy::empty_drop",
"-Wclippy::empty_structs_with_brackets",
"-Wclippy::exit",
"-Wclippy::get_unwrap",
"-Wclippy::rc_buffer",
"-Wclippy::rc_mutex",
"-Wclippy::rest_pat_in_fully_bound_structs",
]

View File

@@ -26,7 +26,7 @@ jobs:
- name: "PR - Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v1
- uses: Swatinem/rust-cache@v2
- name: "PR - Build benchmarks"
uses: actions-rs/cargo@v1
@@ -75,59 +75,61 @@ jobs:
- run-benchmark
steps:
- name: "Install Rust toolchain"
run: rustup show
- name: "Install Rust toolchain"
run: rustup show
- name: "Install critcmp"
# Use debug build: Building takes much longer than the "slowness" of using the debug build.
run: cargo install --debug critcmp
- name: "Install cargo-binstall"
uses: taiki-e/install-action@cargo-binstall
- name: "Linux | Download PR benchmark results"
uses: actions/download-artifact@v3
with:
name: benchmark-results-ubuntu-latest
path: ./target/criterion
- name: "Install critcmp"
run: cargo binstall critcmp -y
- name: "Linux | Compare benchmark results"
shell: bash
run: |
echo "### Benchmark" >> summary.md
echo "#### Linux" >> summary.md
echo "\`\`\`" >> summary.md
critcmp main pr >> summary.md
echo "\`\`\`" >> summary.md
echo "" >> summary.md
- name: "Linux | Download PR benchmark results"
uses: actions/download-artifact@v3
with:
name: benchmark-results-ubuntu-latest
path: ./target/criterion
- name: "Linux | Cleanup benchmark results"
run: rm -rf ./target/criterion
- name: "Linux | Compare benchmark results"
shell: bash
run: |
echo "### Benchmark" >> summary.md
echo "#### Linux" >> summary.md
echo "\`\`\`" >> summary.md
critcmp main pr >> summary.md
echo "\`\`\`" >> summary.md
echo "" >> summary.md
- name: "Windows | Download PR benchmark results"
uses: actions/download-artifact@v3
with:
name: benchmark-results-windows-latest
path: ./target/criterion
- name: "Linux | Cleanup benchmark results"
run: rm -rf ./target/criterion
- name: "Windows | Compare benchmark results"
shell: bash
run: |
echo "#### Windows" >> summary.md
echo "\`\`\`" >> summary.md
critcmp main pr >> summary.md
echo "\`\`\`" >> summary.md
echo "" >> summary.md
- name: "Windows | Download PR benchmark results"
uses: actions/download-artifact@v3
with:
name: benchmark-results-windows-latest
path: ./target/criterion
echo ${{ github.event.pull_request.number }} > pr-number
- name: "Windows | Compare benchmark results"
shell: bash
run: |
echo "#### Windows" >> summary.md
echo "\`\`\`" >> summary.md
critcmp main pr >> summary.md
echo "\`\`\`" >> summary.md
echo "" >> summary.md
cat summary.md > $GITHUB_STEP_SUMMARY
echo ${{ github.event.pull_request.number }} > pr-number
- uses: actions/upload-artifact@v3
name: Upload PR Number
with:
name: pr-number
path: pr-number
cat summary.md > $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v3
name: Upload Summary
with:
name: summary
path: summary.md
- uses: actions/upload-artifact@v3
name: Upload PR Number
with:
name: pr-number
path: pr-number
- uses: actions/upload-artifact@v3
name: Upload Summary
with:
name: summary
path: summary.md

View File

@@ -85,7 +85,6 @@ jobs:
name: ruff
path: target/debug/ruff
cargo-test-wasm:
runs-on: ubuntu-latest
name: "cargo test (wasm)"
@@ -111,14 +110,16 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: "Install Rust toolchain"
run: rustup show
run: rustup component add rustfmt
- uses: Swatinem/rust-cache@v2
- run: ./scripts/add_rule.py --name DoTheThing --code PLC999 --linter pylint
- run: ./scripts/add_rule.py --name DoTheThing --prefix PL --code C0999 --linter pylint
- run: cargo check
- run: cargo fmt --all --check
- run: |
./scripts/add_plugin.py test --url https://pypi.org/project/-test/0.1.0/ --prefix TST
./scripts/add_rule.py --name FirstRule --code TST001 --linter test
./scripts/add_rule.py --name FirstRule --prefix TST --code 001 --linter test
- run: cargo check
- run: cargo fmt --all --check
typos:
name: "spell check"
@@ -176,3 +177,56 @@ jobs:
with:
name: ecosystem-result
path: ecosystem-result
cargo-udeps:
name: "cargo udeps"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: "Install nightly Rust toolchain"
# Only pinned to make caching work, update freely
run: rustup toolchain install nightly-2023-03-30
- uses: Swatinem/rust-cache@v2
- name: "Install cargo-udeps"
uses: taiki-e/install-action@cargo-udeps
- name: "Run cargo-udeps"
run: |
unused_dependencies=$(cargo +nightly-2023-03-30 udeps > unused.txt && cat unused.txt | cut -d $'\n' -f 2-)
if [ -z "$unused_dependencies" ]; then
echo "No unused dependencies found" > $GITHUB_STEP_SUMMARY
exit 0
else
echo "Found unused dependencies" > $GITHUB_STEP_SUMMARY
echo '```console' >> $GITHUB_STEP_SUMMARY
echo "$unused_dependencies" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit 1
fi
pre-commit:
name: "pre-commit"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: "Install Rust toolchain"
run: rustup show
- uses: Swatinem/rust-cache@v2
- name: "Install pre-commit"
run: pip install pre-commit
- name: "Cache pre-commit"
uses: actions/cache@v3
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: "Run pre-commit"
run: |
echo '```console' > $GITHUB_STEP_SUMMARY
# Enable color output for pre-commit and remove it for the summary
SKIP=cargo-fmt,clippy,dev-generate-all pre-commit run --all-files --show-diff-on-failure --color=always | \
tee >(sed -E 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})*)?[mGK]//g' >> $GITHUB_STEP_SUMMARY) >&1
exit_code=${PIPESTATUS[0]}
echo '```' >> $GITHUB_STEP_SUMMARY
exit $exit_code

View File

@@ -65,6 +65,7 @@ jobs:
then
echo "### Ecosystem" >> $GITHUB_OUTPUT
cat pr/ecosystem/ecosystem-result >> $GITHUB_OUTPUT
echo "" >> $GITHUB_OUTPUT
fi
if [[ -f pr/benchmark/summary.md ]]

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
crates/ruff/resources/test/cpython
mkdocs.yml
.overrides
github_search.jsonl
###
# Rust.gitignore

View File

@@ -28,17 +28,17 @@ repos:
- id: cargo-fmt
name: cargo fmt
entry: cargo fmt --
language: rust
language: system
types: [rust]
- id: clippy
name: clippy
entry: cargo clippy --workspace --all-targets --all-features -- -D warnings
language: rust
language: system
pass_filenames: false
- id: ruff
name: ruff
entry: cargo run -p ruff_cli -- check --no-cache --force-exclude --fix --exit-non-zero-on-fix
language: rust
language: system
types_or: [python, pyi]
require_serial: true
exclude: |
@@ -49,7 +49,7 @@ repos:
- id: dev-generate-all
name: dev-generate-all
entry: cargo dev generate-all
language: rust
language: system
pass_filenames: false
exclude: target

View File

@@ -1,5 +1,40 @@
# Breaking Changes
## 0.0.260
### Fixes are now represented as a list of edits ([#3709](https://github.com/charliermarsh/ruff/pull/3709))
Previously, Ruff represented each fix as a single edit, which prohibited Ruff from automatically
fixing violations that required multiple edits across a file. As such, Ruff now represents each
fix as a list of edits.
This primarily affects the JSON API. Ruff's JSON representation used to represent the `fix` field as
a single edit, like so:
```json
{
"message": "Remove unused import: `sys`",
"content": "",
"location": {"row": 1, "column": 0},
"end_location": {"row": 2, "column": 0}
}
```
The updated representation instead includes a list of edits:
```json
{
"message": "Remove unused import: `sys`",
"edits": [
{
"content": "",
"location": {"row": 1, "column": 0},
"end_location": {"row": 2, "column": 0},
}
]
}
```
## 0.0.246
### `multiple-statements-on-one-line-def` (`E704`) was removed ([#2773](https://github.com/charliermarsh/ruff/pull/2773))
@@ -145,4 +180,4 @@ default.
`pyproject.toml` files are now resolved hierarchically, such that for each Python file, we find
the first `pyproject.toml` file in its path, and use that to determine its lint settings.
See the [README](https://github.com/charliermarsh/ruff#pyprojecttoml-discovery) for more.
See the [documentation](https://beta.ruff.rs/docs/configuration/#python-file-discovery) for more.

View File

@@ -116,8 +116,7 @@ At a high level, the steps involved in adding a new lint rule are as follows:
To define the violation, start by creating a dedicated file for your rule under the appropriate
rule linter (e.g., `crates/ruff/src/rules/flake8_bugbear/rules/abstract_base_class.rs`). That file should
contain a struct defined via `#[violation]`, along with a function that creates the violation
based on any required inputs. (Many of the existing examples live in `crates/ruff/src/violations.rs`,
but we're looking to place new rules in their own files.)
based on any required inputs.
To trigger the violation, you'll likely want to augment the logic in `crates/ruff/src/checkers/ast.rs`,
which defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
@@ -215,6 +214,20 @@ them to [PyPI](https://pypi.org/project/ruff/).
Ruff follows the [semver](https://semver.org/) versioning standard. However, as pre-1.0 software,
even patch releases may contain [non-backwards-compatible changes](https://semver.org/#spec-item-4).
## Ecosystem CI
GitHub Actions will run your changes against a number of real-world projects from GitHub and
report on any diagnostic differences. You can also run those checks locally via:
```shell
python scripts/check_ecosystem.py path/to/your/ruff path/to/older/ruff
```
You can also run the Ecosystem CI check in a Docker container across a larger set of projects by
downloading the [`known-github-tomls.json`](https://github.com/akx/ruff-usage-aggregate/blob/master/data/known-github-tomls.jsonl)
as `github_search.jsonl` and following the instructions in [scripts/Dockerfile.ecosystem](scripts/Dockerfile.ecosystem).
Note that this check will take a while to run.
## Benchmarks
First, clone [CPython](https://github.com/python/cpython). It's a large and diverse Python codebase,

914
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ members = ["crates/*"]
[workspace.package]
edition = "2021"
rust-version = "1.67"
rust-version = "1.69"
homepage = "https://beta.ruff.rs/docs/"
documentation = "https://beta.ruff.rs/docs/"
repository = "https://github.com/charliermarsh/ruff"
@@ -11,7 +11,7 @@ authors = ["Charlie Marsh <charlie.r.marsh@gmail.com>"]
[workspace.dependencies]
anyhow = { version = "1.0.69" }
bitflags = { version = "1.3.2" }
bitflags = { version = "2.1.0" }
chrono = { version = "0.4.23", default-features = false, features = ["clock"] }
clap = { version = "4.1.8", features = ["derive"] }
colored = { version = "2.0.0" }
@@ -24,6 +24,7 @@ is-macro = { version = "0.2.2" }
itertools = { version = "0.10.5" }
libcst = { git = "https://github.com/charliermarsh/LibCST", rev = "80e4c1399f95e5beb532fdd1e209ad2dbb470438" }
log = { version = "0.4.17" }
nohash-hasher = { version = "0.2.0" }
once_cell = { version = "1.17.1" }
path-absolutize = { version = "3.0.14" }
proc-macro2 = { version = "1.0.51" }
@@ -37,21 +38,19 @@ rustpython-parser = { features = [
], git = "https://github.com/RustPython/RustPython.git", rev = "c15f670f2c30cfae6b41a1874893590148c74bc4" }
schemars = { version = "0.8.12" }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.93" }
serde_json = { version = "1.0.93", features = ["preserve_order"] }
shellexpand = { version = "3.0.0" }
similar = { version = "2.2.1" }
smallvec = { version = "1.10.0" }
strum = { version = "0.24.1", features = ["strum_macros"] }
strum_macros = { version = "0.24.3" }
syn = { version = "1.0.109" }
syn = { version = "2.0.15" }
test-case = { version = "3.0.0" }
textwrap = { version = "0.16.0" }
toml = { version = "0.7.2" }
[profile.release]
panic = "abort"
lto = "thin"
codegen-units = 1
opt-level = 3
lto = "fat"
[profile.dev.package.insta]
opt-level = 3

35
LICENSE
View File

@@ -195,6 +195,15 @@ are:
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
- flake8-gettext, licensed as follows:
"""
BSD Zero Clause License
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
- flake8-implicit-str-concat, licensed as follows:
"""
The MIT License (MIT)
@@ -393,7 +402,6 @@ are:
THE SOFTWARE.
"""
- autoflake, licensed as follows:
"""
Copyright (C) 2012-2018 Steven Myint
@@ -417,6 +425,31 @@ are:
SOFTWARE.
"""
- autotyping, licensed as follows:
"""
MIT License
Copyright (c) 2023 Jelle Zijlstra
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
- Flake8, licensed as follows:
"""
== Flake8 License (MIT) ==

171
README.md
View File

@@ -47,16 +47,16 @@ all while executing tens or hundreds of times faster than any individual tool.
Ruff is extremely actively developed and used in major open-source projects like:
- [pandas](https://github.com/pandas-dev/pandas)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
- [Apache Airflow](https://github.com/apache/airflow)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Hugging Face](https://github.com/huggingface/transformers)
- [Pandas](https://github.com/pandas-dev/pandas)
- [SciPy](https://github.com/scipy/scipy)
...and many more.
Read the [launch blog post](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster) or
the most recent [project update](https://notes.crmarsh.com/ruff-the-first-200-releases).
Ruff is backed by [Astral](https://astral.sh). Read the [launch post](https://astral.sh/blog/announcing-astral-the-company-behind-ruff),
or the original [project announcement](https://notes.crmarsh.com/python-tooling-could-be-much-much-faster).
## Testimonials
@@ -137,7 +137,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
```yaml
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.256'
rev: 'v0.0.263'
hooks:
- id: ruff
```
@@ -145,6 +145,20 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com) hook:
Ruff can also be used as a [VS Code extension](https://github.com/charliermarsh/ruff-vscode) or
alongside any other editor through the [Ruff LSP](https://github.com/charliermarsh/ruff-lsp).
Ruff can also be used as a [GitHub Action](https://github.com/features/actions) via
[`ruff-action`](https://github.com/chartboost/ruff-action):
```yaml
name: Ruff
on: [ push, pull_request ]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: chartboost/ruff-action@v1
```
### Configuration
Ruff can be configured through a `pyproject.toml`, `ruff.toml`, or `.ruff.toml` file (see:
@@ -160,7 +174,7 @@ select = ["E", "F"]
ignore = []
# Allow autofix for all enabled rules (when `--fix`) is provided.
fixable = ["A", "B", "C", "D", "E", "F", "..."]
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
unfixable = []
# Exclude a variety of commonly ignored directories.
@@ -227,6 +241,55 @@ stylistic rules made obsolete by the use of an autoformatter, like
If you're just getting started with Ruff, **the default rule set is a great place to start**: it
catches a wide variety of common errors (like unused imports) with zero configuration.
Beyond the defaults, Ruff re-implements some of the most popular Flake8 plugins and related code
quality tools, including:
- [autoflake](https://pypi.org/project/autoflake/)
- [eradicate](https://pypi.org/project/eradicate/)
- [flake8-2020](https://pypi.org/project/flake8-2020/)
- [flake8-annotations](https://pypi.org/project/flake8-annotations/)
- [flake8-bandit](https://pypi.org/project/flake8-bandit/) ([#1646](https://github.com/charliermarsh/ruff/issues/1646))
- [flake8-blind-except](https://pypi.org/project/flake8-blind-except/)
- [flake8-boolean-trap](https://pypi.org/project/flake8-boolean-trap/)
- [flake8-bugbear](https://pypi.org/project/flake8-bugbear/)
- [flake8-builtins](https://pypi.org/project/flake8-builtins/)
- [flake8-commas](https://pypi.org/project/flake8-commas/)
- [flake8-comprehensions](https://pypi.org/project/flake8-comprehensions/)
- [flake8-datetimez](https://pypi.org/project/flake8-datetimez/)
- [flake8-debugger](https://pypi.org/project/flake8-debugger/)
- [flake8-django](https://pypi.org/project/flake8-django/)
- [flake8-docstrings](https://pypi.org/project/flake8-docstrings/)
- [flake8-eradicate](https://pypi.org/project/flake8-eradicate/)
- [flake8-errmsg](https://pypi.org/project/flake8-errmsg/)
- [flake8-executable](https://pypi.org/project/flake8-executable/)
- [flake8-gettext](https://pypi.org/project/flake8-gettext/)
- [flake8-implicit-str-concat](https://pypi.org/project/flake8-implicit-str-concat/)
- [flake8-import-conventions](https://github.com/joaopalmeiro/flake8-import-conventions)
- [flake8-logging-format](https://pypi.org/project/flake8-logging-format/)
- [flake8-no-pep420](https://pypi.org/project/flake8-no-pep420)
- [flake8-pie](https://pypi.org/project/flake8-pie/)
- [flake8-print](https://pypi.org/project/flake8-print/)
- [flake8-pyi](https://pypi.org/project/flake8-pyi/)
- [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style/)
- [flake8-quotes](https://pypi.org/project/flake8-quotes/)
- [flake8-raise](https://pypi.org/project/flake8-raise/)
- [flake8-return](https://pypi.org/project/flake8-return/)
- [flake8-self](https://pypi.org/project/flake8-self/)
- [flake8-simplify](https://pypi.org/project/flake8-simplify/)
- [flake8-super](https://pypi.org/project/flake8-super/)
- [flake8-tidy-imports](https://pypi.org/project/flake8-tidy-imports/)
- [flake8-type-checking](https://pypi.org/project/flake8-type-checking/)
- [flake8-use-pathlib](https://pypi.org/project/flake8-use-pathlib/)
- [isort](https://pypi.org/project/isort/)
- [mccabe](https://pypi.org/project/mccabe/)
- [pandas-vet](https://pypi.org/project/pandas-vet/)
- [pep8-naming](https://pypi.org/project/pep8-naming/)
- [pydocstyle](https://pypi.org/project/pydocstyle/)
- [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) ([#980](https://github.com/charliermarsh/ruff/issues/980))
- [pyupgrade](https://pypi.org/project/pyupgrade/)
- [tryceratops](https://pypi.org/project/tryceratops/)
- [yesqa](https://pypi.org/project/yesqa/)
<!-- End section: Rules -->
For a complete enumeration of the supported rules, see [_Rules_](https://beta.ruff.rs/docs/rules/).
@@ -269,50 +332,68 @@ Ruff is released under the MIT license.
## Who's Using Ruff?
Ruff is used in a number of major open-source projects, including:
Ruff is used by a number of major open-source projects and companies, including:
- [pandas](https://github.com/pandas-dev/pandas)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Transformers (Hugging Face)](https://github.com/huggingface/transformers)
- [Diffusers (Hugging Face)](https://github.com/huggingface/diffusers)
- Amazon ([AWS SAM](https://github.com/aws/serverless-application-model))
- [Apache Airflow](https://github.com/apache/airflow)
- [SciPy](https://github.com/scipy/scipy)
- [Zulip](https://github.com/zulip/zulip)
- [Bokeh](https://github.com/bokeh/bokeh)
- [Pydantic](https://github.com/pydantic/pydantic)
- [Dagster](https://github.com/dagster-io/dagster)
- [Dagger](https://github.com/dagger/dagger)
- [Sphinx](https://github.com/sphinx-doc/sphinx)
- [Hatch](https://github.com/pypa/hatch)
- [PDM](https://github.com/pdm-project/pdm)
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
- [Great Expectations](https://github.com/great-expectations/great_expectations)
- [ONNX](https://github.com/onnx/onnx)
- [Polars](https://github.com/pola-rs/polars)
- [Ibis](https://github.com/ibis-project/ibis)
- [Synapse (Matrix)](https://github.com/matrix-org/synapse)
- [SnowCLI (Snowflake)](https://github.com/Snowflake-Labs/snowcli)
- [Dispatch (Netflix)](https://github.com/Netflix/dispatch)
- [Saleor](https://github.com/saleor/saleor)
- [Pynecone](https://github.com/pynecone-io/pynecone)
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
- [Home Assistant](https://github.com/home-assistant/core)
- [Pylint](https://github.com/PyCQA/pylint)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [build (PyPA)](https://github.com/pypa/build)
- AstraZeneca ([Magnus](https://github.com/AstraZeneca/magnus-core))
- Benchling ([Refac](https://github.com/benchling/refac))
- [Babel](https://github.com/python-babel/babel)
- [Bokeh](https://github.com/bokeh/bokeh)
- [Cryptography (PyCA)](https://github.com/pyca/cryptography)
- [Dagger](https://github.com/dagger/dagger)
- [Dagster](https://github.com/dagster-io/dagster)
- [DVC](https://github.com/iterative/dvc)
- [FastAPI](https://github.com/tiangolo/fastapi)
- [Gradio](https://github.com/gradio-app/gradio)
- [Great Expectations](https://github.com/great-expectations/great_expectations)
- Hugging Face ([Transformers](https://github.com/huggingface/transformers), [Datasets](https://github.com/huggingface/datasets), [Diffusers](https://github.com/huggingface/diffusers))
- [Hatch](https://github.com/pypa/hatch)
- [Home Assistant](https://github.com/home-assistant/core)
- [Ibis](https://github.com/ibis-project/ibis)
- [Jupyter](https://github.com/jupyter-server/jupyter_server)
- [LangChain](https://github.com/hwchase17/langchain)
- [LlamaIndex](https://github.com/jerryjliu/llama_index)
- Matrix ([Synapse](https://github.com/matrix-org/synapse))
- Meltano ([Meltano CLI](https://github.com/meltano/meltano), [Singer SDK](https://github.com/meltano/sdk))
- Modern Treasury ([Python SDK](https://github.com/Modern-Treasury/modern-treasury-python-sdk))
- Mozilla ([Firefox](https://github.com/mozilla/gecko-dev))
- [MegaLinter](https://github.com/oxsecurity/megalinter)
- Microsoft ([Semantic Kernel](https://github.com/microsoft/semantic-kernel), [ONNX Runtime](https://github.com/microsoft/onnxruntime))
- Netflix ([Dispatch](https://github.com/Netflix/dispatch))
- [Neon](https://github.com/neondatabase/neon)
- [ONNX](https://github.com/onnx/onnx)
- [OpenBB](https://github.com/OpenBB-finance/OpenBBTerminal)
- [PDM](https://github.com/pdm-project/pdm)
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
- [Pandas](https://github.com/pandas-dev/pandas)
- [Poetry](https://github.com/python-poetry/poetry)
- [Polars](https://github.com/pola-rs/polars)
- [PostHog](https://github.com/PostHog/posthog)
- Prefect ([Python SDK](https://github.com/PrefectHQ/prefect), [Marvin](https://github.com/PrefectHQ/marvin))
- [Pydantic](https://github.com/pydantic/pydantic)
- [PyInstaller](https://github.com/pyinstaller/pyinstaller)
- [Pylint](https://github.com/PyCQA/pylint)
- [Pynecone](https://github.com/pynecone-io/pynecone)
- [Robyn](https://github.com/sansyrox/robyn)
- Scale AI ([Launch SDK](https://github.com/scaleapi/launch-python-client))
- Snowflake ([SnowCLI](https://github.com/Snowflake-Labs/snowcli))
- [Saleor](https://github.com/saleor/saleor)
- [SciPy](https://github.com/scipy/scipy)
- [Sphinx](https://github.com/sphinx-doc/sphinx)
- [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3)
- [Starlite](https://github.com/starlite-api/starlite)
- [The Algorithms](https://github.com/TheAlgorithms/Python)
- [Vega-Altair](https://github.com/altair-viz/altair)
- WordPress ([Openverse](https://github.com/WordPress/openverse))
- [ZenML](https://github.com/zenml-io/zenml)
- [Zulip](https://github.com/zulip/zulip)
- [build (PyPA)](https://github.com/pypa/build)
- [cibuildwheel (PyPA)](https://github.com/pypa/cibuildwheel)
- [delta-rs](https://github.com/delta-io/delta-rs)
- [featuretools](https://github.com/alteryx/featuretools)
- [meson-python](https://github.com/mesonbuild/meson-python)
- [ZenML](https://github.com/zenml-io/zenml)
- [delta-rs](https://github.com/delta-io/delta-rs)
- [Starlite](https://github.com/starlite-api/starlite)
- [telemetry-airflow (Mozilla)](https://github.com/mozilla/telemetry-airflow)
- [Stable Baselines3](https://github.com/DLR-RM/stable-baselines3)
- [PaddlePaddle](https://github.com/PaddlePaddle/Paddle)
- [nox](https://github.com/wntrblm/nox)
- [Neon](https://github.com/neondatabase/neon)
- [The Algorithms](https://github.com/TheAlgorithms/Python)
## License

View File

@@ -5,3 +5,4 @@ extend-exclude = ["snapshots", "black"]
trivias = "trivias"
hel = "hel"
whos = "whos"
spawnve = "spawnve"

View File

@@ -1,6 +1,6 @@
[package]
name = "flake8-to-ruff"
version = "0.0.256"
version = "0.0.263"
edition = { workspace = true }
rust-version = { workspace = true }

View File

@@ -85,8 +85,9 @@ flake8-to-ruff path/to/.flake8 --plugin flake8-builtins --plugin flake8-quotes
ignore unsupported options in the `.flake8` file (or equivalent). (Similarly, Ruff has a few
configuration options that don't exist in Flake8.)
1. Ruff will omit any rule codes that are unimplemented or unsupported by Ruff, including rule
codes from unsupported plugins. (See the [Ruff README](https://github.com/charliermarsh/ruff#user-content-how-does-ruff-compare-to-flake8)
for the complete list of supported plugins.)
codes from unsupported plugins. (See the
[documentation](https://beta.ruff.rs/docs/faq/#how-does-ruff-compare-to-flake8) for the complete
list of supported plugins.)
## License

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.0.256"
version = "0.0.263"
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
@@ -18,16 +18,18 @@ ruff_cache = { path = "../ruff_cache" }
ruff_diagnostics = { path = "../ruff_diagnostics", features = ["serde"] }
ruff_macros = { path = "../ruff_macros" }
ruff_python_ast = { path = "../ruff_python_ast" }
ruff_python_semantic = { path = "../ruff_python_semantic" }
ruff_python_stdlib = { path = "../ruff_python_stdlib" }
ruff_rustpython = { path = "../ruff_rustpython" }
ruff_text_size = { path = "../ruff_text_size" }
annotate-snippets = { version = "0.9.1", features = ["color"] }
anyhow = { workspace = true }
bisection = { version = "0.1.0" }
bitflags = { workspace = true }
chrono = { workspace = true }
clap = { workspace = true, features = ["derive", "string"], optional = true }
colored = { workspace = true }
dirs = { version = "4.0.0" }
dirs = { version = "5.0.0" }
fern = { version = "0.6.1" }
glob = { workspace = true }
globset = { workspace = true }
@@ -38,7 +40,7 @@ itertools = { workspace = true }
libcst = { workspace = true }
log = { workspace = true }
natord = { version = "1.0.9" }
nohash-hasher = { version = "0.2.0" }
nohash-hasher = { workspace = true }
num-bigint = { version = "0.4.3" }
num-traits = { version = "0.2.15" }
once_cell = { workspace = true }
@@ -47,9 +49,8 @@ path-absolutize = { workspace = true, features = [
"use_unix_paths_on_wasm",
] }
pathdiff = { version = "0.2.1" }
pep440_rs = { git = "https://github.com/konstin/pep440-rs.git", features = [
"serde",
], rev = "a8fef4ec47f4c25b070b39cdbe6a0b9847e49941" }
pep440_rs = { version = "0.3.1", features = ["serde"] }
quick-junit = { version = "0.3.2" }
regex = { workspace = true }
result-like = { version = "0.4.6" }
rustc-hash = { workspace = true }
@@ -58,20 +59,26 @@ rustpython-parser = { workspace = true }
schemars = { workspace = true }
semver = { version = "1.0.16" }
serde = { workspace = true }
serde_json = { workspace = true }
similar = { workspace = true, features = ["inline"] }
shellexpand = { workspace = true }
smallvec = { version = "1.10.0" }
smallvec = { workspace = true }
strum = { workspace = true }
strum_macros = { workspace = true }
textwrap = { workspace = true }
thiserror = { version = "1.0.38" }
toml = { workspace = true }
typed-arena = { version = "2.0.2" }
unicode-width = { version = "0.1.10" }
[dev-dependencies]
criterion = { version = "0.4.0" }
insta = { workspace = true, features = ["yaml", "redactions"] }
insta = { workspace = true }
pretty_assertions = "1.3.0"
test-case = { workspace = true }
# Disable colored output in tests
colored = { workspace = true, features = ["no-color"] }
[features]
default = []
logical_lines = []
jupyter_notebook = []

View File

@@ -2,3 +2,7 @@ avoid-*
do-not-*
uses-*
*-used
rewrite-*
prefer-*
consider-*
use-*

View File

@@ -9,6 +9,7 @@ def foo(x, y, z):
print(x, y, z)
# This is a real comment.
# # This is a (nested) comment.
#return True
return False

View File

@@ -0,0 +1,42 @@
class Foo:
def __str__(self):
...
def __repr__(self):
...
def __len__(self):
...
def __length_hint__(self):
...
def __init__(self):
...
def __del__(self):
...
def __bool__(self):
...
def __bytes__(self):
...
def __format__(self, format_spec):
...
def __contains__(self, item):
...
def __complex__(self):
...
def __int__(self):
...
def __float__(self):
...
def __index__(self):
...

View File

@@ -1,11 +1,13 @@
# Error
assert True
assert True # S101
def fn():
x = 1
assert x == 1 # S101
assert x == 2 # S101
# Error
assert x == 1
# Error
assert x == 2
from typing import TYPE_CHECKING
if TYPE_CHECKING:
assert True # OK

View File

@@ -0,0 +1,3 @@
import pickle
pickle.loads()

View File

@@ -0,0 +1,3 @@
from telnetlib import Telnet
Telnet("localhost", 23)

View File

@@ -0,0 +1,20 @@
from subprocess import Popen, call, check_call, check_output, run
# Check different Popen wrappers are checked.
Popen("true", shell=True)
call("true", shell=True)
check_call("true", shell=True)
check_output("true", shell=True)
run("true", shell=True)
# Check values that truthy values are treated as true.
Popen("true", shell=1)
Popen("true", shell=[1])
Popen("true", shell={1: 1})
Popen("true", shell=(1,))
# Check command argument looks unsafe.
var_string = "true"
Popen(var_string, shell=True)
Popen([var_string], shell=True)
Popen([var_string, ""], shell=True)

View File

@@ -0,0 +1,20 @@
from subprocess import Popen, call, check_call, check_output, run
# Different Popen wrappers are checked.
Popen("true", shell=False)
call("true", shell=False)
check_call("true", shell=False)
check_output("true", shell=False)
run("true", shell=False)
# Values that falsey values are treated as false.
Popen("true", shell=0)
Popen("true", shell=[])
Popen("true", shell={})
Popen("true", shell=None)
# Unknown values are treated as falsey.
Popen("true", shell=True if True else False)
# No value is also caught.
Popen("true")

View File

@@ -0,0 +1,5 @@
def foo(shell):
pass
foo(shell=True)

View File

@@ -0,0 +1,25 @@
import os
import commands
import popen2
# Check all shell functions.
os.system("true")
os.popen("true")
os.popen2("true")
os.popen3("true")
os.popen4("true")
popen2.popen2("true")
popen2.popen3("true")
popen2.popen4("true")
popen2.Popen3("true")
popen2.Popen4("true")
commands.getoutput("true")
commands.getstatusoutput("true")
# Check command argument looks unsafe.
var_string = "true"
os.system(var_string)
os.system([var_string])
os.system([var_string, ""])

View File

@@ -0,0 +1,20 @@
import os
# Check all shell functions.
os.execl("true")
os.execle("true")
os.execlp("true")
os.execlpe("true")
os.execv("true")
os.execve("true")
os.execvp("true")
os.execvpe("true")
os.spawnl("true")
os.spawnle("true")
os.spawnlp("true")
os.spawnlpe("true")
os.spawnv("true")
os.spawnve("true")
os.spawnvp("true")
os.spawnvpe("true")
os.startfile("true")

View File

@@ -0,0 +1,44 @@
import os
# Check all functions.
subprocess.Popen("true")
subprocess.call("true")
subprocess.check_call("true")
subprocess.check_output("true")
subprocess.run("true")
os.system("true")
os.popen("true")
os.popen2("true")
os.popen3("true")
os.popen4("true")
popen2.popen2("true")
popen2.popen3("true")
popen2.popen4("true")
popen2.Popen3("true")
popen2.Popen4("true")
commands.getoutput("true")
commands.getstatusoutput("true")
os.execl("true")
os.execle("true")
os.execlp("true")
os.execlpe("true")
os.execv("true")
os.execve("true")
os.execvp("true")
os.execvpe("true")
os.spawnl("true")
os.spawnle("true")
os.spawnlp("true")
os.spawnlpe("true")
os.spawnv("true")
os.spawnve("true")
os.spawnvp("true")
os.spawnvpe("true")
os.startfile("true")
# Check it does not fail for full paths.
os.system("/bin/ls")
os.system("./bin/ls")
os.system(["/bin/ls"])
os.system(["/bin/ls", "/tmp"])
os.system(r"C:\\bin\ls")

View File

@@ -1,7 +1,9 @@
import collections
import datetime as dt
from decimal import Decimal
import logging
import operator
from pathlib import Path
import random
import re
import time
@@ -165,6 +167,26 @@ def float_str_not_inf_or_nan_is_wrong(value=float("3.14")):
pass
# Allow decimals
def decimal_okay(value=Decimal("0.1")):
pass
# Allow dates
def date_okay(value=dt.date(2023, 3, 27)):
pass
# Allow datetimes
def datetime_okay(value=dt.datetime(2023, 3, 27, 13, 51, 59)):
pass
# Allow timedeltas
def timedelta_okay(value=dt.timedelta(hours=1)):
pass
# Allow paths
def path_okay(value=Path(".")):
pass
# B006 and B008
# We should handle arbitrary nesting of these B008.
def nested_combo(a=[float(3), dt.datetime.now()]):

View File

@@ -1,9 +1,10 @@
"""
Should emit:
B017 - on lines 20
B017 - on lines 23 and 41
"""
import asyncio
import unittest
import pytest
CONSTANT = True
@@ -34,3 +35,14 @@ class Foobar(unittest.TestCase):
def raises_with_absolute_reference(self):
with self.assertRaises(asyncio.CancelledError):
Foo()
def test_pytest_raises():
with pytest.raises(Exception):
raise ValueError("Hello")
with pytest.raises(Exception, "hello"):
raise ValueError("This is fine")
with pytest.raises(Exception, match="hello"):
raise ValueError("This is also fine")

View File

@@ -57,3 +57,9 @@ def foo3():
def foo4():
...
def foo5():
foo.bar # Attribute (raise)
object().__class__ # Attribute (raise)
"foo" + "bar" # BinOp (raise)

View File

@@ -28,6 +28,11 @@ except (ValueError, *(RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (*a, *(RuntimeError, (KeyError, TypeError))): # error
pass
try:
pass
except (ValueError, *(RuntimeError, TypeError)): # ok
@@ -38,10 +43,36 @@ try:
except (ValueError, *[RuntimeError, *(TypeError,)]): # ok
pass
try:
pass
except (*a, *b): # ok
pass
try:
pass
except (*a, *(RuntimeError, TypeError)): # ok
pass
try:
pass
except (*a, *(b, c)): # ok
pass
try:
pass
except (*a, *(*b, *c)): # ok
pass
def what_to_catch():
return ...
try:
pass
except what_to_catch(): # ok
pass
pass

View File

@@ -0,0 +1,187 @@
import itertools
from itertools import groupby
shoppers = ["Jane", "Joe", "Sarah"]
items = [
("lettuce", "greens"),
("tomatoes", "greens"),
("cucumber", "greens"),
("chicken breast", "meats & fish"),
("salmon", "meats & fish"),
("ice cream", "frozen items"),
]
carts = {shopper: [] for shopper in shoppers}
def collect_shop_items(shopper, items):
# Imagine this an expensive database query or calculation that is
# advantageous to batch.
carts[shopper] += items
# Invoking the `groupby` function directly
for _section, section_items in groupby(items, key=lambda p: p[1]):
for shopper in shoppers:
shopper = shopper.title()
collect_shop_items(shopper, section_items) # B031
# We're outside the nested loop and used the group again.
collect_shop_items(shopper, section_items) # B031
for _section, section_items in groupby(items, key=lambda p: p[1]):
collect_shop_items("Jane", section_items)
collect_shop_items("Joe", section_items) # B031
# Make sure to detect in other loop constructs as well - `while` loop
for _section, section_items in groupby(items, key=lambda p: p[1]):
countdown = 3
while countdown > 0:
collect_shop_items(shopper, section_items) # B031
countdown -= 1
# Make sure to detect in other loop constructs as well - `list` comprehension
collection = []
for _section, section_items in groupby(items, key=lambda p: p[1]):
collection.append([list(section_items) for _ in range(3)]) # B031
unique_items = set()
another_set = set()
for _section, section_items in groupby(items, key=lambda p: p[1]):
# For nested loops, it should not flag the usage of the name
for item in section_items:
unique_items.add(item)
# But it should be detected when used again
for item in section_items: # B031
another_set.add(item)
for _section, section_items in groupby(items, key=lambda p: p[1]):
# Variable has been overridden, skip checking
section_items = list(unique_items)
collect_shop_items("Jane", section_items)
collect_shop_items("Jane", section_items)
for _section, section_items in groupby(items, key=lambda p: p[1]):
# Variable has been overridden, skip checking
# Not a realistic situation, just for testing purpose
(section_items := list(unique_items))
collect_shop_items("Jane", section_items)
collect_shop_items("Jane", section_items)
for _section, section_items in groupby(items, key=lambda p: p[1]):
# This is ok
collect_shop_items("Jane", section_items)
# Invocation via the `itertools` module
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
for shopper in shoppers:
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
_ = [collect_shop_items(shopper, section_items) for shopper in shoppers] # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# The variable is overridden, skip checking.
_ = [_ for section_items in range(3)]
_ = [collect_shop_items(shopper, section_items) for shopper in shoppers]
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
_ = [item for item in section_items]
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# The iterator is being used for the second time.
_ = [(item1, item2) for item1 in section_items for item2 in section_items] # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
if _section == "greens":
collect_shop_items(shopper, section_items)
else:
collect_shop_items(shopper, section_items)
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# Mutually exclusive branches shouldn't trigger the warning
if _section == "greens":
collect_shop_items(shopper, section_items)
if _section == "greens":
collect_shop_items(shopper, section_items) # B031
elif _section == "frozen items":
collect_shop_items(shopper, section_items) # B031
else:
collect_shop_items(shopper, section_items) # B031
collect_shop_items(shopper, section_items) # B031
elif _section == "frozen items":
# Mix `match` and `if` statements
match shopper:
case "Jane":
collect_shop_items(shopper, section_items)
if _section == "fourth":
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items)
else:
collect_shop_items(shopper, section_items)
# Now, it should detect
collect_shop_items(shopper, section_items) # B031
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
# Mutually exclusive branches shouldn't trigger the warning
match _section:
case "greens":
collect_shop_items(shopper, section_items)
match shopper:
case "Jane":
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items) # B031
case "frozen items":
collect_shop_items(shopper, section_items)
collect_shop_items(shopper, section_items) # B031
case _:
collect_shop_items(shopper, section_items)
# Now, it should detect
collect_shop_items(shopper, section_items) # B031
for group in groupby(items, key=lambda p: p[1]):
# This is bad, but not detected currently
collect_shop_items("Jane", group[1])
collect_shop_items("Joe", group[1])
# https://github.com/charliermarsh/ruff/issues/4050
for _section, section_items in itertools.groupby(items, key=lambda p: p[1]):
if _section == "greens":
for item in section_items:
collect_shop_items(shopper, item)
elif _section == "frozen items":
_ = [item for item in section_items]
else:
collect_shop_items(shopper, section_items)
# Make sure we ignore - but don't fail on more complicated invocations
for _key, (_value1, _value2) in groupby(
[("a", (1, 2)), ("b", (3, 4)), ("a", (5, 6))], key=lambda p: p[1]
):
collect_shop_items("Jane", group[1])
collect_shop_items("Joe", group[1])
# Make sure we ignore - but don't fail on more complicated invocations
for (_key1, _key2), (_value1, _value2) in groupby(
[(("a", "a"), (1, 2)), (("b", "b"), (3, 4)), (("a", "a"), (5, 6))],
key=lambda p: p[1],
):
collect_shop_items("Jane", group[1])
collect_shop_items("Joe", group[1])
# Let's redefine the `groupby` function to make sure we pick up the correct one.
# NOTE: This should always be at the end of the file.
def groupby(data, key=None):
pass
for name, group in groupby(items):
collect_shop_items("Jane", items)
# This shouldn't be flagged as the `groupby` function is different
collect_shop_items("Joe", items)

View File

@@ -7,11 +7,14 @@ set(set(x))
set(list(x))
set(tuple(x))
set(sorted(x))
set(sorted(x, key=lambda y: y))
set(reversed(x))
sorted(list(x))
sorted(tuple(x))
sorted(sorted(x))
sorted(sorted(x, key=lambda y: y))
sorted(reversed(x))
sorted(list(x), key=lambda y: y)
tuple(
list(
[x, 3, "hell"\

View File

@@ -1,6 +1,19 @@
x = [1, 2, 3]
y = [("a", 1), ("b", 2), ("c", 3)]
z = [(1,), (2,), (3,)]
d = {"a": 1, "b": 2, "c": 3}
[i for i in x]
{i for i in x}
{k: v for k, v in y}
{k: v for k, v in d.items()}
[i for i, in z]
[i for i, j in y]
[i for i in x if i > 1]
[i for i in x for j in x]
{v: k for k, v in y}
{k.foo: k for k in y}
{k["foo"]: k for k in y}
{k: v if v else None for k, v in y}

View File

@@ -0,0 +1,10 @@
dict({})
dict({'a': 1})
dict({'x': 1 for x in range(10)})
dict(
{'x': 1 for x in range(10)}
)
dict({}, a=1)
dict({x: 1 for x in range(1)}, a=1)

View File

@@ -1,11 +1,3 @@
# no error
all((x.id for x in bar))
all(x.id for x in bar)
all(x.id for x in bar)
any(x.id for x in bar)
any({x.id for x in bar})
# PIE 802
any([x.id for x in bar])
all([x.id for x in bar])
any( # first comment
@@ -14,3 +6,14 @@ any( # first comment
all( # first comment
[x.id for x in bar], # second comment
) # third comment
any({x.id for x in bar})
# OK
all(x.id for x in bar)
all(x.id for x in bar)
any(x.id for x in bar)
all((x.id for x in bar))
async def f() -> bool:
return all([await use_greeting(greeting) for greeting in await greetings()])

View File

@@ -0,0 +1,113 @@
from django.db import models
from django.db.models import Model
class StrBeforeRandomField(models.Model):
"""Model with `__str__` before a random property."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return ""
random_property = "foo"
class StrBeforeFieldModel(models.Model):
"""Model with `__str__` before fields."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "foobar"
first_name = models.CharField(max_length=32)
class ManagerBeforeField(models.Model):
"""Model with manager before fields."""
objects = "manager"
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "foobar"
first_name = models.CharField(max_length=32)
class CustomMethodBeforeStr(models.Model):
"""Model with a custom method before `__str__`."""
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def my_method(self):
pass
def __str__(self):
return "foobar"
class GetAbsoluteUrlBeforeSave(Model):
"""Model with `get_absolute_url` method before `save` method.
Subclass this directly using the `Model` class.
"""
def get_absolute_url(self):
pass
def save(self):
pass
class ConstantsAreNotFields(models.Model):
"""Model with an assignment to a constant after `__str__`."""
first_name = models.CharField(max_length=32)
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
pass
MY_CONSTANT = id(1)
class PerfectlyFine(models.Model):
"""Model which has everything in perfect order."""
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
objects = "manager"
class Meta:
verbose_name = "test"
verbose_name_plural = "tests"
def __str__(self):
return "Perfectly fine!"
def save(self, **kwargs):
super(PerfectlyFine, self).save(**kwargs)
def get_absolute_url(self):
return "http://%s" % self
def my_method(self):
pass
@property
def random_property(self):
return "%s" % self

View File

@@ -0,0 +1 @@
_(f"{'value'}")

View File

@@ -0,0 +1 @@
_("{}".format("line"))

View File

@@ -0,0 +1 @@
_("%s" % "line")

View File

@@ -0,0 +1,16 @@
import typing as t # banned
import typing as ty # banned
import numpy as nmp # banned
import numpy as npy # banned
import tensorflow.keras.backend as K # banned
import torch.nn.functional as F # banned
from tensorflow.keras import backend as K # banned
from torch.nn import functional as F # banned
from typing import Any # ok
import numpy as np # ok
import tensorflow as tf # ok
import torch.nn as nn # ok
from tensorflow.keras import backend # ok

View File

@@ -0,0 +1,10 @@
from logging.config import BaseConfigurator # banned
from typing import Any, Dict # banned
from typing import * # banned
from pandas import DataFrame # banned
from pandas import * # banned
import logging.config # ok
import typing # ok
import pandas # ok

View File

@@ -1,3 +1,9 @@
import logging
import logging as foo
logging.info("Hello {}".format("World!"))
logging.log(logging.INFO, "Hello {}".format("World!"))
foo.info("Hello {}".format("World!"))
logging.log(logging.INFO, msg="Hello {}".format("World!"))
logging.log(level=logging.INFO, msg="Hello {}".format("World!"))
logging.log(msg="Hello {}".format("World!"), level=logging.INFO)

View File

@@ -1,3 +1,4 @@
import logging
logging.info("Hello %s" % "World!")
logging.log(logging.INFO, "Hello %s" % "World!")

View File

@@ -1,3 +1,4 @@
import logging
logging.info("Hello" + " " + "World!")
logging.log(logging.INFO, "Hello" + " " + "World!")

View File

@@ -2,3 +2,4 @@ import logging
name = "world"
logging.info(f"Hello {name}")
logging.log(logging.INFO, f"Hello {name}")

View File

@@ -1,3 +1,5 @@
import logging
from distutils import log
logging.warn("Hello World!")
log.warn("Hello world!") # This shouldn't be considered as a logger candidate

View File

@@ -11,3 +11,7 @@ _T = TypeVar("_T") # OK
_TTuple = TypeVarTuple("_TTuple") # OK
_P = ParamSpec("_P") # OK
def f():
T = TypeVar("T") # OK

View File

@@ -11,3 +11,6 @@ _T = TypeVar("_T") # OK
_TTuple = TypeVarTuple("_TTuple") # OK
_P = ParamSpec("_P") # OK
def f():
T = TypeVar("T") # OK

View File

@@ -1,79 +1,161 @@
import math
import os
import sys
from math import inf
import numpy as np
def f12(
x,
y: str = os.pathsep, # OK
) -> None:
...
def f11(*, x: str = "x") -> None: # OK
...
) -> None: ...
def f11(*, x: str = "x") -> None: ... # OK
def f13(
x: list[str] = [
x: list[str] = [ # OK
"foo",
"bar",
"baz",
] # OK
) -> None:
...
]
) -> None: ...
def f14(
x: tuple[str, ...] = (
x: tuple[str, ...] = ( # OK
"foo",
"bar",
"baz",
) # OK
) -> None:
...
)
) -> None: ...
def f15(
x: set[str] = {
x: set[str] = { # OK
"foo",
"bar",
"baz",
} # OK
) -> None:
...
def f16(x: frozenset[bytes] = frozenset({b"foo", b"bar", b"baz"})) -> None: # OK
...
}
) -> None: ...
def f151(x: dict[int, int] = {1: 2}) -> None: ... # Ok
def f152(
x: dict[
int, int
] = { # OK
1: 2,
**{3: 4},
}
) -> None: ...
def f153(
x: list[
int
] = [ # OK
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
]
) -> None: ...
def f154(
x: tuple[
str, tuple[str, ...]
] = ( # OK
"foo",
("bar", "baz"),
)
) -> None: ...
def f141(
x: list[
int
] = [ # OK
*range(10)
],
) -> None: ...
def f142(
x: list[
int
] = list( # OK
range(10)
),
) -> None: ...
def f16(
x: frozenset[
bytes
] = frozenset( # OK
{b"foo", b"bar", b"baz"}
)
) -> None: ...
def f17(
x: str = "foo" + "bar", # OK
) -> None:
...
x: str = "foo" # OK
+ "bar",
) -> None: ...
def f18(
x: str = b"foo" + b"bar", # OK
) -> None:
...
x: str = b"foo" # OK
+ b"bar",
) -> None: ...
def f19(
x: object = "foo" + 4, # OK
) -> None:
...
x: object = "foo" # OK
+ 4,
) -> None: ...
def f20(
x: int = 5 + 5, # OK
) -> None:
...
x: int = 5
+ 5, # OK
) -> None: ...
def f21(
x: complex = 3j - 3j, # OK
) -> None:
...
x: complex = 3j
- 3j, # OK
) -> None: ...
def f22(
x: complex = -42.5j + 4.3j, # OK
) -> None:
...
x: complex = -42.5j # OK
+ 4.3j,
) -> None: ...
def f23(
x: bool = True, # OK
) -> None: ...
def f24(
x: float = 3.14, # OK
) -> None: ...
def f25(
x: float = -3.14, # OK
) -> None: ...
def f26(
x: complex = -3.14j, # OK
) -> None: ...
def f27(
x: complex = -3 - 3.14j, # OK
) -> None: ...
def f28(
x: float = math.tau, # OK
) -> None: ...
def f29(
x: float = math.inf, # OK
) -> None: ...
def f30(
x: float = -math.inf, # OK
) -> None: ...
def f31(
x: float = inf, # OK
) -> None: ...
def f32(
x: float = np.inf, # OK
) -> None: ...
def f33(
x: float = math.nan, # OK
) -> None: ...
def f34(
x: float = -math.nan, # OK
) -> None: ...
def f35(
x: complex = math.inf # OK
+ 1j,
) -> None: ...
def f36(
*,
x: str = sys.version, # OK
) -> None: ...
def f37(
*,
x: str = "" # OK
+ "",
) -> None: ...

View File

@@ -11,32 +11,74 @@ def f12(
) -> None: ...
def f11(*, x: str = "x") -> None: ... # OK
def f13(
x: list[
str
] = [ # Error PYI011 Only simple default values allowed for typed arguments
x: list[str] = [ # OK
"foo",
"bar",
"baz",
]
) -> None: ...
def f14(
x: tuple[
str, ...
] = ( # Error PYI011 Only simple default values allowed for typed arguments
x: tuple[str, ...] = ( # OK
"foo",
"bar",
"baz",
)
) -> None: ...
def f15(
x: set[
str
] = { # Error PYI011 Only simple default values allowed for typed arguments
x: set[str] = { # OK
"foo",
"bar",
"baz",
}
) -> None: ...
def f151(x: dict[int, int] = {1: 2}) -> None: ... # Ok
def f152(
x: dict[
int, int
] = { # Error PYI011 Only simple default values allowed for typed arguments
1: 2,
**{3: 4},
}
) -> None: ...
def f153(
x: list[
int
] = [ # Error PYI011 Only simple default values allowed for typed arguments
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
]
) -> None: ...
def f154(
x: tuple[
str, tuple[str, ...]
] = ( # Error PYI011 Only simple default values allowed for typed arguments
"foo",
("bar", "baz"),
)
) -> None: ...
def f141(
x: list[
int
] = [ # Error PYI011 Only simple default values allowed for typed arguments
*range(10)
],
) -> None: ...
def f142(
x: list[
int
] = list( # Error PYI011 Only simple default values allowed for typed arguments
range(10)
),
) -> None: ...
def f16(
x: frozenset[
bytes
@@ -109,8 +151,11 @@ def f35(
+ 1j,
) -> None: ...
def f36(
*, x: str = sys.version, # OK
*,
x: str = sys.version, # OK
) -> None: ...
def f37(
*, x: str = "" + "", # Error PYI011 Only simple default values allowed for typed arguments
*,
x: str = "" # Error PYI011 Only simple default values allowed for typed arguments
+ "",
) -> None: ...

View File

@@ -0,0 +1,75 @@
# Violations of PYI012
class OneAttributeClass:
value: int
pass # PYI012 Class body must not contain `pass`
class OneAttributeClassRev:
pass # PYI012 Class body must not contain `pass`
value: int
class DocstringClass:
"""
My body only contains pass.
"""
pass # PYI012 Class body must not contain `pass`
class NonEmptyChild(Exception):
value: int
pass # PYI012 Class body must not contain `pass`
class NonEmptyChild2(Exception):
pass # PYI012 Class body must not contain `pass`
value: int
class NonEmptyWithInit:
value: int
pass # PYI012 Class body must not contain `pass`
def __init__():
pass
# Not violations (of PYI012)
class EmptyClass:
pass # Y009 Empty body should contain `...`, not `pass`
class EmptyOneLine:
pass # Y009 Empty body should contain `...`, not `pass`
class Dog:
eyes: int = 2
class EmptyEllipsis:
...
class NonEmptyEllipsis:
value: int
... # Y013 Non-empty class body must not contain `...`
class WithInit:
value: int = 0
def __init__():
pass
def function():
pass
pass

View File

@@ -0,0 +1,59 @@
# Violations of PYI012
class OneAttributeClass:
value: int
pass # PYI012 Class body must not contain `pass`
class OneAttributeClassRev:
pass # PYI012 Class body must not contain `pass`
value: int
class DocstringClass:
"""
My body only contains pass.
"""
pass # PYI012 Class body must not contain `pass`
class NonEmptyChild(Exception):
value: int
pass # PYI012 Class body must not contain `pass`
class NonEmptyChild2(Exception):
pass # PYI012 Class body must not contain `pass`
value: int
class NonEmptyWithInit:
value: int
pass # PYI012 Class body must not contain `pass`
def __init__():
pass
# Not violations (of PYI012)
class EmptyClass:
pass # Y009 Empty body should contain `...`, not `pass`
class EmptyOneLine:
pass # Y009 Empty body should contain `...`, not `pass`
class Dog:
eyes: int = 2
class EmptyEllipsis: ...
class NonEmptyEllipsis:
value: int
... # Y013 Non-empty class body must not contain `...`
class WithInit:
value: int = 0
def __init__():
pass
def function():
pass
pass

View File

@@ -39,6 +39,58 @@ def f15(
...
def f151(x={1: 2}) -> None: # Ok
...
def f152(
x={ # OK
1: 2,
**{3: 4},
}
) -> None:
...
def f153(
x=[ # OK
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
]
) -> None:
...
def f154(
x=( # OK
"foo",
("bar", "baz"),
)
) -> None:
...
def f141(
x=[*range(10)], # OK
) -> None:
...
def f142(
x=list(range(10)), # OK
) -> None:
...
def f16(x=frozenset({b"foo", b"bar", b"baz"})) -> None:
... # OK

View File

@@ -4,26 +4,60 @@ def f12(
) -> None: ...
def f11(*, x="x") -> None: ... # OK
def f13(
x=[ # Error PYI014
x=[ # OK
"foo",
"bar",
"baz",
]
) -> None: ...
def f14(
x=( # Error PYI014
x=( # OK
"foo",
"bar",
"baz",
)
) -> None: ...
def f15(
x={ # Error PYI014
x={ # OK
"foo",
"bar",
"baz",
}
) -> None: ...
def f151(x={1: 2}) -> None: ...
def f152(
x={ # Error PYI014
1: 2,
**{3: 4},
}
) -> None: ...
def f153(
x=[ # Error PYI014
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
]
) -> None: ...
def f154(
x=( # Error PYI014
"foo",
("bar", "baz"),
)
) -> None: ...
def f141(
x=[*range(10)], # Error PYI014
) -> None: ...
def f142(
x=list(range(10)), # Error PYI014
) -> None: ...
def f16(x=frozenset({b"foo", b"bar", b"baz"})) -> None: ... # Error PYI014
def f17(
x="foo" + "bar", # Error PYI014
@@ -44,5 +78,5 @@ def f22(
x=-42.5j + 4.3j, # Error PYI014
) -> None: ...
def f23(
x=True, # OK
x=True, # OK
) -> None: ...

View File

@@ -0,0 +1,93 @@
import builtins
import typing
from typing import TypeAlias, Final
field1: int
field2: int = ...
field3 = ... # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
field4: int = 0
field41: int = 0xFFFFFFFF
field42: int = 1234567890
field43: int = -0xFFFFFFFF
field44: int = -1234567890
field5 = 0 # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int") # Y052 Need type annotation for "field5"
field6 = 0 # Y052 Need type annotation for "field6"
field7 = b"" # Y052 Need type annotation for "field7"
field71 = "foo" # Y052 Need type annotation for "field71"
field72: str = "foo"
field8 = False # Y052 Need type annotation for "field8"
field81 = -1 # Y052 Need type annotation for "field81"
field82: float = -98.43
field83 = -42j # Y052 Need type annotation for "field83"
field84 = 5 + 42j # Y052 Need type annotation for "field84"
field85 = -5 - 42j # Y052 Need type annotation for "field85"
field9 = None # Y026 Use typing_extensions.TypeAlias for type aliases, e.g. "field9: TypeAlias = None"
Field95: TypeAlias = None
Field96: TypeAlias = int | None
Field97: TypeAlias = None | typing.SupportsInt | builtins.str | float | bool
field19 = [1, 2, 3] # Y052 Need type annotation for "field19"
field191: list[int] = [1, 2, 3]
field20 = (1, 2, 3) # Y052 Need type annotation for "field20"
field201: tuple[int, ...] = (1, 2, 3)
field21 = {1, 2, 3} # Y052 Need type annotation for "field21"
field211: set[int] = {1, 2, 3}
field212 = {"foo": "bar"} # Y052 Need type annotation for "field212"
field213: dict[str, str] = {"foo": "bar"}
field22: Final = {"foo": 5}
field221: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] # Y015 Only simple default values are allowed for assignments
field223: list[int] = [*range(10)] # Y015 Only simple default values are allowed for assignments
field224: list[int] = list(range(10)) # Y015 Only simple default values are allowed for assignments
field225: list[object] = [{}, 1, 2] # Y015 Only simple default values are allowed for assignments
field226: tuple[str | tuple[str, ...], ...] = ("foo", ("foo", "bar")) # Y015 Only simple default values are allowed for assignments
field227: dict[str, object] = {"foo": {"foo": "bar"}} # Y015 Only simple default values are allowed for assignments
field228: dict[str, list[object]] = {"foo": []} # Y015 Only simple default values are allowed for assignments
# When parsed, this case results in `None` being placed in the `.keys` list for the `ast.Dict` node
field229: dict[int, int] = {1: 2, **{3: 4}} # Y015 Only simple default values are allowed for assignments
field23 = "foo" + "bar" # Y015 Only simple default values are allowed for assignments
field24 = b"foo" + b"bar" # Y015 Only simple default values are allowed for assignments
field25 = 5 * 5 # Y015 Only simple default values are allowed for assignments
# We shouldn't emit Y015 within functions
def f():
field26: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
# We shouldn't emit Y015 for __slots__ or __match_args__
class Class1:
__slots__ = (
'_one',
'_two',
'_three',
'_four',
'_five',
'_six',
'_seven',
'_eight',
'_nine',
'_ten',
'_eleven',
)
__match_args__ = (
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
'eleven',
)
# We shouldn't emit Y015 for __all__
__all__ = ["Class1"]
# Ignore the following for PYI015
field26 = typing.Sequence[int]
field27 = list[str]
field28 = builtins.str
field29 = str
field30 = str | bytes | None

View File

@@ -0,0 +1,100 @@
import builtins
import typing
from typing import TypeAlias, Final, NewType, TypeVar, TypeVarTuple, ParamSpec
# We shouldn't emit Y015 for simple default values
field1: int
field2: int = ...
field3 = ... # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int")
field4: int = 0
field41: int = 0xFFFFFFFF
field42: int = 1234567890
field43: int = -0xFFFFFFFF
field44: int = -1234567890
field5 = 0 # type: int # Y033 Do not use type comments in stubs (e.g. use "x: int" instead of "x = ... # type: int") # Y052 Need type annotation for "field5"
field6 = 0 # Y052 Need type annotation for "field6"
field7 = b"" # Y052 Need type annotation for "field7"
field71 = "foo" # Y052 Need type annotation for "field71"
field72: str = "foo"
field8 = False # Y052 Need type annotation for "field8"
field81 = -1 # Y052 Need type annotation for "field81"
field82: float = -98.43
field83 = -42j # Y052 Need type annotation for "field83"
field84 = 5 + 42j # Y052 Need type annotation for "field84"
field85 = -5 - 42j # Y052 Need type annotation for "field85"
field9 = None # Y026 Use typing_extensions.TypeAlias for type aliases, e.g. "field9: TypeAlias = None"
Field95: TypeAlias = None
Field96: TypeAlias = int | None
Field97: TypeAlias = None | typing.SupportsInt | builtins.str | float | bool
Field98 = NewType('MyInt', int)
Field99 = TypeVar('Field99')
Field100 = TypeVarTuple('Field100')
Field101 = ParamSpec('Field101')
field19 = [1, 2, 3] # Y052 Need type annotation for "field19"
field191: list[int] = [1, 2, 3]
field20 = (1, 2, 3) # Y052 Need type annotation for "field20"
field201: tuple[int, ...] = (1, 2, 3)
field21 = {1, 2, 3} # Y052 Need type annotation for "field21"
field211: set[int] = {1, 2, 3}
field212 = {"foo": "bar"} # Y052 Need type annotation for "field212"
field213: dict[str, str] = {"foo": "bar"}
field22: Final = {"foo": 5}
# We *should* emit Y015 for more complex default values
field221: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] # Y015 Only simple default values are allowed for assignments
field223: list[int] = [*range(10)] # Y015 Only simple default values are allowed for assignments
field224: list[int] = list(range(10)) # Y015 Only simple default values are allowed for assignments
field225: list[object] = [{}, 1, 2] # Y015 Only simple default values are allowed for assignments
field226: tuple[str | tuple[str, ...], ...] = ("foo", ("foo", "bar")) # Y015 Only simple default values are allowed for assignments
field227: dict[str, object] = {"foo": {"foo": "bar"}} # Y015 Only simple default values are allowed for assignments
field228: dict[str, list[object]] = {"foo": []} # Y015 Only simple default values are allowed for assignments
# When parsed, this case results in `None` being placed in the `.keys` list for the `ast.Dict` node
field229: dict[int, int] = {1: 2, **{3: 4}} # Y015 Only simple default values are allowed for assignments
field23 = "foo" + "bar" # Y015 Only simple default values are allowed for assignments
field24 = b"foo" + b"bar" # Y015 Only simple default values are allowed for assignments
field25 = 5 * 5 # Y015 Only simple default values are allowed for assignments
# We shouldn't emit Y015 within functions
def f():
field26: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
# We shouldn't emit Y015 for __slots__ or __match_args__
class Class1:
__slots__ = (
'_one',
'_two',
'_three',
'_four',
'_five',
'_six',
'_seven',
'_eight',
'_nine',
'_ten',
'_eleven',
)
__match_args__ = (
'one',
'two',
'three',
'four',
'five',
'six',
'seven',
'eight',
'nine',
'ten',
'eleven',
)
# We shouldn't emit Y015 for __all__
__all__ = ["Class1"]
# Ignore the following for PYI015
field26 = typing.Sequence[int]
field27 = list[str]
field28 = builtins.str
field29 = str
field30 = str | bytes | None

View File

@@ -0,0 +1,35 @@
# Shouldn't affect non-union field types.
field1: str
# Should emit for duplicate field types.
field2: str | str # PYI016: Duplicate union member `str`
# Should emit for union types in arguments.
def func1(arg1: int | int): # PYI016: Duplicate union member `int`
print(arg1)
# Should emit for unions in return types.
def func2() -> str | str: # PYI016: Duplicate union member `str`
return "my string"
# Should emit in longer unions, even if not directly adjacent.
field3: str | str | int # PYI016: Duplicate union member `str`
field4: int | int | str # PYI016: Duplicate union member `int`
field5: str | int | str # PYI016: Duplicate union member `str`
field6: int | bool | str | int # PYI016: Duplicate union member `int`
# Shouldn't emit for non-type unions.
field7 = str | str
# Should emit for strangely-bracketed unions.
field8: int | (str | int) # PYI016: Duplicate union member `int`
# Should handle user brackets when fixing.
field9: int | (int | str) # PYI016: Duplicate union member `int`
field10: (str | int) | str # PYI016: Duplicate union member `str`
# Should emit for nested unions.
field11: dict[int | int, str]

View File

@@ -0,0 +1,32 @@
# Shouldn't affect non-union field types.
field1: str
# Should emit for duplicate field types.
field2: str | str # PYI016: Duplicate union member `str`
# Should emit for union types in arguments.
def func1(arg1: int | int): # PYI016: Duplicate union member `int`
print(arg1)
# Should emit for unions in return types.
def func2() -> str | str: # PYI016: Duplicate union member `str`
return "my string"
# Should emit in longer unions, even if not directly adjacent.
field3: str | str | int # PYI016: Duplicate union member `str`
field4: int | int | str # PYI016: Duplicate union member `int`
field5: str | int | str # PYI016: Duplicate union member `str`
field6: int | bool | str | int # PYI016: Duplicate union member `int`
# Shouldn't emit for non-type unions.
field7 = str | str
# Should emit for strangely-bracketed unions.
field8: int | (str | int) # PYI016: Duplicate union member `int`
# Should handle user brackets when fixing.
field9: int | (int | str) # PYI016: Duplicate union member `int`
field10: (str | int) | str # PYI016: Duplicate union member `str`
# Should emit for nested unions.
field11: dict[int | int, str]

View File

@@ -49,3 +49,18 @@ def test_list_expressions(param1, param2):
@pytest.mark.parametrize([some_expr, "param2"], [1, 2, 3])
def test_list_mixed_expr_literal(param1, param2):
...
@pytest.mark.parametrize(("param1, " "param2, " "param3"), [(1, 2, 3), (4, 5, 6)])
def test_implicit_str_concat_with_parens(param1, param2, param3):
...
@pytest.mark.parametrize("param1, " "param2, " "param3", [(1, 2, 3), (4, 5, 6)])
def test_implicit_str_concat_no_parens(param1, param2, param3):
...
@pytest.mark.parametrize((("param1, " "param2, " "param3")), [(1, 2, 3), (4, 5, 6)])
def test_implicit_str_concat_with_multi_parens(param1, param2, param3):
...

View File

@@ -2,3 +2,13 @@ def x(y):
if not y:
return
return None # error
class BaseCache:
def get(self, key: str) -> str | None:
print(f"{key} not found")
return None
def get(self, key: str) -> None:
print(f"{key} not found")
return None

View File

@@ -3,7 +3,7 @@
###
def x():
a = 1
return a # error
return a # RET504
# Can be refactored false positives
@@ -211,10 +211,10 @@ def nonlocal_assignment():
def decorator() -> Flask:
app = Flask(__name__)
@app.route('/hello')
@app.route("/hello")
def hello() -> str:
"""Hello endpoint."""
return 'Hello, World!'
return "Hello, World!"
return app
@@ -222,12 +222,13 @@ def decorator() -> Flask:
def default():
y = 1
def f(x = y) -> X:
def f(x=y) -> X:
return x
return y
# Multiple assignment
def get_queryset(option_1, option_2):
queryset: Any = None
queryset = queryset.filter(a=1)
@@ -246,4 +247,28 @@ def get_queryset():
def get_queryset():
queryset = Model.filter(a=1)
return queryset # error
return queryset # RET504
# Function arguments
def str_to_bool(val):
if isinstance(val, bool):
return val
val = val.strip().lower()
if val in ("1", "true", "yes"):
return True
return False
def str_to_bool(val):
if isinstance(val, bool):
return val
val = 1
return val # RET504
def str_to_bool(val):
if isinstance(val, bool):
return some_obj
return val

View File

@@ -16,15 +16,26 @@ if isinstance(a, int) or isinstance(b, bool) or isinstance(a, float): # SIM101
if (isinstance(a, int) or isinstance(a, float)) and isinstance(b, bool): # SIM101
pass
if isinstance(a.b, int) or isinstance(a.b, float): # SIM101
pass
if isinstance(a(), int) or isinstance(a(), float): # SIM101
pass
if isinstance(a, int) and isinstance(b, bool) or isinstance(a, float):
pass
if isinstance(a, bool) or isinstance(b, str):
pass
if isinstance(a, int) or isinstance(a.b, float):
pass
def f():
# OK
def isinstance(a, b):
return False
if isinstance(a, int) or isinstance(a, float):
pass

View File

@@ -46,10 +46,10 @@ if a:
if b:
c
while True:
while x > 0:
# SIM102
if True:
if True:
if y > 0:
if z > 0:
"""this
is valid"""
@@ -64,8 +64,8 @@ is valid"""
# SIM102
if True:
if True:
if x > 0:
if y > 0:
"""this
is valid"""
@@ -78,7 +78,7 @@ is valid"""
("so is"
"this for some reason")
while True:
while x > 0:
# SIM102
if node.module:
if node.module == "multiprocessing" or node.module.startswith(
@@ -129,3 +129,15 @@ if a:
print("baz")
else:
print("bar")
# OK
if False:
if a:
pass
# OK
if True:
if a:
pass

View File

@@ -59,3 +59,15 @@ def bar():
return foo()
except ValueError:
pass
def with_ellipsis():
try:
foo()
except ValueError:
...
def with_ellipsis_and_return():
try:
return foo()
except ValueError:
...

View File

@@ -9,6 +9,17 @@ os.environ.get('foo', 'bar')
os.getenv('foo')
env = os.environ.get('foo')
env = os.environ['foo']
if env := os.environ.get('foo'):
pass
if env := os.environ['foo']:
pass
# Good
os.environ['FOO']
@@ -17,3 +28,13 @@ os.environ.get('FOO')
os.environ.get('FOO', 'bar')
os.getenv('FOO')
env = os.getenv('FOO')
if env := os.getenv('FOO'):
pass
env = os.environ['FOO']
if env := os.environ['FOO']:
pass

View File

@@ -20,3 +20,5 @@ for key in list(obj.keys()):
{k: k for k in obj.keys()} # SIM118
(k for k in obj.keys()) # SIM118
key in (obj or {}).keys() # SIM118

View File

@@ -1,10 +1,10 @@
if a or True: # SIM223
if a or True: # SIM222
pass
if (a or b) or True: # SIM223
if (a or b) or True: # SIM222
pass
if a or (b or True): # SIM223
if a or (b or True): # SIM222
pass
if a and True: # OK
@@ -16,3 +16,139 @@ if True: # OK
def validate(self, value):
return json.loads(value) or True # OK
if a or f() or b or g() or True: # OK
pass
if a or f() or True or g() or b: # SIM222
pass
if True or f() or a or g() or b: # SIM222
pass
if a or True or f() or b or g(): # SIM222
pass
if a and f() and b and g() and False: # OK
pass
if a and f() and False and g() and b: # OK
pass
if False and f() and a and g() and b: # OK
pass
if a and False and f() and b and g(): # OK
pass
a or "" or True # SIM222
a or "foo" or True or "bar" # SIM222
a or 0 or True # SIM222
a or 1 or True or 2 # SIM222
a or 0.0 or True # SIM222
a or 0.1 or True or 0.2 # SIM222
a or [] or True # SIM222
a or list([]) or True # SIM222
a or [1] or True or [2] # SIM222
a or list([1]) or True or list([2]) # SIM222
a or {} or True # SIM222
a or dict() or True # SIM222
a or {1: 1} or True or {2: 2} # SIM222
a or dict({1: 1}) or True or dict({2: 2}) # SIM222
a or set() or True # SIM222
a or set(set()) or True # SIM222
a or {1} or True or {2} # SIM222
a or set({1}) or True or set({2}) # SIM222
a or () or True # SIM222
a or tuple(()) or True # SIM222
a or (1,) or True or (2,) # SIM222
a or tuple((1,)) or True or tuple((2,)) # SIM222
a or frozenset() or True # SIM222
a or frozenset(frozenset()) or True # SIM222
a or frozenset({1}) or True or frozenset({2}) # SIM222
a or frozenset(frozenset({1})) or True or frozenset(frozenset({2})) # SIM222
# Inside test `a` is simplified.
bool(a or [1] or True or [2]) # SIM222
assert a or [1] or True or [2] # SIM222
if (a or [1] or True or [2]) and (a or [1] or True or [2]): # SIM222
pass
0 if a or [1] or True or [2] else 1 # SIM222
while a or [1] or True or [2]: # SIM222
pass
[
0
for a in range(10)
for b in range(10)
if a or [1] or True or [2] # SIM222
if b or [1] or True or [2] # SIM222
]
{
0
for a in range(10)
for b in range(10)
if a or [1] or True or [2] # SIM222
if b or [1] or True or [2] # SIM222
}
{
0: 0
for a in range(10)
for b in range(10)
if a or [1] or True or [2] # SIM222
if b or [1] or True or [2] # SIM222
}
(
0
for a in range(10)
for b in range(10)
if a or [1] or True or [2] # SIM222
if b or [1] or True or [2] # SIM222
)
# Outside test `a` is not simplified.
a or [1] or True or [2] # SIM222
if (a or [1] or True or [2]) == (a or [1]): # SIM222
pass
if f(a or [1] or True or [2]): # SIM222
pass

View File

@@ -12,3 +12,138 @@ if a or False:
if False:
pass
if a and f() and b and g() and False: # OK
pass
if a and f() and False and g() and b: # SIM223
pass
if False and f() and a and g() and b: # SIM223
pass
if a and False and f() and b and g(): # SIM223
pass
if a or f() or b or g() or True: # OK
pass
if a or f() or True or g() or b: # OK
pass
if True or f() or a or g() or b: # OK
pass
if a or True or f() or b or g(): # OK
pass
a and "" and False # SIM223
a and "foo" and False and "bar" # SIM223
a and 0 and False # SIM223
a and 1 and False and 2 # SIM223
a and 0.0 and False # SIM223
a and 0.1 and False and 0.2 # SIM223
a and [] and False # SIM223
a and list([]) and False # SIM223
a and [1] and False and [2] # SIM223
a and list([1]) and False and list([2]) # SIM223
a and {} and False # SIM223
a and dict() and False # SIM223
a and {1: 1} and False and {2: 2} # SIM223
a and dict({1: 1}) and False and dict({2: 2}) # SIM223
a and set() and False # SIM223
a and set(set()) and False # SIM223
a and {1} and False and {2} # SIM223
a and set({1}) and False and set({2}) # SIM223
a and () and False # SIM222
a and tuple(()) and False # SIM222
a and (1,) and False and (2,) # SIM222
a and tuple((1,)) and False and tuple((2,)) # SIM222
a and frozenset() and False # SIM222
a and frozenset(frozenset()) and False # SIM222
a and frozenset({1}) and False and frozenset({2}) # SIM222
a and frozenset(frozenset({1})) and False and frozenset(frozenset({2})) # SIM222
# Inside test `a` is simplified.
bool(a and [] and False and []) # SIM223
assert a and [] and False and [] # SIM223
if (a and [] and False and []) or (a and [] and False and []): # SIM223
pass
0 if a and [] and False and [] else 1 # SIM222
while a and [] and False and []: # SIM223
pass
[
0
for a in range(10)
for b in range(10)
if a and [] and False and [] # SIM223
if b and [] and False and [] # SIM223
]
{
0
for a in range(10)
for b in range(10)
if a and [] and False and [] # SIM223
if b and [] and False and [] # SIM223
}
{
0: 0
for a in range(10)
for b in range(10)
if a and [] and False and [] # SIM223
if b and [] and False and [] # SIM223
}
(
0
for a in range(10)
for b in range(10)
if a and [] and False and [] # SIM223
if b and [] and False and [] # SIM223
)
# Outside test `a` is not simplified.
a and [] and False and [] # SIM223
if (a and [] and False and []) == (a and []): # SIM223
pass
if f(a and [] and False and []): # SIM223
pass

View File

@@ -0,0 +1,27 @@
# SIM910
{}.get(key, None)
# SIM910
{}.get("key", None)
# OK
{}.get(key)
# OK
{}.get("key")
# OK
{}.get(key, False)
# OK
{}.get("key", False)
# SIM910
if a := {}.get(key, None):
pass
# SIM910
a = {}.get(key, None)
# SIM910
({}).get(key, None)

View File

@@ -7,3 +7,4 @@ from ..protocol import commands, definitions, responses
from ..server import example
from .. import server
from . import logger, models
from ..protocol.UpperCaseModule import some_function

View File

@@ -0,0 +1,2 @@
def some_function():
pass

View File

@@ -31,3 +31,6 @@ typing.TypedDict.anything()
# import aliases are resolved
import typing as totally_not_typing
totally_not_typing.TypedDict
# relative imports are respected
from .typing import TypedDict

View File

@@ -1,11 +0,0 @@
# module members cannot be imported with that syntax
import typing.TypedDict
# we don't track reassignments
import typing, other
typing = other
typing.TypedDict()
# yet another false positive
def foo(typing):
typing.TypedDict()

View File

@@ -1,3 +1,6 @@
from __future__ import annotations
def f():
# Even in strict mode, this shouldn't rase an error, since `pkg` is used at runtime,
# and implicitly imports `pkg.bar`.

View File

@@ -2,7 +2,9 @@ from a import a1 # import_from
from c import * # import_from_star
import a # import
import c.d
from z import z1
import b as b1 # import_as
import z
from ..parent import *
from .my import fn

View File

@@ -0,0 +1,4 @@
from mypackage.subpackage import ( # long comment that seems to be a problem
a_long_variable_name_that_causes_problems,
items,
)

View File

@@ -0,0 +1,3 @@
"""Hello, world!"""
x = 1

View File

@@ -0,0 +1,7 @@
from __future__ import annotations
import os
import sys
import pytz
import django.settings
from library import foo
from . import local

View File

@@ -0,0 +1,8 @@
import sys
import baz
from foo import bar, baz
from foo.bar import blah, blub
from foo.bar.baz import something
import foo
import foo.bar
import foo.bar.baz

View File

@@ -0,0 +1,32 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"print(paste(\"Hello\",\"WoRld\"))\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "R",
"language": "R",
"name": "ir"
},
"language_info": {
"codemirror_mode": "r",
"file_extension": ".r",
"mimetype": "text/x-r-source",
"name": "R",
"pygments_lexer": "r",
"version": "3.2.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env python
# coding: utf-8
# In[1]:
def unused_variable():
x = 1
y = 2
print(f"cell one: {y}")
unused_variable()
# Let's do another mistake
# In[2]:
def mutable_argument(z=set()):
print(f"cell two: {z}")
mutable_argument()

View File

@@ -0,0 +1 @@
broken "§=($/=(")

View File

@@ -0,0 +1,88 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cell one: 2\n"
]
}
],
"source": [
"def unused_variable():\n",
" x = 1\n",
" y = 2\n",
" print(f\"cell one: {y}\")\n",
"\n",
"unused_variable()"
],
"metadata": {
"collapsed": false,
"ExecuteTime": {
"start_time": "2023-03-08T23:01:09.705831Z",
"end_time": "2023-03-08T23:01:09.782916Z"
}
}
},
{
"cell_type": "markdown",
"source": [
"Let's do another mistake"
],
"metadata": {
"collapsed": false
}
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true,
"ExecuteTime": {
"start_time": "2023-03-08T23:01:09.733809Z",
"end_time": "2023-03-08T23:01:09.915760Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"cell two: set()\n"
]
}
],
"source": [
"def mutable_argument(z=set()):\n",
" print(f\"cell two: {z}\")\n",
"\n",
"mutable_argument()\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -18,3 +18,7 @@ if True:
columns=["a"],
axis=1,
)
x.drop(["a"], axis=1, **kwargs, inplace=True)
x.drop(["a"], axis=1, inplace=True, **kwargs)
f(x.drop(["a"], axis=1, inplace=True))

View File

@@ -39,3 +39,11 @@ class Test(unittest.TestCase):
def testTest(self):
assert True
from typing import override
@override
def BAD_FUNC():
pass

View File

@@ -13,3 +13,11 @@ class C:
myObj2 = namedtuple("MyObj2", ["a", "b"])
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
class D(TypedDict):
lower: int
CONSTANT: str
mixedCase: bool
_mixedCase: list
mixed_Case: set

Some files were not shown because too many files have changed in this diff Show More