Skip to content

Commit bee559c

Browse files
authoredApr 18, 2021
Merge pull request #157 from ecolell/exception-names
Set N818 to check error suffix on exception names.
2 parents 7cd85f8 + 6d62db8 commit bee559c

File tree

6 files changed

+63
-3
lines changed

6 files changed

+63
-3
lines changed
 

‎README.rst

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ These error codes are emitted:
6767
+------+-------------------------------------------------------+
6868
| N817 | camelcase imported as acronym |
6969
+------+-------------------------------------------------------+
70+
| N818 | error suffix in exception names |
71+
+------+-------------------------------------------------------+
7072

7173
Options
7274
-------

‎run_tests.py

+5
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ class OptionsManager(optparse.OptionParser):
7575
def __init__(self, *args, **kwargs):
7676
optparse.OptionParser.__init__(self, *args, **kwargs)
7777
self.config_options = []
78+
self.ignore = []
79+
80+
def extend_default_ignore(self, new_ignores):
81+
self.ignore += new_ignores
7882

7983

8084
def parse_options(checker, options):
@@ -85,6 +89,7 @@ def parse_options(checker, options):
8589
options_manager.add_option('--ignore', default=[])
8690
options_manager.add_option('--extend-ignore', default=[])
8791
options_manager.add_option('--enable-extensions', default=[])
92+
options_manager.add_option('--extended-default-ignore', default=[])
8893
checker.add_options(options_manager)
8994
processed_options, _ = options_manager.parse_args(options)
9095
checker.parse_options(processed_options)

‎setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def run_tests(self):
4444
license='Expat license',
4545
package_dir={'': 'src'},
4646
py_modules=['pep8ext_naming'],
47-
install_requires=['flake8_polyfill>=1.0.2,<2'],
47+
install_requires=['flake8>=3.9.1', 'flake8_polyfill>=1.0.2,<2'],
4848
zip_safe=False,
4949
entry_points={
5050
'flake8.extension': [

‎src/pep8ext_naming.py

+23
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def add_options(cls, parser):
167167
help='List of method decorators pep8-naming plugin '
168168
'should consider staticmethods (Defaults to '
169169
'%default)')
170+
parser.extend_default_ignore(['N818'])
170171

171172
@classmethod
172173
def parse_options(cls, options):
@@ -291,6 +292,25 @@ class ClassNameCheck(BaseASTCheck):
291292
Classes for internal use have a leading underscore in addition.
292293
"""
293294
N801 = "class name '{name}' should use CapWords convention"
295+
N818 = "exception name '{name}' should be named with an Error suffix"
296+
297+
def get_class_def(self, name, parents):
298+
for parent in parents:
299+
for definition in parent.body:
300+
is_class_definition = isinstance(definition, ast.ClassDef)
301+
if is_class_definition and definition.name == name:
302+
return definition
303+
304+
def superclass_names(self, name, parents):
305+
class_ids = set()
306+
class_def = self.get_class_def(name, parents)
307+
if not class_def:
308+
return class_ids
309+
for base in class_def.bases:
310+
if hasattr(base, "id"):
311+
class_ids.add(base.id)
312+
class_ids.update(self.superclass_names(base.id, parents))
313+
return class_ids
294314

295315
def visit_classdef(self, node, parents, ignore=None):
296316
name = node.name
@@ -299,6 +319,9 @@ def visit_classdef(self, node, parents, ignore=None):
299319
name = name.strip('_')
300320
if not name[:1].isupper() or '_' in name:
301321
yield self.err(node, 'N801', name=name)
322+
superclasses = self.superclass_names(name, parents)
323+
if "Exception" in superclasses and not name.endswith("Error"):
324+
yield self.err(node, 'N818', name=name)
302325

303326

304327
class FunctionNameCheck(BaseASTCheck):

‎testsuite/N818.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#: Okay
2+
class ActionError(Exception):
3+
pass
4+
#: N818
5+
class ActionClass(Exception):
6+
pass
7+
#: Okay
8+
class ActionError(Exception):
9+
pass
10+
class DeepActionError(ActionError):
11+
pass
12+
#: N818
13+
class ActionError(Exception):
14+
pass
15+
class DeepActionClass(ActionError):
16+
pass
17+
#: Okay
18+
class MixinError(Exception):
19+
pass
20+
class Mixin:
21+
pass
22+
class MixinActionError(Mixin, MixinError):
23+
pass
24+
#: N818
25+
class MixinError(Exception):
26+
pass
27+
class Mixin:
28+
pass
29+
class MixinActionClass(Mixin, MixinError):
30+
pass

‎tox.ini

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ commands = python run_tests.py
1717

1818
[testenv:py27-flake8]
1919
deps =
20-
flake8
20+
flake8 >= 3.9.1
2121
commands =
2222
flake8 {posargs} src/pep8ext_naming.py
2323
python setup.py check --restructuredtext
2424

2525
[testenv:py39-flake8]
2626
basepython = python3.9
2727
deps =
28-
flake8
28+
flake8 >= 3.9.1
2929
commands =
3030
flake8 {posargs} src/pep8ext_naming.py
3131
python setup.py check --restructuredtext

0 commit comments

Comments
 (0)
Please sign in to comment.