summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Nowikowski <godfryd@gmail.com>2014-07-25 18:03:11 +0200
committerMichal Nowikowski <godfryd@gmail.com>2014-07-25 18:03:11 +0200
commitc3f867c4c0a014dd8cd79b05b0f0cd974016a8d1 (patch)
tree4863911b60a55aee8d827b671cfb34029243fc13
parent9c6402d7787891d749b36accc9bd61cc0ae1afc6 (diff)
parent997937528f8a1946f4a528ad040139f6ec384a79 (diff)
downloadpylint-c3f867c4c0a014dd8cd79b05b0f0cd974016a8d1.tar.gz
merge
-rw-r--r--ChangeLog17
-rw-r--r--checkers/base.py412
-rw-r--r--checkers/classes.py96
-rw-r--r--checkers/design_analysis.py22
-rw-r--r--checkers/exceptions.py12
-rw-r--r--checkers/format.py90
-rw-r--r--checkers/imports.py18
-rw-r--r--checkers/logging.py42
-rw-r--r--checkers/newstyle.py4
-rw-r--r--checkers/similar.py10
-rw-r--r--checkers/stdlib.py7
-rw-r--r--checkers/strings.py11
-rw-r--r--checkers/typecheck.py67
-rw-r--r--checkers/utils.py29
-rw-r--r--checkers/variables.py41
-rwxr-xr-xepylint.py2
-rw-r--r--examples/pylintrc5
-rw-r--r--gui.py33
-rw-r--r--lint.py120
-rw-r--r--man/pylint.18
-rw-r--r--pyreverse/main.py73
-rw-r--r--pyreverse/writer.py6
-rw-r--r--reporters/text.py6
-rw-r--r--setup.py18
-rw-r--r--test/functional/bad_continuation.py (renamed from test/input/func_bad_continuation.py)6
-rw-r--r--test/functional/bad_continuation.txt63
-rw-r--r--test/functional/cellvar_escaping_loop.py (renamed from test/input/func_loopvar_in_closure.py)20
-rw-r--r--test/functional/cellvar_escaping_loop.txt8
-rw-r--r--test/functional/ctor_arguments.py (renamed from test/input/func_ctor_arguments.py)29
-rw-r--r--test/functional/ctor_arguments.txt17
-rw-r--r--test/functional/exception_is_binary_op.py12
-rw-r--r--test/functional/exception_is_binary_op.txt4
-rw-r--r--test/functional/method_hidden.py (renamed from test/input/func_e0205.py)6
-rw-r--r--test/functional/method_hidden.txt1
-rw-r--r--test/functional/redefined_builtin.py9
-rw-r--r--test/functional/redefined_builtin.txt2
-rw-r--r--test/functional/undefined_variable.py (renamed from test/input/func_undefined_var.py)51
-rw-r--r--test/functional/undefined_variable.txt17
-rw-r--r--test/functional/unnecessary_lambda.py (renamed from test/input/func_w0108.py)90
-rw-r--r--test/functional/unnecessary_lambda.txt7
-rw-r--r--test/functional/useless_else_on_loop.py (renamed from test/input/func_useless_else_on_loop.py)10
-rw-r--r--test/functional/useless_else_on_loop.txt5
-rw-r--r--test/input/func_noerror_9215_lambda_arg_as_decorator.py29
-rw-r--r--test/input/func_w0622.py11
-rw-r--r--test/input/func_w0711.py15
-rw-r--r--test/messages/func_bad_continuation.txt64
-rw-r--r--test/messages/func_ctor_arguments.txt17
-rw-r--r--test/messages/func_e0205.txt2
-rw-r--r--test/messages/func_loopvar_in_closure.txt8
-rw-r--r--test/messages/func_undefined_var.txt14
-rw-r--r--test/messages/func_useless_else_on_loop.txt5
-rw-r--r--test/messages/func_w0108.txt8
-rw-r--r--test/messages/func_w0711.txt4
-rw-r--r--test/test_func.py3
-rw-r--r--test/test_functional.py13
-rw-r--r--testutils.py8
-rw-r--r--utils.py6
57 files changed, 861 insertions, 852 deletions
diff --git a/ChangeLog b/ChangeLog
index bb4bd77..7365516 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,18 @@ ChangeLog for Pylint
or if they are not as expected. New messages: mixed-line-endings,
unexpected-line-ending-format. New option: expected-line-ending-format.
+ * Allow hanging continued indentation for implicitly concatenated
+ strings. Closes issue #232.
+
+ * PyLint works under Python 2.5 again, and its test suite passes.
+
+ * Fix some false positives for the cellvar-from-loop warnings.
+ Closes issue #233.
+
+ * Return new astroid class nodes when the inferencer can detect that
+ that result of a function invocation on a type (like `type` or
+ `abc.ABCMeta`) is requested. Closes #205.
+
* Emit 'undefined-variable' for undefined names when using the
Python 3 `metaclass=` argument.
@@ -52,7 +64,7 @@ ChangeLog for Pylint
* Don't emit 'unused-variable' when assigning to a nonlocal.
Closes issue #275.
-
+
* Do not let ImportError propagate from the import checker, leading to crash
in some namespace package related cases. Closes issue #203.
@@ -1491,3 +1503,6 @@ ChangeLog for Pylint
2003-05-19 -- 0.1
* initial release
+
+
+
diff --git a/checkers/base.py b/checkers/base.py
index 63b153b..fb63c51 100644
--- a/checkers/base.py
+++ b/checkers/base.py
@@ -124,8 +124,8 @@ def _determine_function_name_type(node):
# If the function is a property (decorated with @property
# or @abc.abstractproperty), the name type is 'attr'.
if (isinstance(decorator, astroid.Name) or
- (isinstance(decorator, astroid.Getattr) and
- decorator.attrname == 'abstractproperty')):
+ (isinstance(decorator, astroid.Getattr) and
+ decorator.attrname == 'abstractproperty')):
infered = safe_infer(decorator)
if infered and infered.qname() in PROPERTY_CLASSES:
return 'attr'
@@ -208,7 +208,7 @@ def redefined_by_decorator(node):
if node.decorators:
for decorator in node.decorators.nodes:
if (isinstance(decorator, astroid.Getattr) and
- getattr(decorator.expr, 'name', None) == node.name):
+ getattr(decorator.expr, 'name', None) == node.name):
return True
return False
@@ -218,57 +218,53 @@ class _BasicChecker(BaseChecker):
class BasicErrorChecker(_BasicChecker):
msgs = {
- 'E0100': ('__init__ method is a generator',
- 'init-is-generator',
- 'Used when the special class method __init__ is turned into a '
- 'generator by a yield in its body.'),
- 'E0101': ('Explicit return in __init__',
- 'return-in-init',
- 'Used when the special class method __init__ has an explicit \
- return value.'),
- 'E0102': ('%s already defined line %s',
- 'function-redefined',
- 'Used when a function / class / method is redefined.'),
- 'E0103': ('%r not properly in loop',
- 'not-in-loop',
- 'Used when break or continue keywords are used outside a loop.'),
-
- 'E0104': ('Return outside function',
- 'return-outside-function',
- 'Used when a "return" statement is found outside a function or '
- 'method.'),
- 'E0105': ('Yield outside function',
- 'yield-outside-function',
- 'Used when a "yield" statement is found outside a function or '
- 'method.'),
- 'E0106': ('Return with argument inside generator',
- 'return-arg-in-generator',
- 'Used when a "return" statement with an argument is found '
- 'outside in a generator function or method (e.g. with some '
- '"yield" statements).',
- {'maxversion': (3, 3)}),
- 'E0107': ("Use of the non-existent %s operator",
- 'nonexistent-operator',
- "Used when you attempt to use the C-style pre-increment or"
- "pre-decrement operator -- and ++, which doesn't exist in Python."),
- 'E0108': ('Duplicate argument name %s in function definition',
- 'duplicate-argument-name',
- 'Duplicate argument names in function definitions are syntax'
- ' errors.'),
- 'E0110': ('Abstract class with abstract methods instantiated',
- 'abstract-class-instantiated',
- 'Used when an abstract class with `abc.ABCMeta` as metaclass '
- 'has abstract methods and is instantiated.',
- {'minversion': (3, 0)}),
- 'W0120': ('Else clause on loop without a break statement',
- 'useless-else-on-loop',
- 'Loops should only have an else clause if they can exit early '
- 'with a break statement, otherwise the statements under else '
- 'should be on the same scope as the loop itself.'),
- }
-
- def __init__(self, linter):
- _BasicChecker.__init__(self, linter)
+ 'E0100': ('__init__ method is a generator',
+ 'init-is-generator',
+ 'Used when the special class method __init__ is turned into a '
+ 'generator by a yield in its body.'),
+ 'E0101': ('Explicit return in __init__',
+ 'return-in-init',
+ 'Used when the special class method __init__ has an explicit '
+ 'return value.'),
+ 'E0102': ('%s already defined line %s',
+ 'function-redefined',
+ 'Used when a function / class / method is redefined.'),
+ 'E0103': ('%r not properly in loop',
+ 'not-in-loop',
+ 'Used when break or continue keywords are used outside a loop.'),
+ 'E0104': ('Return outside function',
+ 'return-outside-function',
+ 'Used when a "return" statement is found outside a function or '
+ 'method.'),
+ 'E0105': ('Yield outside function',
+ 'yield-outside-function',
+ 'Used when a "yield" statement is found outside a function or '
+ 'method.'),
+ 'E0106': ('Return with argument inside generator',
+ 'return-arg-in-generator',
+ 'Used when a "return" statement with an argument is found '
+ 'outside in a generator function or method (e.g. with some '
+ '"yield" statements).',
+ {'maxversion': (3, 3)}),
+ 'E0107': ("Use of the non-existent %s operator",
+ 'nonexistent-operator',
+ "Used when you attempt to use the C-style pre-increment or"
+ "pre-decrement operator -- and ++, which doesn't exist in Python."),
+ 'E0108': ('Duplicate argument name %s in function definition',
+ 'duplicate-argument-name',
+ 'Duplicate argument names in function definitions are syntax'
+ ' errors.'),
+ 'E0110': ('Abstract class with abstract methods instantiated',
+ 'abstract-class-instantiated',
+ 'Used when an abstract class with `abc.ABCMeta` as metaclass '
+ 'has abstract methods and is instantiated.',
+ {'minversion': (3, 0)}),
+ 'W0120': ('Else clause on loop without a break statement',
+ 'useless-else-on-loop',
+ 'Loops should only have an else clause if they can exit early '
+ 'with a break statement, otherwise the statements under else '
+ 'should be on the same scope as the loop itself.'),
+ }
@check_messages('function-redefined')
def visit_class(self, node):
@@ -289,11 +285,11 @@ class BasicErrorChecker(_BasicChecker):
else:
values = [r.value for r in returns]
# Are we returning anything but None from constructors
- if [v for v in values if
- not (v is None or
- (isinstance(v, astroid.Const) and v.value is None) or
- (isinstance(v, astroid.Name) and v.name == 'None')
- )]:
+ if [v for v in values
+ if not (v is None or
+ (isinstance(v, astroid.Const) and v.value is None) or
+ (isinstance(v, astroid.Name) and v.name == 'None')
+ )]:
self.add_message('return-in-init', node=node)
elif node.is_generator():
# make sure we don't mix non-None returns and yields
@@ -342,8 +338,8 @@ class BasicErrorChecker(_BasicChecker):
def visit_unaryop(self, node):
"""check use of the non-existent ++ and -- operator operator"""
if ((node.op in '+-') and
- isinstance(node.operand, astroid.UnaryOp) and
- (node.operand.op == node.op)):
+ isinstance(node.operand, astroid.UnaryOp) and
+ (node.operand.op == node.op)):
self.add_message('nonexistent-operator', node=node, args=node.op*2)
@check_messages('abstract-class-instantiated')
@@ -364,14 +360,12 @@ class BasicErrorChecker(_BasicChecker):
# by ClassNode.metaclass()
for ancestor in infered.ancestors():
if (ancestor.qname() == 'abc.ABC' and
- has_abstract_methods(infered)):
-
+ has_abstract_methods(infered)):
self.add_message('abstract-class-instantiated', node=node)
break
return
if (metaclass.qname() == 'abc.ABCMeta' and
- has_abstract_methods(infered)):
-
+ has_abstract_methods(infered)):
self.add_message('abstract-class-instantiated', node=node)
def _check_else_on_loop(self, node):
@@ -417,88 +411,88 @@ functions, methods
name = 'basic'
msgs = {
- 'W0101': ('Unreachable code',
- 'unreachable',
- 'Used when there is some code behind a "return" or "raise" \
- statement, which will never be accessed.'),
- 'W0102': ('Dangerous default value %s as argument',
- 'dangerous-default-value',
- 'Used when a mutable value as list or dictionary is detected in \
- a default value for an argument.'),
- 'W0104': ('Statement seems to have no effect',
- 'pointless-statement',
- 'Used when a statement doesn\'t have (or at least seems to) \
- any effect.'),
- 'W0105': ('String statement has no effect',
- 'pointless-string-statement',
- 'Used when a string is used as a statement (which of course \
- has no effect). This is a particular case of W0104 with its \
- own message so you can easily disable it if you\'re using \
- those strings as documentation, instead of comments.'),
- 'W0106': ('Expression "%s" is assigned to nothing',
- 'expression-not-assigned',
- 'Used when an expression that is not a function call is assigned\
- to nothing. Probably something else was intended.'),
- 'W0108': ('Lambda may not be necessary',
- 'unnecessary-lambda',
- 'Used when the body of a lambda expression is a function call \
- on the same argument list as the lambda itself; such lambda \
- expressions are in all but a few cases replaceable with the \
- function being called in the body of the lambda.'),
- 'W0109': ("Duplicate key %r in dictionary",
- 'duplicate-key',
- "Used when a dictionary expression binds the same key multiple \
- times."),
- 'W0122': ('Use of exec',
- 'exec-used',
- 'Used when you use the "exec" statement (function for Python 3), to discourage its \
- usage. That doesn\'t mean you can not use it !'),
- 'W0123': ('Use of eval',
- 'eval-used',
- 'Used when you use the "eval" function, to discourage its '
- 'usage. Consider using `ast.literal_eval` for safely evaluating '
- 'strings containing Python expressions '
- 'from untrusted sources. '),
- 'W0141': ('Used builtin function %r',
- 'bad-builtin',
- 'Used when a black listed builtin function is used (see the '
- 'bad-function option). Usual black listed functions are the ones '
- 'like map, or filter , where Python offers now some cleaner '
- 'alternative like list comprehension.'),
- 'W0142': ('Used * or ** magic',
- 'star-args',
- 'Used when a function or method is called using `*args` or '
- '`**kwargs` to dispatch arguments. This doesn\'t improve '
- 'readability and should be used with care.'),
- 'W0150': ("%s statement in finally block may swallow exception",
- 'lost-exception',
- "Used when a break or a return statement is found inside the \
- finally clause of a try...finally block: the exceptions raised \
- in the try clause will be silently swallowed instead of being \
- re-raised."),
- 'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?',
- 'assert-on-tuple',
- 'A call of assert on a tuple will always evaluate to true if '
- 'the tuple is not empty, and will always evaluate to false if '
- 'it is.'),
- 'W0121': ('Use raise ErrorClass(args) instead of raise ErrorClass, args.',
- 'old-raise-syntax',
- "Used when the alternate raise syntax 'raise foo, bar' is used "
- "instead of 'raise foo(bar)'.",
- {'maxversion': (3, 0)}),
-
- 'C0121': ('Missing required attribute "%s"', # W0103
- 'missing-module-attribute',
- 'Used when an attribute required for modules is missing.'),
-
- 'E0109': ('Missing argument to reversed()',
- 'missing-reversed-argument',
- 'Used when reversed() builtin didn\'t receive an argument.'),
- 'E0111': ('The first reversed() argument is not a sequence',
- 'bad-reversed-sequence',
- 'Used when the first argument to reversed() builtin '
- 'isn\'t a sequence (does not implement __reversed__, '
- 'nor __getitem__ and __len__'),
+ 'W0101': ('Unreachable code',
+ 'unreachable',
+ 'Used when there is some code behind a "return" or "raise" '
+ 'statement, which will never be accessed.'),
+ 'W0102': ('Dangerous default value %s as argument',
+ 'dangerous-default-value',
+ 'Used when a mutable value as list or dictionary is detected in '
+ 'a default value for an argument.'),
+ 'W0104': ('Statement seems to have no effect',
+ 'pointless-statement',
+ 'Used when a statement doesn\'t have (or at least seems to) '
+ 'any effect.'),
+ 'W0105': ('String statement has no effect',
+ 'pointless-string-statement',
+ 'Used when a string is used as a statement (which of course '
+ 'has no effect). This is a particular case of W0104 with its '
+ 'own message so you can easily disable it if you\'re using '
+ 'those strings as documentation, instead of comments.'),
+ 'W0106': ('Expression "%s" is assigned to nothing',
+ 'expression-not-assigned',
+ 'Used when an expression that is not a function call is assigned '
+ 'to nothing. Probably something else was intended.'),
+ 'W0108': ('Lambda may not be necessary',
+ 'unnecessary-lambda',
+ 'Used when the body of a lambda expression is a function call '
+ 'on the same argument list as the lambda itself; such lambda '
+ 'expressions are in all but a few cases replaceable with the '
+ 'function being called in the body of the lambda.'),
+ 'W0109': ("Duplicate key %r in dictionary",
+ 'duplicate-key',
+ 'Used when a dictionary expression binds the same key multiple '
+ 'times.'),
+ 'W0122': ('Use of exec',
+ 'exec-used',
+ 'Used when you use the "exec" statement (function for Python 3), to discourage its '
+ 'usage. That doesn\'t mean you can not use it !'),
+ 'W0123': ('Use of eval',
+ 'eval-used',
+ 'Used when you use the "eval" function, to discourage its '
+ 'usage. Consider using `ast.literal_eval` for safely evaluating '
+ 'strings containing Python expressions '
+ 'from untrusted sources. '),
+ 'W0141': ('Used builtin function %r',
+ 'bad-builtin',
+ 'Used when a black listed builtin function is used (see the '
+ 'bad-function option). Usual black listed functions are the ones '
+ 'like map, or filter , where Python offers now some cleaner '
+ 'alternative like list comprehension.'),
+ 'W0142': ('Used * or ** magic',
+ 'star-args',
+ 'Used when a function or method is called using `*args` or '
+ '`**kwargs` to dispatch arguments. This doesn\'t improve '
+ 'readability and should be used with care.'),
+ 'W0150': ("%s statement in finally block may swallow exception",
+ 'lost-exception',
+ 'Used when a break or a return statement is found inside the '
+ 'finally clause of a try...finally block: the exceptions raised '
+ 'in the try clause will be silently swallowed instead of being '
+ 're-raised.'),
+ 'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?',
+ 'assert-on-tuple',
+ 'A call of assert on a tuple will always evaluate to true if '
+ 'the tuple is not empty, and will always evaluate to false if '
+ 'it is.'),
+ 'W0121': ('Use raise ErrorClass(args) instead of raise ErrorClass, args.',
+ 'old-raise-syntax',
+ "Used when the alternate raise syntax 'raise foo, bar' is used "
+ "instead of 'raise foo(bar)'.",
+ {'maxversion': (3, 0)}),
+
+ 'C0121': ('Missing required attribute "%s"', # W0103
+ 'missing-module-attribute',
+ 'Used when an attribute required for modules is missing.'),
+
+ 'E0109': ('Missing argument to reversed()',
+ 'missing-reversed-argument',
+ 'Used when reversed() builtin didn\'t receive an argument.'),
+ 'E0111': ('The first reversed() argument is not a sequence',
+ 'bad-reversed-sequence',
+ 'Used when the first argument to reversed() builtin '
+ 'isn\'t a sequence (does not implement __reversed__, '
+ 'nor __getitem__ and __len__'),
}
@@ -507,14 +501,14 @@ functions, methods
'metavar' : '<attributes>',
'help' : 'Required attributes for module, separated by a '
'comma'}
- ),
+ ),
('bad-functions',
{'default' : BAD_FUNCTIONS,
'type' :'csv', 'metavar' : '<builtin function names>',
'help' : 'List of builtins function names that should not be '
'used, separated by a comma'}
- ),
- )
+ ),
+ )
reports = (('RP0101', 'Statistics by type', report_by_type_stats),)
def __init__(self, linter):
@@ -549,7 +543,7 @@ functions, methods
"""check for various kind of statements without effect"""
expr = node.value
if isinstance(expr, astroid.Const) and isinstance(expr.value,
- basestring):
+ basestring):
# treat string statement in a separated message
# Handle PEP-257 attribute docstrings.
# An attribute docstring is defined as being a string right after
@@ -561,7 +555,7 @@ functions, methods
else:
sibling = expr.previous_sibling()
if (sibling.scope() is scope and
- isinstance(sibling, astroid.Assign)):
+ isinstance(sibling, astroid.Assign)):
return
self.add_message('pointless-string-statement', node=node)
return
@@ -572,11 +566,12 @@ functions, methods
# warn W0106 if we have any underlying function call (we can't predict
# side effects), else pointless-statement
if (isinstance(expr, (astroid.Yield, astroid.CallFunc)) or
- (isinstance(node.parent, astroid.TryExcept) and
- node.parent.body == [node])):
+ (isinstance(node.parent, astroid.TryExcept) and
+ node.parent.body == [node])):
return
if any(expr.nodes_of_class(astroid.CallFunc)):
- self.add_message('expression-not-assigned', node=node, args=expr.as_string())
+ self.add_message('expression-not-assigned', node=node,
+ args=expr.as_string())
else:
self.add_message('pointless-statement', node=node)
@@ -609,15 +604,15 @@ functions, methods
ordinary_args = list(node.args.args)
if node.args.kwarg:
if (not call.kwargs
- or not isinstance(call.kwargs, astroid.Name)
- or node.args.kwarg != call.kwargs.name):
+ or not isinstance(call.kwargs, astroid.Name)
+ or node.args.kwarg != call.kwargs.name):
return
elif call.kwargs:
return
if node.args.vararg:
if (not call.starargs
- or not isinstance(call.starargs, astroid.Name)
- or node.args.vararg != call.starargs.name):
+ or not isinstance(call.starargs, astroid.Name)
+ or node.args.vararg != call.starargs.name):
return
elif call.starargs:
return
@@ -630,6 +625,11 @@ functions, methods
return
if node.args.args[i].name != call.args[i].name:
return
+ if (isinstance(node.body.func, astroid.Getattr) and
+ isinstance(node.body.func.expr, astroid.CallFunc)):
+ # Chained call, the intermediate call might
+ # return something else (but we don't check that, yet).
+ return
self.add_message('unnecessary-lambda', line=node.fromlineno, node=node)
@check_messages('dangerous-default-value')
@@ -646,7 +646,7 @@ functions, methods
continue
builtins = astroid.bases.BUILTINS
if (isinstance(value, astroid.Instance) and
- value.qname() in ['.'.join([builtins, x]) for x in ('set', 'dict', 'list')]):
+ value.qname() in ['.'.join([builtins, x]) for x in ('set', 'dict', 'list')]):
if value is default:
msg = default.as_string()
elif type(value) is astroid.Instance:
@@ -702,7 +702,7 @@ functions, methods
self.add_message('exec-used', node=node)
@check_messages('bad-builtin', 'star-args', 'eval-used',
- 'exec-used', 'missing-reversed-argument',
+ 'exec-used', 'missing-reversed-argument',
'bad-reversed-sequence')
def visit_callfunc(self, node):
"""visit a CallFunc node -> check if this is not a blacklisted builtin
@@ -739,7 +739,7 @@ functions, methods
def visit_assert(self, node):
"""check the use of an assert statement on a tuple."""
if node.fail is None and isinstance(node.test, astroid.Tuple) and \
- len(node.test.elts) == 2:
+ len(node.test.elts) == 2:
self.add_message('assert-on-tuple', node=node)
@check_messages('duplicate-key')
@@ -784,7 +784,7 @@ functions, methods
return
_node = _parent
_parent = _node.parent
-
+
def _check_reversed(self, node):
""" check that the argument to `reversed` is a sequence """
try:
@@ -803,17 +803,17 @@ functions, methods
except InferenceError:
return
if (getattr(func, 'name', None) == 'iter' and
- is_builtin_object(func)):
+ is_builtin_object(func)):
self.add_message('bad-reversed-sequence', node=node)
return
if isinstance(argument, astroid.Instance):
- if (argument._proxied.name == 'dict' and
- is_builtin_object(argument._proxied)):
- self.add_message('bad-reversed-sequence', node=node)
- return
+ if (argument._proxied.name == 'dict' and
+ is_builtin_object(argument._proxied)):
+ self.add_message('bad-reversed-sequence', node=node)
+ return
elif any(ancestor.name == 'dict' and is_builtin_object(ancestor)
- for ancestor in argument._proxied.ancestors()):
+ for ancestor in argument._proxied.ancestors()):
# mappings aren't accepted by reversed()
self.add_message('bad-reversed-sequence', node=node)
return
@@ -826,10 +826,10 @@ functions, methods
break
else:
break
- else:
+ else:
# check if it is a .deque. It doesn't seem that
- # we can retrieve special methods
- # from C implemented constructs
+ # we can retrieve special methods
+ # from C implemented constructs
if argument._proxied.qname().endswith(".deque"):
return
self.add_message('bad-reversed-sequence', node=node)
@@ -855,53 +855,51 @@ def _create_naming_options():
for name_type, (rgx, human_readable_name) in _NAME_TYPES.iteritems():
name_type = name_type.replace('_', '-')
name_options.append((
- '%s-rgx' % (name_type,),
+ '%s-rgx' % (name_type,),
{'default': rgx, 'type': 'regexp', 'metavar': '<regexp>',
'help': 'Regular expression matching correct %s names' % (human_readable_name,)}))
name_options.append((
- '%s-name-hint' % (name_type,),
+ '%s-name-hint' % (name_type,),
{'default': rgx.pattern, 'type': 'string', 'metavar': '<string>',
'help': 'Naming hint for %s names' % (human_readable_name,)}))
-
- return tuple(name_options)
+ return tuple(name_options)
class NameChecker(_BasicChecker):
msgs = {
- 'C0102': ('Black listed name "%s"',
- 'blacklisted-name',
- 'Used when the name is listed in the black list (unauthorized \
- names).'),
- 'C0103': ('Invalid %s name "%s"%s',
- 'invalid-name',
- 'Used when the name doesn\'t match the regular expression \
- associated to its type (constant, variable, class...).'),
+ 'C0102': ('Black listed name "%s"',
+ 'blacklisted-name',
+ 'Used when the name is listed in the black list (unauthorized '
+ 'names).'),
+ 'C0103': ('Invalid %s name "%s"%s',
+ 'invalid-name',
+ 'Used when the name doesn\'t match the regular expression '
+ 'associated to its type (constant, variable, class...).'),
}
- options = (# XXX use set
- ('good-names',
+ options = (('good-names',
{'default' : ('i', 'j', 'k', 'ex', 'Run', '_'),
'type' :'csv', 'metavar' : '<names>',
'help' : 'Good variable names which should always be accepted,'
' separated by a comma'}
- ),
+ ),
('bad-names',
{'default' : ('foo', 'bar', 'baz', 'toto', 'tutu', 'tata'),
'type' :'csv', 'metavar' : '<names>',
'help' : 'Bad variable names which should always be refused, '
'separated by a comma'}
- ),
+ ),
('name-group',
{'default' : (),
'type' :'csv', 'metavar' : '<name1:name2>',
'help' : ('Colon-delimited sets of names that determine each'
' other\'s naming style when the name regexes'
' allow several styles.')}
- ),
+ ),
('include-naming-hint',
{'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
'help': 'Include a hint for the correct naming format with invalid-name'}
- ),
- ) + _create_naming_options()
+ ),
+ ) + _create_naming_options()
def __init__(self, linter):
@@ -1023,30 +1021,30 @@ class NameChecker(_BasicChecker):
class DocStringChecker(_BasicChecker):
msgs = {
- 'C0111': ('Missing %s docstring', # W0131
- 'missing-docstring',
- 'Used when a module, function, class or method has no docstring.\
- Some special methods like __init__ doesn\'t necessary require a \
- docstring.'),
- 'C0112': ('Empty %s docstring', # W0132
- 'empty-docstring',
- 'Used when a module, function, class or method has an empty \
- docstring (it would be too easy ;).'),
- }
+ 'C0111': ('Missing %s docstring', # W0131
+ 'missing-docstring',
+ 'Used when a module, function, class or method has no docstring.'
+ 'Some special methods like __init__ doesn\'t necessary require a '
+ 'docstring.'),
+ 'C0112': ('Empty %s docstring', # W0132
+ 'empty-docstring',
+ 'Used when a module, function, class or method has an empty '
+ 'docstring (it would be too easy ;).'),
+ }
options = (('no-docstring-rgx',
{'default' : NO_REQUIRED_DOC_RGX,
'type' : 'regexp', 'metavar' : '<regexp>',
'help' : 'Regular expression which should only match '
'function or class names that do not require a '
'docstring.'}
- ),
+ ),
('docstring-min-length',
{'default' : -1,
'type' : 'int', 'metavar' : '<int>',
'help': ('Minimum line length for functions/classes that'
' require docstrings, shorter ones are exempt.')}
- ),
- )
+ ),
+ )
def open(self):
@@ -1106,7 +1104,7 @@ class PassChecker(_BasicChecker):
'unnecessary-pass',
'Used when a "pass" statement that can be avoided is '
'encountered.'),
- }
+ }
@check_messages('unnecessary-pass')
def visit_pass(self, node):
if len(node.parent.child_sequence(node)) > 1:
@@ -1126,7 +1124,7 @@ class LambdaForComprehensionChecker(_BasicChecker):
'"filter". It could be clearer as a list '
'comprehension or generator expression.',
{'maxversion': (3, 0)}),
- }
+ }
@check_messages('deprecated-lambda')
def visit_callfunc(self, node):
@@ -1139,7 +1137,7 @@ class LambdaForComprehensionChecker(_BasicChecker):
return
infered = safe_infer(node.func)
if (is_builtin_object(infered)
- and infered.name in ['map', 'filter']):
+ and infered.name in ['map', 'filter']):
self.add_message('deprecated-lambda', node=node)
diff --git a/checkers/classes.py b/checkers/classes.py
index 570f7ac..61769f2 100644
--- a/checkers/classes.py
+++ b/checkers/classes.py
@@ -20,14 +20,14 @@ from __future__ import generators
import sys
import astroid
-from astroid import YES, Instance, are_exclusive, AssAttr
+from astroid import YES, Instance, are_exclusive, AssAttr, Class
from astroid.bases import Generator
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
-from pylint.checkers.utils import (PYMETHODS, overrides_a_method,
- check_messages, is_attr_private, is_attr_protected, node_frame_class,
- safe_infer)
+from pylint.checkers.utils import (
+ PYMETHODS, overrides_a_method, check_messages, is_attr_private,
+ is_attr_protected, node_frame_class, safe_infer)
if sys.version_info >= (3, 0):
NEXT_METHOD = '__next__'
@@ -106,12 +106,12 @@ MSGS = {
'Used when a static method has "self" or a value specified in '
'valid-classmethod-first-arg option or '
'valid-metaclass-classmethod-first-arg option as first argument.'
- ),
+ ),
'R0201': ('Method could be a function',
'no-self-use',
'Used when a method doesn\'t use its bound instance, and so could\
be written as a function.'
- ),
+ ),
'E0221': ('Interface resolved to %s is not a class',
'interface-is-not-class',
@@ -133,7 +133,7 @@ MSGS = {
'abstract-method',
'Used when an abstract method (i.e. raise NotImplementedError) is \
not overridden in concrete class.'
- ),
+ ),
'F0220': ('failed to resolve interfaces implemented by %s (%s)', # W0224
'unresolved-interface',
'Used when a PyLint as failed to find interfaces implemented by \
@@ -198,45 +198,43 @@ class ClassChecker(BaseChecker):
# configuration options
options = (('ignore-iface-methods',
{'default' : (#zope interface
- 'isImplementedBy', 'deferred', 'extends', 'names',
- 'namesAndDescriptions', 'queryDescriptionFor', 'getBases',
- 'getDescriptionFor', 'getDoc', 'getName', 'getTaggedValue',
- 'getTaggedValueTags', 'isEqualOrExtendedBy', 'setTaggedValue',
- 'isImplementedByInstancesOf',
- # twisted
- 'adaptWith',
- # logilab.common interface
- 'is_implemented_by'),
+ 'isImplementedBy', 'deferred', 'extends', 'names',
+ 'namesAndDescriptions', 'queryDescriptionFor', 'getBases',
+ 'getDescriptionFor', 'getDoc', 'getName', 'getTaggedValue',
+ 'getTaggedValueTags', 'isEqualOrExtendedBy', 'setTaggedValue',
+ 'isImplementedByInstancesOf',
+ # twisted
+ 'adaptWith',
+ # logilab.common interface
+ 'is_implemented_by'),
'type' : 'csv',
'metavar' : '<method names>',
'help' : 'List of interface methods to ignore, \
separated by a comma. This is used for instance to not check methods defines \
in Zope\'s Interface base class.'}
- ),
-
+ ),
('defining-attr-methods',
{'default' : ('__init__', '__new__', 'setUp'),
'type' : 'csv',
'metavar' : '<method names>',
'help' : 'List of method names used to declare (i.e. assign) \
instance attributes.'}
- ),
+ ),
('valid-classmethod-first-arg',
{'default' : ('cls',),
'type' : 'csv',
'metavar' : '<argument names>',
'help' : 'List of valid names for the first argument in \
a class method.'}
- ),
+ ),
('valid-metaclass-classmethod-first-arg',
{'default' : ('mcs',),
'type' : 'csv',
'metavar' : '<argument names>',
'help' : 'List of valid names for the first argument in \
a metaclass class method.'}
- ),
-
- )
+ ),
+ )
def __init__(self, linter=None):
BaseChecker.__init__(self, linter)
@@ -272,9 +270,13 @@ a metaclass class method.'}
if not self.linter.is_message_enabled('attribute-defined-outside-init'):
return
defining_methods = self.config.defining_attr_methods
+ current_module = cnode.root()
for attr, nodes in cnode.instance_attrs.iteritems():
+ # skip nodes which are not in the current module and it may screw up
+ # the output, while it's not worth it
nodes = [n for n in nodes if not
- isinstance(n.statement(), (astroid.Delete, astroid.AugAssign))]
+ isinstance(n.statement(), (astroid.Delete, astroid.AugAssign))
+ and n.root() is current_module]
if not nodes:
continue # error detected by typechecking
# check if any method attr is defined in is a defining method
@@ -341,8 +343,12 @@ a metaclass class method.'}
# check if the method is hidden by an attribute
try:
overridden = klass.instance_attr(node.name)[0] # XXX
- args = (overridden.root().name, overridden.fromlineno)
- self.add_message('method-hidden', args=args, node=node)
+ overridden_frame = overridden.frame()
+ if overridden_frame.type == 'method':
+ overridden_frame = overridden_frame.parent.frame()
+ if isinstance(overridden_frame, Class) and klass._is_subtype_of(overridden_frame.qname()):
+ args = (overridden.root().name, overridden.fromlineno)
+ self.add_message('method-hidden', args=args, node=node)
except astroid.NotFoundError:
pass
@@ -392,7 +398,7 @@ a metaclass class method.'}
if infered is YES:
continue
if (not isinstance(infered, astroid.Const) or
- not isinstance(infered.value, str)):
+ not isinstance(infered.value, str)):
self.add_message('invalid-slots-object',
args=infered.as_string(),
node=elt)
@@ -410,7 +416,7 @@ a metaclass class method.'}
for infered_node in infered:
if (infered_node is YES
- or isinstance(infered_node, Generator)):
+ or isinstance(infered_node, Generator)):
continue
if isinstance(infered_node, astroid.Instance):
try:
@@ -443,10 +449,10 @@ a metaclass class method.'}
return
class_node = node.parent.frame()
if (self._meth_could_be_func and node.type == 'method'
- and not node.name in PYMETHODS
- and not (node.is_abstract() or
- overrides_a_method(class_node, node.name))
- and class_node.type != 'interface'):
+ and not node.name in PYMETHODS
+ and not (node.is_abstract() or
+ overrides_a_method(class_node, node.name))
+ and class_node.type != 'interface'):
self.add_message('no-self-use', node=node)
def visit_getattr(self, node):
@@ -621,8 +627,8 @@ a metaclass class method.'}
# static method
if node.type == 'staticmethod':
if (first_arg == 'self' or
- first_arg in self.config.valid_classmethod_first_arg or
- first_arg in self.config.valid_metaclass_classmethod_first_arg):
+ first_arg in self.config.valid_classmethod_first_arg or
+ first_arg in self.config.valid_metaclass_classmethod_first_arg):
self.add_message('bad-staticmethod-argument', args=first, node=node)
return
self._first_attrs[-1] = None
@@ -633,19 +639,22 @@ a metaclass class method.'}
elif metaclass:
# metaclass __new__ or classmethod
if node.type == 'classmethod':
- self._check_first_arg_config(first,
+ self._check_first_arg_config(
+ first,
self.config.valid_metaclass_classmethod_first_arg, node,
'bad-mcs-classmethod-argument', node.name)
# metaclass regular method
else:
- self._check_first_arg_config(first,
+ self._check_first_arg_config(
+ first,
self.config.valid_classmethod_first_arg, node, 'bad-mcs-method-argument',
node.name)
# regular class
else:
# class method
if node.type == 'classmethod':
- self._check_first_arg_config(first,
+ self._check_first_arg_config(
+ first,
self.config.valid_classmethod_first_arg, node, 'bad-classmethod-argument',
node.name)
# regular method without self as argument
@@ -658,11 +667,8 @@ a metaclass class method.'}
if len(config) == 1:
valid = repr(config[0])
else:
- valid = ', '.join(
- repr(v)
- for v in config[:-1])
- valid = '%s or %r' % (
- valid, config[-1])
+ valid = ', '.join(repr(v) for v in config[:-1])
+ valid = '%s or %r' % (valid, config[-1])
self.add_message(message, args=(method_name, valid), node=node)
def _check_bases_classes(self, node):
@@ -719,7 +725,7 @@ a metaclass class method.'}
continue
# check signature
self._check_signature(method, imethod,
- '%s interface' % iface.name)
+ '%s interface' % iface.name)
except astroid.InferenceError:
if e0221_hack[0]:
return
@@ -738,7 +744,7 @@ a metaclass class method.'}
method
"""
if (not self.linter.is_message_enabled('super-init-not-called') and
- not self.linter.is_message_enabled('non-parent-init-called')):
+ not self.linter.is_message_enabled('non-parent-init-called')):
return
klass_node = node.parent.frame()
to_call = _ancestors_to_call(klass_node)
@@ -750,7 +756,7 @@ a metaclass class method.'}
continue
# skip the test if using super
if isinstance(expr.expr, astroid.CallFunc) and \
- isinstance(expr.expr.func, astroid.Name) and \
+ isinstance(expr.expr.func, astroid.Name) and \
expr.expr.func.name == 'super':
return
try:
diff --git a/checkers/design_analysis.py b/checkers/design_analysis.py
index c9ef4df..0725ccf 100644
--- a/checkers/design_analysis.py
+++ b/checkers/design_analysis.py
@@ -105,59 +105,59 @@ class MisdesignChecker(BaseChecker):
options = (('max-args',
{'default' : 5, 'type' : 'int', 'metavar' : '<int>',
'help': 'Maximum number of arguments for function / method'}
- ),
+ ),
('ignored-argument-names',
{'default' : IGNORED_ARGUMENT_NAMES,
'type' :'regexp', 'metavar' : '<regexp>',
'help' : 'Argument names that match this expression will be '
'ignored. Default to name with leading underscore'}
- ),
+ ),
('max-locals',
{'default' : 15, 'type' : 'int', 'metavar' : '<int>',
'help': 'Maximum number of locals for function / method body'}
- ),
+ ),
('max-returns',
{'default' : 6, 'type' : 'int', 'metavar' : '<int>',
'help': 'Maximum number of return / yield for function / '
'method body'}
- ),
+ ),
('max-branches',
{'default' : 12, 'type' : 'int', 'metavar' : '<int>',
'help': 'Maximum number of branch for function / method body'}
- ),
+ ),
('max-statements',
{'default' : 50, 'type' : 'int', 'metavar' : '<int>',
'help': 'Maximum number of statements in function / method '
'body'}
- ),
+ ),
('max-parents',
{'default' : 7,
'type' : 'int',
'metavar' : '<num>',
'help' : 'Maximum number of parents for a class (see R0901).'}
- ),
+ ),
('max-attributes',
{'default' : 7,
'type' : 'int',
'metavar' : '<num>',
'help' : 'Maximum number of attributes for a class \
(see R0902).'}
- ),
+ ),
('min-public-methods',
{'default' : 2,
'type' : 'int',
'metavar' : '<num>',
'help' : 'Minimum number of public methods for a class \
(see R0903).'}
- ),
+ ),
('max-public-methods',
{'default' : 20,
'type' : 'int',
'metavar' : '<num>',
'help' : 'Maximum number of public methods for a class \
(see R0904).'}
- ),
- )
+ ),
+ )
def __init__(self, linter=None):
BaseChecker.__init__(self, linter)
diff --git a/checkers/exceptions.py b/checkers/exceptions.py
index c91c95d..94186eb 100644
--- a/checkers/exceptions.py
+++ b/checkers/exceptions.py
@@ -137,8 +137,8 @@ class ExceptionsChecker(BaseChecker):
'help' : 'Exceptions that will emit a warning '
'when being caught. Defaults to "%s"' % (
', '.join(OVERGENERAL_EXCEPTIONS),)}
- ),
- )
+ ),
+ )
@check_messages('raising-string', 'nonstandard-exception', 'raising-bad-type',
'raising-non-exception', 'notimplemented-raised', 'bad-exception-context')
@@ -162,7 +162,7 @@ class ExceptionsChecker(BaseChecker):
elif (not isinstance(cause, astroid.Class) and
not inherit_from_std_ex(cause)):
self.add_message('bad-exception-context',
- node=node)
+ node=node)
expr = node.exc
if self._check_raise_value(node, expr):
return
@@ -269,12 +269,12 @@ class ExceptionsChecker(BaseChecker):
previous_exc.name, exc.name)
self.add_message('bad-except-order', node=handler.type, args=msg)
if (exc.name in self.config.overgeneral_exceptions
- and exc.root().name == EXCEPTIONS_MODULE
- and not is_raising(handler.body)):
+ and exc.root().name == EXCEPTIONS_MODULE
+ and not is_raising(handler.body)):
self.add_message('broad-except', args=exc.name, node=handler.type)
if (not inherit_from_std_ex(exc) and
- exc.root().name != BUILTINS_NAME):
+ exc.root().name != BUILTINS_NAME):
# try to see if the exception is based on a C based
# exception, by infering all the base classes and
# looking for inference errors
diff --git a/checkers/format.py b/checkers/format.py
index 858dff7..ed45e8e 100644
--- a/checkers/format.py
+++ b/checkers/format.py
@@ -68,7 +68,7 @@ MSGS = {
'C0302': ('Too many lines in module (%s)', # was W0302
'too-many-lines',
'Used when a module has too much lines, reducing its readability.'
- ),
+ ),
'C0303': ('Trailing whitespace',
'trailing-whitespace',
'Used when there is whitespace between the end of a line and the '
@@ -117,20 +117,20 @@ MSGS = {
if sys.version_info < (3, 0):
MSGS.update({
- 'W0331': ('Use of the <> operator',
- 'old-ne-operator',
- 'Used when the deprecated "<>" operator is used instead \
- of "!=".'),
- 'W0332': ('Use of "l" as long integer identifier',
- 'lowercase-l-suffix',
- 'Used when a lower case "l" is used to mark a long integer. You '
- 'should use a upper case "L" since the letter "l" looks too much '
- 'like the digit "1"'),
- 'W0333': ('Use of the `` operator',
- 'backtick',
- 'Used when the deprecated "``" (backtick) operator is used '
- 'instead of the str() function.',
- {'scope': WarningScope.NODE}),
+ 'W0331': ('Use of the <> operator',
+ 'old-ne-operator',
+ 'Used when the deprecated "<>" operator is used instead '
+ 'of "!=".'),
+ 'W0332': ('Use of "l" as long integer identifier',
+ 'lowercase-l-suffix',
+ 'Used when a lower case "l" is used to mark a long integer. You '
+ 'should use a upper case "L" since the letter "l" looks too much '
+ 'like the digit "1"'),
+ 'W0333': ('Use of the `` operator',
+ 'backtick',
+ 'Used when the deprecated "``" (backtick) operator is used '
+ 'instead of the str() function.',
+ {'scope': WarningScope.NODE}),
})
@@ -151,29 +151,28 @@ def _column_distance(token1, token2):
def _last_token_on_line_is(tokens, line_end, token):
- return (
- line_end > 0 and tokens.token(line_end-1) == token or
- line_end > 1 and tokens.token(line_end-2) == token
- and tokens.type(line_end-1) == tokenize.COMMENT)
+ return (line_end > 0 and tokens.token(line_end-1) == token or
+ line_end > 1 and tokens.token(line_end-2) == token
+ and tokens.type(line_end-1) == tokenize.COMMENT)
def _token_followed_by_eol(tokens, position):
- return (tokens.type(position+1) == tokenize.NL or
- tokens.type(position+1) == tokenize.COMMENT and
- tokens.type(position+2) == tokenize.NL)
+ return (tokens.type(position+1) == tokenize.NL or
+ tokens.type(position+1) == tokenize.COMMENT and
+ tokens.type(position+2) == tokenize.NL)
def _get_indent_length(line):
- """Return the length of the indentation on the given token's line."""
- result = 0
- for char in line:
- if char == ' ':
- result += 1
- elif char == '\t':
- result += _TAB_LENGTH
- else:
- break
- return result
+ """Return the length of the indentation on the given token's line."""
+ result = 0
+ for char in line:
+ if char == ' ':
+ result += 1
+ elif char == '\t':
+ result += _TAB_LENGTH
+ else:
+ break
+ return result
def _get_indent_hint_line(bar_positions, bad_position):
@@ -432,9 +431,9 @@ class FormatChecker(BaseTokenChecker):
'help': ('Regexp for a line that is allowed to be longer than '
'the limit.')}),
('single-line-if-stmt',
- {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
- 'help' : ('Allow the body of an if to be on the same '
- 'line as the test if there is no else.')}),
+ {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
+ 'help' : ('Allow the body of an if to be on the same '
+ 'line as the test if there is no else.')}),
('no-space-check',
{'default': ','.join(_NO_SPACE_CHECK_CHOICES),
'type': 'multiple_choice',
@@ -444,11 +443,11 @@ class FormatChecker(BaseTokenChecker):
('max-module-lines',
{'default' : 1000, 'type' : 'int', 'metavar' : '<int>',
'help': 'Maximum number of lines in a module'}
- ),
+ ),
('indent-string',
{'default' : ' ', 'type' : "string", 'metavar' : '<string>',
- 'help' : 'String used as indentation unit. This is usually \
-" " (4 spaces) or "\\t" (1 tab).'}),
+ 'help' : 'String used as indentation unit. This is usually '
+ '" " (4 spaces) or "\\t" (1 tab).'}),
('indent-after-paren',
{'type': 'int', 'metavar': '<int>', 'default': 4,
'help': 'Number of spaces of indent required inside a hanging '
@@ -526,8 +525,9 @@ class FormatChecker(BaseTokenChecker):
if not depth:
# ')' can't happen after if (foo), since it would be a syntax error.
if (tokens[i+1][1] in (':', ')', ']', '}', 'in') or
- tokens[i+1][0] in (tokenize.NEWLINE, tokenize.ENDMARKER,
- tokenize.COMMENT)):
+ tokens[i+1][0] in (tokenize.NEWLINE,
+ tokenize.ENDMARKER,
+ tokenize.COMMENT)):
# The empty tuple () is always accepted.
if i == start + 2:
return
@@ -604,7 +604,7 @@ class FormatChecker(BaseTokenChecker):
if self._inside_brackets('['):
return
if (self._inside_brackets('{') and
- _DICT_SEPARATOR in self.config.no_space_check):
+ _DICT_SEPARATOR in self.config.no_space_check):
policy = (_IGNORE, _IGNORE)
else:
policy = (_MUST_NOT, _MUST)
@@ -832,7 +832,7 @@ class FormatChecker(BaseTokenChecker):
return
state, valid_offsets = self._current_line.get_valid_offsets(next_idx)
- # Special handling for hanging comments and strings. If the last line ended
+ # Special handling for hanging comments and strings. If the last line ended
# with a comment (string) and the new line contains only a comment, the line
# may also be indented to the start of the previous token.
if same_token_around_nl(tokenize.COMMENT) or same_token_around_nl(tokenize.STRING):
@@ -872,7 +872,7 @@ class FormatChecker(BaseTokenChecker):
# by taking the last line of the body and adding 1, which
# should be the line of finally:
if (isinstance(node.parent, nodes.TryFinally)
- and node in node.parent.finalbody):
+ and node in node.parent.finalbody):
prev_line = node.parent.body[0].tolineno + 1
else:
prev_line = node.parent.statement().fromlineno
@@ -905,10 +905,10 @@ class FormatChecker(BaseTokenChecker):
# For try... except... finally..., the two nodes
# appear to be on the same line due to how the AST is built.
if (isinstance(node, nodes.TryExcept) and
- isinstance(node.parent, nodes.TryFinally)):
+ isinstance(node.parent, nodes.TryFinally)):
return
if (isinstance(node.parent, nodes.If) and not node.parent.orelse
- and self.config.single_line_if_stmt):
+ and self.config.single_line_if_stmt):
return
self.add_message('multiple-statements', node=node)
self._visited_lines[line] = 2
diff --git a/checkers/imports.py b/checkers/imports.py
index 9ae3935..3242b75 100644
--- a/checkers/imports.py
+++ b/checkers/imports.py
@@ -48,7 +48,8 @@ def get_first_import(node, context, name, base, level):
break
elif isinstance(first, astroid.From):
if level == first.level and any(
- fullname == '%s.%s' % (first.modname, iname[0]) for iname in first.names):
+ fullname == '%s.%s' % (first.modname, iname[0])
+ for iname in first.names):
found = True
break
if found and not are_exclusive(first, node):
@@ -178,30 +179,29 @@ class ImportsChecker(BaseChecker):
'metavar' : '<modules>',
'help' : 'Deprecated modules which should not be used, \
separated by a comma'}
- ),
+ ),
('import-graph',
{'default' : '',
'type' : 'string',
'metavar' : '<file.dot>',
'help' : 'Create a graph of every (i.e. internal and \
external) dependencies in the given file (report RP0402 must not be disabled)'}
- ),
+ ),
('ext-import-graph',
{'default' : '',
'type' : 'string',
'metavar' : '<file.dot>',
'help' : 'Create a graph of external dependencies in the \
given file (report RP0402 must not be disabled)'}
- ),
+ ),
('int-import-graph',
{'default' : '',
'type' : 'string',
'metavar' : '<file.dot>',
'help' : 'Create a graph of internal dependencies in the \
given file (report RP0402 must not be disabled)'}
- ),
-
- )
+ ),
+ )
def __init__(self, linter=None):
BaseChecker.__init__(self, linter)
@@ -212,7 +212,7 @@ given file (report RP0402 must not be disabled)'}
self.report_external_dependencies),
('RP0402', 'Modules dependencies graph',
self.report_dependencies_graph),
- )
+ )
def open(self):
"""called before visiting project (i.e set of modules)"""
@@ -252,7 +252,7 @@ given file (report RP0402 must not be disabled)'}
if prev:
# consecutive future statements are possible
if not (isinstance(prev, astroid.From)
- and prev.modname == '__future__'):
+ and prev.modname == '__future__'):
self.add_message('misplaced-future', node=node)
return
for name, _ in node.names:
diff --git a/checkers/logging.py b/checkers/logging.py
index cbdf0f2..d82d74b 100644
--- a/checkers/logging.py
+++ b/checkers/logging.py
@@ -22,16 +22,16 @@ from pylint.checkers.utils import check_messages
MSGS = {
'W1201': ('Specify string format arguments as logging function parameters',
- 'logging-not-lazy',
- 'Used when a logging statement has a call form of '
- '"logging.<logging method>(format_string % (format_args...))". '
- 'Such calls should leave string interpolation to the logging '
- 'method itself and be written '
- '"logging.<logging method>(format_string, format_args...)" '
- 'so that the program may avoid incurring the cost of the '
- 'interpolation in those cases in which no message will be '
- 'logged. For more, see '
- 'http://www.python.org/dev/peps/pep-0282/.'),
+ 'logging-not-lazy',
+ 'Used when a logging statement has a call form of '
+ '"logging.<logging method>(format_string % (format_args...))". '
+ 'Such calls should leave string interpolation to the logging '
+ 'method itself and be written '
+ '"logging.<logging method>(format_string, format_args...)" '
+ 'so that the program may avoid incurring the cost of the '
+ 'interpolation in those cases in which no message will be '
+ 'logged. For more, see '
+ 'http://www.python.org/dev/peps/pep-0282/.'),
'E1200': ('Unsupported logging format character %r (%#02x) at index %d',
'logging-unsupported-format',
'Used when an unsupported format character is used in a logging\
@@ -65,10 +65,10 @@ class LoggingChecker(checkers.BaseChecker):
{'default' : ('logging',),
'type' : 'csv',
'metavar' : '<comma separated list>',
- 'help' : ('Logging modules to check that the string format '
- 'arguments are in logging function parameter format')}
- ),
- )
+ 'help' : 'Logging modules to check that the string format '
+ 'arguments are in logging function parameter format'}
+ ),
+ )
def visit_module(self, unused_node):
"""Clears any state left in this checker from last module checked."""
@@ -105,19 +105,19 @@ class LoggingChecker(checkers.BaseChecker):
def visit_callfunc(self, node):
"""Checks calls to logging methods."""
def is_logging_name():
- return (isinstance(node.func, astroid.Getattr) and
- isinstance(node.func.expr, astroid.Name) and
- node.func.expr.name in self._logging_names)
+ return (isinstance(node.func, astroid.Getattr) and
+ isinstance(node.func.expr, astroid.Name) and
+ node.func.expr.name in self._logging_names)
def is_logger_class():
try:
for inferred in node.func.infer():
if isinstance(inferred, astroid.BoundMethod):
parent = inferred._proxied.parent
- if (isinstance(parent, astroid.Class) and
- (parent.qname() == 'logging.Logger' or
- any(ancestor.qname() == 'logging.Logger'
- for ancestor in parent.ancestors()))):
+ if (isinstance(parent, astroid.Class) and
+ (parent.qname() == 'logging.Logger' or
+ any(ancestor.qname() == 'logging.Logger'
+ for ancestor in parent.ancestors()))):
return True, inferred._proxied.name
except astroid.exceptions.InferenceError:
pass
diff --git a/checkers/newstyle.py b/checkers/newstyle.py
index f801c44..cc8f640 100644
--- a/checkers/newstyle.py
+++ b/checkers/newstyle.py
@@ -89,8 +89,8 @@ class NewStyleConflictChecker(BaseChecker):
"""check property usage"""
parent = node.parent.frame()
if (isinstance(parent, astroid.Class) and
- not parent.newstyle and
- isinstance(node.func, astroid.Name)):
+ not parent.newstyle and
+ isinstance(node.func, astroid.Name)):
name = node.func.name
if name == 'property':
self.add_message('property-on-old-class', node=node)
diff --git a/checkers/similar.py b/checkers/similar.py
index cf671bf..e5c9300 100644
--- a/checkers/similar.py
+++ b/checkers/similar.py
@@ -107,7 +107,7 @@ class Similar(object):
for index2 in find(lineset1[index1]):
non_blank = 0
for num, ((_, line1), (_, line2)) in enumerate(
- izip(lines1(index1), lines2(index2))):
+ izip(lines1(index1), lines2(index2))):
if line1 != line2:
if non_blank > min_lines:
yield num, lineset1, index1, lineset2, index2
@@ -249,16 +249,16 @@ class SimilarChecker(BaseChecker, Similar):
('ignore-comments',
{'default' : True, 'type' : 'yn', 'metavar' : '<y or n>',
'help': 'Ignore comments when computing similarities.'}
- ),
+ ),
('ignore-docstrings',
{'default' : True, 'type' : 'yn', 'metavar' : '<y or n>',
'help': 'Ignore docstrings when computing similarities.'}
- ),
+ ),
('ignore-imports',
{'default' : False, 'type' : 'yn', 'metavar' : '<y or n>',
'help': 'Ignore imports when computing similarities.'}
- ),
- )
+ ),
+ )
# reports
reports = (('RP0801', 'Duplication', report_similarities),)
diff --git a/checkers/stdlib.py b/checkers/stdlib.py
index a1c3133..9913e99 100644
--- a/checkers/stdlib.py
+++ b/checkers/stdlib.py
@@ -24,7 +24,7 @@ from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
from pylint.checkers import utils
-_VALID_OPEN_MODE_REGEX = r'^(r?U|[rwa]\+?b?)$'
+_VALID_OPEN_MODE_REGEX = re.compile(r'^(r?U|[rwa]\+?b?)$')
if sys.version_info >= (3, 0):
OPEN_MODULE = '_io'
@@ -58,8 +58,9 @@ class OpenModeChecker(BaseChecker):
if mode_arg:
mode_arg = utils.safe_infer(mode_arg)
if (isinstance(mode_arg, astroid.Const)
- and not re.match(_VALID_OPEN_MODE_REGEX, mode_arg.value)):
- self.add_message('bad-open-mode', node=node, args=(mode_arg.value))
+ and not _VALID_OPEN_MODE_REGEX.match(mode_arg.value)):
+ self.add_message('bad-open-mode', node=node,
+ args=(mode_arg.value))
except (utils.NoSuchArgumentError, TypeError):
pass
diff --git a/checkers/strings.py b/checkers/strings.py
index af2ceea..8251a80 100644
--- a/checkers/strings.py
+++ b/checkers/strings.py
@@ -211,7 +211,7 @@ class StringFormatChecker(BaseChecker):
args = node.right
if not (isinstance(left, astroid.Const)
- and isinstance(left.value, basestring)):
+ and isinstance(left.value, basestring)):
return
format_string = left.value
try:
@@ -298,9 +298,8 @@ class StringMethodsChecker(BaseChecker):
def visit_callfunc(self, node):
func = utils.safe_infer(node.func)
if (isinstance(func, astroid.BoundMethod)
- and isinstance(func.bound, astroid.Instance)
- and func.bound.name in ('str', 'unicode', 'bytes')):
-
+ and isinstance(func.bound, astroid.Instance)
+ and func.bound.name in ('str', 'unicode', 'bytes')):
if func.name in ('strip', 'lstrip', 'rstrip') and node.args:
arg = utils.safe_infer(node.args[0])
if not isinstance(arg, astroid.Const):
@@ -413,7 +412,7 @@ class StringMethodsChecker(BaseChecker):
previous = previous.getattr(specifier)[0]
except astroid.NotFoundError:
if (hasattr(previous, 'has_dynamic_getattr') and
- previous.has_dynamic_getattr()):
+ previous.has_dynamic_getattr()):
# Don't warn if the object has a custom __getattr__
break
path = get_access_path(key, parsed)
@@ -504,7 +503,7 @@ class StringConstantChecker(BaseTokenChecker):
# No special checks on raw strings at the moment.
if 'r' not in prefix:
self.process_non_raw_string_token(prefix, string_body,
- start_row, start_col)
+ start_row, start_col)
def process_non_raw_string_token(self, prefix, string_body, start_row,
start_col):
diff --git a/checkers/typecheck.py b/checkers/typecheck.py
index efc0909..fb8f3c6 100644
--- a/checkers/typecheck.py
+++ b/checkers/typecheck.py
@@ -18,7 +18,6 @@
import re
import shlex
-import sys
import astroid
from astroid import InferenceError, NotFoundError, YES, Instance
@@ -74,12 +73,13 @@ MSGS = {
'E1125': ('Missing mandatory keyword argument %r in %s call',
'missing-kwoa',
('Used when a function call does not pass a mandatory'
- ' keyword-only argument.'),
+ ' keyword-only argument.'),
{'minversion': (3, 0)}),
'E1126': ('Sequence index is not an int, slice, or instance with __index__',
'invalid-sequence-index',
- 'Used when a sequence type is indexed with an invalid type. Valid \
- types are ints, slices, and objects with an __index__ method.'),
+ 'Used when a sequence type is indexed with an invalid type. '
+ 'Valid types are ints, slices, and objects with an __index__ '
+ 'method.'),
'E1127': ('Slice index is not an int, None, or instance with __index__',
'invalid-slice-index',
'Used when a slice index is not an integer, None, or an object \
@@ -87,7 +87,7 @@ MSGS = {
}
# builtin sequence types in Python 2 and 3.
-sequence_types = set(['str', 'unicode', 'list', 'tuple', 'bytearray',
+SEQUENCE_TYPES = set(['str', 'unicode', 'list', 'tuple', 'bytearray',
'xrange', 'range', 'bytes', 'memoryview'])
def _determine_callable(callable_obj):
@@ -146,39 +146,38 @@ class TypeChecker(BaseChecker):
'help' : 'Tells whether missing members accessed in mixin \
class should be ignored. A mixin class is detected if its name ends with \
"mixin" (case insensitive).'}
- ),
- ('ignored-modules',
- {'default': (),
- 'type': 'csv',
- 'metavar': '<module names>',
- 'help': 'List of module names for which member attributes \
+ ),
+ ('ignored-modules',
+ {'default': (),
+ 'type': 'csv',
+ 'metavar': '<module names>',
+ 'help': 'List of module names for which member attributes \
should not be checked (useful for modules/projects where namespaces are \
manipulated during runtime and thus existing member attributes cannot be \
deduced by static analysis'},
- ),
+ ),
('ignored-classes',
{'default' : ('SQLObject',),
'type' : 'csv',
'metavar' : '<members names>',
'help' : 'List of classes names for which member attributes \
should not be checked (useful for classes with attributes dynamically set).'}
- ),
+ ),
('zope',
{'default' : False, 'type' : 'yn', 'metavar': '<y_or_n>',
'help' : 'When zope mode is activated, add a predefined set \
of Zope acquired attributes to generated-members.'}
- ),
+ ),
('generated-members',
- {'default' : (
- 'REQUEST', 'acl_users', 'aq_parent'),
+ {'default' : ('REQUEST', 'acl_users', 'aq_parent'),
'type' : 'string',
'metavar' : '<members names>',
'help' : 'List of members which are set dynamically and \
missed by pylint inference system, and so shouldn\'t trigger E0201 when \
accessed. Python regular expressions are accepted.'}
- ),
- )
+ ),
+ )
def open(self):
# do this in open since config not fully initialized in __init__
@@ -326,7 +325,7 @@ accessed. Python regular expressions are accepted.'}
expr = node.func.expr
klass = safe_infer(expr)
if (klass is None or klass is astroid.YES or
- not isinstance(klass, astroid.Instance)):
+ not isinstance(klass, astroid.Instance)):
return
try:
@@ -354,12 +353,12 @@ accessed. Python regular expressions are accepted.'}
property_like = False
if isinstance(infered, astroid.Class):
if (infered.root().name == BUILTINS and
- infered.name == 'property'):
+ infered.name == 'property'):
property_like = True
else:
for ancestor in infered.ancestors():
if (ancestor.name == 'property' and
- ancestor.root().name == BUILTINS):
+ ancestor.root().name == BUILTINS):
property_like = True
break
if property_like:
@@ -386,7 +385,7 @@ accessed. Python regular expressions are accepted.'}
if isinstance(arg, astroid.Keyword):
keyword = arg.arg
if keyword in keyword_args:
- self.add_message('duplicate-keyword-arg', node=node,
+ self.add_message('duplicate-keyword-arg', node=node,
args=(keyword, 'function'))
keyword_args.add(keyword)
else:
@@ -461,7 +460,8 @@ accessed. Python regular expressions are accepted.'}
break
else:
# Too many positional arguments.
- self.add_message('too-many-function-args', node=node, args=(callable_name,))
+ self.add_message('too-many-function-args',
+ node=node, args=(callable_name,))
break
# 2. Match the keyword arguments.
@@ -470,13 +470,15 @@ accessed. Python regular expressions are accepted.'}
i = parameter_name_to_index[keyword]
if parameters[i][1]:
# Duplicate definition of function parameter.
- self.add_message('redundant-keyword-arg', node=node, args=(keyword, callable_name))
+ self.add_message('redundant-keyword-arg',
+ node=node, args=(keyword, callable_name))
else:
parameters[i][1] = True
elif keyword in kwparams:
if kwparams[keyword][1]: # XXX is that even possible?
# Duplicate definition of function parameter.
- self.add_message('redundant-keyword-arg', node=node, args=(keyword, callable_name))
+ self.add_message('redundant-keyword-arg', node=node,
+ args=(keyword, callable_name))
else:
kwparams[keyword][1] = True
elif called.args.kwarg is not None:
@@ -484,7 +486,8 @@ accessed. Python regular expressions are accepted.'}
pass
else:
# Unexpected keyword argument.
- self.add_message('unexpected-keyword-arg', node=node, args=(keyword, callable_name))
+ self.add_message('unexpected-keyword-arg', node=node,
+ args=(keyword, callable_name))
# 3. Match the *args, if any. Note that Python actually processes
# *args _before_ any keyword arguments, but we wait until after
@@ -521,12 +524,14 @@ accessed. Python regular expressions are accepted.'}
display_name = '<tuple>'
else:
display_name = repr(name)
- self.add_message('no-value-for-parameter', node=node, args=(display_name, callable_name))
+ self.add_message('no-value-for-parameter', node=node,
+ args=(display_name, callable_name))
for name in kwparams:
defval, assigned = kwparams[name]
if defval is None and not assigned:
- self.add_message('missing-kwoa', node=node, args=(name, callable_name))
+ self.add_message('missing-kwoa', node=node,
+ args=(name, callable_name))
@check_messages('invalid-sequence-index')
def visit_extslice(self, node):
@@ -544,7 +549,7 @@ accessed. Python regular expressions are accepted.'}
# slice or instances with __index__.
parent_type = safe_infer(node.parent.value)
-
+
if not isinstance(parent_type, (astroid.Class, astroid.Instance)):
return
@@ -580,7 +585,7 @@ accessed. Python regular expressions are accepted.'}
if not itemmethod.parent:
return
- if itemmethod.parent.name not in sequence_types:
+ if itemmethod.parent.name not in SEQUENCE_TYPES:
return
# For ExtSlice objects coming from visit_extslice, no further
@@ -634,7 +639,7 @@ accessed. Python regular expressions are accepted.'}
if index_type.pytype() in (BUILTINS + '.int',
BUILTINS + '.NoneType'):
continue
-
+
try:
index_type.getattr('__index__')
return
diff --git a/checkers/utils.py b/checkers/utils.py
index 01989be..d88d620 100644
--- a/checkers/utils.py
+++ b/checkers/utils.py
@@ -67,11 +67,10 @@ def clobber_in_except(node):
if is_builtin(name):
return (True, (name, 'builtins'))
else:
- scope, stmts = node.lookup(name)
- if (stmts and
- not isinstance(stmts[0].ass_type(),
- (astroid.Assign, astroid.AugAssign,
- astroid.ExceptHandler))):
+ stmts = node.lookup(name)[1]
+ if (stmts and not isinstance(stmts[0].ass_type(),
+ (astroid.Assign, astroid.AugAssign,
+ astroid.ExceptHandler))):
return (True, (name, 'outer scope (line %s)' % stmts[0].fromlineno))
return (False, None)
@@ -155,10 +154,10 @@ def is_defined_before(var_node):
elif isinstance(_node, astroid.With):
for expr, vars in _node.items:
if expr.parent_of(var_node):
- break
+ break
if (vars and
- isinstance(vars, astroid.AssName) and
- vars.name == varname):
+ isinstance(vars, astroid.AssName) and
+ vars.name == varname):
return True
elif isinstance(_node, (astroid.Lambda, astroid.Function)):
if _node.args.is_argument(varname):
@@ -205,9 +204,9 @@ def is_func_decorator(node):
if isinstance(parent, astroid.Decorators):
return True
if (parent.is_statement or
- isinstance(parent, astroid.Lambda) or
- isinstance(parent, (scoped_nodes.ComprehensionScope,
- scoped_nodes.ListComp))):
+ isinstance(parent, astroid.Lambda) or
+ isinstance(parent, (scoped_nodes.ComprehensionScope,
+ scoped_nodes.ListComp))):
break
parent = parent.parent
return False
@@ -269,7 +268,7 @@ PYMETHODS = set(('__new__', '__init__', '__del__', '__hash__',
'__or__', '__ior__', '__ror__',
'__xor__', '__ixor__', '__rxor__',
# XXX To be continued
- ))
+ ))
def check_messages(*messages):
"""decorator to store messages that are handled by a checker method"""
@@ -365,7 +364,7 @@ def is_attr_protected(attrname):
details), False otherwise.
"""
return attrname[0] == '_' and not attrname == '_' and not (
- attrname.startswith('__') and attrname.endswith('__'))
+ attrname.startswith('__') and attrname.endswith('__'))
def node_frame_class(node):
"""return klass node for a method node (or a staticmethod or a
@@ -386,8 +385,8 @@ def is_super_call(expr):
is super. Check before that you're in a method.
"""
return (isinstance(expr, astroid.CallFunc) and
- isinstance(expr.func, astroid.Name) and
- expr.func.name == 'super')
+ isinstance(expr.func, astroid.Name) and
+ expr.func.name == 'super')
def is_attr_private(attrname):
"""Check that attribute name is private (at least two leading underscores,
diff --git a/checkers/variables.py b/checkers/variables.py
index 3b9bcda..fc4c99e 100644
--- a/checkers/variables.py
+++ b/checkers/variables.py
@@ -27,10 +27,11 @@ from logilab.common.modutils import file_from_modpath
from pylint.interfaces import IAstroidChecker
from pylint.utils import get_global_option
from pylint.checkers import BaseChecker
-from pylint.checkers.utils import (PYMETHODS, is_ancestor_name, is_builtin,
- is_defined_before, is_error, is_func_default, is_func_decorator,
- assign_parent, check_messages, is_inside_except, clobber_in_except,
- get_all_elements)
+from pylint.checkers.utils import (
+ PYMETHODS, is_ancestor_name, is_builtin,
+ is_defined_before, is_error, is_func_default, is_func_decorator,
+ assign_parent, check_messages, is_inside_except, clobber_in_except,
+ get_all_elements)
def in_for_else_branch(parent, stmt):
@@ -102,7 +103,7 @@ def _detect_global_scope(node, frame, defframe):
(astroid.Function, astroid.Arguments)):
return False
elif any(not isinstance(f, (astroid.Class, astroid.Module))
- for f in (frame, defframe)):
+ for f in (frame, defframe)):
# Not interested in other frames, since they are already
# not in a global scope.
return False
@@ -234,8 +235,7 @@ class VariablesChecker(BaseChecker):
name = 'variables'
msgs = MSGS
priority = -1
- options = (
- ("init-import",
+ options = (("init-import",
{'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>',
'help' : 'Tells whether we should check for unused import in \
__init__ files.'}),
@@ -249,8 +249,8 @@ variables (i.e. expectedly not used).'}),
'metavar' : '<comma separated list>',
'help' : 'List of additional names supposed to be defined in \
builtins. Remember that you should avoid to define new builtins when possible.'
- }),
- )
+ }),
+ )
def __init__(self, linter=None):
BaseChecker.__init__(self, linter)
self._to_consume = None
@@ -306,7 +306,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
self.add_message('undefined-all-variable',
args=elt_name,
node=elt)
- except SyntaxError, exc:
+ except SyntaxError:
# don't yield an syntax-error warning,
# because it will be later yielded
# when the file will be checked
@@ -545,7 +545,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
def _is_direct_lambda_call():
return (isinstance(node_scope.parent, astroid.CallFunc)
and node_scope.parent.func is node_scope)
-
+
node_scope = node.scope()
if not isinstance(node_scope, (astroid.Lambda, astroid.Function)):
return
@@ -594,7 +594,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
_astmts = astmts[:1]
for i, stmt in enumerate(astmts[1:]):
if (astmts[i].statement().parent_of(stmt)
- and not in_for_else_branch(astmts[i].statement(), stmt)):
+ and not in_for_else_branch(astmts[i].statement(), stmt)):
continue
_astmts.append(stmt)
astmts = _astmts
@@ -634,7 +634,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
# a decorator, then start from the parent frame of the function instead
# of the function frame - and thus open an inner class scope
if (is_func_default(node) or is_func_decorator(node)
- or is_ancestor_name(frame, node)):
+ or is_ancestor_name(frame, node)):
start_index = len(self._to_consume) - 2
else:
start_index = len(self._to_consume) - 1
@@ -648,7 +648,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
# names. The only exception is when the starting scope is a
# comprehension and its direct outer scope is a class
if scope_type == 'class' and i != start_index and not (
- base_scope_type == 'comprehension' and i == start_index-1):
+ base_scope_type == 'comprehension' and i == start_index-1):
# XXX find a way to handle class scope in a smoother way
continue
# the name has already been consumed, only check it's not a loop
@@ -690,9 +690,11 @@ builtins. Remember that you should avoid to define new builtins when possible.'
and name in child.names
for child in defframe.get_children())
if (maybee0601
- and stmt.fromlineno <= defstmt.fromlineno
- and not is_defined_before(node)
- and not are_exclusive(stmt, defstmt, ('NameError', 'Exception', 'BaseException'))):
+ and stmt.fromlineno <= defstmt.fromlineno
+ and not is_defined_before(node)
+ and not are_exclusive(stmt, defstmt, ('NameError',
+ 'Exception',
+ 'BaseException'))):
if defstmt is stmt and isinstance(node, (astroid.DelName,
astroid.AssName)):
self.add_message('undefined-variable', args=name, node=node)
@@ -872,9 +874,8 @@ class VariablesChecker3k(VariablesChecker):
name = metaclass.root().name
if name:
- found = consumed.setdefault(name,
- module_locals.get(name, module_imports.get(name))
- )
+ found = consumed.setdefault(
+ name, module_locals.get(name, module_imports.get(name)))
if found is None and not metaclass:
name = None
diff --git a/epylint.py b/epylint.py
index 24e9e95..beae481 100755
--- a/epylint.py
+++ b/epylint.py
@@ -46,7 +46,7 @@ You may also use py_run to run pylint with desired options and get back (or not)
its output.
"""
-import sys, os, re
+import sys, os
import os.path as osp
from subprocess import Popen, PIPE
diff --git a/examples/pylintrc b/examples/pylintrc
index 047b473..5f21f58 100644
--- a/examples/pylintrc
+++ b/examples/pylintrc
@@ -107,6 +107,9 @@ max-module-lines=1000
# tab).
indent-string=' '
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
[BASIC]
@@ -227,7 +230,7 @@ ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
-# and thus extisting member attributes cannot be deduced by static analysis
+# and thus existing member attributes cannot be deduced by static analysis
ignored-modules=
# List of classes names for which member attributes should not be checked
diff --git a/gui.py b/gui.py
index a882a2b..fcc84e0 100644
--- a/gui.py
+++ b/gui.py
@@ -171,10 +171,11 @@ class LintGui(object):
rightscrollbar.pack(side=RIGHT, fill=Y)
bottomscrollbar = Scrollbar(msg_frame, orient=HORIZONTAL)
bottomscrollbar.pack(side=BOTTOM, fill=X)
- self.lb_messages = Listbox(msg_frame,
- yscrollcommand=rightscrollbar.set,
- xscrollcommand=bottomscrollbar.set,
- bg="white")
+ self.lb_messages = Listbox(
+ msg_frame,
+ yscrollcommand=rightscrollbar.set,
+ xscrollcommand=bottomscrollbar.set,
+ bg="white")
self.lb_messages.bind("<Double-Button-1>", self.show_sourcefile)
self.lb_messages.pack(expand=True, fill=BOTH)
rightscrollbar.config(command=self.lb_messages.yview)
@@ -185,10 +186,11 @@ class LintGui(object):
rightscrollbar2.pack(side=RIGHT, fill=Y)
bottomscrollbar2 = Scrollbar(history_frame, orient=HORIZONTAL)
bottomscrollbar2.pack(side=BOTTOM, fill=X)
- self.showhistory = Listbox(history_frame,
- yscrollcommand=rightscrollbar2.set,
- xscrollcommand=bottomscrollbar2.set,
- bg="white")
+ self.showhistory = Listbox(
+ history_frame,
+ yscrollcommand=rightscrollbar2.set,
+ xscrollcommand=bottomscrollbar2.set,
+ bg="white")
self.showhistory.pack(expand=True, fill=BOTH)
rightscrollbar2.config(command=self.showhistory.yview)
bottomscrollbar2.config(command=self.showhistory.xview)
@@ -217,10 +219,11 @@ class LintGui(object):
rightscrollbar.pack(side=RIGHT, fill=Y)
bottomscrollbar = Scrollbar(res_frame, orient=HORIZONTAL)
bottomscrollbar.pack(side=BOTTOM, fill=X)
- self.results = Listbox(res_frame,
- yscrollcommand=rightscrollbar.set,
- xscrollcommand=bottomscrollbar.set,
- bg="white", font="Courier")
+ self.results = Listbox(
+ res_frame,
+ yscrollcommand=rightscrollbar.set,
+ xscrollcommand=bottomscrollbar.set,
+ bg="white", font="Courier")
self.results.pack(expand=True, fill=BOTH, side=BOTTOM)
rightscrollbar.config(command=self.results.yview)
bottomscrollbar.config(command=self.results.xview)
@@ -399,8 +402,10 @@ class LintGui(object):
def file_open(self, package=False, _=None):
"""launch a file browser"""
if not package:
- filename = askopenfilename(parent=self.root, filetypes=[('pythonfiles', '*.py'),
- ('allfiles', '*')], title='Select Module')
+ filename = askopenfilename(parent=self.root,
+ filetypes=[('pythonfiles', '*.py'),
+ ('allfiles', '*')],
+ title='Select Module')
else:
filename = askdirectory(title="Select A Folder", mustexist=1)
diff --git a/lint.py b/lint.py
index 4184985..5be37f3 100644
--- a/lint.py
+++ b/lint.py
@@ -27,9 +27,8 @@
"""
# import this first to avoid builtin namespace pollution
-from pylint.checkers import utils
+from pylint.checkers import utils #pylint: disable=unused-import
-import functools
import sys
import os
import tokenize
@@ -43,14 +42,14 @@ from logilab.common.textutils import splitstrip, unquote
from logilab.common.ureports import Table, Text, Section
from logilab.common.__pkginfo__ import version as common_version
-from astroid import MANAGER, nodes, AstroidBuildingException
+from astroid import MANAGER, AstroidBuildingException
from astroid.__pkginfo__ import version as astroid_version
from astroid.modutils import load_module_from_name, get_module_part
from pylint.utils import (
MSG_TYPES, OPTION_RGX,
PyLintASTWalker, UnknownMessage, MessagesHandlerMixIn, ReportsHandlerMixIn,
- MessagesStore, FileState, EmptyReport, WarningScope,
+ MessagesStore, FileState, EmptyReport,
expand_modules, tokenize_module)
from pylint.interfaces import IRawChecker, ITokenChecker, IAstroidChecker
from pylint.checkers import (BaseTokenChecker,
@@ -65,7 +64,7 @@ from pylint.__pkginfo__ import version
def _get_python_path(filepath):
dirname = os.path.dirname(os.path.realpath(
- os.path.expanduser(filepath)))
+ os.path.expanduser(filepath)))
while True:
if not os.path.exists(os.path.join(dirname, "__init__.py")):
return dirname
@@ -94,7 +93,7 @@ MSGS = {
'F0010': ('error while code parsing: %s',
'parse-error',
'Used when an exception occured while building the Astroid '
- 'representation which could be handled by astroid.'),
+ 'representation which could be handled by astroid.'),
'I0001': ('Unable to run raw checkers on built-in module %s',
'raw-checker-failed',
@@ -183,7 +182,7 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
{'type' : 'csv', 'metavar' : '<file>[,<file>...]',
'dest' : 'black_list', 'default' : ('CVS',),
'help' : 'Add files or directories to the blacklist. '
- 'They should be base names, not paths.'}),
+ 'They should be base names, not paths.'}),
('persistent',
{'default': True, 'type' : 'yn', 'metavar' : '<y_or_n>',
'level': 1,
@@ -193,85 +192,86 @@ class PyLinter(OptionsManagerMixIn, MessagesHandlerMixIn, ReportsHandlerMixIn,
{'type' : 'csv', 'metavar' : '<modules>', 'default' : (),
'level': 1,
'help' : 'List of plugins (as comma separated values of '
- 'python modules names) to load, usually to register '
- 'additional checkers.'}),
+ 'python modules names) to load, usually to register '
+ 'additional checkers.'}),
('output-format',
{'default': 'text', 'type': 'string', 'metavar' : '<format>',
'short': 'f',
'group': 'Reports',
'help' : 'Set the output format. Available formats are text,'
- ' parseable, colorized, msvs (visual studio) and html. You '
- 'can also give a reporter class, eg mypackage.mymodule.'
- 'MyReporterClass.'}),
+ ' parseable, colorized, msvs (visual studio) and html. You '
+ 'can also give a reporter class, eg mypackage.mymodule.'
+ 'MyReporterClass.'}),
('files-output',
{'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>',
'group': 'Reports', 'level': 1,
'help' : 'Put messages in a separate file for each module / '
- 'package specified on the command line instead of printing '
- 'them on stdout. Reports (if any) will be written in a file '
- 'name "pylint_global.[txt|html]".'}),
+ 'package specified on the command line instead of printing '
+ 'them on stdout. Reports (if any) will be written in a file '
+ 'name "pylint_global.[txt|html]".'}),
('reports',
{'default': 1, 'type' : 'yn', 'metavar' : '<y_or_n>',
'short': 'r',
'group': 'Reports',
'help' : 'Tells whether to display a full report or only the '
- 'messages'}),
+ 'messages'}),
('evaluation',
{'type' : 'string', 'metavar' : '<python_expression>',
'group': 'Reports', 'level': 1,
'default': '10.0 - ((float(5 * error + warning + refactor + '
- 'convention) / statement) * 10)',
- 'help' : 'Python expression which should return a note less \
-than 10 (10 is the highest note). You have access to the variables errors \
-warning, statement which respectively contain the number of errors / warnings\
- messages and the total number of statements analyzed. This is used by the \
- global evaluation report (RP0004).'}),
+ 'convention) / statement) * 10)',
+ 'help' : 'Python expression which should return a note less '
+ 'than 10 (10 is the highest note). You have access '
+ 'to the variables errors warning, statement which '
+ 'respectively contain the number of errors / '
+ 'warnings messages and the total number of '
+ 'statements analyzed. This is used by the global '
+ 'evaluation report (RP0004).'}),
('comment',
{'default': 0, 'type' : 'yn', 'metavar' : '<y_or_n>',
'group': 'Reports', 'level': 1,
'help' : 'Add a comment according to your evaluation note. '
- 'This is used by the global evaluation report (RP0004).'}),
+ 'This is used by the global evaluation report (RP0004).'}),
('enable',
{'type' : 'csv', 'metavar': '<msg ids>',
'short': 'e',
'group': 'Messages control',
'help' : 'Enable the message, report, category or checker with the '
- 'given id(s). You can either give multiple identifier '
- 'separated by comma (,) or put this option multiple time. '
- 'See also the "--disable" option for examples. '}),
+ 'given id(s). You can either give multiple identifier '
+ 'separated by comma (,) or put this option multiple time. '
+ 'See also the "--disable" option for examples. '}),
('disable',
{'type' : 'csv', 'metavar': '<msg ids>',
'short': 'd',
'group': 'Messages control',
'help' : 'Disable the message, report, category or checker '
- 'with the given id(s). You can either give multiple identifiers'
- ' separated by comma (,) or put this option multiple times '
- '(only on the command line, not in the configuration file '
- 'where it should appear only once).'
- 'You can also use "--disable=all" to disable everything first '
- 'and then reenable specific checks. For example, if you want '
- 'to run only the similarities checker, you can use '
- '"--disable=all --enable=similarities". '
- 'If you want to run only the classes checker, but have no '
- 'Warning level messages displayed, use'
- '"--disable=all --enable=classes --disable=W"'}),
+ 'with the given id(s). You can either give multiple identifiers'
+ ' separated by comma (,) or put this option multiple times '
+ '(only on the command line, not in the configuration file '
+ 'where it should appear only once).'
+ 'You can also use "--disable=all" to disable everything first '
+ 'and then reenable specific checks. For example, if you want '
+ 'to run only the similarities checker, you can use '
+ '"--disable=all --enable=similarities". '
+ 'If you want to run only the classes checker, but have no '
+ 'Warning level messages displayed, use'
+ '"--disable=all --enable=classes --disable=W"'}),
('msg-template',
{'type' : 'string', 'metavar': '<template>',
- #'short': 't',
'group': 'Reports',
'help' : ('Template used to display messages. '
'This is a python new-style format string '
'used to format the message information. '
'See doc for all details')
- }),
+ }),
('include-ids', _deprecated_option('i', 'yn')),
('symbols', _deprecated_option('s', 'yn')),
@@ -323,7 +323,7 @@ warning, statement which respectively contain the number of errors / warnings\
report_messages_stats),
('RP0004', 'Global evaluation',
self.report_evaluation),
- )
+ )
self.register_checker(self)
self._dynamic_plugins = set()
self.load_provider_defaults()
@@ -516,7 +516,7 @@ warning, statement which respectively contain the number of errors / warnings\
messages = set(msg for msg in checker.msgs
if msg[0] != 'F' and self.is_message_enabled(msg))
if (messages or
- any(self.report_is_enabled(r[0]) for r in checker.reports)):
+ any(self.report_is_enabled(r[0]) for r in checker.reports)):
neededcheckers.append(checker)
# Sort checkers by priority
neededcheckers = sorted(neededcheckers, key=attrgetter('priority'),
@@ -668,7 +668,7 @@ warning, statement which respectively contain the number of errors / warnings\
"""initialize counters"""
self.stats = {'by_module' : {},
'by_msg' : {},
- }
+ }
for msg_cat in MSG_TYPES.itervalues():
self.stats[msg_cat] = 0
@@ -844,11 +844,11 @@ group are mutually exclusive.'),
self._plugins = []
try:
preprocess_options(args, {
- # option: (callback, takearg)
- 'init-hook': (cb_init_hook, True),
- 'rcfile': (self.cb_set_rcfile, True),
- 'load-plugins': (self.cb_add_plugins, True),
- })
+ # option: (callback, takearg)
+ 'init-hook': (cb_init_hook, True),
+ 'rcfile': (self.cb_set_rcfile, True),
+ 'load-plugins': (self.cb_add_plugins, True),
+ })
except ArgumentPreprocessingError, ex:
print >> sys.stderr, ex
sys.exit(32)
@@ -863,15 +863,15 @@ group are mutually exclusive.'),
{'action' : 'callback', 'callback' : lambda *args: 1,
'type' : 'string', 'metavar': '<code>',
'level': 1,
- 'help' : 'Python code to execute, usually for sys.path \
-manipulation such as pygtk.require().'}),
+ 'help' : 'Python code to execute, usually for sys.path '
+ 'manipulation such as pygtk.require().'}),
('help-msg',
{'action' : 'callback', 'type' : 'string', 'metavar': '<msg-id>',
'callback' : self.cb_help_message,
'group': 'Commands',
- 'help' : '''Display a help message for the given message id and \
-exit. The value may be a comma separated list of message ids.'''}),
+ 'help' : 'Display a help message for the given message id and '
+ 'exit. The value may be a comma separated list of message ids.'}),
('list-msgs',
{'action' : 'callback', 'metavar': '<msg-id>',
@@ -888,9 +888,10 @@ exit. The value may be a comma separated list of message ids.'''}),
('generate-rcfile',
{'action' : 'callback', 'callback' : self.cb_generate_config,
'group': 'Commands',
- 'help' : '''Generate a sample configuration file according to \
-the current configuration. You can put other options before this one to get \
-them in the generated configuration.'''}),
+ 'help' : 'Generate a sample configuration file according to '
+ 'the current configuration. You can put other options '
+ 'before this one to get them in the generated '
+ 'configuration.'}),
('generate-man',
{'action' : 'callback', 'callback' : self.cb_generate_manpage,
@@ -900,9 +901,9 @@ them in the generated configuration.'''}),
('errors-only',
{'action' : 'callback', 'callback' : self.cb_error_mode,
'short': 'E',
- 'help' : '''In error mode, checkers without error messages are \
-disabled and for others, only the ERROR messages are displayed, and no reports \
-are done by default'''}),
+ 'help' : 'In error mode, checkers without error messages are '
+ 'disabled and for others, only the ERROR messages are '
+ 'displayed, and no reports are done by default'''}),
('profile',
{'type' : 'yn', 'metavar' : '<y_or_n>',
@@ -916,6 +917,7 @@ are done by default'''}),
linter.load_plugin_modules(self._plugins)
# add some help section
linter.add_help_section('Environment variables', config.ENV_HELP, level=1)
+ # pylint: disable=bad-continuation
linter.add_help_section('Output',
'Using the default text output, the message format is : \n'
' \n'
@@ -928,7 +930,7 @@ are done by default'''}),
' * (E) error, for probable bugs in the code \n'
' * (F) fatal, if an error occurred which prevented pylint from doing further\n'
'processing.\n'
- , level=1)
+ , level=1)
linter.add_help_section('Output status code',
'Pylint should leave with following status code: \n'
' * 0 if everything went fine \n'
@@ -941,7 +943,7 @@ are done by default'''}),
' \n'
'status 1 to 16 will be bit-ORed so you can know which different categories has\n'
'been issued by analysing pylint output status code\n',
- level=1)
+ level=1)
# read configuration
linter.disable('pointless-except')
linter.disable('suppressed-message')
diff --git a/man/pylint.1 b/man/pylint.1
index 480ac18..57954c8 100644
--- a/man/pylint.1
+++ b/man/pylint.1
@@ -1,4 +1,4 @@
-.TH pylint 1 "2014-4-18" pylint
+.TH pylint 1 "2014-7-25" pylint
.SH NAME
.B pylint
\- python code static checker
@@ -75,7 +75,7 @@ Put messages in a separate file for each module / package specified on the comma
.IP "--reports=<y_or_n>, -r <y_or_n>"
Tells whether to display a full report or only the messages [current: yes]
.IP "--evaluation=<python_expression>"
-Python expression which should return a note less than 10 (10 is the highest note). You have access to the variables errors warning, statement which respectively contain the number of errors / warnings messages and the total number of statements analyzed. This is used by the global evaluation report (RP0004). [current: 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)]
+Python expression which should return a note less than 10 (10 is the highest note). You have access to the variables errors warning, statement which respectively contain the number of errors / warnings messages and the total number of statements analyzed. This is used by the global evaluation report (RP0004). [current: 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)]
.IP "--comment=<y_or_n>"
Add a comment according to your evaluation note. This is used by the global evaluation report (RP0004). [current: no]
.IP "--msg-template=<template>"
@@ -130,6 +130,8 @@ List of optional constructs for which whitespace checking is disabled [current:
Maximum number of lines in a module [current: 1000]
.IP "--indent-string=<string>"
String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 tab). [current: ' ']
+.IP "--indent-after-paren=<int>"
+Number of spaces of indent required inside a hanging or continued line. [current: 4]
.SH BASIC
.IP "--required-attributes=<attributes>"
@@ -211,7 +213,7 @@ List of note tags to take in consideration, separated by a comma. [current: FIXM
.IP "--ignore-mixin-members=<y_or_n>"
Tells whether missing members accessed in mixin class should be ignored. A mixin class is detected if its name ends with "mixin" (case insensitive). [current: yes]
.IP "--ignored-modules=<module names>"
-List of module names for which member attributes should not be checked (useful for modules/projects where namespaces are manipulated during runtime and thus extisting member attributes cannot be deduced by static analysis [current: none]
+List of module names for which member attributes should not be checked (useful for modules/projects where namespaces are manipulated during runtime and thus existing member attributes cannot be deduced by static analysis [current: none]
.IP "--ignored-classes=<members names>"
List of classes names for which member attributes should not be checked (useful for classes with attributes dynamically set). [current: SQLObject]
.IP "--zope=<y_or_n>"
diff --git a/pyreverse/main.py b/pyreverse/main.py
index 7801835..d4991b5 100644
--- a/pyreverse/main.py
+++ b/pyreverse/main.py
@@ -29,10 +29,10 @@ from pylint.pyreverse import writer
from pylint.pyreverse.utils import insert_default_options
OPTIONS = (
-("filter-mode",
- dict(short='f', default='PUB_ONLY', dest='mode', type='string',
- action='store', metavar='<mode>',
- help="""filter attributes and functions according to
+ ("filter-mode",
+ dict(short='f', default='PUB_ONLY', dest='mode', type='string',
+ action='store', metavar='<mode>',
+ help="""filter attributes and functions according to
<mode>. Correct modes are :
'PUB_ONLY' filter all non public attributes
[DEFAULT], equivalent to PRIVATE+SPECIAL_A
@@ -42,43 +42,42 @@ OPTIONS = (
'OTHER' filter protected and private
attributes""")),
-("class",
-dict(short='c', action="append", metavar="<class>", dest="classes", default=[],
- help="create a class diagram with all classes related to <class>;\
+ ("class",
+ dict(short='c', action="append", metavar="<class>", dest="classes", default=[],
+ help="create a class diagram with all classes related to <class>;\
this uses by default the options -ASmy")),
-("show-ancestors",
-dict(short="a", action="store", metavar='<ancestor>', type='int',
- help='show <ancestor> generations of ancestor classes not in <projects>')),
-("all-ancestors",
-dict(short="A", default=None,
- help="show all ancestors off all classes in <projects>")),
-("show-associated",
-dict(short='s', action="store", metavar='<ass_level>', type='int',
- help='show <ass_level> levels of associated classes not in <projects>')),
-("all-associated",
-dict(short='S', default=None,
- help='show recursively all associated off all associated classes')),
+ ("show-ancestors",
+ dict(short="a", action="store", metavar='<ancestor>', type='int',
+ help='show <ancestor> generations of ancestor classes not in <projects>')),
+ ("all-ancestors",
+ dict(short="A", default=None,
+ help="show all ancestors off all classes in <projects>")),
+ ("show-associated",
+ dict(short='s', action="store", metavar='<ass_level>', type='int',
+ help='show <ass_level> levels of associated classes not in <projects>')),
+ ("all-associated",
+ dict(short='S', default=None,
+ help='show recursively all associated off all associated classes')),
+ ("show-builtin",
+ dict(short="b", action="store_true", default=False,
+ help='include builtin objects in representation of classes')),
-("show-builtin",
-dict(short="b", action="store_true", default=False,
- help='include builtin objects in representation of classes')),
-
-("module-names",
-dict(short="m", default=None, type='yn', metavar='[yn]',
- help='include module name in representation of classes')),
-# TODO : generate dependencies like in pylint
-#("package-dependencies",
-#dict(short="M", action="store", metavar='<package_depth>', type='int',
- #help='show <package_depth> module dependencies beyond modules in \
-#<projects> (for the package diagram)')),
-("only-classnames",
-dict(short='k', action="store_true", default=False,
- help="don't show attributes and methods in the class boxes; \
+ ("module-names",
+ dict(short="m", default=None, type='yn', metavar='[yn]',
+ help='include module name in representation of classes')),
+ # TODO : generate dependencies like in pylint
+ # ("package-dependencies",
+ # dict(short="M", action="store", metavar='<package_depth>', type='int',
+ # help='show <package_depth> module dependencies beyond modules in \
+ # <projects> (for the package diagram)')),
+ ("only-classnames",
+ dict(short='k', action="store_true", default=False,
+ help="don't show attributes and methods in the class boxes; \
this disables -f values")),
-("output", dict(short="o", dest="output_format", action="store",
- default="dot", metavar="<format>",
- help="create a *.<format> output file if format available.")),
+ ("output", dict(short="o", dest="output_format", action="store",
+ default="dot", metavar="<format>",
+ help="create a *.<format> output file if format available.")),
)
# FIXME : quiet mode
#( ('quiet',
diff --git a/pyreverse/writer.py b/pyreverse/writer.py
index 6b35548..8628a8c 100644
--- a/pyreverse/writer.py
+++ b/pyreverse/writer.py
@@ -51,7 +51,7 @@ class DiagramWriter(object):
# package dependencies
for rel in diagram.get_relationships('depends'):
self.printer.emit_edge(rel.from_object.fig_id, rel.to_object.fig_id,
- **self.pkg_edges)
+ **self.pkg_edges)
def write_classes(self, diagram):
"""write a class diagram"""
@@ -99,7 +99,7 @@ class DotWriter(DiagramWriter):
dict(arrowtail='node', arrowhead='empty', style='dashed'),
dict(fontcolor='green', arrowtail='none',
arrowhead='diamond', style='solid'),
- ]
+ ]
DiagramWriter.__init__(self, config, styles)
def set_printer(self, file_name, basename):
@@ -147,7 +147,7 @@ class VCGWriter(DiagramWriter):
linestyle='dotted', backarrowsize=10),
dict(arrowstyle='solid', backarrowstyle='none',
textcolor='green'),
- ]
+ ]
DiagramWriter.__init__(self, config, styles)
def set_printer(self, file_name, basename):
diff --git a/reporters/text.py b/reporters/text.py
index bd99837..04245f7 100644
--- a/reporters/text.py
+++ b/reporters/text.py
@@ -38,7 +38,7 @@ class TextReporter(BaseReporter):
def __init__(self, output=None):
BaseReporter.__init__(self, output)
- self._modules = {}
+ self._modules = set()
self._template = None
def on_set_current_module(self, module, filepath):
@@ -54,7 +54,7 @@ class TextReporter(BaseReporter):
if m.module not in self._modules:
if m.module:
self.writeln('************* Module %s' % m.module)
- self._modules[m.module] = 1
+ self._modules.add(m.module)
else:
self.writeln('************* ')
self.write_message(m)
@@ -128,7 +128,7 @@ class ColorizedTextReporter(TextReporter):
modsep = colorize_ansi('************* %s' % msg.module,
color, style)
self.writeln(modsep)
- self._modules[msg.module] = 1
+ self._modules.add(msg.module)
color, style = self._get_decoration(msg.C)
for attr in ('msg', 'symbol', 'category', 'C'):
setattr(msg, attr, colorize_ansi(getattr(msg, attr), color, style))
diff --git a/setup.py b/setup.py
index 226b39e..476b953 100644
--- a/setup.py
+++ b/setup.py
@@ -135,7 +135,7 @@ class MyInstallLib(install_lib.install_lib):
# since python2.5's copytree doesn't support the ignore
# parameter, the following loop to remove the exclude set
# was added
- for (dirpath, dirnames, filenames) in os.walk(dest):
+ for (dirpath, _, filenames) in os.walk(dest):
for n in filenames:
if n in exclude:
os.remove(os.path.join(dirpath, n))
@@ -176,12 +176,12 @@ def install(**kwargs):
kwargs['install_requires'] = install_requires
kwargs['dependency_links'] = dependency_links
kwargs['entry_points'] = {'console_scripts': [
- 'pylint = pylint:run_pylint',
- 'pylint-gui = pylint:run_pylint_gui',
- 'epylint = pylint:run_epylint',
- 'pyreverse = pylint:run_pyreverse',
- 'symilar = pylint:run_symilar',
- ]}
+ 'pylint = pylint:run_pylint',
+ 'pylint-gui = pylint:run_pylint_gui',
+ 'epylint = pylint:run_epylint',
+ 'pyreverse = pylint:run_pyreverse',
+ 'symilar = pylint:run_symilar',
+ ]}
kwargs['packages'] = packages
return setup(name=distname,
version=version,
@@ -196,8 +196,8 @@ def install(**kwargs):
data_files=data_files,
ext_modules=ext_modules,
cmdclass={'install_lib': MyInstallLib,
- 'build_py': build_py},
+ 'build_py': build_py},
**kwargs)
-if __name__ == '__main__' :
+if __name__ == '__main__':
install()
diff --git a/test/input/func_bad_continuation.py b/test/functional/bad_continuation.py
index f303915..3d62521 100644
--- a/test/input/func_bad_continuation.py
+++ b/test/functional/bad_continuation.py
@@ -1,7 +1,5 @@
"""Regression test case for bad-continuation."""
-__revision__ = 1
-
# Various alignment for brackets
LIST0 = [
1, 2, 3
@@ -39,7 +37,7 @@ W2 = ['some', 'contents' # with a continued comment that may be aligned
'and',
'more', # but this
# [bad-continuation] is not accepted
- 'contents', # nor this. [bad-continuation]
+ 'contents', # [bad-continuation] nor this.
]
# Values in dictionaries should be indented 4 spaces further if they are on a
@@ -108,7 +106,7 @@ def continue3(
"""A function with misaligned arguments"""
print some_arg, some_other_arg
-def continue4(
+def continue4( # pylint:disable=missing-docstring
arg1,
arg2): print arg1, arg2
diff --git a/test/functional/bad_continuation.txt b/test/functional/bad_continuation.txt
new file mode 100644
index 0000000..732858e
--- /dev/null
+++ b/test/functional/bad_continuation.txt
@@ -0,0 +1,63 @@
+bad-continuation:12::Wrong hanging indentation.
+ ] # [bad-continuation]
+| ^|
+bad-continuation:17::Wrong continued indentation.
+ 7, # [bad-continuation]
+ | ^
+bad-continuation:25::Wrong hanging indentation.
+ 'b': 2, # [bad-continuation]
+ ^|
+bad-continuation:31::Wrong hanging indentation.
+ 'b': 2, # [bad-continuation]
+ ^|
+bad-continuation:39::Wrong continued indentation.
+ # [bad-continuation] is not accepted
+ | | ^
+bad-continuation:40::Wrong continued indentation.
+ 'contents', # [bad-continuation] nor this.
+ | ^
+bad-continuation:49::Wrong hanging indentation in dict value.
+ 'value2', # [bad-continuation]
+ | ^ |
+bad-continuation:59::Wrong continued indentation.
+ 'wrong', # [bad-continuation]
+ ^ |
+bad-continuation:83::Wrong hanging indentation in dict value.
+'value1', # [bad-continuation]
+^ | |
+bad-continuation:87::Wrong hanging indentation in dict value.
+ 'value1', # [bad-continuation]
+ ^ | |
+bad-continuation:104::Wrong hanging indentation before block.
+ some_arg, # [bad-continuation]
+ ^ |
+bad-continuation:105::Wrong hanging indentation before block.
+ some_other_arg): # [bad-continuation]
+ ^ |
+bad-continuation:125::Wrong continued indentation.
+ "b") # [bad-continuation]
+ ^ |
+bad-continuation:139::Wrong hanging indentation before block.
+ ): pass # [bad-continuation]
+| ^|
+bad-continuation:142::Wrong continued indentation before block.
+ 2): # [bad-continuation]
+ ^ |
+bad-continuation:150::Wrong continued indentation.
+ 2 and # [bad-continuation]
+ | ^
+bad-continuation:155::Wrong hanging indentation before block.
+ 2): pass # [bad-continuation]
+ ^ | |
+bad-continuation:162::Wrong continued indentation before block.
+ 2 or # [bad-continuation]
+ |^ |
+bad-continuation:166::Wrong continued indentation before block.
+ 2): pass # [bad-continuation]
+ ^ | |
+bad-continuation:172::Wrong hanging indentation before block.
+ 2): # [bad-continuation]
+ ^ | |
+bad-continuation:183::Wrong continued indentation.
+ 2): # [bad-continuation]
+ ^ |
diff --git a/test/input/func_loopvar_in_closure.py b/test/functional/cellvar_escaping_loop.py
index 3a791d3..316bc47 100644
--- a/test/input/func_loopvar_in_closure.py
+++ b/test/functional/cellvar_escaping_loop.py
@@ -1,8 +1,5 @@
"""Tests for loopvar-in-closure."""
-__revision__ = 0
-
-
def good_case():
"""No problems here."""
lst = []
@@ -18,7 +15,7 @@ def good_case2():
def good_case3():
"""No problems here."""
lst = []
- for i in range(10):
+ for i in range(10): # [unused-variable]
lst.append(lambda i=i: i)
@@ -42,7 +39,7 @@ def good_case6():
the value will not change any more."""
for i in range(10):
print i
- return lambda: i
+ return lambda: i # [undefined-loop-variable]
def good_case7():
@@ -75,12 +72,12 @@ def bad_case():
lst = []
for i in range(10):
print i
- lst.append(lambda: i)
+ lst.append(lambda: i) # [cell-var-from-loop]
def bad_case2():
"""Closing over a loop variable."""
- return [lambda: i for i in range(10)]
+ return [lambda: i for i in range(10)] # [cell-var-from-loop]
def bad_case3():
@@ -88,7 +85,7 @@ def bad_case3():
lst = []
for i in range(10):
j = i * i
- lst.append(lambda: j)
+ lst.append(lambda: j) # [cell-var-from-loop]
return lst
@@ -98,7 +95,7 @@ def bad_case4():
for i in range(10):
def nested():
"""Nested function."""
- return i**2
+ return i**2 # [cell-var-from-loop]
lst.append(nested)
return lst
@@ -119,7 +116,7 @@ def bad_case5():
the result is [9] * 10 again.
"""
- return (lambda: i for i in range(10))
+ return (lambda: i for i in range(10)) # [cell-var-from-loop]
def bad_case6():
@@ -127,6 +124,5 @@ def bad_case6():
lst = []
for i, j in zip(range(10), range(10, 20)):
print j
- lst.append(lambda: i)
+ lst.append(lambda: i) # [cell-var-from-loop]
return lst
-
diff --git a/test/functional/cellvar_escaping_loop.txt b/test/functional/cellvar_escaping_loop.txt
new file mode 100644
index 0000000..4448d44
--- /dev/null
+++ b/test/functional/cellvar_escaping_loop.txt
@@ -0,0 +1,8 @@
+unused-variable:18:good_case3:Unused variable 'i'
+undefined-loop-variable:42:good_case6.<lambda>:Using possibly undefined loop variable 'i'
+cell-var-from-loop:75:bad_case.<lambda>:Cell variable i defined in loop
+cell-var-from-loop:80:bad_case2.<lambda>:Cell variable i defined in loop
+cell-var-from-loop:88:bad_case3.<lambda>:Cell variable j defined in loop
+cell-var-from-loop:98:bad_case4.nested:Cell variable i defined in loop
+cell-var-from-loop:119:bad_case5.<lambda>:Cell variable i defined in loop
+cell-var-from-loop:127:bad_case6.<lambda>:Cell variable i defined in loop
diff --git a/test/input/func_ctor_arguments.py b/test/functional/ctor_arguments.py
index f9a3430..7dc0a09 100644
--- a/test/input/func_ctor_arguments.py
+++ b/test/functional/ctor_arguments.py
@@ -1,9 +1,9 @@
"""Test function argument checker on __init__
-Based on test/input/func_arguments.py
+Based on test/functional/arguments.py
"""
# pylint: disable=C0111,R0903,W0231
-__revision__ = ''
+
class Class1Arg(object):
def __init__(self, first_argument):
@@ -32,35 +32,36 @@ class ClassNew(object):
return first_argument, kwarg
Class1Arg(420)
-Class1Arg()
-Class1Arg(1337, 347)
+Class1Arg() # [no-value-for-parameter]
+Class1Arg(1337, 347) # [too-many-function-args]
-Class3Arg(420, 789)
+Class3Arg(420, 789) # [no-value-for-parameter]
+# +1:[no-value-for-parameter,no-value-for-parameter,no-value-for-parameter]
Class3Arg()
Class3Arg(1337, 347, 456)
-Class3Arg('bab', 'bebe', None, 5.6)
+Class3Arg('bab', 'bebe', None, 5.6) # [too-many-function-args]
ClassDefaultArg(1, two=5)
ClassDefaultArg(two=5)
-Class1Arg(bob=4)
-ClassDefaultArg(1, 4, coin="hello")
+Class1Arg(bob=4) # [no-value-for-parameter,unexpected-keyword-arg]
+ClassDefaultArg(1, 4, coin="hello") # [unexpected-keyword-arg]
-ClassDefaultArg(1, one=5)
+ClassDefaultArg(1, one=5) # [redundant-keyword-arg]
Subclass1Arg(420)
-Subclass1Arg()
-Subclass1Arg(1337, 347)
+Subclass1Arg() # [no-value-for-parameter]
+Subclass1Arg(1337, 347) # [too-many-function-args]
ClassAllArgs()
ClassAllArgs(1, 2, 3, even=4, more=5)
ClassMultiInheritance(1)
-ClassMultiInheritance(1, 2, 3)
+ClassMultiInheritance(1, 2, 3) # [too-many-function-args]
ClassNew(1, kwarg=1)
-ClassNew(1, 2, 3)
-ClassNew(one=2)
+ClassNew(1, 2, 3) # [too-many-function-args]
+ClassNew(one=2) # [no-value-for-parameter,unexpected-keyword-arg]
class Metaclass(type):
diff --git a/test/functional/ctor_arguments.txt b/test/functional/ctor_arguments.txt
new file mode 100644
index 0000000..85cf139
--- /dev/null
+++ b/test/functional/ctor_arguments.txt
@@ -0,0 +1,17 @@
+no-value-for-parameter:35::No value for argument 'first_argument' in constructor call
+too-many-function-args:36::Too many positional arguments for constructor call
+no-value-for-parameter:38::No value for argument 'third_argument' in constructor call
+no-value-for-parameter:40::No value for argument 'first_argument' in constructor call
+no-value-for-parameter:40::No value for argument 'second_argument' in constructor call
+no-value-for-parameter:40::No value for argument 'third_argument' in constructor call
+too-many-function-args:42::Too many positional arguments for constructor call
+no-value-for-parameter:47::No value for argument 'first_argument' in constructor call
+unexpected-keyword-arg:47::Unexpected keyword argument 'bob' in constructor call
+unexpected-keyword-arg:48::Unexpected keyword argument 'coin' in constructor call
+redundant-keyword-arg:50::Argument 'one' passed by position and keyword in constructor call
+no-value-for-parameter:53::No value for argument 'first_argument' in constructor call
+too-many-function-args:54::Too many positional arguments for constructor call
+too-many-function-args:60::Too many positional arguments for constructor call
+too-many-function-args:63::Too many positional arguments for constructor call
+no-value-for-parameter:64::No value for argument 'first_argument' in constructor call
+unexpected-keyword-arg:64::Unexpected keyword argument 'one' in constructor call
diff --git a/test/functional/exception_is_binary_op.py b/test/functional/exception_is_binary_op.py
new file mode 100644
index 0000000..443a478
--- /dev/null
+++ b/test/functional/exception_is_binary_op.py
@@ -0,0 +1,12 @@
+"""Warn about binary operations used as exceptions."""
+
+try:
+ pass
+except Exception or StandardError: # [binary-op-exception]
+ print "caught1"
+except Exception and StandardError: # [binary-op-exception]
+ print "caught2"
+except Exception or StandardError: # [binary-op-exception]
+ print "caught3"
+except (Exception or StandardError), exc: # [binary-op-exception]
+ print "caught4"
diff --git a/test/functional/exception_is_binary_op.txt b/test/functional/exception_is_binary_op.txt
new file mode 100644
index 0000000..039bc3f
--- /dev/null
+++ b/test/functional/exception_is_binary_op.txt
@@ -0,0 +1,4 @@
+binary-op-exception:5::Exception to catch is the result of a binary "or" operation
+binary-op-exception:7::Exception to catch is the result of a binary "and" operation
+binary-op-exception:9::Exception to catch is the result of a binary "or" operation
+binary-op-exception:11::Exception to catch is the result of a binary "or" operation
diff --git a/test/input/func_e0205.py b/test/functional/method_hidden.py
index 34208f9..0510f55 100644
--- a/test/input/func_e0205.py
+++ b/test/functional/method_hidden.py
@@ -1,9 +1,7 @@
-# pylint: disable=R0903
+# pylint: disable=too-few-public-methods
"""check method hidding ancestor attribute
"""
-__revision__ = ''
-
class Abcd(object):
"""dummy"""
def __init__(self):
@@ -11,7 +9,7 @@ class Abcd(object):
class Cdef(Abcd):
"""dummy"""
- def abcd(self):
+ def abcd(self): # [method-hidden]
"""test
"""
print self
diff --git a/test/functional/method_hidden.txt b/test/functional/method_hidden.txt
new file mode 100644
index 0000000..c15f3bc
--- /dev/null
+++ b/test/functional/method_hidden.txt
@@ -0,0 +1 @@
+method-hidden:12:Cdef.abcd:An attribute defined in functional.method_hidden line 8 hides this method
diff --git a/test/functional/redefined_builtin.py b/test/functional/redefined_builtin.py
new file mode 100644
index 0000000..ace2ea6
--- /dev/null
+++ b/test/functional/redefined_builtin.py
@@ -0,0 +1,9 @@
+"""Tests for redefining builtins."""
+
+def function():
+ """Redefined local."""
+ type = 1 # [redefined-builtin]
+ print type
+
+# pylint:disable=invalid-name
+map = {} # [redefined-builtin]
diff --git a/test/functional/redefined_builtin.txt b/test/functional/redefined_builtin.txt
new file mode 100644
index 0000000..71518ce
--- /dev/null
+++ b/test/functional/redefined_builtin.txt
@@ -0,0 +1,2 @@
+redefined-builtin:5:function:Redefining built-in 'type'
+redefined-builtin:9::Redefining built-in 'map'
diff --git a/test/input/func_undefined_var.py b/test/functional/undefined_variable.py
index fb5fc30..25f0145 100644
--- a/test/input/func_undefined_var.py
+++ b/test/functional/undefined_variable.py
@@ -1,38 +1,33 @@
-"""test access to undefined variables"""
+"""Test warnings about access to undefined variables."""
# pylint: disable=too-few-public-methods, no-init, no-self-use
-__revision__ = '$Id:'
DEFINED = 1
if DEFINED != 1:
- if DEFINED in (unknown, DEFINED):
+ if DEFINED in (unknown, DEFINED): # [undefined-variable]
DEFINED += 1
def in_method(var):
"""method doc"""
- var = nomoreknown
+ var = nomoreknown # [undefined-variable]
assert var
-DEFINED = {DEFINED:__revision__}
+DEFINED = {DEFINED:__revision__} # [undefined-variable]
+# +1:[undefined-variable]
DEFINED[__revision__] = OTHER = 'move this is astroid test'
OTHER += '$'
-def bad_default(var, default=unknown2):
+def bad_default(var, default=unknown2): # [undefined-variable]
"""function with defaut arg's value set to an unexistant name"""
print var, default
- print xxxx
- print xxxx #see story #1000
- augvar += 1
- del vardel
-
-# Warning for Attribute access to undefinde attributes ?
-#class Attrs(object):
- #"""dummy class for wrong attribute access"""
-#AOU = Attrs()
-#AOU.number *= 1.3
-#del AOU.badattr
+ print xxxx # [undefined-variable]
+ augvar += 1 # [undefined-variable,unused-variable]
+ del vardel # [undefined-variable]
+
+LMBD = lambda x, y=doesnotexist: x+y # [undefined-variable]
+LMBD2 = lambda x, y: x+z # [undefined-variable]
try:
POUET # don't catch me
@@ -41,19 +36,19 @@ except NameError:
try:
POUETT # don't catch me
-except Exception: # pylint:disable = W0703
+except Exception: # pylint:disable = broad-except
POUETT = 'something'
try:
POUETTT # don't catch me
-except: # pylint:disable = W0702
+except: # pylint:disable = bare-except
POUETTT = 'something'
print POUET, POUETT, POUETTT
try:
- PLOUF # catch me
+ PLOUF # [used-before-assignment]
except ValueError:
PLOUF = 'something'
@@ -62,7 +57,7 @@ print PLOUF
def if_branch_test(something):
"""hop"""
if something == 0:
- if xxx == 1:
+ if xxx == 1: # [used-before-assignment]
pass
else:
print xxx
@@ -77,30 +72,32 @@ def decorator(arg):
@decorator(arg=[i * 2 for i in range(15)])
def func1():
"""A function with a decorator that contains a listcomp."""
- pass
@decorator(arg=(i * 2 for i in range(15)))
def func2():
"""A function with a decorator that contains a genexpr."""
- pass
+
+@decorator(lambda x: x > 0)
+def main():
+ """A function with a decorator that contains a lambda."""
# Test shared scope.
-def test_arguments(arg=TestClass):
+def test_arguments(arg=TestClass): # [used-before-assignment]
""" TestClass isn't defined yet. """
return arg
-class TestClass(Ancestor):
+class TestClass(Ancestor): # [used-before-assignment]
""" contains another class, which uses an undefined ancestor. """
- class MissingAncestor(Ancestor1):
+ class MissingAncestor(Ancestor1): # [used-before-assignment]
""" no op """
def test1(self):
""" It should trigger here, because the two classes
have the same scope.
"""
- class UsingBeforeDefinition(Empty):
+ class UsingBeforeDefinition(Empty): # [used-before-assignment]
""" uses Empty before definition """
class Empty(object):
""" no op """
diff --git a/test/functional/undefined_variable.txt b/test/functional/undefined_variable.txt
new file mode 100644
index 0000000..5695be1
--- /dev/null
+++ b/test/functional/undefined_variable.txt
@@ -0,0 +1,17 @@
+undefined-variable:7::Undefined variable 'unknown'
+undefined-variable:13:in_method:Undefined variable 'nomoreknown'
+undefined-variable:16::Undefined variable '__revision__'
+undefined-variable:18::Undefined variable '__revision__'
+undefined-variable:22:bad_default:Undefined variable 'unknown2'
+undefined-variable:25:bad_default:Undefined variable 'xxxx'
+undefined-variable:26:bad_default:Undefined variable 'augvar'
+unused-variable:26:bad_default:Unused variable 'augvar'
+undefined-variable:27:bad_default:Undefined variable 'vardel'
+undefined-variable:29:<lambda>:Undefined variable 'doesnotexist'
+undefined-variable:30:<lambda>:Undefined variable 'z'
+used-before-assignment:51::Using variable 'PLOUF' before assignment
+used-before-assignment:60:if_branch_test:Using variable 'xxx' before assignment
+used-before-assignment:86:test_arguments:Using variable 'TestClass' before assignment
+used-before-assignment:90:TestClass:Using variable 'Ancestor' before assignment
+used-before-assignment:93:TestClass.MissingAncestor:Using variable 'Ancestor1' before assignment
+used-before-assignment:100:TestClass.test1.UsingBeforeDefinition:Using variable 'Empty' before assignment
diff --git a/test/input/func_w0108.py b/test/functional/unnecessary_lambda.py
index 0d4cc62..1c9b424 100644
--- a/test/input/func_w0108.py
+++ b/test/functional/unnecessary_lambda.py
@@ -1,40 +1,50 @@
-# pylint: disable=W0142
-"""test suspicious lambda expressions
-"""
-
-__revision__ = ''
-
-# Some simple examples of the most commonly encountered forms.
-_ = lambda: list() # replaceable with "list"
-_ = lambda x: hash(x) # replaceable with "hash"
-_ = lambda x, y: min(x, y) # replaceable with "min"
-
-# A function that can take any arguments given to it.
-_ANYARGS = lambda *args, **kwargs: 'completely arbitrary return value'
-
-# Some more complex forms of unnecessary lambda expressions.
-_ = lambda *args: _ANYARGS(*args)
-_ = lambda **kwargs: _ANYARGS(**kwargs)
-_ = lambda *args, **kwargs: _ANYARGS(*args, **kwargs)
-_ = lambda x, y, z, *args, **kwargs: _ANYARGS(x, y, z, *args, **kwargs)
-
-# Lambdas that are *not* unnecessary and should *not* trigger warnings.
-_ = lambda x: x
-_ = lambda x: x()
-_ = lambda x=4: hash(x)
-_ = lambda x, y: range(y, x)
-_ = lambda x: range(5, x)
-_ = lambda x, y: range(x, 5)
-_ = lambda x, y, z: x.y(z)
-_ = lambda: 5
-_ = lambda **kwargs: _ANYARGS()
-_ = lambda **kwargs: _ANYARGS(**dict([('three', 3)]))
-_ = lambda **kwargs: _ANYARGS(**{'three': 3})
-_ = lambda dict_arg, **kwargs: _ANYARGS(kwargs, **dict_arg)
-_ = lambda *args: _ANYARGS()
-_ = lambda *args: _ANYARGS(*list([3, 4]))
-_ = lambda *args: _ANYARGS(*[3, 4])
-_ = lambda list_arg, *args: _ANYARGS(args, *list_arg)
-_ = lambda: _ANYARGS(*[3])
-_ = lambda: _ANYARGS(**{'three': 3})
-_ = lambda: _ANYARGS(*[3], **{'three': 3})
+# pylint: disable=star-args, undefined-variable
+"""test suspicious lambda expressions
+"""
+
+__revision__ = ''
+
+# Some simple examples of the most commonly encountered forms.
+# +1: [unnecessary-lambda]
+_ = lambda: list() # replaceable with "list"
+# +1: [unnecessary-lambda]
+_ = lambda x: hash(x) # replaceable with "hash"
+# +1: [unnecessary-lambda]
+_ = lambda x, y: min(x, y) # replaceable with "min"
+
+# A function that can take any arguments given to it.
+_ANYARGS = lambda *args, **kwargs: 'completely arbitrary return value'
+
+# Some more complex forms of unnecessary lambda expressions.
+# +1: [unnecessary-lambda]
+_ = lambda *args: _ANYARGS(*args)
+# +1: [unnecessary-lambda]
+_ = lambda **kwargs: _ANYARGS(**kwargs)
+# +1: [unnecessary-lambda]
+_ = lambda *args, **kwargs: _ANYARGS(*args, **kwargs)
+# +1: [unnecessary-lambda]
+_ = lambda x, y, z, *args, **kwargs: _ANYARGS(x, y, z, *args, **kwargs)
+
+# Lambdas that are *not* unnecessary and should *not* trigger warnings.
+_ = lambda x: x
+_ = lambda x: x()
+_ = lambda x=4: hash(x)
+_ = lambda x, y: list(range(y, x))
+_ = lambda x: list(range(5, x))
+_ = lambda x, y: list(range(x, 5))
+_ = lambda x, y, z: x.y(z)
+_ = lambda: 5
+_ = lambda **kwargs: _ANYARGS()
+_ = lambda **kwargs: _ANYARGS(**dict([('three', 3)]))
+_ = lambda **kwargs: _ANYARGS(**{'three': 3})
+_ = lambda dict_arg, **kwargs: _ANYARGS(kwargs, **dict_arg)
+_ = lambda *args: _ANYARGS()
+_ = lambda *args: _ANYARGS(*list([3, 4]))
+_ = lambda *args: _ANYARGS(*[3, 4])
+_ = lambda list_arg, *args: _ANYARGS(args, *list_arg)
+_ = lambda: _ANYARGS(*[3])
+_ = lambda: _ANYARGS(**{'three': 3})
+_ = lambda: _ANYARGS(*[3], **{'three': 3})
+
+# Don't warn about this.
+_ = lambda: code().analysis()
diff --git a/test/functional/unnecessary_lambda.txt b/test/functional/unnecessary_lambda.txt
new file mode 100644
index 0000000..de13882
--- /dev/null
+++ b/test/functional/unnecessary_lambda.txt
@@ -0,0 +1,7 @@
+unnecessary-lambda:9:<lambda>:Lambda may not be necessary
+unnecessary-lambda:11:<lambda>:Lambda may not be necessary
+unnecessary-lambda:13:<lambda>:Lambda may not be necessary
+unnecessary-lambda:20:<lambda>:Lambda may not be necessary
+unnecessary-lambda:22:<lambda>:Lambda may not be necessary
+unnecessary-lambda:24:<lambda>:Lambda may not be necessary
+unnecessary-lambda:26:<lambda>:Lambda may not be necessary
diff --git a/test/input/func_useless_else_on_loop.py b/test/functional/useless_else_on_loop.py
index 289366a..4f27cf7 100644
--- a/test/input/func_useless_else_on_loop.py
+++ b/test/functional/useless_else_on_loop.py
@@ -7,14 +7,14 @@ def test_return_for():
for i in range(10):
if i % 2:
return i
- else:
+ else: # [useless-else-on-loop]
print 'math is broken'
def test_return_while():
"""else + return is not accetable."""
while True:
return 1
- else:
+ else: # [useless-else-on-loop]
print 'math is broken'
@@ -23,19 +23,19 @@ while True:
"""A function with a loop."""
for _ in range(10):
break
-else:
+else: # [useless-else-on-loop]
print 'or else!'
while True:
while False:
break
-else:
+else: # [useless-else-on-loop]
print 'or else!'
for j in range(10):
pass
-else:
+else: # [useless-else-on-loop]
print 'fat chance'
for j in range(10):
break
diff --git a/test/functional/useless_else_on_loop.txt b/test/functional/useless_else_on_loop.txt
new file mode 100644
index 0000000..93309b6
--- /dev/null
+++ b/test/functional/useless_else_on_loop.txt
@@ -0,0 +1,5 @@
+useless-else-on-loop:10:test_return_for:Else clause on loop without a break statement
+useless-else-on-loop:17:test_return_while:Else clause on loop without a break statement
+useless-else-on-loop:26::Else clause on loop without a break statement
+useless-else-on-loop:33::Else clause on loop without a break statement
+useless-else-on-loop:38::Else clause on loop without a break statement
diff --git a/test/input/func_noerror_9215_lambda_arg_as_decorator.py b/test/input/func_noerror_9215_lambda_arg_as_decorator.py
deleted file mode 100644
index cbbc747..0000000
--- a/test/input/func_noerror_9215_lambda_arg_as_decorator.py
+++ /dev/null
@@ -1,29 +0,0 @@
-"""Demonstrate false undefined variable for lambda functions.
-
-http://www.logilab.org/ticket/9215
-"""
-
-__revision__ = None
-
-def decorator(expr):
- """Function returning decorator."""
- def func(function):
- """Pass-thru decorator."""
- return function
- # use expr
- expr(0)
- return func
-
-# this lambda is flagged
-# E0602: 16:main.<lambda>: Undefined variable 'x'
-@decorator(lambda x: x > 0)
-def main():
- """Dummy function."""
- # this one is not flagged
- decorator(lambda y: y > 0)
-
-if __name__ == "__main__":
- main()
-
-
-
diff --git a/test/input/func_w0622.py b/test/input/func_w0622.py
deleted file mode 100644
index 5769841..0000000
--- a/test/input/func_w0622.py
+++ /dev/null
@@ -1,11 +0,0 @@
-# pylint: disable=C0103
-"""test built-in redefinition
-"""
-__revision__ = 0
-
-def function():
- """yo"""
- type = 1
- print type
-
-map = {}
diff --git a/test/input/func_w0711.py b/test/input/func_w0711.py
deleted file mode 100644
index 97c3697..0000000
--- a/test/input/func_w0711.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""find binary operations used as exceptions
-"""
-
-__revision__ = 1
-
-try:
- __revision__ += 1
-except Exception or StandardError:
- print "caught1"
-except Exception and StandardError:
- print "caught2"
-except Exception or StandardError:
- print "caught3"
-except (Exception or StandardError), exc:
- print "caught4"
diff --git a/test/messages/func_bad_continuation.txt b/test/messages/func_bad_continuation.txt
deleted file mode 100644
index 42087e5..0000000
--- a/test/messages/func_bad_continuation.txt
+++ /dev/null
@@ -1,64 +0,0 @@
-C: 14: Wrong hanging indentation.
- ] # [bad-continuation]
-| ^|
-C: 19: Wrong continued indentation.
- 7, # [bad-continuation]
- | ^
-C: 27: Wrong hanging indentation.
- 'b': 2, # [bad-continuation]
- ^|
-C: 33: Wrong hanging indentation.
- 'b': 2, # [bad-continuation]
- ^|
-C: 41: Wrong continued indentation.
- # [bad-continuation] is not accepted
- | | ^
-C: 42: Wrong continued indentation.
- 'contents', # nor this. [bad-continuation]
- | ^
-C: 51: Wrong hanging indentation in dict value.
- 'value2', # [bad-continuation]
- | ^ |
-C: 61: Wrong continued indentation.
- 'wrong', # [bad-continuation]
- ^ |
-C: 85: Wrong hanging indentation in dict value.
-'value1', # [bad-continuation]
-^ | |
-C: 89: Wrong hanging indentation in dict value.
- 'value1', # [bad-continuation]
- ^ | |
-C:106: Wrong hanging indentation before block.
- some_arg, # [bad-continuation]
- ^ |
-C:107: Wrong hanging indentation before block.
- some_other_arg): # [bad-continuation]
- ^ |
-C:111:continue4: Missing function docstring
-C:127: Wrong continued indentation.
- "b") # [bad-continuation]
- ^ |
-C:141: Wrong hanging indentation before block.
- ): pass # [bad-continuation]
-| ^|
-C:144: Wrong continued indentation before block.
- 2): # [bad-continuation]
- ^ |
-C:152: Wrong continued indentation.
- 2 and # [bad-continuation]
- | ^
-C:157: Wrong hanging indentation before block.
- 2): pass # [bad-continuation]
- ^ | |
-C:164: Wrong continued indentation before block.
- 2 or # [bad-continuation]
- |^ |
-C:168: Wrong continued indentation before block.
- 2): pass # [bad-continuation]
- ^ | |
-C:174: Wrong hanging indentation before block.
- 2): # [bad-continuation]
- ^ | |
-C:185: Wrong continued indentation.
- 2): # [bad-continuation]
- ^ |
diff --git a/test/messages/func_ctor_arguments.txt b/test/messages/func_ctor_arguments.txt
deleted file mode 100644
index b8d62b1..0000000
--- a/test/messages/func_ctor_arguments.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-E: 35: No value for argument 'first_argument' in constructor call
-E: 36: Too many positional arguments for constructor call
-E: 38: No value for argument 'third_argument' in constructor call
-E: 39: No value for argument 'first_argument' in constructor call
-E: 39: No value for argument 'second_argument' in constructor call
-E: 39: No value for argument 'third_argument' in constructor call
-E: 41: Too many positional arguments for constructor call
-E: 46: No value for argument 'first_argument' in constructor call
-E: 46: Unexpected keyword argument 'bob' in constructor call
-E: 47: Unexpected keyword argument 'coin' in constructor call
-E: 49: Argument 'one' passed by position and keyword in constructor call
-E: 52: No value for argument 'first_argument' in constructor call
-E: 53: Too many positional arguments for constructor call
-E: 59: Too many positional arguments for constructor call
-E: 62: Too many positional arguments for constructor call
-E: 63: No value for argument 'first_argument' in constructor call
-E: 63: Unexpected keyword argument 'one' in constructor call
diff --git a/test/messages/func_e0205.txt b/test/messages/func_e0205.txt
deleted file mode 100644
index c7402ce..0000000
--- a/test/messages/func_e0205.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-E: 14:Cdef.abcd: An attribute defined in input.func_e0205 line 10 hides this method
-
diff --git a/test/messages/func_loopvar_in_closure.txt b/test/messages/func_loopvar_in_closure.txt
deleted file mode 100644
index 5b068f4..0000000
--- a/test/messages/func_loopvar_in_closure.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-W: 21:good_case3: Unused variable 'i'
-W: 45:good_case6.<lambda>: Using possibly undefined loop variable 'i'
-W: 78:bad_case.<lambda>: Cell variable i defined in loop
-W: 83:bad_case2.<lambda>: Cell variable i defined in loop
-W: 91:bad_case3.<lambda>: Cell variable j defined in loop
-W:101:bad_case4.nested: Cell variable i defined in loop
-W:122:bad_case5.<lambda>: Cell variable i defined in loop
-W:130:bad_case6.<lambda>: Cell variable i defined in loop
diff --git a/test/messages/func_undefined_var.txt b/test/messages/func_undefined_var.txt
deleted file mode 100644
index 5505156..0000000
--- a/test/messages/func_undefined_var.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-E: 8: Undefined variable 'unknown'
-E: 14:in_method: Undefined variable 'nomoreknown'
-E: 22:bad_default: Undefined variable 'unknown2'
-E: 25:bad_default: Undefined variable 'xxxx'
-E: 26:bad_default: Undefined variable 'xxxx'
-E: 27:bad_default: Undefined variable 'augvar'
-E: 28:bad_default: Undefined variable 'vardel'
-E: 56: Using variable 'PLOUF' before assignment
-E: 65:if_branch_test: Using variable 'xxx' before assignment
-E: 89:test_arguments: Using variable 'TestClass' before assignment
-E: 93:TestClass: Using variable 'Ancestor' before assignment
-E: 96:TestClass.MissingAncestor: Using variable 'Ancestor1' before assignment
-E:103:TestClass.test1.UsingBeforeDefinition: Using variable 'Empty' before assignment
-W: 27:bad_default: Unused variable 'augvar'
diff --git a/test/messages/func_useless_else_on_loop.txt b/test/messages/func_useless_else_on_loop.txt
deleted file mode 100644
index 6c2c60c..0000000
--- a/test/messages/func_useless_else_on_loop.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-W: 10:test_return_for: Else clause on loop without a break statement
-W: 17:test_return_while: Else clause on loop without a break statement
-W: 26: Else clause on loop without a break statement
-W: 33: Else clause on loop without a break statement
-W: 38: Else clause on loop without a break statement
diff --git a/test/messages/func_w0108.txt b/test/messages/func_w0108.txt
deleted file mode 100644
index 70e0925..0000000
--- a/test/messages/func_w0108.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-W: 8:<lambda>: Lambda may not be necessary
-W: 9:<lambda>: Lambda may not be necessary
-W: 10:<lambda>: Lambda may not be necessary
-W: 16:<lambda>: Lambda may not be necessary
-W: 17:<lambda>: Lambda may not be necessary
-W: 18:<lambda>: Lambda may not be necessary
-W: 19:<lambda>: Lambda may not be necessary
-
diff --git a/test/messages/func_w0711.txt b/test/messages/func_w0711.txt
deleted file mode 100644
index a158818..0000000
--- a/test/messages/func_w0711.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-W: 8: Exception to catch is the result of a binary "or" operation
-W: 10: Exception to catch is the result of a binary "and" operation
-W: 12: Exception to catch is the result of a binary "or" operation
-W: 14: Exception to catch is the result of a binary "or" operation
diff --git a/test/test_func.py b/test/test_func.py
index 2d573c2..51b6ba3 100644
--- a/test/test_func.py
+++ b/test/test_func.py
@@ -44,7 +44,8 @@ class LintTestNonExistentModuleTC(LintTestUsingModule):
class TestTests(testlib.TestCase):
"""check that all testable messages have been checked"""
- PORTED = set(['I0001', 'I0010', 'W0712', 'E1001', 'W1402', 'E1310'])
+ PORTED = set(['I0001', 'I0010', 'W0712', 'E1001', 'W1402', 'E1310', 'E0202',
+ 'W0711', 'W0108'])
@testlib.tag('coverage')
def test_exhaustivity(self):
diff --git a/test/test_functional.py b/test/test_functional.py
index bd65ce3..449c933 100644
--- a/test/test_functional.py
+++ b/test/test_functional.py
@@ -193,11 +193,18 @@ class LintModuleTest(testlib.TestCase):
lines = []
if self._produces_output() and expected:
with open(self._test_file.expected_output, 'U') as fobj:
+ used = True
for line in fobj:
- parts = line.split(':')
- linenum = int(parts[1])
- if (linenum, parts[0]) in expected:
+ parts = line.split(':', 2)
+ if len(parts) != 3 and used:
lines.append(line)
+ else:
+ linenum = int(parts[1])
+ if (linenum, parts[0]) in expected:
+ used = True
+ lines.append(line)
+ else:
+ used = False
return expected, ''.join(lines)
def _get_received(self):
diff --git a/testutils.py b/testutils.py
index ef423c5..1dd083f 100644
--- a/testutils.py
+++ b/testutils.py
@@ -99,7 +99,7 @@ class TestReporter(BaseReporter):
def add_message(self, msg_id, location, msg):
"""manage message of different type and in the context of path """
- fpath, module, obj, line, _ = location
+ _, _, obj, line, _ = location
self.message_ids[msg_id] = 1
if obj:
obj = ':%s' % obj
@@ -282,7 +282,7 @@ class LintTestUsingModule(testlib.TestCase):
tocheck = [self.package+'.'+self.module]
if self.depends:
tocheck += [self.package+'.%s' % name.replace('.py', '')
- for name, file in self.depends]
+ for name, _ in self.depends]
self._test(tocheck)
def _check_result(self, got):
@@ -380,9 +380,7 @@ def make_tests(input_dir, msg_dir, filter_rgx, callbacks):
for callback in callbacks:
test = callback(input_dir, msg_dir, module_file, messages_file,
- dependencies)
+ dependencies)
if test:
tests.append(test)
-
-
return tests
diff --git a/utils.py b/utils.py
index 65e9ce0..b476dc1 100644
--- a/utils.py
+++ b/utils.py
@@ -106,7 +106,7 @@ def tokenize_module(module):
if sys.version_info < (3, 0):
if module.file_encoding is not None:
readline = lambda: stream.readline().decode(module.file_encoding,
- 'replace')
+ 'replace')
return list(tokenize.generate_tokens(readline))
return list(tokenize.tokenize(readline))
@@ -285,7 +285,7 @@ class MessagesHandlerMixIn(object):
msgid may be either a numeric or symbolic message id.
"""
try:
- msgid = self.msgs_store.check_message_id(msg_descr).msgid
+ msgid = self.msgs_store.check_message_id(msg_descr).msgid
except UnknownMessage:
# The linter checks for messages that are not registered
# due to version mismatch, just treat them as message IDs
@@ -818,7 +818,7 @@ def register_plugins(linter, directory):
if base in imported or base == '__pycache__':
continue
if extension in PY_EXTS and base != '__init__' or (
- not extension and isdir(join(directory, base))):
+ not extension and isdir(join(directory, base))):
try:
module = load_module_from_file(join(directory, filename))
except ValueError: