Skip to content

Commit

Permalink
Add docs and extra test case
Browse files Browse the repository at this point in the history
  • Loading branch information
RJ722 committed Mar 29, 2020
1 parent de5386f commit d0b6e87
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 29 deletions.
52 changes: 47 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ tool for higher code quality.
* tested: tests itself and has complete test coverage
* complements pyflakes and has the same output syntax
* sorts unused classes and functions by size with `--sort-by-size`
* respects `# noqa` comments
* supports Python 2.7 and Python \>= 3.5

## Installation
Expand Down Expand Up @@ -58,6 +59,16 @@ We collect whitelists for common Python modules and packages in
a whole file or directory, use the `--exclude` parameter (e.g.,
`--exclude *settings.py,docs/`).

The other, more common way of ignoring results is to annotate the line causing
the false positive with `# noqa <ERROR_CODE>` in a trailing comment.

The `ERROR_CODE` specifies what kind of dead code to ignore (see the table
below for details). In case no error code is specified, Vulture ignores all
results for the line.

Note that the line number for any decorated object is the same as the line
number of the first decorator.

**Ignoring names**

You can use `--ignore-names foo*,ba[rz]` to let Vulture ignore all names
Expand Down Expand Up @@ -130,9 +141,9 @@ Calling :

results in the following output:

dead_code.py:1: unused import 'os' (90% confidence)
dead_code.py:4: unused function 'greet' (60% confidence)
dead_code.py:8: unused variable 'message' (60% confidence)
dead_code.py:1: V104 unused import 'os' (90% confidence)
dead_code.py:4: V103 unused function 'greet' (60% confidence)
dead_code.py:8: V106 unused variable 'message' (60% confidence)

Vulture correctly reports "os" and "message" as unused, but it fails to
detect that "greet" is actually used. The recommended method to deal
Expand All @@ -158,8 +169,39 @@ Passing both the original program and the whitelist to Vulture

makes Vulture ignore the `greet` method:

dead_code.py:1: unused import 'os' (90% confidence)
dead_code.py:8: unused variable 'message' (60% confidence)
dead_code.py:1: V104 unused import 'os' (90% confidence)
dead_code.py:8: V106 unused variable 'message' (60% confidence)

**Using "# noqa"**

```python
import os

class Greeter:
def greet(self): # noqa: V103
print("Hi")

def hello_world():
message = "Hello, world!"
greeter = Greeter()
greet_func = getattr(greeter, "greet")
greet_func()

if __name__ == "__main__":
hello_world()
```

## Error codes

| Error Code | Description |
| ---------- | ----------------- |
| V101 | Unused Attribute |
| V102 | Unused Class |
| V103 | Unused Function |
| V104 | Unused Import |
| V105 | Unused Property |
| V106 | Unused Variable |
| V201 | Unreachable Code |

## Exit codes

Expand Down
17 changes: 15 additions & 2 deletions tests/test_noqa.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from vulture.noqa import NOQA_REGEXP, parse_error_codes
from vulture.noqa import NOQA_REGEXP, _parse_error_codes
from . import check, v

assert v # Silence pyflakes.
Expand All @@ -19,7 +19,7 @@
)
def test_noqa_regex_present(line, codes):
match = NOQA_REGEXP.search(line)
parsed = parse_error_codes(match)
parsed = _parse_error_codes(match)
assert parsed == codes


Expand Down Expand Up @@ -277,3 +277,16 @@ def test_noqa_with_invalid_codes(v):
"""
)
check(v.unused_imports, ["this"])


@pytest.mark.parametrize(
"first_file, second_file",
[
("foo = None", "bar = None # noqa"),
("bar = None # noqa", "foo = None"),
],
)
def test_noqa_multiple_files(first_file, second_file, v):
v.scan(first_file, filename="first_file.py")
v.scan(second_file, filename="second_file.py")
check(v.unused_vars, ["foo"])
8 changes: 2 additions & 6 deletions tests/test_script.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import glob
import os.path
import subprocess
import sys
Expand Down Expand Up @@ -61,12 +62,7 @@ def call_vulture_with_excludes(excludes):
return call_vulture(["vulture/", "--exclude", get_csv(excludes)])

assert call_vulture_with_excludes(["core.py", "utils.py"]) == 1
assert (
call_vulture_with_excludes(
["core.py", "utils.py", "lines.py", "noqa.py"]
)
== 0
)
assert call_vulture_with_excludes(glob.glob("vulture/*.py")) == 0


def test_make_whitelist():
Expand Down
13 changes: 5 additions & 8 deletions vulture/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

import argparse
import ast
from collections import defaultdict
from fnmatch import fnmatch, fnmatchcase
import os.path
import pkgutil
Expand Down Expand Up @@ -476,13 +475,11 @@ def _define(
ignore=None,
):
def ignored(lineno):
if (ignore and ignore(self.filename, name)) or _match(
name, self.ignore_names
):
return True

# Check if the reported line is annotated with "# noqa".
return noqa.ignore_line(self.noqa_lines, lineno, typ)
return (
(ignore and ignore(self.filename, name))
or _match(name, self.ignore_names)
or noqa.ignore_line(self.noqa_lines, lineno, ERROR_CODES[typ])
)

last_node = last_node or first_node
typ = collection.typ
Expand Down
12 changes: 4 additions & 8 deletions vulture/noqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
)


def parse_error_codes(match):
def _parse_error_codes(match):
# If no error code is specified, add the line to the "all" category.
return [
c.strip() for c in (match.groupdict()["codes"] or "all").split(",")
Expand All @@ -26,15 +26,11 @@ def parse_noqa(code):
for lineno, line in enumerate(code, start=1):
match = NOQA_REGEXP.search(line)
if match:
for error_code in parse_error_codes(match):
for error_code in _parse_error_codes(match):
noqa_lines[error_code].add(lineno)
return noqa_lines


def ignore_line(noqa_lines, lineno, typ):
def ignore_line(noqa_lines, lineno, error_code):
"""Check if the reported line is annotated with "# noqa"."""
from vulture.core import ERROR_CODES

return (
lineno in noqa_lines[ERROR_CODES[typ]] or lineno in noqa_lines["all"]
)
return lineno in noqa_lines[error_code] or lineno in noqa_lines["all"]

0 comments on commit d0b6e87

Please sign in to comment.