diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | checkers/classes.py | 12 | ||||
-rw-r--r-- | test/input/func_bad_context_manager.py | 53 | ||||
-rw-r--r-- | test/messages/func_bad_context_manager.txt | 2 |
4 files changed, 70 insertions, 0 deletions
@@ -2,6 +2,9 @@ ChangeLog for Pylint ==================== -- + * Add 'bad-context-manager' error, checking that '__exit__' + special method accepts the right number of arguments. + * Run pylint as a python module 'python -m pylint' (anatoly techtonik) * Check for non-exception classes inside an except clause diff --git a/checkers/classes.py b/checkers/classes.py index 4c8022d..7ced271 100644 --- a/checkers/classes.py +++ b/checkers/classes.py @@ -152,6 +152,11 @@ MSGS = { 'non-iterator-returned', 'Used when an __iter__ method returns something which is not an \ iterable (i.e. has no `%s` method)' % NEXT_METHOD), + 'E0235': ('__exit__ must accept 3 arguments: type, value, traceback', + 'bad-context-manager', + 'Used when the __exit__ special method, belonging to a \ + context manager, does not accept 3 arguments \ + (type, value, traceback).') } @@ -325,6 +330,8 @@ a metaclass class method.'} # check non-iterators in __iter__ if node.name == '__iter__': self._check_iter(node) + elif node.name == '__exit__': + self._check_exit(node) def _check_iter(self, node): try: @@ -344,6 +351,11 @@ a metaclass class method.'} node=node) break + def _check_exit(self, node): + positional = sum(1 for arg in node.args.args if arg.name != 'self') + if positional != 3 and not node.args.vararg: + self.add_message('bad-context-manager', + node=node) def leave_function(self, node): """on method node, check if this method couldn't be a function diff --git a/test/input/func_bad_context_manager.py b/test/input/func_bad_context_manager.py new file mode 100644 index 0000000..620190d --- /dev/null +++ b/test/input/func_bad_context_manager.py @@ -0,0 +1,53 @@ +"""Check that __exit__ special method accepts 3 arguments """ + +# pylint: disable=too-few-public-methods, invalid-name + +__revision__ = 0 + +class FirstGoodContextManager(object): + """ 3 arguments """ + + def __enter__(self): + return self + + def __exit__(self, exc_type, value, tb): + pass + +class SecondGoodContextManager(object): + """ 3 keyword arguments """ + + def __enter__(self): + return self + + def __exit__(self, exc_type=None, value=None, tb=None): + pass + +class ThirdGoodContextManager(object): + """ 1 argument and variable arguments """ + + def __enter__(self): + return self + + def __exit__(self, exc_type, *args): + pass + +class FirstBadContextManager(object): + """ 1 argument """ + + def __enter__(self): + return self + + def __exit__(self, exc_type): + pass + +class SecondBadContextManager(object): + """ Too many arguments """ + + def __enter__(self): + return self + + def __exit__(self, exc_type, value, tb, stack): + pass + + + diff --git a/test/messages/func_bad_context_manager.txt b/test/messages/func_bad_context_manager.txt new file mode 100644 index 0000000..1111e6d --- /dev/null +++ b/test/messages/func_bad_context_manager.txt @@ -0,0 +1,2 @@ +E: 40:FirstBadContextManager.__exit__: __exit__ must accept 3 arguments: type, value, traceback
+E: 49:SecondBadContextManager.__exit__: __exit__ must accept 3 arguments: type, value, traceback
|