Skip to content

Commit

Permalink
feat: add check for .format() (#7)
Browse files Browse the repository at this point in the history
Adding .format() check, minor testing related fixes.

Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>
  • Loading branch information
henryiii committed Sep 7, 2022
1 parent b85c843 commit 7c7bfc9
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 18 deletions.
11 changes: 5 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,13 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install package
run: python -m pip install .[test]
- name: Install nox
run: python -m pip install nox

- name: Test package
run: python -m pytest -ra

- name: Upload coverage report
uses: codecov/codecov-action@v3.1.0
run: |
nox -s tests
nox -s tests_flake8
dist:
name: Distribution build
Expand Down
2 changes: 0 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ repos:
- id: debug-statements
- id: end-of-file-fixer
- id: mixed-line-ending
- id: name-tests-test
args: ["--pytest-test-first"]
- id: requirements-txt-fixer
- id: trailing-whitespace

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
A checker for flake8 that helps format nice error messages. Currently there are
two checks:

- **EM101**: Check for raw usage of string literals in Exception raising.
- **EM102**: Check for raw usage of f-string literals in Exception raising.
- **EM101**: Check for raw usage of a string literal in Exception raising.
- **EM102**: Check for raw usage of an f-string literal in Exception raising.
- **EM103**: Check for raw usage of `.format` on a string literal in Exception
raising.

The issue is that Python includes the line with the raise in the default
traceback (and most other formatters, like Rich and IPython to too). That means
Expand Down Expand Up @@ -59,7 +61,8 @@ error that is known to be triggerable by a user.
There is one option, `--errmsg-max-string-length`, which defaults to 0 but can
be set to a larger value. The check will ignore string literals shorter than
this length. This option is supported in configuration mode as well. This will
only affect string literals and not f-strings.
only affect string literals and not f-strings. This option is also supported
when running directly, without flake8.

## Usage

Expand All @@ -73,9 +76,6 @@ script entry-point (`pipx run flake8-errmsg <files>`) or module entry-point

## FAQ

Q: Why not look for `"".format()` too? <br/> A: Tools like pyupgrade should help
move to fstrings, so these should be rare. But it would likely be easy to add.

Q: Why Python 3.10+ only? <br/> A: This is a static checker and for developers.
Developers and static checks should be on 3.10 already. And I was lazy and match
statements are fantastic for this sort of thing. And the AST module changed in
Expand Down
1 change: 0 additions & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ def build(session: nox.Session) -> None:
"""
Build an SDist and wheel.
"""

session.install("build")
session.run("python", "-m", "build")

Expand Down
18 changes: 15 additions & 3 deletions src/flake8_errmsg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
Copyright (c) 2022 Henry Schreiner. All rights reserved.
flake8-errmsg: Flake8 checker for raw literals inside raises.
flake8-errmsg: Flake8 checker for raw string literals inside raises.
"""

from __future__ import annotations
Expand All @@ -18,7 +18,7 @@

__all__ = ("__version__", "run_on_file", "main", "ErrMsgASTPlugin")

__version__ = "0.3.0"
__version__ = "0.4.0"


class Flake8ASTErrorInfo(NamedTuple):
Expand All @@ -40,6 +40,13 @@ def visit_Raise(self, node: ast.Raise) -> None:
self.errors.append(EM101(node))
case ast.Call(args=[ast.JoinedStr(), *_]):
self.errors.append(EM102(node))
case ast.Call(
args=[
ast.Call(func=ast.Attribute(attr="format", value=ast.Constant())),
*_,
]
):
self.errors.append(EM103(node))
case _:
pass

Expand All @@ -54,19 +61,24 @@ def EM102(node: ast.AST) -> Flake8ASTErrorInfo:
return Flake8ASTErrorInfo(node.lineno, node.col_offset, msg, Visitor)


def EM103(node: ast.AST) -> Flake8ASTErrorInfo:
msg = "EM103 Exception must not use a .format() string directly, assign to variable first"
return Flake8ASTErrorInfo(node.lineno, node.col_offset, msg, Visitor)


MAX_STRING_LENGTH = 0


@dataclasses.dataclass
class ErrMsgASTPlugin:
# Options have to be class variables in flake8 plugins
max_string_length: ClassVar[int] = 0

tree: ast.AST

_: dataclasses.KW_ONLY
name: str = "flake8_errmsg"
version: str = "0.1.0"
options: Any = None

def run(self) -> Iterator[Flake8ASTErrorInfo]:
visitor = Visitor(self.max_string_length)
Expand Down
15 changes: 15 additions & 0 deletions tests/example1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import annotations


def f_a():
raise RuntimeError("This is an example exception")


def f_b():
example = "example"
raise RuntimeError(f"This is an {example} exception")


def f_c():
msg = "hello"
raise RuntimeError(msg)
16 changes: 16 additions & 0 deletions tests/test_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,19 @@ def test_string_length():
results[0].msg
== "EM102 Exception must not use an f-string literal, assign to variable first"
)


ERR2 = """\
raise RuntimeError("this {} is".format("that"))
"""


def test_err2():
node = ast.parse(ERR2)
results = list(m.ErrMsgASTPlugin(node).run())
assert len(results) == 1
assert results[0].line_number == 1
assert (
results[0].msg
== "EM103 Exception must not use a .format() string directly, assign to variable first"
)

0 comments on commit 7c7bfc9

Please sign in to comment.