Skip to content

Commit

Permalink
Misc fixes
Browse files Browse the repository at this point in the history
- Update README
- Rename PLU100 -> PLU001
- Fix bug causing two blocks of blank lines with a comment between them
  to count as a single block
- Rename test case files
- Properly exclude test case files from linting
- Remove unused config files
- And more
  • Loading branch information
sorenlind committed Oct 26, 2022
1 parent a7d6c43 commit 58c711f
Show file tree
Hide file tree
Showing 21 changed files with 206 additions and 112 deletions.
14 changes: 7 additions & 7 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[flake8]
max-line-length=88
ignore=
E203, # whitespace before ‘:’
W503, # line break before binary operator
ANN101, # missing type annotation for self in method
ANN102, # missing type annotation for cls in classmethod
E741, # allow variable names I, O and l (but I and O still prevented by pylint)
ANN401, # allow using the Any type hint
E501, # Similar to Pylint line-too-long but Pylint can ignore string literals
E203, # Whitespace before ‘:’
W503, # Line break before binary operator
ANN101, # Missing type annotation for self in method
ANN102, # Missing type annotation for cls in classmethod
E741, # Allow variable names I, O and l (but I and O still prevented by pylint)
ANN401, # Allow using the Any type hint
E501, # Too long lines, handled by Pylint
exclude=
.git,
__pycache__,
Expand Down
3 changes: 2 additions & 1 deletion .markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
},
"MD013": {
"line_length": 88
}
},
"MD014": false
}
1 change: 1 addition & 0 deletions .pydocstyle
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ add-ignore=
D301 # Use r""" if any backslashes in a docstring

match = .*\.py
match-dir = ^(?!(case_files|build))[^\.].*
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,66 @@
# Flake8-plus

Flake8-plus is a plugin for [Flake8](https://github.com/PyCQA/flake8) that detects
incorrect amounts of vertical whitespace before the first toplevel `import` statement.
By default, the plugin issues a warning if there are blank lines immediately preceding
the first toplevel `import`. The plugin can be configured to expect any number of blank
lines.

## Installation

Flake8-plus can be installed from PyPI using `pip`:

```shell
$ pip install flake8-plus
```

You can verify that it has been installed as follows (the version numbers you see may
vary):

```shell
$ flake8 --version
5.0.4 (flake8-plus: 0.1.0, mccabe: 0.7.0, pycodestyle: 2.9.1, pyflakes: 2.5.0)
```

## Configuration

You can set the required number of blank lines before the first `import`. This can be
done from the command line:

```shell
$ flake8 --blanks-before-imports 1
```

Or from one of the `setup.cfg`, `tox.ini`, or `.flake8` files:

```ini
[flake8]
blanks-before-imports=1
```

## Why no blank lines?

Neither Black, Flake8 nor Pylint enforces a specific number of blank lines preceding the
first `import` and consequently there seems to be no consensus or standard. The table
below shows the frequency of the number of blank lines before the first toplevel
`import` statement in the code bases for [Black](https://github.com/psf/black),
[Flake8](https://github.com/PyCQA/flake8) and [Pylint](https://github.com/PyCQA/pylint)
(as of October 2022).

| Package | Total files | 0 blanks | 1 blank | 2 blanks | Folder |
| ------- | ----------: | -------: | ------: | -------: | ------------- |
| Black | 33 | 21 | 12 | 0 | `src` |
| Flake8 | 32 | 32 | 0 | 0 | `src/flake8/` |
| Pylint | 177 | 3 | 170 | 4 | `pylint` |

Clearly, there is no real consensus. Black seems undecided, Flake8 consistently uses 0
blanks, and Pylint seems to prefer 1 blank line. However, it's worth noting that the
Pylint code does not consistently include module docstrings (thereby breaking
`pylint(missing-module-docstring)`). For that reason, and also because this is a Flake8
plugin, the plugin follows the style of Flake8 as the default.

## Reported problems

| Code |  Description |
| ------ | ------------------------------------------------------- |
| PLU001 | "expected {} blank lines before first import, found {}" |
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// language - current active spelling language
"language": "en",
// words - list of words to be always considered correct
"words": ["docstring"],
"words": ["docstring", "docstrings", "toplevel", "Pylint"],
// flagWords - list of words to be always considered incorrect
// This is useful for offensive words and common spelling errors.
// For example "hte" should be "the"
Expand Down
4 changes: 2 additions & 2 deletions flake8_plus/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from . import defaults
from .config import Config
from .version import VERSION
from .visitors.plu100_visitor import PLU100Visitor
from .visitors.plu001_visitor import PLU001Visitor


class Plugin:
Expand All @@ -18,7 +18,7 @@ class Plugin:
name = "flake8-plus"
version = VERSION
visitors = [
PLU100Visitor,
PLU001Visitor,
]

def __init__(self, tree: ast.AST, lines: list[str]):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
"""The flake8-plus visitor."""
"""Exception classes raised by various operations within pylint."""
import ast
from typing import Any

from ..config import Config
from ..problem import Problem


class PLU100Visitor(ast.NodeVisitor):
"""Visitor class for the PLU100 rule."""
class PLU001Visitor(ast.NodeVisitor):
"""Visitor class for the PLU001 rule."""

def __init__(self, lines: list[str], config: Config):
"""
Initialize a PLU100Visitor instance.
Initialize a PLU001Visitor instance.
Args:
lines (list[str]): The physical lines.
Expand Down Expand Up @@ -43,7 +43,7 @@ def _process_node(self, node: ast.AST):
actual = self._compute_blank_before(node.lineno)
if actual != self.config.blanks_before_imports:
message = _build_message(actual, self.config.blanks_before_imports)
problem = Problem(node.lineno, node.col_offset, "PLU100", message)
problem = Problem(node.lineno, node.col_offset, "PLU001", message)
self.problems.append(problem)
elif hasattr(node, "end_lineno") and (node.end_lineno is not None):
self._last_end = node.end_lineno
Expand All @@ -52,9 +52,13 @@ def _compute_blank_before(self, line_number: int) -> int:
if line_number <= (self._last_end + 1):
return 0

line_numbers = range(self._last_end + 1, line_number)
blanks = [l for l in line_numbers if not self._lines[l - 1].strip()]
return len(blanks)
indices_reversed = reversed(range(self._last_end, line_number - 1))
n_blanks = 0
for index in indices_reversed:
if self._lines[index].strip():
break
n_blanks += 1
return n_blanks


def _build_message(blanks_actual: int, blanks_expected: int) -> str:
Expand Down
3 changes: 0 additions & 3 deletions pyproject_.toml

This file was deleted.

1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ def _validate_version(tag: Optional[str], version: str) -> bool:
entry_points={
"flake8.extension": [
"PLU = flake8_plus:Plugin",
# "PLU = flake8_plus:some_func",
],
},
)
37 changes: 0 additions & 37 deletions setup_.cfg

This file was deleted.

80 changes: 80 additions & 0 deletions tests/case_files/plu001/cases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
[
{
"filename": "comments_2_blanks_comment_1_blank.py",
"cases": [
{
"blanks_expected": 0,
"problems": [{ "line": 8, "col": 1, "blanks_before": 1 }]
},
{
"blanks_expected": 1,
"problems": []
}
]
},
{
"filename": "docstring_1_blank.py",
"cases": [
{
"blanks_expected": 0,
"problems": [{ "line": 3, "col": 1, "blanks_before": 1 }]
},
{
"blanks_expected": 1,
"problems": []
}
]
},
{
"filename": "docstring_2_blanks_comment_1_blank.py",
"cases": [
{
"blanks_expected": 0,
"problems": [{ "line": 6, "col": 1, "blanks_before": 1 }]
},
{
"blanks_expected": 1,
"problems": []
}
]
},
{
"filename": "docstring_constant_1_blank.py",
"cases": [
{
"blanks_expected": 0,
"problems": [{ "line": 4, "col": 1, "blanks_before": 1 }]
},
{
"blanks_expected": 1,
"problems": []
}
]
},
{
"filename": "docstring.py",
"cases": [
{
"blanks_expected": 0,
"problems": []
},
{
"blanks_expected": 1,
"problems": [{ "line": 2, "col": 1, "blanks_before": 0 }]
}
]
},
{
"filename": "multiline_docstring_1_blank.py",
"cases": [
{
"blanks_expected": 0,
"problems": [{ "line": 7, "col": 1, "blanks_before": 1 }]
},
{
"blanks_expected": 1,
"problems": []
}
]
}
]
10 changes: 10 additions & 0 deletions tests/case_files/plu001/comments_2_blanks_comment_1_blank.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Comment 1
# Comment 2
# Comment 3


# pylint: disable=duplicate-code

from __future__ import annotations

import collections
File renamed without changes.
8 changes: 8 additions & 0 deletions tests/case_files/plu001/docstring_2_blanks_comment_1_blank.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Docstring."""


# pylint: disable=duplicate-code

from __future__ import annotations

import collections
7 changes: 7 additions & 0 deletions tests/case_files/plu001/multiline_docstring_1_blank.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
Docstring.
Is this blank?
"""

import ast
17 changes: 0 additions & 17 deletions tests/case_files/plu100/bad.py

This file was deleted.

24 changes: 0 additions & 24 deletions tests/case_files/plu100/cases.json

This file was deleted.

Loading

0 comments on commit 58c711f

Please sign in to comment.