Skip to content

Commit

Permalink
Merge branch 'main' into simplify2
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Jan 7, 2023
2 parents 70682e2 + bdb9a4d commit d490e47
Show file tree
Hide file tree
Showing 345 changed files with 9,524 additions and 4,740 deletions.
34 changes: 18 additions & 16 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,33 +56,35 @@ prior to merging.

There are four phases to adding a new lint rule:

1. Define the rule in `src/registry.rs`.
2. Define the _logic_ for triggering the rule in `src/checkers/ast.rs` (for AST-based checks),
1. Define the violation in `src/violations.rs` (e.g., `ModuleImportNotAtTopOfFile`).
2. Map the violation to a code in `src/registry.rs` (e.g., `E402`).
3. Define the _logic_ for triggering the violation in `src/checkers/ast.rs` (for AST-based checks),
`src/checkers/tokens.rs` (for token-based checks), or `src/checkers/lines.rs` (for text-based checks).
3. Add a test fixture.
4. Update the generated files (documentation and generated code).
4. Add a test fixture.
5. Update the generated files (documentation and generated code).

To define the rule, open up `src/registry.rs`. You'll need to define both a `CheckCode` and
`CheckKind`. As an example, you can grep for `E402` and `ModuleImportNotAtTopOfFile`, and follow the
pattern implemented therein.
To define the violation, open up `src/violations.rs`, and define a new struct using the
`define_violation!` macro. There are plenty of examples in that file, so feel free to pattern-match
against the existing structs.

To trigger the rule, you'll likely want to augment the logic in `src/checkers/ast.rs`, which defines
the Python AST visitor, responsible for iterating over the abstract syntax tree and collecting
lint-rule violations as it goes. If you need to inspect the AST, you can run
`cargo +nightly dev print-ast` with a Python file. Grep for the `Check::new` invocations to
understand how other, similar rules are implemented.
To trigger the violation, you'll likely want to augment the logic in `src/checkers/ast.rs`, which
defines the Python AST visitor, responsible for iterating over the abstract syntax tree and
collecting diagnostics as it goes.

If you need to inspect the AST, you can run `cargo +nightly dev print-ast` with a Python file. Grep
for the `Check::new` invocations to understand how other, similar rules are implemented.

To add a test fixture, create a file under `resources/test/fixtures/[plugin-name]`, named to match
the `CheckCode` you defined earlier (e.g., `E402.py`). This file should contain a variety of
the code you defined earlier (e.g., `E402.py`). This file should contain a variety of
violations and non-violations designed to evaluate and demonstrate the behavior of your lint rule.

Run `cargo +nightly dev generate-all` to generate the code for your new fixture. Then run Ruff
locally with (e.g.) `cargo run resources/test/fixtures/pycodestyle/E402.py --no-cache --select E402`.

Once you're satisfied with the output, codify the behavior as a snapshot test by adding a new
`test_case` macro in the relevant `src/[plugin-name]/mod.rs` file. Then, run `cargo test`. Your
test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the generated
snapshot, then commit the snapshot file alongside the rest of your changes.
`test_case` macro in the relevant `src/[plugin-name]/mod.rs` file. Then, run `cargo test --all`.
Your test will fail, but you'll be prompted to follow-up with `cargo insta review`. Accept the
generated snapshot, then commit the snapshot file alongside the rest of your changes.

Finally, regenerate the documentation and generated code with `cargo +nightly dev generate-all`.

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ For more, see [flake8-pytest-style](https://pypi.org/project/flake8-pytest-style
| PT006 | ParametrizeNamesWrongType | Wrong name(s) type in `@pytest.mark.parametrize`, expected `tuple` | 🛠 |
| PT007 | ParametrizeValuesWrongType | Wrong values type in `@pytest.mark.parametrize` expected `list` of `tuple` | |
| PT008 | PatchWithLambda | Use `return_value=` instead of patching with `lambda` | |
| PT009 | UnittestAssertion | Use a regular `assert` instead of unittest-style `...` | |
| PT009 | UnittestAssertion | Use a regular `assert` instead of unittest-style `...` | 🛠 |
| PT010 | RaisesWithoutException | set the expected exception in `pytest.raises()` | |
| PT011 | RaisesTooBroad | `pytest.raises(...)` is too broad, set the `match` parameter or use a more specific exception | |
| PT012 | RaisesWithMultipleStatements | `pytest.raises()` block should contain a single simple statement | |
Expand Down Expand Up @@ -985,7 +985,7 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/
| SIM208 | DoubleNegation | Use `expr` instead of `not (not expr)` | 🛠 |
| SIM210 | IfExprWithTrueFalse | Use `bool(expr)` instead of `True if expr else False` | 🛠 |
| SIM211 | IfExprWithFalseTrue | Use `not expr` instead of `False if expr else True` | 🛠 |
| SIM212 | IfExprWithTwistedArms | Use `expr2 if expr2 else expr1` instead of `expr1 if not expr2 else expr2` | 🛠 |
| SIM212 | IfExprWithTwistedArms | Use `body if body else else` instead of `else if not body else body` | 🛠 |
| SIM220 | AAndNotA | Use `False` instead of `... and not ...` | 🛠 |
| SIM221 | AOrNotA | Use `True` instead of `... or not ...` | 🛠 |
| SIM222 | OrTrue | Use `True` instead of `... or True` | 🛠 |
Expand Down
77 changes: 72 additions & 5 deletions resources/test/fixtures/flake8_pytest_style/PT009.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,76 @@
import pytest
import unittest


def test_xxx():
assert 1 == 1 # OK no parameters
class Test(unittest.TestCase):
def test_xxx(self):
assert 1 == 1 # OK no parameters

def test_assert_true(self):
expr = 1
msg = "Must be True"
self.assertTrue(expr) # Error
self.assertTrue(expr=expr) # Error
self.assertTrue(expr, msg) # Error
self.assertTrue(expr=expr, msg=msg) # Error
self.assertTrue(msg=msg, expr=expr) # Error
self.assertTrue(*(expr, msg)) # Error, unfixable
self.assertTrue(**{"expr": expr, "msg": msg}) # Error, unfixable
self.assertTrue(msg=msg, expr=expr, unexpected_arg=False) # Error, unfixable
self.assertTrue(msg=msg) # Error, unfixable

def test_xxx():
self.assertEqual(1, 1) # Error
def test_assert_false(self):
self.assertFalse(True) # Error

def test_assert_equal(self):
self.assertEqual(1, 2) # Error

def test_assert_not_equal(self):
self.assertNotEqual(1, 1) # Error

def test_assert_greater(self):
self.assertGreater(1, 2) # Error

def test_assert_greater_equal(self):
self.assertGreaterEqual(1, 2) # Error

def test_assert_less(self):
self.assertLess(2, 1) # Error

def test_assert_less_equal(self):
self.assertLessEqual(1, 2) # Error

def test_assert_in(self):
self.assertIn(1, [2, 3]) # Error

def test_assert_not_in(self):
self.assertNotIn(2, [2, 3]) # Error

def test_assert_is_none(self):
self.assertIsNone(0) # Error

def test_assert_is_not_none(self):
self.assertIsNotNone(0) # Error

def test_assert_is(self):
self.assertIs([], []) # Error

def test_assert_is_not(self):
self.assertIsNot(1, 1) # Error

def test_assert_is_instance(self):
self.assertIsInstance(1, str) # Error

def test_assert_is_not_instance(self):
self.assertNotIsInstance(1, int) # Error

def test_assert_regex(self):
self.assertRegex("abc", r"def") # Error

def test_assert_not_regex(self):
self.assertNotRegex("abc", r"abc") # Error

def test_assert_regexp_matches(self):
self.assertRegexpMatches("abc", r"def") # Error

def test_assert_not_regexp_matches(self):
self.assertNotRegex("abc", r"abc") # Error
7 changes: 5 additions & 2 deletions resources/test/fixtures/isort/split.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

# isort: split

import a
import b
import c
import d

# isort: split

import a
import b
Loading

0 comments on commit d490e47

Please sign in to comment.