8th day of python challenges 111-117
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import pylint.lint
|
||||
|
||||
|
||||
def is_module(filename):
|
||||
return filename.endswith(".py")
|
||||
|
||||
|
||||
def is_package(filename, location):
|
||||
return os.path.exists(os.path.join(location, filename, "__init__.py"))
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _patch_stdout(out):
|
||||
sys.stdout = out
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
|
||||
|
||||
LIB_DIRS = [os.path.dirname(os.__file__)]
|
||||
MODULES_TO_CHECK = [
|
||||
(location, module)
|
||||
for location in LIB_DIRS
|
||||
for module in os.listdir(location)
|
||||
if is_module(module) or is_package(module, location)
|
||||
]
|
||||
MODULES_NAMES = [m[1] for m in MODULES_TO_CHECK]
|
||||
|
||||
|
||||
@pytest.mark.acceptance
|
||||
@pytest.mark.parametrize(
|
||||
("test_module_location", "test_module_name"), MODULES_TO_CHECK, ids=MODULES_NAMES
|
||||
)
|
||||
def test_libmodule(test_module_location, test_module_name):
|
||||
os.chdir(test_module_location)
|
||||
with _patch_stdout(io.StringIO()):
|
||||
try:
|
||||
pylint.lint.Run([test_module_name, "--enable=all", "--ignore=test"])
|
||||
except SystemExit as ex:
|
||||
assert ex.code != 32
|
||||
return
|
||||
|
||||
assert False, "shouldn't get there"
|
53
venv/lib/python3.6/site-packages/pylint/test/conftest.py
Normal file
53
venv/lib/python3.6/site-packages/pylint/test/conftest.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# pylint: disable=redefined-outer-name
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from pylint import checkers
|
||||
from pylint.lint import PyLinter
|
||||
|
||||
# pylint: disable=no-name-in-module
|
||||
from pylint.testutils import MinimalTestReporter
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def linter(checker, register, enable, disable, reporter):
|
||||
_linter = PyLinter()
|
||||
_linter.set_reporter(reporter())
|
||||
checkers.initialize(_linter)
|
||||
if register:
|
||||
register(_linter)
|
||||
if checker:
|
||||
_linter.register_checker(checker(_linter))
|
||||
if disable:
|
||||
for msg in disable:
|
||||
_linter.disable(msg)
|
||||
if enable:
|
||||
for msg in enable:
|
||||
_linter.enable(msg)
|
||||
os.environ.pop("PYLINTRC", None)
|
||||
return _linter
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checker():
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def register():
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def enable():
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def disable():
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def reporter():
|
||||
return MinimalTestReporter
|
2
venv/lib/python3.6/site-packages/pylint/test/data/ascript
Executable file
2
venv/lib/python3.6/site-packages/pylint/test/data/ascript
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/python
|
||||
"""ttttttttttttttttttttoooooooooooooooooooooooooooooooooooooooooooooooooooooo lllllllllllooooooooooooooooooooooooooooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnngggggggggggggggggg"""
|
@@ -0,0 +1,12 @@
|
||||
digraph "classes_No_Name" {
|
||||
charset="utf-8"
|
||||
rankdir=BT
|
||||
"0" [label="{Ancestor|attr : str\lcls_member\l|get_value()\lset_value()\l}", shape="record"];
|
||||
"1" [label="{DoNothing|\l|}", shape="record"];
|
||||
"2" [label="{Interface|\l|get_value()\lset_value()\l}", shape="record"];
|
||||
"3" [label="{Specialization|TYPE : str\lrelation\ltop : str\l|}", shape="record"];
|
||||
"3" -> "0" [arrowhead="empty", arrowtail="none"];
|
||||
"0" -> "2" [arrowhead="empty", arrowtail="node", style="dashed"];
|
||||
"1" -> "0" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="cls_member", style="solid"];
|
||||
"1" -> "3" [arrowhead="diamond", arrowtail="none", fontcolor="green", label="relation", style="solid"];
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
""" docstring for file clientmodule.py """
|
||||
from data.suppliermodule_test import Interface, DoNothing
|
||||
|
||||
class Ancestor:
|
||||
""" Ancestor method """
|
||||
__implements__ = (Interface,)
|
||||
cls_member = DoNothing()
|
||||
|
||||
def __init__(self, value):
|
||||
local_variable = 0
|
||||
self.attr = 'this method shouldn\'t have a docstring'
|
||||
self.__value = value
|
||||
|
||||
def get_value(self):
|
||||
""" nice docstring ;-) """
|
||||
return self.__value
|
||||
|
||||
def set_value(self, value):
|
||||
self.__value = value
|
||||
return 'this method shouldn\'t have a docstring'
|
||||
|
||||
class Specialization(Ancestor):
|
||||
TYPE = 'final class'
|
||||
top = 'class'
|
||||
|
||||
def __init__(self, value, _id):
|
||||
Ancestor.__init__(self, value)
|
||||
self._id = _id
|
||||
self.relation = DoNothing()
|
@@ -0,0 +1,8 @@
|
||||
digraph "packages_No_Name" {
|
||||
charset="utf-8"
|
||||
rankdir=BT
|
||||
"0" [label="data", shape="box"];
|
||||
"1" [label="data.clientmodule_test", shape="box"];
|
||||
"2" [label="data.suppliermodule_test", shape="box"];
|
||||
"1" -> "2" [arrowhead="open", arrowtail="none"];
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
""" file suppliermodule.py """
|
||||
|
||||
class Interface:
|
||||
def get_value(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def set_value(self, value):
|
||||
raise NotImplementedError
|
||||
|
||||
class DoNothing: pass
|
@@ -0,0 +1,4 @@
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
TEST = map(str, (1, 2, 3)) # [bad-builtin]
|
||||
TEST1 = filter(str, (1, 2, 3)) # [bad-builtin]
|
@@ -0,0 +1,28 @@
|
||||
# pylint: disable=literal-comparison,missing-docstring,misplaced-comparison-constant
|
||||
|
||||
X = 123
|
||||
Y = len('test')
|
||||
|
||||
if X is 0: # [compare-to-zero]
|
||||
pass
|
||||
|
||||
if Y is not 0: # [compare-to-zero]
|
||||
pass
|
||||
|
||||
if X == 0: # [compare-to-zero]
|
||||
pass
|
||||
|
||||
if Y != 0: # [compare-to-zero]
|
||||
pass
|
||||
|
||||
if X > 0:
|
||||
pass
|
||||
|
||||
if X < 0:
|
||||
pass
|
||||
|
||||
if 0 < X:
|
||||
pass
|
||||
|
||||
if 0 > X:
|
||||
pass
|
@@ -0,0 +1,40 @@
|
||||
"""Checks of Dosctrings 'docstring-first-line-empty' 'bad-docstring-quotes'"""
|
||||
|
||||
|
||||
def check_messages(*messages):
|
||||
"""
|
||||
docstring"""
|
||||
return messages
|
||||
|
||||
def function2():
|
||||
"""Test Ok"""
|
||||
|
||||
class FFFF:
|
||||
"""
|
||||
Test Docstring First Line Empty
|
||||
"""
|
||||
|
||||
def method1(self):
|
||||
'''
|
||||
Test Triple Single Quotes docstring
|
||||
'''
|
||||
|
||||
def method2(self):
|
||||
"bad docstring 1"
|
||||
|
||||
def method3(self):
|
||||
'bad docstring 2'
|
||||
|
||||
def method4(self):
|
||||
' """bad docstring 3 '
|
||||
|
||||
@check_messages('bad-open-mode', 'redundant-unittest-assert',
|
||||
'deprecated-module')
|
||||
def method5(self):
|
||||
"""Test OK 1 with decorators"""
|
||||
|
||||
def method6(self):
|
||||
r"""Test OK 2 with raw string"""
|
||||
|
||||
def method7(self):
|
||||
u"""Test OK 3 with unicode string"""
|
@@ -0,0 +1,26 @@
|
||||
"""Checks use of "else if" triggers a refactor message"""
|
||||
|
||||
def my_function():
|
||||
"""docstring"""
|
||||
myint = 2
|
||||
if myint > 5:
|
||||
pass
|
||||
else:
|
||||
if myint <= 5:
|
||||
pass
|
||||
else:
|
||||
myint = 3
|
||||
if myint > 2:
|
||||
if myint > 3:
|
||||
pass
|
||||
elif myint == 3:
|
||||
pass
|
||||
elif myint < 3:
|
||||
pass
|
||||
else:
|
||||
if myint:
|
||||
pass
|
||||
else:
|
||||
if myint:
|
||||
pass
|
||||
myint = 4
|
@@ -0,0 +1,16 @@
|
||||
# pylint: disable=literal-comparison,missing-docstring
|
||||
|
||||
X = ''
|
||||
Y = 'test'
|
||||
|
||||
if X is '': # [compare-to-empty-string]
|
||||
pass
|
||||
|
||||
if Y is not "": # [compare-to-empty-string]
|
||||
pass
|
||||
|
||||
if X == "": # [compare-to-empty-string]
|
||||
pass
|
||||
|
||||
if Y != '': # [compare-to-empty-string]
|
||||
pass
|
@@ -0,0 +1,205 @@
|
||||
"""Checks use of "too-complex" check"""
|
||||
|
||||
|
||||
def f1():
|
||||
"""McCabe rating: 1"""
|
||||
pass
|
||||
|
||||
|
||||
def f2(n):
|
||||
"""McCabe rating: 1"""
|
||||
k = n + 4
|
||||
s = k + n
|
||||
return s
|
||||
|
||||
|
||||
def f3(n):
|
||||
"""McCabe rating: 3"""
|
||||
if n > 3:
|
||||
return "bigger than three"
|
||||
elif n > 4:
|
||||
return "is never executed"
|
||||
else:
|
||||
return "smaller than or equal to three"
|
||||
|
||||
|
||||
def f4():
|
||||
"""McCabe rating: 2"""
|
||||
for i in range(10):
|
||||
print(i)
|
||||
|
||||
|
||||
def f5(mylist):
|
||||
"""McCabe rating: 2"""
|
||||
for i in mylist:
|
||||
print(i)
|
||||
else:
|
||||
print(None)
|
||||
|
||||
|
||||
def f6(n):
|
||||
"""McCabe rating: 2"""
|
||||
if n > 4:
|
||||
return f(n - 1)
|
||||
else:
|
||||
return n
|
||||
|
||||
|
||||
def f7():
|
||||
"""McCabe rating: 3"""
|
||||
def b():
|
||||
"""McCabe rating: 2"""
|
||||
def c():
|
||||
"""McCabe rating: 1"""
|
||||
pass
|
||||
c()
|
||||
b()
|
||||
|
||||
|
||||
def f8():
|
||||
"""McCabe rating: 4"""
|
||||
try:
|
||||
print(1)
|
||||
except TypeA:
|
||||
print(2)
|
||||
except TypeB:
|
||||
print(3)
|
||||
else:
|
||||
print(4)
|
||||
|
||||
|
||||
def f9():
|
||||
"""McCabe rating: 9"""
|
||||
myint = 2
|
||||
if myint > 5:
|
||||
pass
|
||||
else:
|
||||
if myint <= 5:
|
||||
pass
|
||||
else:
|
||||
myint = 3
|
||||
if myint > 2:
|
||||
if myint > 3:
|
||||
pass
|
||||
elif myint == 3:
|
||||
pass
|
||||
elif myint < 3:
|
||||
pass
|
||||
else:
|
||||
if myint:
|
||||
pass
|
||||
else:
|
||||
if myint:
|
||||
pass
|
||||
myint = 4
|
||||
|
||||
|
||||
def f10():
|
||||
"""McCabe rating: 11"""
|
||||
myint = 2
|
||||
if myint == 5:
|
||||
return myint
|
||||
elif myint == 6:
|
||||
return myint
|
||||
elif myint == 7:
|
||||
return myint
|
||||
elif myint == 8:
|
||||
return myint
|
||||
elif myint == 9:
|
||||
return myint
|
||||
elif myint == 10:
|
||||
if myint == 8:
|
||||
while True:
|
||||
return True
|
||||
elif myint == 8:
|
||||
with myint:
|
||||
return 8
|
||||
else:
|
||||
if myint == 2:
|
||||
return myint
|
||||
return myint
|
||||
return myint
|
||||
|
||||
|
||||
class MyClass1(object):
|
||||
"""Class of example to test mccabe"""
|
||||
_name = 'MyClass' # To force a tail.node=None
|
||||
|
||||
def method1():
|
||||
"""McCabe rating: 1"""
|
||||
pass
|
||||
|
||||
def method2(self, param1):
|
||||
"""McCabe rating: 18"""
|
||||
if not param1:
|
||||
pass
|
||||
pass
|
||||
if param1:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
|
||||
pass
|
||||
|
||||
if param1:
|
||||
pass
|
||||
if param1:
|
||||
pass
|
||||
if param1:
|
||||
pass
|
||||
if param1:
|
||||
pass
|
||||
if param1:
|
||||
pass
|
||||
if param1:
|
||||
pass
|
||||
if param1:
|
||||
for value in range(5):
|
||||
pass
|
||||
|
||||
pass
|
||||
for count in range(6):
|
||||
with open('myfile') as fp:
|
||||
count += 1
|
||||
pass
|
||||
pass
|
||||
try:
|
||||
pass
|
||||
if not param1:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
if param1:
|
||||
raise BaseException('Error')
|
||||
with open('myfile2') as fp2:
|
||||
pass
|
||||
pass
|
||||
finally:
|
||||
if param1 is not None:
|
||||
pass
|
||||
for count2 in range(8):
|
||||
try:
|
||||
pass
|
||||
except BaseException('Error2'):
|
||||
pass
|
||||
return param1
|
||||
|
||||
|
||||
for count in range(10):
|
||||
if count == 1:
|
||||
exit(0)
|
||||
elif count == 2:
|
||||
exit(1)
|
||||
else:
|
||||
exit(2)
|
||||
|
||||
|
||||
def method3(self):
|
||||
try:
|
||||
if True:
|
||||
pass
|
||||
else:
|
||||
pass
|
||||
finally:
|
||||
pass
|
||||
return True
|
@@ -0,0 +1,45 @@
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
class SomeException(Exception):
|
||||
pass
|
||||
|
||||
class SubclassException(SomeException):
|
||||
pass
|
||||
|
||||
AliasException = SomeException
|
||||
|
||||
try:
|
||||
pass
|
||||
except (SomeException, SomeException): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (SomeException, SubclassException): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (SomeException, AliasException): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (AliasException, SubclassException): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
# +1:[overlapping-except, overlapping-except, overlapping-except]
|
||||
except (SomeException, AliasException, SubclassException):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ArithmeticError, FloatingPointError): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, UnicodeDecodeError): # [overlapping-except]
|
||||
pass
|
@@ -0,0 +1,18 @@
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
import socket
|
||||
|
||||
try:
|
||||
pass
|
||||
except (IOError, OSError): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (socket.error, OSError): # [overlapping-except]
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ConnectionError, socket.error): # [overlapping-except]
|
||||
pass
|
@@ -0,0 +1,85 @@
|
||||
"""Checks variable types aren't redefined within a method or a function"""
|
||||
|
||||
# pylint: disable=too-few-public-methods,missing-docstring,unused-variable,invalid-name, useless-object-inheritance
|
||||
|
||||
_OK = True
|
||||
|
||||
class MyClass(object):
|
||||
|
||||
class Klass(object):
|
||||
def __init__(self):
|
||||
self.var2 = 'var'
|
||||
|
||||
def __init__(self):
|
||||
self.var = True
|
||||
self.var1 = 2
|
||||
self.var2 = 1.
|
||||
self.var1 = 2. # [redefined-variable-type]
|
||||
self.a_str = "hello"
|
||||
a_str = False
|
||||
(a_str, b_str) = (1, 2) # no support for inference on tuple assignment
|
||||
a_str = 2.0 if self.var else 1.0 # no support for inference on ifexpr
|
||||
|
||||
def _getter(self):
|
||||
return self.a_str
|
||||
def _setter(self, val):
|
||||
self.a_str = val
|
||||
var2 = property(_getter, _setter)
|
||||
|
||||
def some_method(self):
|
||||
def func():
|
||||
var = 1
|
||||
test = 'bar'
|
||||
var = 'baz' # [redefined-variable-type]
|
||||
self.var = 1 # the rule checks for redefinitions in the scope of a function or method
|
||||
test = 'foo'
|
||||
myint = 2
|
||||
myint = False # [redefined-variable-type]
|
||||
|
||||
_OK = "This is OK" # [redefined-variable-type]
|
||||
|
||||
if _OK:
|
||||
SOME_FLOAT = 1.
|
||||
|
||||
def dummy_function():
|
||||
return 2
|
||||
|
||||
def other_function():
|
||||
instance = MyClass()
|
||||
instance = True # [redefined-variable-type]
|
||||
|
||||
SOME_FLOAT = dummy_function() # [redefined-variable-type]
|
||||
|
||||
A_GLOB = None
|
||||
A_GLOB = [1, 2, 3]
|
||||
|
||||
def func2(x):
|
||||
if x:
|
||||
var = 'foo'
|
||||
else:
|
||||
var = True
|
||||
|
||||
if x:
|
||||
var2 = 'foo'
|
||||
elif not x:
|
||||
var2 = 2
|
||||
else:
|
||||
pass
|
||||
|
||||
if x:
|
||||
var3 = 'foo'
|
||||
var3 = 2 # [redefined-variable-type]
|
||||
else:
|
||||
pass
|
||||
|
||||
var = 2 # [redefined-variable-type]
|
||||
|
||||
if x:
|
||||
pass
|
||||
elif not x:
|
||||
var4 = True
|
||||
elif _OK:
|
||||
pass
|
||||
else:
|
||||
var4 = 2.
|
||||
var4 = 'baz' # [redefined-variable-type]
|
@@ -0,0 +1,43 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.bad_builtin
|
||||
"""
|
||||
|
||||
import os.path as osp
|
||||
|
||||
import pytest
|
||||
|
||||
from pylint.extensions.bad_builtin import BadBuiltinChecker
|
||||
from pylint.lint import fix_import_path
|
||||
|
||||
|
||||
EXPECTED = [
|
||||
"Used builtin function 'map'. Using a list comprehension can be clearer.",
|
||||
"Used builtin function 'filter'. Using a list comprehension can be clearer.",
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def checker(checker):
|
||||
return BadBuiltinChecker
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def disable(disable):
|
||||
return ['I']
|
||||
|
||||
|
||||
def test_types_redefined(linter):
|
||||
elif_test = osp.join(osp.dirname(osp.abspath(__file__)), 'data',
|
||||
'bad_builtin.py')
|
||||
with fix_import_path([elif_test]):
|
||||
linter.check([elif_test])
|
||||
msgs = sorted(linter.reporter.messages, key=lambda item: item.line)
|
||||
assert len(msgs) == 2
|
||||
for msg, expected in zip(msgs, EXPECTED):
|
||||
assert msg.symbol == 'bad-builtin'
|
||||
assert msg.msg == expected
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
|
||||
# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
|
||||
# Copyright (c) 2018 Anthony Sottile <asottile@umich.edu>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Unit tests for the pylint checkers in :mod:`pylint.extensions.check_docs`,
|
||||
in particular the parameter documentation checker `DocstringChecker`
|
||||
"""
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import pytest
|
||||
|
||||
import astroid
|
||||
|
||||
import pylint.extensions._check_docs_utils as utils
|
||||
|
||||
|
||||
@pytest.mark.parametrize("string,count", [
|
||||
('abc', 0),
|
||||
('', 0),
|
||||
(' abc', 2),
|
||||
('\n abc', 0),
|
||||
(' \n abc', 3),
|
||||
])
|
||||
def test_space_indentation(string, count):
|
||||
"""Test for pylint_plugin.ParamDocChecker"""
|
||||
assert utils.space_indentation(string) == count
|
||||
|
||||
|
||||
@pytest.mark.parametrize("raise_node,expected", [
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
raise NotImplementedError #@
|
||||
'''), {"NotImplementedError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
raise NotImplementedError("Not implemented!") #@
|
||||
'''), {"NotImplementedError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
raise #@
|
||||
'''), {"RuntimeError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
if another_func():
|
||||
raise #@
|
||||
'''), {"RuntimeError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
try:
|
||||
another_func()
|
||||
raise #@
|
||||
except NameError:
|
||||
pass
|
||||
'''), {"RuntimeError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
try:
|
||||
another_func()
|
||||
except NameError:
|
||||
raise #@
|
||||
'''), {"NameError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except:
|
||||
raise #@
|
||||
'''), set()),
|
||||
|
||||
(astroid.extract_node('''
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except (RuntimeError, ValueError):
|
||||
raise #@
|
||||
'''), {"RuntimeError", "ValueError"}),
|
||||
|
||||
(astroid.extract_node('''
|
||||
import not_a_module
|
||||
def my_func():
|
||||
try:
|
||||
fake_func()
|
||||
except not_a_module.Error:
|
||||
raise #@
|
||||
'''), set()),
|
||||
|
||||
])
|
||||
def test_exception(raise_node, expected):
|
||||
found = utils.possible_exc_types(raise_node)
|
||||
assert found == expected
|
@@ -0,0 +1,63 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
|
||||
# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.check_mccabe
|
||||
"""
|
||||
|
||||
import os.path as osp
|
||||
|
||||
import pytest
|
||||
|
||||
from pylint.extensions import mccabe
|
||||
|
||||
EXPECTED_MSGS = [
|
||||
"'f1' is too complex. The McCabe rating is 1",
|
||||
"'f2' is too complex. The McCabe rating is 1",
|
||||
"'f3' is too complex. The McCabe rating is 3",
|
||||
"'f4' is too complex. The McCabe rating is 2",
|
||||
"'f5' is too complex. The McCabe rating is 2",
|
||||
"'f6' is too complex. The McCabe rating is 2",
|
||||
"'f7' is too complex. The McCabe rating is 3",
|
||||
"'f8' is too complex. The McCabe rating is 4",
|
||||
"'f9' is too complex. The McCabe rating is 9",
|
||||
"'method1' is too complex. The McCabe rating is 1",
|
||||
"This 'for' is too complex. The McCabe rating is 4",
|
||||
"'method3' is too complex. The McCabe rating is 2",
|
||||
"'f10' is too complex. The McCabe rating is 11",
|
||||
"'method2' is too complex. The McCabe rating is 18",
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def enable(enable):
|
||||
return ['too-complex']
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def disable(disable):
|
||||
return ['all']
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def register(register):
|
||||
return mccabe.register
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fname_mccabe_example():
|
||||
return osp.join(osp.dirname(osp.abspath(__file__)), 'data', 'mccabe.py')
|
||||
|
||||
|
||||
@pytest.mark.parametrize("complexity, expected", [
|
||||
(0, EXPECTED_MSGS),
|
||||
(9, EXPECTED_MSGS[-2:]),
|
||||
])
|
||||
def test_max_mccabe_rate(linter, fname_mccabe_example, complexity, expected):
|
||||
linter.global_set_option('max-complexity', complexity)
|
||||
linter.check([fname_mccabe_example])
|
||||
real_msgs = [message.msg for message in linter.reporter.messages]
|
||||
assert sorted(expected) == sorted(real_msgs)
|
@@ -0,0 +1,781 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
|
||||
# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
|
||||
# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
|
||||
# Copyright (c) 2018 Adam Dangoor <adamdangoor@gmail.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Unit tests for the raised exception documentation checking in the
|
||||
`DocstringChecker` in :mod:`pylint.extensions.check_docs`
|
||||
"""
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import astroid
|
||||
from pylint.testutils import CheckerTestCase, Message, set_config
|
||||
|
||||
from pylint.extensions.docparams import DocstringParameterChecker
|
||||
|
||||
|
||||
class TestDocstringCheckerRaise(CheckerTestCase):
|
||||
"""Tests for pylint_plugin.RaiseDocChecker"""
|
||||
CHECKER_CLASS = DocstringParameterChecker
|
||||
|
||||
def test_ignores_no_docstring(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
raise RuntimeError('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_unknown_style(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring."""
|
||||
raise RuntimeError('hi')
|
||||
''')
|
||||
raise_node = node.body[0]
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
@set_config(accept_no_raise_doc=False)
|
||||
def test_warns_unknown_style(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring."""
|
||||
raise RuntimeError('hi')
|
||||
''')
|
||||
raise_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_missing_sphinx_raises(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Never
|
||||
"""
|
||||
raise RuntimeError('hi')
|
||||
raise NameError('hi')
|
||||
''')
|
||||
raise_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_missing_google_raises(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises:
|
||||
NameError: Never
|
||||
"""
|
||||
raise RuntimeError('hi')
|
||||
raise NameError('hi')
|
||||
''')
|
||||
raise_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_google_attr_raises_exact_exc(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a google docstring.
|
||||
|
||||
Raises:
|
||||
re.error: Sometimes
|
||||
"""
|
||||
import re
|
||||
raise re.error('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
pass
|
||||
|
||||
def test_find_google_attr_raises_substr_exc(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a google docstring.
|
||||
|
||||
Raises:
|
||||
re.error: Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_valid_missing_google_attr_raises(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a google docstring.
|
||||
|
||||
Raises:
|
||||
re.anothererror: Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi')
|
||||
''')
|
||||
raise_node = node.body[1]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('error', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_invalid_missing_google_attr_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a google docstring.
|
||||
|
||||
Raises:
|
||||
bogusmodule.error: Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi') #@
|
||||
''')
|
||||
# pylint allows this to pass since the comparison between Raises and
|
||||
# raise are based on the class name, not the qualified name.
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
@set_config(accept_no_raise_doc=False)
|
||||
def test_google_raises_with_prefix(self):
|
||||
code_snippet = '''
|
||||
def my_func(self):
|
||||
"""This is a google docstring.
|
||||
|
||||
Raises:
|
||||
{prefix}re.error: Sometimes
|
||||
"""
|
||||
import re
|
||||
raise re.error('hi') #@
|
||||
'''
|
||||
for prefix in ["~", "!"]:
|
||||
raise_node = astroid.extract_node(code_snippet.format(prefix=prefix))
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_missing_numpy_raises(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
NameError
|
||||
Never
|
||||
"""
|
||||
raise RuntimeError('hi')
|
||||
raise NameError('hi')
|
||||
''')
|
||||
raise_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignore_spurious_sphinx_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises RuntimeError: Always
|
||||
:except NameError: Never
|
||||
:raise OSError: Never
|
||||
:exception ValueError: Never
|
||||
"""
|
||||
raise RuntimeError('Blah') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_all_sphinx_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises RuntimeError: Always
|
||||
:except NameError: Never
|
||||
:raise OSError: Never
|
||||
:exception ValueError: Never
|
||||
"""
|
||||
raise RuntimeError('hi') #@
|
||||
raise NameError('hi')
|
||||
raise OSError(2, 'abort!')
|
||||
raise ValueError('foo')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_all_google_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises:
|
||||
RuntimeError: Always
|
||||
NameError: Never
|
||||
"""
|
||||
raise RuntimeError('hi') #@
|
||||
raise NameError('hi')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_all_numpy_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
RuntimeError
|
||||
Always
|
||||
NameError
|
||||
Never
|
||||
"""
|
||||
raise RuntimeError('hi') #@
|
||||
raise NameError('hi')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_finds_rethrown_sphinx_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Sometimes
|
||||
"""
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
raise #@
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_rethrown_google_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises:
|
||||
NameError: Sometimes
|
||||
"""
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
raise #@
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_rethrown_numpy_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
NameError
|
||||
Sometimes
|
||||
"""
|
||||
try:
|
||||
fake_func()
|
||||
except RuntimeError:
|
||||
raise #@
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_finds_rethrown_sphinx_multiple_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Sometimes
|
||||
"""
|
||||
try:
|
||||
fake_func()
|
||||
except (RuntimeError, ValueError):
|
||||
raise #@
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError, ValueError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_rethrown_google_multiple_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises:
|
||||
NameError: Sometimes
|
||||
"""
|
||||
try:
|
||||
fake_func()
|
||||
except (RuntimeError, ValueError):
|
||||
raise #@
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError, ValueError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_rethrown_numpy_multiple_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
NameError
|
||||
Sometimes
|
||||
"""
|
||||
try:
|
||||
fake_func()
|
||||
except (RuntimeError, ValueError):
|
||||
raise #@
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError, ValueError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_caught_sphinx_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Sometimes
|
||||
"""
|
||||
try:
|
||||
raise RuntimeError('hi') #@
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_caught_google_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Raises:
|
||||
NameError: Sometimes
|
||||
"""
|
||||
try:
|
||||
raise RuntimeError('hi') #@
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_caught_numpy_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a numpy docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
NameError
|
||||
Sometimes
|
||||
"""
|
||||
try:
|
||||
raise RuntimeError('hi') #@
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
raise NameError('hi')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_numpy_attr_raises_exact_exc(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a numpy docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
re.error
|
||||
Sometimes
|
||||
"""
|
||||
import re
|
||||
raise re.error('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
pass
|
||||
|
||||
def test_find_numpy_attr_raises_substr_exc(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a numpy docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
re.error
|
||||
Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_valid_missing_numpy_attr_raises(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a numpy docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
re.anothererror
|
||||
Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi')
|
||||
''')
|
||||
raise_node = node.body[1]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('error', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_invalid_missing_numpy_attr_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a numpy docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
bogusmodule.error
|
||||
Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi') #@
|
||||
''')
|
||||
# pylint allows this to pass since the comparison between Raises and
|
||||
# raise are based on the class name, not the qualified name.
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
@set_config(accept_no_raise_doc=False)
|
||||
def test_numpy_raises_with_prefix(self):
|
||||
code_snippet = '''
|
||||
def my_func(self):
|
||||
"""This is a numpy docstring.
|
||||
|
||||
Raises
|
||||
------
|
||||
{prefix}re.error
|
||||
Sometimes
|
||||
"""
|
||||
import re
|
||||
raise re.error('hi') #@
|
||||
'''
|
||||
for prefix in ["~", "!"]:
|
||||
raise_node = astroid.extract_node(code_snippet.format(prefix=prefix))
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_missing_sphinx_raises_infer_from_instance(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Never
|
||||
"""
|
||||
my_exception = RuntimeError('hi')
|
||||
raise my_exception #@
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_missing_sphinx_raises_infer_from_function(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Never
|
||||
"""
|
||||
def ex_func(val):
|
||||
return RuntimeError(val)
|
||||
raise ex_func('hi') #@
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_sphinx_attr_raises_exact_exc(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a sphinx docstring.
|
||||
|
||||
:raises re.error: Sometimes
|
||||
"""
|
||||
import re
|
||||
raise re.error('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_sphinx_attr_raises_substr_exc(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a sphinx docstring.
|
||||
|
||||
:raises re.error: Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi') #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_valid_missing_sphinx_attr_raises(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a sphinx docstring.
|
||||
|
||||
:raises re.anothererror: Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi')
|
||||
''')
|
||||
raise_node = node.body[1]
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('error', ))):
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_find_invalid_missing_sphinx_attr_raises(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a sphinx docstring.
|
||||
|
||||
:raises bogusmodule.error: Sometimes
|
||||
"""
|
||||
from re import error
|
||||
raise error('hi') #@
|
||||
''')
|
||||
# pylint allows this to pass since the comparison between Raises and
|
||||
# raise are based on the class name, not the qualified name.
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
@set_config(accept_no_raise_doc=False)
|
||||
def test_sphinx_raises_with_prefix(self):
|
||||
code_snippet = '''
|
||||
def my_func(self):
|
||||
"""This is a sphinx docstring.
|
||||
|
||||
:raises {prefix}re.error: Sometimes
|
||||
"""
|
||||
import re
|
||||
raise re.error('hi') #@
|
||||
'''
|
||||
for prefix in ["~", "!"]:
|
||||
raise_node = astroid.extract_node(code_snippet.format(prefix=prefix))
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_raise_uninferable(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
from unknown import Unknown
|
||||
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Never
|
||||
"""
|
||||
raise Unknown('hi') #@
|
||||
raise NameError('hi')
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_returns_from_inner_functions(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:raises NameError: Never
|
||||
"""
|
||||
def ex_func(val):
|
||||
def inner_func(value):
|
||||
return OSError(value)
|
||||
return RuntimeError(val)
|
||||
raise ex_func('hi') #@
|
||||
raise NameError('hi')
|
||||
''')
|
||||
node = raise_node.frame()
|
||||
with self.assertAddsMessages(
|
||||
Message(
|
||||
msg_id='missing-raises-doc',
|
||||
node=node,
|
||||
args=('RuntimeError', ))):
|
||||
# we do NOT expect a warning about the OSError in inner_func!
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_returns_use_only_names(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def myfunc():
|
||||
"""This is a docstring
|
||||
|
||||
:raises NameError: Never
|
||||
"""
|
||||
def inner_func():
|
||||
return 42
|
||||
|
||||
raise inner_func() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_ignores_returns_use_only_exception_instances(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def myfunc():
|
||||
"""This is a docstring
|
||||
|
||||
:raises MyException: Never
|
||||
"""
|
||||
class MyException(Exception):
|
||||
pass
|
||||
def inner_func():
|
||||
return MyException
|
||||
|
||||
raise inner_func() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_no_crash_when_inferring_handlers(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
import collections
|
||||
|
||||
def test():
|
||||
"""raises
|
||||
|
||||
:raise U: pass
|
||||
"""
|
||||
try:
|
||||
pass
|
||||
except collections.U as exc:
|
||||
raise #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_no_crash_when_cant_find_exception(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
import collections
|
||||
|
||||
def test():
|
||||
"""raises
|
||||
|
||||
:raise U: pass
|
||||
"""
|
||||
try:
|
||||
pass
|
||||
except U as exc:
|
||||
raise #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
||||
|
||||
def test_no_error_notimplemented_documented(self):
|
||||
raise_node = astroid.extract_node('''
|
||||
def my_func():
|
||||
"""
|
||||
Raises:
|
||||
NotImplementedError: When called.
|
||||
"""
|
||||
raise NotImplementedError #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_raise(raise_node)
|
@@ -0,0 +1,600 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
|
||||
# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
|
||||
# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
|
||||
# Copyright (c) 2016 Moises Lopez <moylop260@vauxoo.com>
|
||||
# Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Unit tests for the return documentation checking in the
|
||||
`DocstringChecker` in :mod:`pylint.extensions.check_docs`
|
||||
"""
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import astroid
|
||||
from pylint.testutils import CheckerTestCase, Message, set_config
|
||||
|
||||
from pylint.extensions.docparams import DocstringParameterChecker
|
||||
|
||||
|
||||
class TestDocstringCheckerReturn(CheckerTestCase):
|
||||
"""Tests for pylint_plugin.RaiseDocChecker"""
|
||||
CHECKER_CLASS = DocstringParameterChecker
|
||||
|
||||
def test_ignores_no_docstring(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
return False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
@set_config(accept_no_return_doc=False)
|
||||
def test_warns_no_docstring(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node),
|
||||
Message(msg_id='missing-return-type-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_ignores_unknown_style(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring."""
|
||||
return False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_partial_sphinx_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: Always False
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-type-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_sphinx_returns_annotations(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self) -> bool:
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: Always False
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_sphinx_missing_return_type_with_annotations(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self) -> bool:
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: Always False
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
|
||||
def test_warn_partial_sphinx_returns_type(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_missing_sphinx_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
:param doc_type: Sphinx
|
||||
:type doc_type: str
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node),
|
||||
Message(msg_id='missing-return-type-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_partial_google_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
Always False
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-type-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_partial_google_returns_type(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_missing_google_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Parameters:
|
||||
doc_type (str): Google
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node),
|
||||
Message(msg_id='missing-return-type-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_partial_numpy_returns_type(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
doc_type : str
|
||||
Numpy
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warn_missing_numpy_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
doc_type : str
|
||||
Numpy
|
||||
"""
|
||||
return False
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node),
|
||||
Message(msg_id='missing-return-type-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_find_sphinx_returns(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:return: Always False
|
||||
:rtype: bool
|
||||
"""
|
||||
return False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_find_google_returns(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
bool: Always False
|
||||
"""
|
||||
return False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_find_numpy_returns(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
Always False
|
||||
"""
|
||||
return False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_ignores_sphinx_return_none(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
:param doc_type: Sphinx
|
||||
:type doc_type: str
|
||||
"""
|
||||
return #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_ignores_google_return_none(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Args:
|
||||
doc_type (str): Google
|
||||
"""
|
||||
return #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_ignores_numpy_return_none(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
doc_type : str
|
||||
Numpy
|
||||
"""
|
||||
return #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_finds_sphinx_return_custom_class(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: An object
|
||||
:rtype: :class:`mymodule.Class`
|
||||
"""
|
||||
return mymodule.Class() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_finds_google_return_custom_class(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
mymodule.Class: An object
|
||||
"""
|
||||
return mymodule.Class() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_finds_numpy_return_custom_class(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
mymodule.Class
|
||||
An object
|
||||
"""
|
||||
return mymodule.Class() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_finds_sphinx_return_list_of_custom_class(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: An object
|
||||
:rtype: list(:class:`mymodule.Class`)
|
||||
"""
|
||||
return [mymodule.Class()] #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_finds_google_return_list_of_custom_class(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
list(:class:`mymodule.Class`): An object
|
||||
"""
|
||||
return [mymodule.Class()] #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_finds_numpy_return_list_of_custom_class(self):
|
||||
return_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list(:class:`mymodule.Class`)
|
||||
An object
|
||||
"""
|
||||
return [mymodule.Class()] #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warns_sphinx_return_list_of_custom_class_without_description(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:rtype: list(:class:`mymodule.Class`)
|
||||
"""
|
||||
return [mymodule.Class()]
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warns_google_return_list_of_custom_class_without_description(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
list(:class:`mymodule.Class`):
|
||||
"""
|
||||
return [mymodule.Class()]
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warns_numpy_return_list_of_custom_class_without_description(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list(:class:`mymodule.Class`)
|
||||
"""
|
||||
return [mymodule.Class()]
|
||||
''')
|
||||
return_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-return-doc', node=node)):
|
||||
self.checker.visit_return(return_node)
|
||||
|
||||
def test_warns_sphinx_redundant_return_doc(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: One
|
||||
"""
|
||||
return None
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_sphinx_redundant_rtype_doc(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
return None
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_google_redundant_return_doc(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
One
|
||||
"""
|
||||
return None
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_google_redundant_rtype_doc(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
int:
|
||||
"""
|
||||
return None
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_numpy_redundant_return_doc(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
One
|
||||
"""
|
||||
return None
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_numpy_redundant_rtype_doc(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
"""
|
||||
return None
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_ignores_sphinx_redundant_return_doc_multiple_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: One
|
||||
:rtype: int
|
||||
|
||||
:returns: None sometimes
|
||||
:rtype: None
|
||||
"""
|
||||
if a_func():
|
||||
return None
|
||||
return 1
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_ignores_google_redundant_return_doc_multiple_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
int or None: One, or sometimes None.
|
||||
"""
|
||||
if a_func():
|
||||
return None
|
||||
return 1
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_ignores_numpy_redundant_return_doc_multiple_returns(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
One
|
||||
None
|
||||
Sometimes
|
||||
"""
|
||||
if a_func():
|
||||
return None
|
||||
return 1
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_ignore_sphinx_redundant_return_doc_yield(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func_with_yield(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: One
|
||||
:rtype: generator
|
||||
"""
|
||||
for value in range(3):
|
||||
yield value
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_google_redundant_return_doc_yield(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns:
|
||||
int: One
|
||||
"""
|
||||
yield 1
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_numpy_redundant_return_doc_yield(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Returns
|
||||
-------
|
||||
int
|
||||
One
|
||||
"""
|
||||
yield 1
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-returns-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
@@ -0,0 +1,397 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
|
||||
# Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
|
||||
# Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Unit tests for the yield documentation checking in the
|
||||
`DocstringChecker` in :mod:`pylint.extensions.check_docs`
|
||||
"""
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import astroid
|
||||
from pylint.testutils import CheckerTestCase, Message, set_config
|
||||
|
||||
from pylint.extensions.docparams import DocstringParameterChecker
|
||||
|
||||
|
||||
class TestDocstringCheckerYield(CheckerTestCase):
|
||||
"""Tests for pylint_plugin.RaiseDocChecker"""
|
||||
CHECKER_CLASS = DocstringParameterChecker
|
||||
|
||||
def test_ignores_no_docstring(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
yield False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
@set_config(accept_no_yields_doc=False)
|
||||
def test_warns_no_docstring(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node),
|
||||
Message(msg_id='missing-yield-type-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_ignores_unknown_style(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring."""
|
||||
yield False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_partial_sphinx_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: Always False
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-type-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_partial_sphinx_yields_type(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_missing_sphinx_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
:param doc_type: Sphinx
|
||||
:type doc_type: str
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node),
|
||||
Message(msg_id='missing-yield-type-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_partial_google_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
Always False
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-type-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_partial_google_yields_type(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
bool:
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_missing_google_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Parameters:
|
||||
doc_type (str): Google
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node),
|
||||
Message(msg_id='missing-yield-type-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warn_missing_numpy_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self, doc_type):
|
||||
"""This is a docstring.
|
||||
|
||||
Arguments
|
||||
---------
|
||||
doc_type : str
|
||||
Numpy
|
||||
"""
|
||||
yield False
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node),
|
||||
Message(msg_id='missing-yield-type-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_find_sphinx_yields(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:return: Always False
|
||||
:rtype: bool
|
||||
"""
|
||||
yield False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_find_google_yields(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
bool: Always False
|
||||
"""
|
||||
yield False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_find_numpy_yields(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields
|
||||
-------
|
||||
bool
|
||||
Always False
|
||||
"""
|
||||
yield False #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_finds_sphinx_yield_custom_class(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: An object
|
||||
:rtype: :class:`mymodule.Class`
|
||||
"""
|
||||
yield mymodule.Class() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_finds_google_yield_custom_class(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
mymodule.Class: An object
|
||||
"""
|
||||
yield mymodule.Class() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_finds_numpy_yield_custom_class(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields
|
||||
-------
|
||||
mymodule.Class
|
||||
An object
|
||||
"""
|
||||
yield mymodule.Class() #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_finds_sphinx_yield_list_of_custom_class(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:returns: An object
|
||||
:rtype: list(:class:`mymodule.Class`)
|
||||
"""
|
||||
yield [mymodule.Class()] #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_finds_google_yield_list_of_custom_class(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
list(:class:`mymodule.Class`): An object
|
||||
"""
|
||||
yield [mymodule.Class()] #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_finds_numpy_yield_list_of_custom_class(self):
|
||||
yield_node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields
|
||||
-------
|
||||
list(:class:`mymodule.Class`)
|
||||
An object
|
||||
"""
|
||||
yield [mymodule.Class()] #@
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warns_sphinx_yield_list_of_custom_class_without_description(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
:rtype: list(:class:`mymodule.Class`)
|
||||
"""
|
||||
yield [mymodule.Class()]
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warns_google_yield_list_of_custom_class_without_description(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
list(:class:`mymodule.Class`):
|
||||
"""
|
||||
yield [mymodule.Class()]
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
def test_warns_numpy_yield_list_of_custom_class_without_description(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields
|
||||
-------
|
||||
list(:class:`mymodule.Class`)
|
||||
"""
|
||||
yield [mymodule.Class()]
|
||||
''')
|
||||
yield_node = node.body[0]
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='missing-yield-doc', node=node)):
|
||||
self.checker.visit_yield(yield_node)
|
||||
|
||||
# No such thing as redundant yield documentation for sphinx because it
|
||||
# doesn't support yield documentation
|
||||
|
||||
def test_ignores_google_redundant_yield_doc_multiple_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
int or None: One, or sometimes None.
|
||||
"""
|
||||
if a_func():
|
||||
yield None
|
||||
yield 1
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_ignores_numpy_redundant_yield_doc_multiple_yields(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields
|
||||
-------
|
||||
int
|
||||
One
|
||||
None
|
||||
Sometimes
|
||||
"""
|
||||
if a_func():
|
||||
yield None
|
||||
yield 1
|
||||
''')
|
||||
with self.assertNoMessages():
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
# No such thing as redundant yield documentation for sphinx because it
|
||||
# doesn't support yield documentation
|
||||
|
||||
def test_warns_google_redundant_yield_doc_return(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields:
|
||||
int: One
|
||||
"""
|
||||
return 1
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-yields-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
||||
|
||||
def test_warns_numpy_redundant_yield_doc_return(self):
|
||||
node = astroid.extract_node('''
|
||||
def my_func(self):
|
||||
"""This is a docstring.
|
||||
|
||||
Yields
|
||||
-------
|
||||
int
|
||||
One
|
||||
"""
|
||||
return 1
|
||||
''')
|
||||
with self.assertAddsMessages(
|
||||
Message(msg_id='redundant-yields-doc', node=node)):
|
||||
self.checker.visit_functiondef(node)
|
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
|
||||
# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
|
||||
# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.emptystring
|
||||
"""
|
||||
|
||||
import os
|
||||
import os.path as osp
|
||||
import unittest
|
||||
|
||||
from pylint import checkers
|
||||
from pylint.extensions.comparetozero import CompareToZeroChecker
|
||||
from pylint.lint import PyLinter
|
||||
from pylint.reporters import BaseReporter
|
||||
|
||||
|
||||
class CompareToZeroTestReporter(BaseReporter):
|
||||
|
||||
def handle_message(self, msg):
|
||||
self.messages.append(msg)
|
||||
|
||||
def on_set_current_module(self, module, filepath):
|
||||
self.messages = []
|
||||
|
||||
|
||||
class CompareToZeroUsedTC(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls._linter = PyLinter()
|
||||
cls._linter.set_reporter(CompareToZeroTestReporter())
|
||||
checkers.initialize(cls._linter)
|
||||
cls._linter.register_checker(CompareToZeroChecker(cls._linter))
|
||||
cls._linter.disable('I')
|
||||
|
||||
def test_comparetozero_message(self):
|
||||
elif_test = osp.join(osp.dirname(osp.abspath(__file__)), 'data',
|
||||
'compare_to_zero.py')
|
||||
self._linter.check([elif_test])
|
||||
msgs = self._linter.reporter.messages
|
||||
self.assertEqual(len(msgs), 4)
|
||||
for msg in msgs:
|
||||
self.assertEqual(msg.symbol, 'compare-to-zero')
|
||||
self.assertEqual(msg.msg, 'Avoid comparisons to zero')
|
||||
self.assertEqual(msgs[0].line, 6)
|
||||
self.assertEqual(msgs[1].line, 9)
|
||||
self.assertEqual(msgs[2].line, 12)
|
||||
self.assertEqual(msgs[3].line, 15)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@@ -0,0 +1,54 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
|
||||
# Copyright (c) 2016 Luis Escobar <lescobar@vauxoo.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.check_docstring
|
||||
"""
|
||||
|
||||
import os.path as osp
|
||||
|
||||
import pytest
|
||||
|
||||
from pylint.extensions.docstyle import DocStringStyleChecker
|
||||
|
||||
|
||||
EXPECTED_MSGS = [
|
||||
'First line empty in function docstring',
|
||||
'First line empty in class docstring',
|
||||
'First line empty in method docstring',
|
||||
'Bad docstring quotes in method, expected """, given \'\'\'',
|
||||
'Bad docstring quotes in method, expected """, given "',
|
||||
'Bad docstring quotes in method, expected """, given \'',
|
||||
'Bad docstring quotes in method, expected """, given \'',
|
||||
]
|
||||
|
||||
EXPECTED_SYMBOLS = [
|
||||
'docstring-first-line-empty',
|
||||
'docstring-first-line-empty',
|
||||
'docstring-first-line-empty',
|
||||
'bad-docstring-quotes',
|
||||
'bad-docstring-quotes',
|
||||
'bad-docstring-quotes',
|
||||
'bad-docstring-quotes',
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checker(checker):
|
||||
return DocStringStyleChecker
|
||||
|
||||
|
||||
def test_docstring_message(linter):
|
||||
docstring_test = osp.join(osp.dirname(osp.abspath(__file__)), 'data',
|
||||
'docstring.py')
|
||||
linter.check([docstring_test])
|
||||
msgs = linter.reporter.messages
|
||||
assert len(msgs) == 7
|
||||
for msg, expected_symbol, expected_msg in zip(msgs,
|
||||
EXPECTED_SYMBOLS,
|
||||
EXPECTED_MSGS):
|
||||
assert msg.symbol == expected_symbol
|
||||
assert msg.msg == expected_msg
|
@@ -0,0 +1,33 @@
|
||||
# Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2015 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
|
||||
# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.check_elif
|
||||
"""
|
||||
|
||||
import os.path as osp
|
||||
|
||||
import pytest
|
||||
|
||||
from pylint.extensions.check_elif import ElseifUsedChecker
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checker(checker):
|
||||
return ElseifUsedChecker
|
||||
|
||||
|
||||
def test_elseif_message(linter):
|
||||
elif_test = osp.join(osp.dirname(osp.abspath(__file__)), 'data',
|
||||
'elif.py')
|
||||
linter.check([elif_test])
|
||||
msgs = linter.reporter.messages
|
||||
assert len(msgs) == 2
|
||||
for msg in msgs:
|
||||
assert msg.symbol == 'else-if-used'
|
||||
assert msg.msg == 'Consider using "elif" instead of "else if"'
|
||||
assert msgs[0].line == 9
|
||||
assert msgs[1].line == 21
|
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
|
||||
# Copyright (c) 2016 Alexander Todorov <atodorov@otb.bg>
|
||||
# Copyright (c) 2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2017 Derek Gustafson <degustaf@gmail.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.emptystring
|
||||
"""
|
||||
|
||||
import os.path as osp
|
||||
import pytest
|
||||
|
||||
from pylint.extensions.emptystring import CompareToEmptyStringChecker
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def checker(checker):
|
||||
return CompareToEmptyStringChecker
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def disable(disable):
|
||||
return ['I']
|
||||
|
||||
|
||||
def test_emptystring_message(linter):
|
||||
elif_test = osp.join(osp.dirname(osp.abspath(__file__)), 'data',
|
||||
'empty_string_comparison.py')
|
||||
linter.check([elif_test])
|
||||
msgs = linter.reporter.messages
|
||||
expected_lineno = [6, 9, 12, 15]
|
||||
assert len(msgs) == len(expected_lineno)
|
||||
for msg, lineno in zip(msgs, expected_lineno):
|
||||
assert msg.symbol == 'compare-to-empty-string'
|
||||
assert msg.msg == 'Avoid comparisons to empty string'
|
||||
assert msg.line == lineno
|
@@ -0,0 +1,69 @@
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.overlapping_exceptions
|
||||
"""
|
||||
|
||||
from sys import version_info
|
||||
from os.path import join, dirname
|
||||
|
||||
from pylint.extensions.overlapping_exceptions import OverlappingExceptionsChecker
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def checker(checker):
|
||||
return OverlappingExceptionsChecker
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def disable(disable):
|
||||
return ['I']
|
||||
|
||||
|
||||
def test_overlapping_exceptions(linter):
|
||||
test = join(dirname(__file__), 'data', 'overlapping_exceptions.py')
|
||||
linter.check([test])
|
||||
msgs = linter.reporter.messages
|
||||
|
||||
expected = [
|
||||
(13, 'Overlapping exceptions (SomeException and SomeException are the same)'),
|
||||
(18, 'Overlapping exceptions (SomeException is an ancestor class of SubclassException)'),
|
||||
(23, 'Overlapping exceptions (SomeException and AliasException are the same)'),
|
||||
(28, 'Overlapping exceptions (AliasException is an ancestor class of SubclassException)'),
|
||||
(34, 'Overlapping exceptions (SomeException and AliasException are the same)'),
|
||||
(34, 'Overlapping exceptions (SomeException is an ancestor class of SubclassException)'),
|
||||
(34, 'Overlapping exceptions (AliasException is an ancestor class of SubclassException)'),
|
||||
(39, 'Overlapping exceptions (ArithmeticError is an ancestor class of FloatingPointError)'),
|
||||
(44, 'Overlapping exceptions (ValueError is an ancestor class of UnicodeDecodeError)')
|
||||
]
|
||||
|
||||
assert len(msgs) == len(expected)
|
||||
for msg, exp in zip(msgs, expected):
|
||||
assert msg.msg_id == 'W0714'
|
||||
assert msg.symbol == 'overlapping-except'
|
||||
assert msg.category == 'warning'
|
||||
assert (msg.line, msg.msg) == exp
|
||||
|
||||
|
||||
@pytest.mark.skipif(version_info < (3, 3),
|
||||
reason="not relevant to Python version")
|
||||
def test_overlapping_exceptions_py33(linter):
|
||||
"""From Python 3.3 both IOError and socket.error are aliases for OSError."""
|
||||
test = join(dirname(__file__), 'data', 'overlapping_exceptions_py33.py')
|
||||
linter.check([test])
|
||||
msgs = linter.reporter.messages
|
||||
|
||||
expected = [
|
||||
(7, 'Overlapping exceptions (IOError and OSError are the same)'),
|
||||
(12, 'Overlapping exceptions (socket.error and OSError are the same)'),
|
||||
(17, 'Overlapping exceptions (socket.error is an ancestor class of ConnectionError)'),
|
||||
]
|
||||
|
||||
assert len(msgs) == len(expected)
|
||||
for msg, exp in zip(msgs, expected):
|
||||
assert msg.msg_id == 'W0714'
|
||||
assert msg.symbol == 'overlapping-except'
|
||||
assert msg.category == 'warning'
|
||||
assert (msg.line, msg.msg) == exp
|
@@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
|
||||
# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
|
||||
|
||||
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
|
||||
|
||||
"""Tests for the pylint checker in :mod:`pylint.extensions.check_elif
|
||||
"""
|
||||
|
||||
import os.path as osp
|
||||
|
||||
import pytest
|
||||
|
||||
from pylint.extensions.redefined_variable_type import MultipleTypesChecker
|
||||
from pylint.lint import fix_import_path
|
||||
|
||||
|
||||
EXPECTED = [
|
||||
'Redefinition of self.var1 type from int to float',
|
||||
'Redefinition of var type from int to str',
|
||||
'Redefinition of myint type from int to bool',
|
||||
'Redefinition of _OK type from bool to str',
|
||||
'Redefinition of instance type from redefined.MyClass to bool',
|
||||
'Redefinition of SOME_FLOAT type from float to int',
|
||||
'Redefinition of var3 type from str to int',
|
||||
'Redefinition of var type from bool to int',
|
||||
'Redefinition of var4 type from float to str',
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def checker(checker):
|
||||
return MultipleTypesChecker
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def disable(disable):
|
||||
return ['I']
|
||||
|
||||
|
||||
def test_types_redefined(linter):
|
||||
elif_test = osp.join(osp.dirname(osp.abspath(__file__)), 'data',
|
||||
'redefined.py')
|
||||
with fix_import_path([elif_test]):
|
||||
linter.check([elif_test])
|
||||
msgs = sorted(linter.reporter.messages, key=lambda item: item.line)
|
||||
assert len(msgs) == 9
|
||||
for msg, expected in zip(msgs, EXPECTED):
|
||||
assert msg.symbol == 'redefined-variable-type'
|
||||
assert msg.msg == expected
|
@@ -0,0 +1,17 @@
|
||||
""" This should not warn about `prop` being abstract in Child """
|
||||
# pylint: disable=too-few-public-methods, no-absolute-import,metaclass-assignment, useless-object-inheritance
|
||||
|
||||
import abc
|
||||
|
||||
class Parent(object):
|
||||
"""Abstract Base Class """
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def prop(self):
|
||||
""" Abstract """
|
||||
|
||||
class Child(Parent):
|
||||
""" No warning for the following. """
|
||||
prop = property(lambda self: 1)
|
@@ -0,0 +1,20 @@
|
||||
"""Don't warn if the class is instantiated in its own body."""
|
||||
# pylint: disable=missing-docstring, useless-object-inheritance
|
||||
|
||||
|
||||
import abc
|
||||
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class Ala(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def bala(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def portocala(cls):
|
||||
instance = cls()
|
||||
return instance
|
@@ -0,0 +1,82 @@
|
||||
"""Check that instantiating a class with
|
||||
`abc.ABCMeta` as metaclass fails if it defines
|
||||
abstract methods.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-few-public-methods, missing-docstring, useless-object-inheritance
|
||||
# pylint: disable=no-absolute-import, metaclass-assignment
|
||||
# pylint: disable=abstract-method, import-error, wildcard-import
|
||||
|
||||
import abc
|
||||
from abc import ABCMeta
|
||||
from lala import Bala
|
||||
|
||||
|
||||
class GoodClass(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
class SecondGoodClass(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def test(self):
|
||||
""" do nothing. """
|
||||
|
||||
class ThirdGoodClass(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
def test(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
class FourthGoodClass(object):
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
class BadClass(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
""" do nothing. """
|
||||
|
||||
class SecondBadClass(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
""" do nothing. """
|
||||
|
||||
class ThirdBadClass(object):
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
pass
|
||||
|
||||
class FourthBadClass(ThirdBadClass):
|
||||
pass
|
||||
|
||||
|
||||
class SomeMetaclass(object):
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def prop(self):
|
||||
pass
|
||||
|
||||
class FifthGoodClass(SomeMetaclass):
|
||||
"""Don't consider this abstract if some attributes are
|
||||
there, but can't be inferred.
|
||||
"""
|
||||
prop = Bala # missing
|
||||
|
||||
|
||||
def main():
|
||||
""" do nothing """
|
||||
GoodClass()
|
||||
SecondGoodClass()
|
||||
ThirdGoodClass()
|
||||
FourthGoodClass()
|
||||
BadClass() # [abstract-class-instantiated]
|
||||
SecondBadClass() # [abstract-class-instantiated]
|
||||
ThirdBadClass() # [abstract-class-instantiated]
|
||||
FourthBadClass() # [abstract-class-instantiated]
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
max_pyver=3.0
|
@@ -0,0 +1,4 @@
|
||||
abstract-class-instantiated:79:main:Abstract class 'BadClass' with abstract methods instantiated
|
||||
abstract-class-instantiated:80:main:Abstract class 'SecondBadClass' with abstract methods instantiated
|
||||
abstract-class-instantiated:81:main:Abstract class 'ThirdBadClass' with abstract methods instantiated
|
||||
abstract-class-instantiated:82:main:Abstract class 'FourthBadClass' with abstract methods instantiated
|
@@ -0,0 +1,128 @@
|
||||
"""Check that instantiating a class with
|
||||
`abc.ABCMeta` as metaclass fails if it defines
|
||||
abstract methods.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-few-public-methods, missing-docstring
|
||||
# pylint: disable=abstract-method, import-error, useless-object-inheritance
|
||||
|
||||
import abc
|
||||
import weakref
|
||||
from lala import Bala
|
||||
|
||||
|
||||
class GoodClass(object, metaclass=abc.ABCMeta):
|
||||
pass
|
||||
|
||||
class SecondGoodClass(object, metaclass=abc.ABCMeta):
|
||||
def test(self):
|
||||
""" do nothing. """
|
||||
|
||||
class ThirdGoodClass(object, metaclass=abc.ABCMeta):
|
||||
""" This should not raise the warning. """
|
||||
def test(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
class BadClass(object, metaclass=abc.ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
""" do nothing. """
|
||||
|
||||
class SecondBadClass(object, metaclass=abc.ABCMeta):
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
""" do nothing. """
|
||||
|
||||
class ThirdBadClass(SecondBadClass):
|
||||
pass
|
||||
|
||||
|
||||
class Structure(object, metaclass=abc.ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def __iter__(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __len__(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __contains__(self, _):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __hash__(self):
|
||||
pass
|
||||
|
||||
class Container(Structure):
|
||||
def __contains__(self, _):
|
||||
pass
|
||||
|
||||
class Sizable(Structure):
|
||||
def __len__(self):
|
||||
pass
|
||||
|
||||
class Hashable(Structure):
|
||||
__hash__ = 42
|
||||
|
||||
|
||||
class Iterator(Structure):
|
||||
def keys(self): # pylint: disable=no-self-use
|
||||
return iter([1, 2, 3])
|
||||
|
||||
__iter__ = keys
|
||||
|
||||
class AbstractSizable(Structure):
|
||||
@abc.abstractmethod
|
||||
def length(self):
|
||||
pass
|
||||
__len__ = length
|
||||
|
||||
class NoMroAbstractMethods(Container, Iterator, Sizable, Hashable):
|
||||
pass
|
||||
|
||||
class BadMroAbstractMethods(Container, Iterator, AbstractSizable):
|
||||
pass
|
||||
|
||||
class SomeMetaclass(metaclass=abc.ABCMeta):
|
||||
|
||||
@abc.abstractmethod
|
||||
def prop(self):
|
||||
pass
|
||||
|
||||
class FourthGoodClass(SomeMetaclass):
|
||||
"""Don't consider this abstract if some attributes are
|
||||
there, but can't be inferred.
|
||||
"""
|
||||
prop = Bala # missing
|
||||
|
||||
|
||||
def main():
|
||||
""" do nothing """
|
||||
GoodClass()
|
||||
SecondGoodClass()
|
||||
ThirdGoodClass()
|
||||
FourthGoodClass()
|
||||
weakref.WeakKeyDictionary()
|
||||
weakref.WeakValueDictionary()
|
||||
NoMroAbstractMethods()
|
||||
|
||||
BadMroAbstractMethods() # [abstract-class-instantiated]
|
||||
BadClass() # [abstract-class-instantiated]
|
||||
SecondBadClass() # [abstract-class-instantiated]
|
||||
ThirdBadClass() # [abstract-class-instantiated]
|
||||
|
||||
|
||||
if 1: # pylint: disable=using-constant-test
|
||||
class FourthBadClass(object, metaclass=abc.ABCMeta):
|
||||
|
||||
def test(self):
|
||||
pass
|
||||
else:
|
||||
class FourthBadClass(object, metaclass=abc.ABCMeta):
|
||||
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
pass
|
||||
|
||||
|
||||
def main2():
|
||||
FourthBadClass() # [abstract-class-instantiated]
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.0
|
@@ -0,0 +1,5 @@
|
||||
abstract-class-instantiated:108:main:Abstract class 'BadMroAbstractMethods' with abstract methods instantiated
|
||||
abstract-class-instantiated:109:main:Abstract class 'BadClass' with abstract methods instantiated
|
||||
abstract-class-instantiated:110:main:Abstract class 'SecondBadClass' with abstract methods instantiated
|
||||
abstract-class-instantiated:111:main:Abstract class 'ThirdBadClass' with abstract methods instantiated
|
||||
abstract-class-instantiated:128:main2:Abstract class 'FourthBadClass' with abstract methods instantiated
|
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
Check that instantiating a class with `abc.ABCMeta` as ancestor fails if it
|
||||
defines abstract methods.
|
||||
"""
|
||||
|
||||
# pylint: disable=too-few-public-methods, missing-docstring, no-init
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
|
||||
class BadClass(abc.ABC):
|
||||
@abc.abstractmethod
|
||||
def test(self):
|
||||
pass
|
||||
|
||||
def main():
|
||||
""" do nothing """
|
||||
BadClass() # [abstract-class-instantiated]
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.4
|
@@ -0,0 +1 @@
|
||||
abstract-class-instantiated:19:main:Abstract class 'BadClass' with abstract methods instantiated
|
@@ -0,0 +1,90 @@
|
||||
"""Test abstract-method warning."""
|
||||
from __future__ import print_function
|
||||
|
||||
# pylint: disable=missing-docstring, no-init, no-self-use
|
||||
# pylint: disable=too-few-public-methods, useless-object-inheritance
|
||||
import abc
|
||||
|
||||
class Abstract(object):
|
||||
def aaaa(self):
|
||||
"""should be overridden in concrete class"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def bbbb(self):
|
||||
"""should be overridden in concrete class"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AbstractB(Abstract):
|
||||
"""Abstract class.
|
||||
|
||||
this class is checking that it does not output an error msg for
|
||||
unimplemeted methods in abstract classes
|
||||
"""
|
||||
def cccc(self):
|
||||
"""should be overridden in concrete class"""
|
||||
raise NotImplementedError()
|
||||
|
||||
class Concrete(Abstract): # [abstract-method]
|
||||
"""Concrete class"""
|
||||
|
||||
def aaaa(self):
|
||||
"""overidden form Abstract"""
|
||||
|
||||
|
||||
class Structure(object):
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def __iter__(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __len__(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __contains__(self, _):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __hash__(self):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Container(Structure):
|
||||
def __contains__(self, _):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Sizable(Structure):
|
||||
def __len__(self):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Hashable(Structure):
|
||||
__hash__ = 42
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Iterator(Structure):
|
||||
def keys(self):
|
||||
return iter([1, 2, 3])
|
||||
|
||||
__iter__ = keys
|
||||
|
||||
|
||||
class AbstractSizable(Structure):
|
||||
@abc.abstractmethod
|
||||
def length(self):
|
||||
pass
|
||||
__len__ = length
|
||||
|
||||
|
||||
class GoodComplexMRO(Container, Iterator, Sizable, Hashable):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class BadComplexMro(Container, Iterator, AbstractSizable):
|
||||
pass
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
max_pyver=3.0
|
@@ -0,0 +1,16 @@
|
||||
abstract-method:28:Concrete:"Method 'bbbb' is abstract in class 'Abstract' but is not overridden"
|
||||
abstract-method:53:Container:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:53:Container:"Method '__iter__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:53:Container:"Method '__len__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:59:Sizable:"Method '__contains__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:59:Sizable:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:59:Sizable:"Method '__iter__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:65:Hashable:"Method '__contains__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:65:Hashable:"Method '__iter__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:65:Hashable:"Method '__len__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:70:Iterator:"Method '__contains__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:70:Iterator:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:70:Iterator:"Method '__len__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:89:BadComplexMro:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:89:BadComplexMro:"Method '__len__' is abstract in class 'AbstractSizable' but is not overridden"
|
||||
abstract-method:89:BadComplexMro:"Method 'length' is abstract in class 'AbstractSizable' but is not overridden"
|
@@ -0,0 +1,88 @@
|
||||
"""Test abstract-method warning."""
|
||||
from __future__ import print_function
|
||||
|
||||
# pylint: disable=missing-docstring, no-init, no-self-use
|
||||
# pylint: disable=too-few-public-methods, useless-object-inheritance
|
||||
import abc
|
||||
|
||||
class Abstract(object):
|
||||
def aaaa(self):
|
||||
"""should be overridden in concrete class"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def bbbb(self):
|
||||
"""should be overridden in concrete class"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class AbstractB(Abstract):
|
||||
"""Abstract class.
|
||||
|
||||
this class is checking that it does not output an error msg for
|
||||
unimplemeted methods in abstract classes
|
||||
"""
|
||||
def cccc(self):
|
||||
"""should be overridden in concrete class"""
|
||||
raise NotImplementedError()
|
||||
|
||||
class Concrete(Abstract): # [abstract-method]
|
||||
"""Concrete class"""
|
||||
|
||||
def aaaa(self):
|
||||
"""overidden form Abstract"""
|
||||
|
||||
|
||||
class Structure(object, metaclass=abc.ABCMeta):
|
||||
@abc.abstractmethod
|
||||
def __iter__(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __len__(self):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __contains__(self, _):
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def __hash__(self):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Container(Structure):
|
||||
def __contains__(self, _):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Sizable(Structure):
|
||||
def __len__(self):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Hashable(Structure):
|
||||
__hash__ = 42
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class Iterator(Structure):
|
||||
def keys(self):
|
||||
return iter([1, 2, 3])
|
||||
|
||||
__iter__ = keys
|
||||
|
||||
|
||||
class AbstractSizable(Structure):
|
||||
@abc.abstractmethod
|
||||
def length(self):
|
||||
pass
|
||||
__len__ = length
|
||||
|
||||
|
||||
class GoodComplexMRO(Container, Iterator, Sizable, Hashable):
|
||||
pass
|
||||
|
||||
|
||||
# +1: [abstract-method, abstract-method, abstract-method]
|
||||
class BadComplexMro(Container, Iterator, AbstractSizable):
|
||||
pass
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.0
|
@@ -0,0 +1,16 @@
|
||||
abstract-method:28:Concrete:"Method 'bbbb' is abstract in class 'Abstract' but is not overridden"
|
||||
abstract-method:51:Container:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:51:Container:"Method '__iter__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:51:Container:"Method '__len__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:57:Sizable:"Method '__contains__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:57:Sizable:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:57:Sizable:"Method '__iter__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:63:Hashable:"Method '__contains__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:63:Hashable:"Method '__iter__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:63:Hashable:"Method '__len__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:68:Iterator:"Method '__contains__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:68:Iterator:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:68:Iterator:"Method '__len__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:87:BadComplexMro:"Method '__hash__' is abstract in class 'Structure' but is not overridden"
|
||||
abstract-method:87:BadComplexMro:"Method '__len__' is abstract in class 'AbstractSizable' but is not overridden"
|
||||
abstract-method:87:BadComplexMro:"Method 'length' is abstract in class 'AbstractSizable' but is not overridden"
|
@@ -0,0 +1,40 @@
|
||||
# pylint: disable=missing-docstring,too-few-public-methods,invalid-name
|
||||
# pylint: disable=attribute-defined-outside-init, useless-object-inheritance
|
||||
|
||||
class Aaaa(object):
|
||||
"""class with attributes defined in wrong order"""
|
||||
|
||||
def __init__(self):
|
||||
var1 = self._var2 # [access-member-before-definition]
|
||||
self._var2 = 3
|
||||
self._var3 = var1
|
||||
|
||||
|
||||
class Bbbb(object):
|
||||
A = 23
|
||||
B = A
|
||||
|
||||
def __getattr__(self, attr):
|
||||
try:
|
||||
return self.__repo
|
||||
except AttributeError:
|
||||
self.__repo = attr
|
||||
return attr
|
||||
|
||||
|
||||
def catchme(self, attr):
|
||||
"""no AttributeError catched"""
|
||||
try:
|
||||
return self._repo # [access-member-before-definition]
|
||||
except ValueError:
|
||||
self._repo = attr
|
||||
return attr
|
||||
|
||||
|
||||
class Mixin(object):
|
||||
|
||||
def test_mixin(self):
|
||||
"""Don't emit access-member-before-definition for mixin classes."""
|
||||
if self.already_defined:
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self.already_defined = None
|
@@ -0,0 +1,2 @@
|
||||
access-member-before-definition:8:Aaaa.__init__:Access to member '_var2' before its definition line 9
|
||||
access-member-before-definition:28:Bbbb.catchme:Access to member '_repo' before its definition line 30
|
@@ -0,0 +1,21 @@
|
||||
# pylint: disable=too-few-public-methods, print-statement, useless-object-inheritance
|
||||
"""test access to __name__ gives undefined member on new/old class instances
|
||||
but not on new/old class object
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
class Aaaa:
|
||||
"""old class"""
|
||||
def __init__(self):
|
||||
print(self.__name__) # [no-member]
|
||||
print(self.__class__.__name__)
|
||||
|
||||
class NewClass(object):
|
||||
"""new class"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print('new', cls.__name__)
|
||||
return object.__new__(cls, *args, **kwargs)
|
||||
|
||||
def __init__(self):
|
||||
print('init', self.__name__) # [no-member]
|
@@ -0,0 +1,2 @@
|
||||
no-member:10:Aaaa.__init__:Instance of 'Aaaa' has no '__name__' member:INFERENCE
|
||||
no-member:21:NewClass.__init__:Instance of 'NewClass' has no '__name__' member:INFERENCE
|
@@ -0,0 +1,59 @@
|
||||
# pylint: disable=too-few-public-methods, W0231, print-statement, useless-object-inheritance
|
||||
# pylint: disable=no-classmethod-decorator
|
||||
"""Test external access to protected class members."""
|
||||
from __future__ import print_function
|
||||
|
||||
class MyClass(object):
|
||||
"""Class with protected members."""
|
||||
_cls_protected = 5
|
||||
|
||||
def __init__(self, other):
|
||||
MyClass._cls_protected = 6
|
||||
self._protected = 1
|
||||
self.public = other
|
||||
self.attr = 0
|
||||
|
||||
def test(self):
|
||||
"""Docstring."""
|
||||
self._protected += self._cls_protected
|
||||
print(self.public._haha) # [protected-access]
|
||||
|
||||
def clsmeth(cls):
|
||||
"""Docstring."""
|
||||
cls._cls_protected += 1
|
||||
print(cls._cls_protected)
|
||||
clsmeth = classmethod(clsmeth)
|
||||
|
||||
def _private_method(self):
|
||||
"""Doing nothing."""
|
||||
|
||||
|
||||
class Subclass(MyClass):
|
||||
"""Subclass with protected members."""
|
||||
|
||||
def __init__(self):
|
||||
MyClass._protected = 5
|
||||
super(Subclass, self)._private_method()
|
||||
|
||||
INST = Subclass()
|
||||
INST.attr = 1
|
||||
print(INST.attr)
|
||||
INST._protected = 2 # [protected-access]
|
||||
print(INST._protected) # [protected-access]
|
||||
INST._cls_protected = 3 # [protected-access]
|
||||
print(INST._cls_protected) # [protected-access]
|
||||
|
||||
|
||||
class Issue1031(object):
|
||||
"""Test for GitHub issue 1031"""
|
||||
_attr = 1
|
||||
|
||||
def correct_access(self):
|
||||
"""Demonstrates correct access"""
|
||||
return type(self)._attr
|
||||
|
||||
def incorrect_access(self):
|
||||
"""Demonstrates incorrect access"""
|
||||
if self._attr == 1:
|
||||
return type(INST)._protected # [protected-access]
|
||||
return None
|
@@ -0,0 +1,6 @@
|
||||
protected-access:19:MyClass.test:Access to a protected member _haha of a client class
|
||||
protected-access:41::Access to a protected member _protected of a client class
|
||||
protected-access:42::Access to a protected member _protected of a client class
|
||||
protected-access:43::Access to a protected member _cls_protected of a client class
|
||||
protected-access:44::Access to a protected member _cls_protected of a client class
|
||||
protected-access:58:Issue1031.incorrect_access:Access to a protected member _protected of a client class
|
@@ -0,0 +1,20 @@
|
||||
# pylint:disable=W0105, W0511
|
||||
"""Test for backslash escapes in byte vs unicode strings"""
|
||||
|
||||
# Would be valid in Unicode, but probably not what you want otherwise
|
||||
BAD_UNICODE = b'\u0042' # [anomalous-unicode-escape-in-string]
|
||||
BAD_LONG_UNICODE = b'\U00000042' # [anomalous-unicode-escape-in-string]
|
||||
# +1:[anomalous-unicode-escape-in-string]
|
||||
BAD_NAMED_UNICODE = b'\N{GREEK SMALL LETTER ALPHA}'
|
||||
|
||||
GOOD_UNICODE = u'\u0042'
|
||||
GOOD_LONG_UNICODE = u'\U00000042'
|
||||
GOOD_NAMED_UNICODE = u'\N{GREEK SMALL LETTER ALPHA}'
|
||||
|
||||
|
||||
# Valid raw strings
|
||||
RAW_BACKSLASHES = r'raw'
|
||||
RAW_UNICODE = ur"\u0062\n"
|
||||
|
||||
# In a comment you can have whatever you want: \ \\ \n \m
|
||||
# even things that look like bad strings: "C:\Program Files"
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
max_pyver=3.0
|
@@ -0,0 +1,3 @@
|
||||
anomalous-unicode-escape-in-string:5::"Anomalous Unicode escape in byte string: '\u'. String constant might be missing an r or u prefix."
|
||||
anomalous-unicode-escape-in-string:6::"Anomalous Unicode escape in byte string: '\U'. String constant might be missing an r or u prefix."
|
||||
anomalous-unicode-escape-in-string:8::"Anomalous Unicode escape in byte string: '\N'. String constant might be missing an r or u prefix."
|
@@ -0,0 +1,19 @@
|
||||
# pylint:disable=W0105, W0511
|
||||
"""Test for backslash escapes in byte vs unicode strings"""
|
||||
|
||||
# Would be valid in Unicode, but probably not what you want otherwise
|
||||
BAD_UNICODE = b'\u0042' # [anomalous-unicode-escape-in-string]
|
||||
BAD_LONG_UNICODE = b'\U00000042' # [anomalous-unicode-escape-in-string]
|
||||
# +1:[anomalous-unicode-escape-in-string]
|
||||
BAD_NAMED_UNICODE = b'\N{GREEK SMALL LETTER ALPHA}'
|
||||
|
||||
GOOD_UNICODE = u'\u0042'
|
||||
GOOD_LONG_UNICODE = u'\U00000042'
|
||||
GOOD_NAMED_UNICODE = u'\N{GREEK SMALL LETTER ALPHA}'
|
||||
|
||||
|
||||
# Valid raw strings
|
||||
RAW_BACKSLASHES = r'raw'
|
||||
|
||||
# In a comment you can have whatever you want: \ \\ \n \m
|
||||
# even things that look like bad strings: "C:\Program Files"
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.0
|
@@ -0,0 +1,3 @@
|
||||
anomalous-unicode-escape-in-string:5::"Anomalous Unicode escape in byte string: '\u'. String constant might be missing an r or u prefix."
|
||||
anomalous-unicode-escape-in-string:6::"Anomalous Unicode escape in byte string: '\U'. String constant might be missing an r or u prefix."
|
||||
anomalous-unicode-escape-in-string:8::"Anomalous Unicode escape in byte string: '\N'. String constant might be missing an r or u prefix."
|
@@ -0,0 +1,217 @@
|
||||
# pylint: disable=too-few-public-methods, no-absolute-import,missing-docstring,import-error,wrong-import-position
|
||||
# pylint: disable=wrong-import-order, useless-object-inheritance
|
||||
|
||||
def decorator(fun):
|
||||
"""Decorator"""
|
||||
return fun
|
||||
|
||||
|
||||
class DemoClass(object):
|
||||
"""Test class for method invocations."""
|
||||
|
||||
@staticmethod
|
||||
def static_method(arg):
|
||||
"""static method."""
|
||||
return arg + arg
|
||||
|
||||
@classmethod
|
||||
def class_method(cls, arg):
|
||||
"""class method"""
|
||||
return arg + arg
|
||||
|
||||
def method(self, arg):
|
||||
"""method."""
|
||||
return (self, arg)
|
||||
|
||||
@decorator
|
||||
def decorated_method(self, arg):
|
||||
"""decorated method."""
|
||||
return (self, arg)
|
||||
|
||||
|
||||
def function_1_arg(first_argument):
|
||||
"""one argument function"""
|
||||
return first_argument
|
||||
|
||||
def function_3_args(first_argument, second_argument, third_argument):
|
||||
"""three arguments function"""
|
||||
return first_argument, second_argument, third_argument
|
||||
|
||||
def function_default_arg(one=1, two=2):
|
||||
"""fonction with default value"""
|
||||
return two, one
|
||||
|
||||
|
||||
function_1_arg(420)
|
||||
function_1_arg() # [no-value-for-parameter]
|
||||
function_1_arg(1337, 347) # [too-many-function-args]
|
||||
|
||||
function_3_args(420, 789) # [no-value-for-parameter]
|
||||
# +1:[no-value-for-parameter,no-value-for-parameter,no-value-for-parameter]
|
||||
function_3_args()
|
||||
function_3_args(1337, 347, 456)
|
||||
function_3_args('bab', 'bebe', None, 5.6) # [too-many-function-args]
|
||||
|
||||
function_default_arg(1, two=5)
|
||||
function_default_arg(two=5)
|
||||
|
||||
function_1_arg(bob=4) # [unexpected-keyword-arg,no-value-for-parameter]
|
||||
function_default_arg(1, 4, coin="hello") # [unexpected-keyword-arg]
|
||||
|
||||
function_default_arg(1, one=5) # [redundant-keyword-arg]
|
||||
|
||||
# Remaining tests are for coverage of correct names in messages.
|
||||
LAMBDA = lambda arg: 1
|
||||
|
||||
LAMBDA() # [no-value-for-parameter]
|
||||
|
||||
def method_tests():
|
||||
"""Method invocations."""
|
||||
demo = DemoClass()
|
||||
demo.static_method() # [no-value-for-parameter]
|
||||
DemoClass.static_method() # [no-value-for-parameter]
|
||||
|
||||
demo.class_method() # [no-value-for-parameter]
|
||||
DemoClass.class_method() # [no-value-for-parameter]
|
||||
|
||||
demo.method() # [no-value-for-parameter]
|
||||
DemoClass.method(demo) # [no-value-for-parameter]
|
||||
|
||||
demo.decorated_method() # [no-value-for-parameter]
|
||||
DemoClass.decorated_method(demo) # [no-value-for-parameter]
|
||||
|
||||
# Test a regression (issue #234)
|
||||
import sys
|
||||
|
||||
class Text(object):
|
||||
""" Regression """
|
||||
|
||||
if sys.version_info > (3,):
|
||||
def __new__(cls):
|
||||
""" empty """
|
||||
return object.__new__(cls)
|
||||
else:
|
||||
def __new__(cls):
|
||||
""" empty """
|
||||
return object.__new__(cls)
|
||||
|
||||
Text()
|
||||
|
||||
class TestStaticMethod(object):
|
||||
|
||||
@staticmethod
|
||||
def test(first, second=None, **kwargs):
|
||||
return first, second, kwargs
|
||||
|
||||
def func(self):
|
||||
self.test(42)
|
||||
self.test(42, second=34)
|
||||
self.test(42, 42)
|
||||
self.test() # [no-value-for-parameter]
|
||||
self.test(42, 42, 42) # [too-many-function-args]
|
||||
|
||||
|
||||
class TypeCheckConstructor(object):
|
||||
def __init__(self, first, second):
|
||||
self.first = first
|
||||
self.second = second
|
||||
def test(self):
|
||||
type(self)(1, 2, 3) # [too-many-function-args]
|
||||
# +1: [no-value-for-parameter,no-value-for-parameter]
|
||||
type(self)()
|
||||
type(self)(1, lala=2) # [no-value-for-parameter,unexpected-keyword-arg]
|
||||
type(self)(1, 2)
|
||||
type(self)(first=1, second=2)
|
||||
|
||||
|
||||
class Test(object):
|
||||
""" lambda needs Test instance as first argument """
|
||||
lam = lambda self, icon: (self, icon)
|
||||
|
||||
def test(self):
|
||||
self.lam(42)
|
||||
self.lam() # [no-value-for-parameter]
|
||||
self.lam(1, 2, 3) # [too-many-function-args]
|
||||
|
||||
Test().lam() # [no-value-for-parameter]
|
||||
|
||||
# Don't emit a redundant-keyword-arg for this example,
|
||||
# it's perfectly valid
|
||||
|
||||
class Issue642(object):
|
||||
attr = 0
|
||||
def __str__(self):
|
||||
return "{self.attr}".format(self=self)
|
||||
|
||||
# These should not emit anything regarding the number of arguments,
|
||||
# since they have something invalid.
|
||||
from ala_bala_portocola import unknown
|
||||
|
||||
# pylint: disable=not-a-mapping,not-an-iterable
|
||||
|
||||
function_1_arg(*unknown)
|
||||
function_1_arg(1, *2)
|
||||
function_1_arg(1, 2, 3, **unknown)
|
||||
function_1_arg(4, 5, **1)
|
||||
function_1_arg(5, 6, **{unknown: 1})
|
||||
function_1_arg(**{object: 1})
|
||||
function_1_arg(**{1: 2})
|
||||
|
||||
def no_context_but_redefined(*args):
|
||||
args = [1]
|
||||
#+1: [no-value-for-parameter, no-value-for-parameter]
|
||||
expect_three(*list(args))
|
||||
|
||||
def no_context_one_elem(*args):
|
||||
expect_three(args) # [no-value-for-parameter, no-value-for-parameter]
|
||||
|
||||
# Don't emit no-value-for-parameter for this, since we
|
||||
# don't have the context at our disposal.
|
||||
def expect_three(one, two, three):
|
||||
return one + two + three
|
||||
|
||||
|
||||
def no_context(*args):
|
||||
expect_three(*args)
|
||||
|
||||
def no_context_two(*args):
|
||||
expect_three(*list(args))
|
||||
|
||||
def no_context_three(*args):
|
||||
expect_three(*set(args))
|
||||
|
||||
def compare_prices(arg):
|
||||
return set((arg, ))
|
||||
|
||||
def find_problems2(prob_dates):
|
||||
for fff in range(10):
|
||||
prob_dates |= compare_prices(fff)
|
||||
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
def namedtuple_replace_issue_1036():
|
||||
cls = namedtuple('cls', 'a b c')
|
||||
new_instance = cls(1, 2, 3)._replace(
|
||||
a=24,
|
||||
b=24,
|
||||
c=42
|
||||
)
|
||||
# +1:[unexpected-keyword-arg,unexpected-keyword-arg]
|
||||
new_bad_instance = cls(1, 2, 3)._replace(d=24, e=32)
|
||||
return new_instance, new_bad_instance
|
||||
|
||||
|
||||
from functools import partial
|
||||
|
||||
def some_func(first, second, third):
|
||||
return first + second + third
|
||||
|
||||
|
||||
partial(some_func, 1, 2)(3)
|
||||
partial(some_func, third=1, second=2)(3)
|
||||
partial(some_func, 1, third=2)(second=3)
|
||||
partial(some_func, 1)(1) # [no-value-for-parameter]
|
||||
partial(some_func, 1)(third=1) # [no-value-for-parameter]
|
||||
partial(some_func, 1, 2)(third=1, fourth=4) # [unexpected-keyword-arg]
|
@@ -0,0 +1,39 @@
|
||||
no-value-for-parameter:46::No value for argument 'first_argument' in function call
|
||||
too-many-function-args:47::Too many positional arguments for function call
|
||||
no-value-for-parameter:49::No value for argument 'third_argument' in function call
|
||||
no-value-for-parameter:51::No value for argument 'first_argument' in function call
|
||||
no-value-for-parameter:51::No value for argument 'second_argument' in function call
|
||||
no-value-for-parameter:51::No value for argument 'third_argument' in function call
|
||||
too-many-function-args:53::Too many positional arguments for function call
|
||||
no-value-for-parameter:58::No value for argument 'first_argument' in function call
|
||||
unexpected-keyword-arg:58::Unexpected keyword argument 'bob' in function call
|
||||
unexpected-keyword-arg:59::Unexpected keyword argument 'coin' in function call
|
||||
redundant-keyword-arg:61::Argument 'one' passed by position and keyword in function call
|
||||
no-value-for-parameter:66::No value for argument 'arg' in lambda call
|
||||
no-value-for-parameter:71:method_tests:No value for argument 'arg' in staticmethod call
|
||||
no-value-for-parameter:72:method_tests:No value for argument 'arg' in staticmethod call
|
||||
no-value-for-parameter:74:method_tests:No value for argument 'arg' in classmethod call
|
||||
no-value-for-parameter:75:method_tests:No value for argument 'arg' in classmethod call
|
||||
no-value-for-parameter:77:method_tests:No value for argument 'arg' in method call
|
||||
no-value-for-parameter:78:method_tests:No value for argument 'arg' in unbound method call
|
||||
no-value-for-parameter:80:method_tests:No value for argument 'arg' in method call
|
||||
no-value-for-parameter:81:method_tests:No value for argument 'arg' in unbound method call
|
||||
no-value-for-parameter:110:TestStaticMethod.func:No value for argument 'first' in staticmethod call
|
||||
too-many-function-args:111:TestStaticMethod.func:Too many positional arguments for staticmethod call
|
||||
too-many-function-args:119:TypeCheckConstructor.test:Too many positional arguments for constructor call
|
||||
no-value-for-parameter:121:TypeCheckConstructor.test:No value for argument 'first' in constructor call
|
||||
no-value-for-parameter:121:TypeCheckConstructor.test:No value for argument 'second' in constructor call
|
||||
no-value-for-parameter:122:TypeCheckConstructor.test:No value for argument 'second' in constructor call
|
||||
unexpected-keyword-arg:122:TypeCheckConstructor.test:Unexpected keyword argument 'lala' in constructor call
|
||||
no-value-for-parameter:133:Test.test:No value for argument 'icon' in method call
|
||||
too-many-function-args:134:Test.test:Too many positional arguments for method call
|
||||
no-value-for-parameter:136::No value for argument 'icon' in method call
|
||||
no-value-for-parameter:163:no_context_but_redefined:No value for argument 'three' in function call
|
||||
no-value-for-parameter:163:no_context_but_redefined:No value for argument 'two' in function call
|
||||
no-value-for-parameter:166:no_context_one_elem:No value for argument 'three' in function call
|
||||
no-value-for-parameter:166:no_context_one_elem:No value for argument 'two' in function call
|
||||
unexpected-keyword-arg:202:namedtuple_replace_issue_1036:Unexpected keyword argument 'd' in method call
|
||||
unexpected-keyword-arg:202:namedtuple_replace_issue_1036:Unexpected keyword argument 'e' in method call
|
||||
no-value-for-parameter:215::No value for argument 'third' in function call
|
||||
no-value-for-parameter:216::No value for argument 'second' in function call
|
||||
unexpected-keyword-arg:217::Unexpected keyword argument 'fourth' in function call
|
@@ -0,0 +1,210 @@
|
||||
"""Test that we are emitting arguments-differ when the arguments are different."""
|
||||
# pylint: disable=missing-docstring, too-few-public-methods, unused-argument,useless-super-delegation, useless-object-inheritance
|
||||
|
||||
class Parent(object):
|
||||
|
||||
def test(self):
|
||||
pass
|
||||
|
||||
|
||||
class Child(Parent):
|
||||
|
||||
def test(self, arg): # [arguments-differ]
|
||||
pass
|
||||
|
||||
|
||||
class ParentDefaults(object):
|
||||
|
||||
def test(self, arg=None, barg=None):
|
||||
pass
|
||||
|
||||
class ChildDefaults(ParentDefaults):
|
||||
|
||||
def test(self, arg=None): # [arguments-differ]
|
||||
pass
|
||||
|
||||
|
||||
class Classmethod(object):
|
||||
|
||||
@classmethod
|
||||
def func(cls, data):
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def func1(cls):
|
||||
return cls
|
||||
|
||||
|
||||
class ClassmethodChild(Classmethod):
|
||||
|
||||
@staticmethod
|
||||
def func(): # [arguments-differ]
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def func1(cls):
|
||||
return cls()
|
||||
|
||||
|
||||
class Builtins(dict):
|
||||
"""Ignore for builtins, for which we don't know the number of required args."""
|
||||
|
||||
@classmethod
|
||||
def fromkeys(cls, arg, arg1):
|
||||
pass
|
||||
|
||||
|
||||
class Varargs(object):
|
||||
|
||||
def has_kwargs(self, arg, **kwargs):
|
||||
pass
|
||||
|
||||
def no_kwargs(self, args):
|
||||
pass
|
||||
|
||||
|
||||
class VarargsChild(Varargs):
|
||||
|
||||
def has_kwargs(self, arg): # [arguments-differ]
|
||||
"Not okay to lose capabilities."
|
||||
|
||||
def no_kwargs(self, arg, **kwargs): # [arguments-differ]
|
||||
"Not okay to add extra capabilities."
|
||||
|
||||
|
||||
class Super(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __private(self):
|
||||
pass
|
||||
|
||||
def __private2_(self):
|
||||
pass
|
||||
|
||||
def ___private3(self):
|
||||
pass
|
||||
|
||||
def method(self, param):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Sub(Super):
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def __init__(self, arg):
|
||||
super(Sub, self).__init__()
|
||||
|
||||
def __private(self, arg):
|
||||
pass
|
||||
|
||||
def __private2_(self, arg):
|
||||
pass
|
||||
|
||||
def ___private3(self, arg):
|
||||
pass
|
||||
|
||||
def method(self, param='abc'):
|
||||
pass
|
||||
|
||||
|
||||
class Staticmethod(object):
|
||||
|
||||
@staticmethod
|
||||
def func(data):
|
||||
return data
|
||||
|
||||
|
||||
class StaticmethodChild(Staticmethod):
|
||||
|
||||
@classmethod
|
||||
def func(cls, data):
|
||||
return data
|
||||
|
||||
|
||||
class Property(object):
|
||||
|
||||
@property
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
class PropertySetter(Property):
|
||||
|
||||
@property
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
@close.setter
|
||||
def close(self, attr):
|
||||
return attr
|
||||
|
||||
|
||||
class StaticmethodChild2(Staticmethod):
|
||||
|
||||
def func(self, data):
|
||||
super(StaticmethodChild2, self).func(data)
|
||||
|
||||
|
||||
class SuperClass(object):
|
||||
|
||||
@staticmethod
|
||||
def impl(arg1, arg2, **kwargs):
|
||||
return arg1 + arg2
|
||||
|
||||
|
||||
class MyClass(SuperClass):
|
||||
|
||||
def impl(self, *args, **kwargs): # [arguments-differ]
|
||||
|
||||
super(MyClass, self).impl(*args, **kwargs)
|
||||
|
||||
|
||||
class FirstHasArgs(object):
|
||||
|
||||
def test(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
class SecondChangesArgs(FirstHasArgs):
|
||||
|
||||
def test(self, first, second, *args): # [arguments-differ]
|
||||
pass
|
||||
|
||||
class Positional(object):
|
||||
|
||||
def test(self, first, second):
|
||||
pass
|
||||
|
||||
|
||||
class PositionalChild(Positional):
|
||||
|
||||
def test(self, *args): # [arguments-differ]
|
||||
"""Accepts too many.
|
||||
|
||||
Why subclassing in the first case if the behavior is different?
|
||||
"""
|
||||
super(PositionalChild, self).test(args[0], args[1])
|
||||
|
||||
|
||||
class HasSpecialMethod(object):
|
||||
|
||||
def __getitem__(self, key):
|
||||
return key
|
||||
|
||||
|
||||
class OverridesSpecialMethod(HasSpecialMethod):
|
||||
|
||||
def __getitem__(self, cheie):
|
||||
return cheie + 1
|
||||
|
||||
|
||||
class ParentClass(object):
|
||||
|
||||
def meth(self, arg, arg1):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ChildClass(ParentClass):
|
||||
|
||||
def meth(self, _arg, dummy):
|
||||
pass
|
@@ -0,0 +1,8 @@
|
||||
arguments-differ:12:Child.test:Parameters differ from overridden 'test' method
|
||||
arguments-differ:23:ChildDefaults.test:Parameters differ from overridden 'test' method
|
||||
arguments-differ:41:ClassmethodChild.func:Parameters differ from overridden 'func' method
|
||||
arguments-differ:68:VarargsChild.has_kwargs:Parameters differ from overridden 'has_kwargs' method
|
||||
arguments-differ:71:VarargsChild.no_kwargs:Parameters differ from overridden 'no_kwargs' method
|
||||
arguments-differ:157:MyClass.impl:Parameters differ from overridden 'impl' method
|
||||
arguments-differ:170:SecondChangesArgs.test:Parameters differ from overridden 'test' method
|
||||
arguments-differ:181:PositionalChild.test:Parameters differ from overridden 'test' method
|
@@ -0,0 +1,36 @@
|
||||
# pylint: disable=missing-docstring,too-few-public-methods
|
||||
class AbstractFoo:
|
||||
|
||||
def kwonly_1(self, first, *, second, third):
|
||||
"Normal positional with two positional only params."
|
||||
|
||||
def kwonly_2(self, *, first, second):
|
||||
"Two positional only parameter."
|
||||
|
||||
def kwonly_3(self, *, first, second):
|
||||
"Two positional only params."
|
||||
|
||||
def kwonly_4(self, *, first, second=None):
|
||||
"One positional only and another with a default."
|
||||
|
||||
def kwonly_5(self, *, first, **kwargs):
|
||||
"Keyword only and keyword variadics."
|
||||
|
||||
|
||||
class Foo(AbstractFoo):
|
||||
|
||||
def kwonly_1(self, first, *, second): # [arguments-differ]
|
||||
"One positional and only one positional only param."
|
||||
|
||||
def kwonly_2(self, first): # [arguments-differ]
|
||||
"Only one positional parameter instead of two positional only parameters."
|
||||
|
||||
def kwonly_3(self, first, second): # [arguments-differ]
|
||||
"Two positional params."
|
||||
|
||||
def kwonly_4(self, first, second): # [arguments-differ]
|
||||
"Two positional params."
|
||||
|
||||
def kwonly_5(self, *, first): # [arguments-differ]
|
||||
"Keyword only, but no variadics."
|
||||
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.0
|
@@ -0,0 +1,5 @@
|
||||
arguments-differ:22:Foo.kwonly_1:Parameters differ from overridden 'kwonly_1' method
|
||||
arguments-differ:25:Foo.kwonly_2:Parameters differ from overridden 'kwonly_2' method
|
||||
arguments-differ:28:Foo.kwonly_3:Parameters differ from overridden 'kwonly_3' method
|
||||
arguments-differ:31:Foo.kwonly_4:Parameters differ from overridden 'kwonly_4' method
|
||||
arguments-differ:34:Foo.kwonly_5:Parameters differ from overridden 'kwonly_5' method
|
@@ -0,0 +1,11 @@
|
||||
'''Assert check example'''
|
||||
|
||||
# pylint: disable=misplaced-comparison-constant, comparison-with-itself
|
||||
assert (1 == 1, 2 == 2), "no error"
|
||||
assert (1 == 1, 2 == 2) # [assert-on-tuple]
|
||||
assert 1 == 1, "no error"
|
||||
assert (1 == 1, ), "no error"
|
||||
assert (1 == 1, )
|
||||
assert (1 == 1, 2 == 2, 3 == 5), "no error"
|
||||
assert ()
|
||||
assert (True, 'error msg') # [assert-on-tuple]
|
@@ -0,0 +1,2 @@
|
||||
assert-on-tuple:5::Assert called on a 2-uple. Did you mean 'assert x,y'?
|
||||
assert-on-tuple:11::Assert called on a 2-uple. Did you mean 'assert x,y'?
|
@@ -0,0 +1,150 @@
|
||||
""" Checks assigning attributes not found in class slots
|
||||
will trigger assigning-non-slot warning.
|
||||
"""
|
||||
# pylint: disable=too-few-public-methods, no-init, missing-docstring, no-absolute-import, import-error, useless-object-inheritance
|
||||
from collections import deque
|
||||
|
||||
from missing import Unknown
|
||||
|
||||
class Empty(object):
|
||||
""" empty """
|
||||
|
||||
class Bad(object):
|
||||
""" missing not in slots. """
|
||||
|
||||
__slots__ = ['member']
|
||||
|
||||
def __init__(self):
|
||||
self.missing = 42 # [assigning-non-slot]
|
||||
|
||||
class Bad2(object):
|
||||
""" missing not in slots """
|
||||
__slots__ = [deque.__name__, 'member']
|
||||
|
||||
def __init__(self):
|
||||
self.deque = 42
|
||||
self.missing = 42 # [assigning-non-slot]
|
||||
|
||||
class Bad3(Bad):
|
||||
""" missing not found in slots """
|
||||
|
||||
__slots__ = ['component']
|
||||
|
||||
def __init__(self):
|
||||
self.component = 42
|
||||
self.member = 24
|
||||
self.missing = 42 # [assigning-non-slot]
|
||||
super(Bad3, self).__init__()
|
||||
|
||||
class Good(Empty):
|
||||
""" missing not in slots, but Empty doesn't
|
||||
specify __slots__.
|
||||
"""
|
||||
__slots__ = ['a']
|
||||
|
||||
def __init__(self):
|
||||
self.missing = 42
|
||||
|
||||
class Good2(object):
|
||||
""" Using __dict__ in slots will be safe. """
|
||||
|
||||
__slots__ = ['__dict__', 'comp']
|
||||
|
||||
def __init__(self):
|
||||
self.comp = 4
|
||||
self.missing = 5
|
||||
|
||||
class PropertyGood(object):
|
||||
""" Using properties is safe. """
|
||||
|
||||
__slots__ = ['tmp', '_value']
|
||||
|
||||
@property
|
||||
def test(self):
|
||||
return self._value
|
||||
|
||||
@test.setter
|
||||
def test(self, value):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self._value = value
|
||||
|
||||
def __init__(self):
|
||||
self.test = 42
|
||||
|
||||
class PropertyGood2(object):
|
||||
""" Using properties in the body of the class is safe. """
|
||||
__slots__ = ['_value']
|
||||
|
||||
def _getter(self):
|
||||
return self._value
|
||||
|
||||
def _setter(self, value):
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
self._value = value
|
||||
|
||||
test = property(_getter, _setter)
|
||||
|
||||
def __init__(self):
|
||||
self.test = 24
|
||||
|
||||
class UnicodeSlots(object):
|
||||
"""Using unicode objects in __slots__ is okay.
|
||||
|
||||
On Python 3.3 onward, u'' is equivalent to '',
|
||||
so this test should be safe for both versions.
|
||||
"""
|
||||
__slots__ = (u'first', u'second')
|
||||
|
||||
def __init__(self):
|
||||
self.first = 42
|
||||
self.second = 24
|
||||
|
||||
|
||||
class DataDescriptor(object):
|
||||
def __init__(self, name, default=''):
|
||||
self.__name = name
|
||||
self.__default = default
|
||||
|
||||
def __get__(self, inst, cls):
|
||||
return getattr(inst, self.__name, self.__default)
|
||||
|
||||
def __set__(self, inst, value):
|
||||
setattr(inst, self.__name, value)
|
||||
|
||||
|
||||
class NonDataDescriptor(object):
|
||||
def __get__(self, inst, cls):
|
||||
return 42
|
||||
|
||||
|
||||
class SlotsWithDescriptor(object):
|
||||
__slots__ = ['_err']
|
||||
data_descriptor = DataDescriptor('_err')
|
||||
non_data_descriptor = NonDataDescriptor()
|
||||
missing_descriptor = Unknown()
|
||||
|
||||
|
||||
def dont_emit_for_descriptors():
|
||||
inst = SlotsWithDescriptor()
|
||||
# This should not emit, because attr is
|
||||
# a data descriptor
|
||||
inst.data_descriptor = 'foo'
|
||||
inst.non_data_descriptor = 'lala' # [assigning-non-slot]
|
||||
|
||||
|
||||
class ClassWithSlots(object):
|
||||
__slots__ = ['foobar']
|
||||
|
||||
|
||||
class ClassReassigningDunderClass(object):
|
||||
__slots__ = ['foobar']
|
||||
|
||||
def release(self):
|
||||
self.__class__ = ClassWithSlots
|
||||
|
||||
|
||||
class ClassReassingingInvalidLayoutClass(object):
|
||||
__slots__ = []
|
||||
|
||||
def release(self):
|
||||
self.__class__ = ClassWithSlots # [assigning-non-slot]
|
@@ -0,0 +1,5 @@
|
||||
assigning-non-slot:18:Bad.__init__:Assigning to attribute 'missing' not defined in class slots
|
||||
assigning-non-slot:26:Bad2.__init__:Assigning to attribute 'missing' not defined in class slots
|
||||
assigning-non-slot:36:Bad3.__init__:Assigning to attribute 'missing' not defined in class slots
|
||||
assigning-non-slot:132:dont_emit_for_descriptors:Assigning to attribute 'non_data_descriptor' not defined in class slots
|
||||
assigning-non-slot:150:ClassReassingingInvalidLayoutClass.release:Assigning to attribute '__class__' not defined in class slots
|
@@ -0,0 +1,31 @@
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
|
||||
def some_func():
|
||||
pass
|
||||
|
||||
|
||||
def decorate(func):
|
||||
"""Decorate *fn* to return ``self`` to enable chained method calls."""
|
||||
def wrapper(self, *args, **kw):
|
||||
func(self, *args, **kw)
|
||||
return 42
|
||||
return wrapper
|
||||
|
||||
|
||||
class Class:
|
||||
|
||||
def some_method(self):
|
||||
pass
|
||||
|
||||
@decorate
|
||||
def some_other_decorated_method(self):
|
||||
pass
|
||||
|
||||
def some_other_method(self):
|
||||
value = self.some_method() # [assignment-from-no-return]
|
||||
other_value = self.some_other_decorated_method()
|
||||
return value + other_value
|
||||
|
||||
|
||||
VALUE = some_func() # [assignment-from-no-return]
|
@@ -0,0 +1,2 @@
|
||||
assignment-from-no-return:26:Class.some_other_method:Assigning result of a function call, where the function has no return
|
||||
assignment-from-no-return:31::Assigning result of a function call, where the function has no return
|
@@ -0,0 +1,28 @@
|
||||
# pylint: disable=missing-docstring
|
||||
|
||||
import asyncio
|
||||
|
||||
|
||||
async def bla1():
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
async def bla2():
|
||||
await asyncio.sleep(2)
|
||||
|
||||
|
||||
async def combining_coroutine1():
|
||||
await bla1()
|
||||
await bla2()
|
||||
|
||||
|
||||
async def combining_coroutine2():
|
||||
future1 = bla1()
|
||||
future2 = bla2()
|
||||
await asyncio.gather(future1, future2)
|
||||
|
||||
|
||||
def do_stuff():
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(combining_coroutine1())
|
||||
loop.run_until_complete(combining_coroutine2())
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.6
|
@@ -0,0 +1,63 @@
|
||||
"""Check that Python 3.5's async functions are properly analyzed by Pylint."""
|
||||
# pylint: disable=missing-docstring,invalid-name,too-few-public-methods
|
||||
# pylint: disable=using-constant-test, useless-object-inheritance
|
||||
|
||||
async def next(): # [redefined-builtin]
|
||||
pass
|
||||
|
||||
async def some_function(arg1, arg2): # [unused-argument]
|
||||
await arg1
|
||||
|
||||
|
||||
class OtherClass(object):
|
||||
|
||||
@staticmethod
|
||||
def test():
|
||||
return 42
|
||||
|
||||
|
||||
class Class(object):
|
||||
|
||||
async def some_method(self):
|
||||
super(OtherClass, self).test() # [bad-super-call]
|
||||
|
||||
|
||||
# +1: [too-many-arguments,too-many-return-statements, too-many-branches]
|
||||
async def complex_function(this, function, has, more, arguments, than,
|
||||
one, _, should, have):
|
||||
if 1:
|
||||
return this
|
||||
if 1:
|
||||
return function
|
||||
if 1:
|
||||
return has
|
||||
if 1:
|
||||
return more
|
||||
if 1:
|
||||
return arguments
|
||||
if 1:
|
||||
return than
|
||||
try:
|
||||
return one
|
||||
finally:
|
||||
pass
|
||||
if 2:
|
||||
return should
|
||||
while True:
|
||||
pass
|
||||
if 1:
|
||||
return have
|
||||
if 2:
|
||||
return function
|
||||
if 3:
|
||||
pass
|
||||
|
||||
|
||||
# +1: [duplicate-argument-name, duplicate-argument-name, dangerous-default-value]
|
||||
async def func(a, a, b=[]):
|
||||
return a, b
|
||||
|
||||
|
||||
# +1: [empty-docstring, blacklisted-name]
|
||||
async def foo():
|
||||
""
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.5
|
@@ -0,0 +1,11 @@
|
||||
redefined-builtin:5:next:"Redefining built-in 'next'"
|
||||
unused-argument:8:some_function:"Unused argument 'arg2'"
|
||||
bad-super-call:22:Class.some_method:"Bad first argument 'OtherClass' given to super()"
|
||||
too-many-arguments:26:complex_function:Too many arguments (10/5)
|
||||
too-many-branches:26:complex_function:Too many branches (13/12)
|
||||
too-many-return-statements:26:complex_function:Too many return statements (10/6)
|
||||
dangerous-default-value:57:func:Dangerous default value [] as argument
|
||||
duplicate-argument-name:57:func:Duplicate argument name a in function definition
|
||||
duplicate-argument-name:57:func:Duplicate argument name a in function definition
|
||||
blacklisted-name:62:foo:Black listed name "foo"
|
||||
empty-docstring:62:foo:Empty function docstring
|
@@ -0,0 +1,62 @@
|
||||
# pylint: disable=missing-docstring,too-few-public-methods,invalid-name, useless-object-inheritance
|
||||
|
||||
class A(object):
|
||||
|
||||
def __init__(self):
|
||||
self.x = 0
|
||||
self.setUp()
|
||||
|
||||
def set_y(self, y):
|
||||
self.y = y
|
||||
|
||||
def set_x(self, x):
|
||||
self.x = x
|
||||
|
||||
def set_z(self, z):
|
||||
self.z = z # [attribute-defined-outside-init]
|
||||
|
||||
def setUp(self):
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
|
||||
|
||||
class B(A):
|
||||
|
||||
def test(self):
|
||||
self.z = 44 # [attribute-defined-outside-init]
|
||||
|
||||
|
||||
class C(object):
|
||||
|
||||
def __init__(self):
|
||||
self._init()
|
||||
|
||||
def _init(self):
|
||||
self.z = 44
|
||||
|
||||
|
||||
class D(object):
|
||||
|
||||
def setUp(self):
|
||||
self.set_z()
|
||||
|
||||
def set_z(self):
|
||||
self.z = 42
|
||||
|
||||
|
||||
class E(object):
|
||||
|
||||
def __init__(self):
|
||||
i = self._init
|
||||
i()
|
||||
|
||||
def _init(self):
|
||||
self.z = 44
|
||||
|
||||
|
||||
class Mixin(object):
|
||||
|
||||
def test_mixin(self):
|
||||
"""Don't emit attribute-defined-outside-init for mixin classes."""
|
||||
if self.defined_already: # pylint: disable=access-member-before-definition
|
||||
self.defined_already = None
|
@@ -0,0 +1,2 @@
|
||||
attribute-defined-outside-init:16:A.set_z:Attribute 'z' defined outside __init__
|
||||
attribute-defined-outside-init:26:B.test:Attribute 'z' defined outside __init__
|
@@ -0,0 +1,232 @@
|
||||
"""Regression test case for bad-continuation."""
|
||||
# pylint: disable=print-statement,implicit-str-concat-in-sequence,using-constant-test,missing-docstring,wrong-import-position
|
||||
# Various alignment for brackets
|
||||
from __future__ import print_function
|
||||
|
||||
LIST0 = [
|
||||
1, 2, 3
|
||||
]
|
||||
LIST1 = [
|
||||
1, 2, 3
|
||||
]
|
||||
LIST2 = [
|
||||
1, 2, 3
|
||||
] # [bad-continuation]
|
||||
|
||||
# Alignment inside literals
|
||||
W0 = [1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, # [bad-continuation]
|
||||
8, 9, 10,
|
||||
11, 12, 13,
|
||||
# and a comment
|
||||
14, 15, 16]
|
||||
|
||||
W1 = {
|
||||
'a': 1,
|
||||
'b': 2, # [bad-continuation]
|
||||
'c': 3,
|
||||
}
|
||||
|
||||
W2 = {
|
||||
'a': 1,
|
||||
'b': 2, # [bad-continuation]
|
||||
'c': 3,
|
||||
}
|
||||
|
||||
W2 = ['some', 'contents' # with a continued comment that may be aligned
|
||||
# under the previous comment (optionally)
|
||||
'and',
|
||||
'more', # but this
|
||||
# [bad-continuation] is not accepted
|
||||
'contents', # [bad-continuation] nor this.
|
||||
]
|
||||
|
||||
# Values in dictionaries should be indented 4 spaces further if they are on a
|
||||
# different line than their key
|
||||
W4 = {
|
||||
'key1':
|
||||
'value1', # Grandfather in the old style
|
||||
'key2':
|
||||
'value2', # [bad-continuation]
|
||||
'key3':
|
||||
'value3', # Comma here
|
||||
}
|
||||
|
||||
# And should follow the same rules as continuations within parens
|
||||
W5 = {
|
||||
'key1': 'long value'
|
||||
'long continuation',
|
||||
'key2': 'breaking'
|
||||
'wrong', # [bad-continuation]
|
||||
'key3': 2*(
|
||||
2+2),
|
||||
'key4': ('parenthesis',
|
||||
'continuation') # No comma here
|
||||
}
|
||||
|
||||
# Allow values to line up with their keys when the key is next to the brace
|
||||
W6 = {'key1':
|
||||
'value1',
|
||||
'key2':
|
||||
'value2',
|
||||
}
|
||||
|
||||
# Or allow them to be indented
|
||||
W7 = {'key1':
|
||||
'value1',
|
||||
'key2':
|
||||
'value2'
|
||||
}
|
||||
|
||||
# Bug that caused a warning on the previous two cases permitted these odd
|
||||
# incorrect indentations
|
||||
W8 = {'key1':
|
||||
'value1', # [bad-continuation]
|
||||
}
|
||||
|
||||
W9 = {'key1':
|
||||
'value1', # [bad-continuation]
|
||||
}
|
||||
|
||||
# Alignment of arguments in function definitions
|
||||
def continue1(some_arg,
|
||||
some_other_arg):
|
||||
"""A function with well-aligned arguments."""
|
||||
print(some_arg, some_other_arg)
|
||||
|
||||
|
||||
def continue2(
|
||||
some_arg,
|
||||
some_other_arg):
|
||||
"""A function with well-aligned arguments."""
|
||||
print(some_arg, some_other_arg)
|
||||
|
||||
def continue3(
|
||||
some_arg, # [bad-continuation]
|
||||
some_other_arg): # [bad-continuation]
|
||||
"""A function with misaligned arguments"""
|
||||
print(some_arg, some_other_arg)
|
||||
|
||||
def continue4( # pylint:disable=missing-docstring
|
||||
arg1,
|
||||
arg2): print(arg1, arg2)
|
||||
|
||||
|
||||
def callee(*args):
|
||||
"""noop"""
|
||||
print(args)
|
||||
|
||||
|
||||
callee(
|
||||
"a",
|
||||
"b"
|
||||
)
|
||||
|
||||
callee("a",
|
||||
"b") # [bad-continuation]
|
||||
|
||||
callee(5, {'a': 'b',
|
||||
'c': 'd'})
|
||||
|
||||
if (
|
||||
1
|
||||
): pass
|
||||
|
||||
if (
|
||||
1
|
||||
): pass
|
||||
if (
|
||||
1
|
||||
): pass # [bad-continuation]
|
||||
|
||||
if (1 and
|
||||
2): # [bad-continuation]
|
||||
pass
|
||||
|
||||
while (1 and
|
||||
2):
|
||||
pass
|
||||
|
||||
while (1 and
|
||||
2 and # [bad-continuation]
|
||||
3):
|
||||
pass
|
||||
|
||||
if (
|
||||
2): pass # [bad-continuation]
|
||||
|
||||
if (1 or
|
||||
2 or
|
||||
3): pass
|
||||
|
||||
if (1 or
|
||||
2 or # [bad-continuation]
|
||||
3): print(1, 2)
|
||||
|
||||
if (1 and
|
||||
2): pass # [bad-continuation]
|
||||
|
||||
if (
|
||||
2): pass
|
||||
|
||||
if (
|
||||
2): # [bad-continuation]
|
||||
pass
|
||||
|
||||
L1 = (lambda a,
|
||||
b: a + b)
|
||||
|
||||
if not (1 and
|
||||
2):
|
||||
print(3)
|
||||
|
||||
if not (1 and
|
||||
2): # [bad-continuation]
|
||||
print(3)
|
||||
|
||||
continue2("foo",
|
||||
some_other_arg="this "
|
||||
"is "
|
||||
"fine")
|
||||
|
||||
from contextlib import contextmanager
|
||||
@contextmanager
|
||||
def mycontext(*args):
|
||||
yield args
|
||||
|
||||
with mycontext(
|
||||
"this is",
|
||||
"great stuff",
|
||||
"mane"):
|
||||
pass
|
||||
|
||||
# pylint: disable=using-constant-test
|
||||
# More indentation included to distinguish this from the rest.
|
||||
def long_function_name(
|
||||
var_one, var_two, var_three,
|
||||
var_four):
|
||||
print(var_one, var_two, var_three, var_four)
|
||||
|
||||
|
||||
def short_func_name(first, second, third):
|
||||
# Add some extra indentation on the conditional continuation line.
|
||||
if (first
|
||||
and second == first == 'some_big_long_statement_that_should_not_trigger'):
|
||||
third()
|
||||
|
||||
|
||||
# Some normal multi-line statements with double-indented continuation lines.
|
||||
LARGE_COLLECTION = [
|
||||
"spam",
|
||||
"eggs",
|
||||
"beans",
|
||||
]
|
||||
|
||||
long_function_name(
|
||||
"1", "2", "3", "4")
|
||||
|
||||
CONCATENATED_TEXT = (
|
||||
"spam"
|
||||
"eggs"
|
||||
"beans")
|
@@ -0,0 +1,63 @@
|
||||
bad-continuation:14::"Wrong hanging indentation.
|
||||
] # [bad-continuation]
|
||||
| ^|"
|
||||
bad-continuation:19::"Wrong continued indentation (remove 3 spaces).
|
||||
7, # [bad-continuation]
|
||||
| ^"
|
||||
bad-continuation:27::"Wrong hanging indentation (add 1 space).
|
||||
'b': 2, # [bad-continuation]
|
||||
^|"
|
||||
bad-continuation:33::"Wrong hanging indentation (add 1 space).
|
||||
'b': 2, # [bad-continuation]
|
||||
^|"
|
||||
bad-continuation:41::"Wrong continued indentation.
|
||||
# [bad-continuation] is not accepted
|
||||
| | ^"
|
||||
bad-continuation:42::"Wrong continued indentation (remove 20 spaces).
|
||||
'contents', # [bad-continuation] nor this.
|
||||
| ^"
|
||||
bad-continuation:51::"Wrong hanging indentation in dict value.
|
||||
'value2', # [bad-continuation]
|
||||
| ^ |"
|
||||
bad-continuation:61::"Wrong continued indentation (add 4 spaces).
|
||||
'wrong', # [bad-continuation]
|
||||
^ |"
|
||||
bad-continuation:85::"Wrong hanging indentation in dict value.
|
||||
'value1', # [bad-continuation]
|
||||
^ | |"
|
||||
bad-continuation:89::"Wrong hanging indentation in dict value.
|
||||
'value1', # [bad-continuation]
|
||||
^ | |"
|
||||
bad-continuation:106::"Wrong hanging indentation before block (add 4 spaces).
|
||||
some_arg, # [bad-continuation]
|
||||
^ |"
|
||||
bad-continuation:107::"Wrong hanging indentation before block (add 4 spaces).
|
||||
some_other_arg): # [bad-continuation]
|
||||
^ |"
|
||||
bad-continuation:127::"Wrong continued indentation (add 3 spaces).
|
||||
""b"") # [bad-continuation]
|
||||
^ |"
|
||||
bad-continuation:141::"Wrong hanging indentation before block.
|
||||
): pass # [bad-continuation]
|
||||
| ^|"
|
||||
bad-continuation:144::"Wrong continued indentation before block (add 4 spaces).
|
||||
2): # [bad-continuation]
|
||||
^ |"
|
||||
bad-continuation:152::"Wrong continued indentation (remove 2 spaces).
|
||||
2 and # [bad-continuation]
|
||||
| ^"
|
||||
bad-continuation:157::"Wrong hanging indentation before block.
|
||||
2): pass # [bad-continuation]
|
||||
^ | |"
|
||||
bad-continuation:164::"Wrong continued indentation before block.
|
||||
2 or # [bad-continuation]
|
||||
|^ |"
|
||||
bad-continuation:168::"Wrong continued indentation before block.
|
||||
2): pass # [bad-continuation]
|
||||
^ | |"
|
||||
bad-continuation:174::"Wrong hanging indentation before block.
|
||||
2): # [bad-continuation]
|
||||
^ | |"
|
||||
bad-continuation:185::"Wrong continued indentation (add 4 spaces).
|
||||
2): # [bad-continuation]
|
||||
^ |"
|
@@ -0,0 +1,8 @@
|
||||
# pylint: disable=missing-docstring, unused-argument
|
||||
|
||||
async def upload_post(
|
||||
content: bytes,
|
||||
source: str,
|
||||
tags: dict) -> dict:
|
||||
# regression test for https://github.com/PyCQA/pylint/issues/1415
|
||||
raise NotImplementedError('Not implemented')
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.6
|
@@ -0,0 +1,52 @@
|
||||
"""Regression test case for bad-continuation with tabs"""
|
||||
# pylint: disable=too-few-public-methods,missing-docstring,invalid-name,unused-variable, useless-object-inheritance
|
||||
# Various alignment for brackets
|
||||
|
||||
# Issue 638
|
||||
TEST1 = ["foo",
|
||||
"bar",
|
||||
"baz"
|
||||
]
|
||||
|
||||
MY_LIST = [
|
||||
1, 2, 3,
|
||||
4, 5, 6
|
||||
]
|
||||
|
||||
# Issue 1148
|
||||
class Abc(object):
|
||||
def b(self, c):
|
||||
# bock indentation
|
||||
self.d(
|
||||
c) # (is: tabs only)
|
||||
|
||||
def d(self, e):
|
||||
# bad hanging indentation
|
||||
self.b(
|
||||
e) # [bad-continuation] (is: 2 tabs + 7 spaces)
|
||||
|
||||
def f(self):
|
||||
# block indentiation (is: all tabs only)
|
||||
return [
|
||||
self.b,
|
||||
self.d
|
||||
]
|
||||
|
||||
def g(self):
|
||||
# bad hanging indentation
|
||||
# the closing ] requires 7 - 8 more spcaes; see h(), i()
|
||||
return [self.b,
|
||||
self.d # (is: 2 tabs + 8 spaces)
|
||||
] # [bad-continuation] (is: tabs only)
|
||||
|
||||
def h(self):
|
||||
# hanging indentation: all lined up with first token 'self.b'
|
||||
return [self.b,
|
||||
self.d # (is: 2 tabs + 8 spaces)
|
||||
] # (is: 2 tabs + 8 spaces)
|
||||
|
||||
def i(self):
|
||||
# hangin identation: closing ] lined up with opening [
|
||||
return [self.b,
|
||||
self.d # (2 tabs + 8 spaces)
|
||||
] # (2 tabs + 7 spaces)
|
@@ -0,0 +1,3 @@
|
||||
[FORMAT]
|
||||
indent-string='\t'
|
||||
indent-after-paren=1
|
@@ -0,0 +1,6 @@
|
||||
bad-continuation:26::"Wrong hanging indentation (add 1 space).
|
||||
e) # [bad-continuation] (is: 2 tabs + 7 spaces)
|
||||
^|"
|
||||
bad-continuation:40::"Wrong continued indentation.
|
||||
] # [bad-continuation] (is: tabs only)
|
||||
^ ||"
|
@@ -0,0 +1,45 @@
|
||||
# pylint: disable=missing-docstring, bare-except, broad-except
|
||||
|
||||
__revision__ = 1
|
||||
|
||||
try:
|
||||
__revision__ += 1
|
||||
except Exception:
|
||||
__revision__ = 0
|
||||
except TypeError: # [bad-except-order]
|
||||
__revision__ = 0
|
||||
|
||||
try:
|
||||
__revision__ += 1
|
||||
except LookupError:
|
||||
__revision__ = 0
|
||||
except IndexError: # [bad-except-order]
|
||||
__revision__ = 0
|
||||
|
||||
try:
|
||||
__revision__ += 1
|
||||
except (LookupError, NameError):
|
||||
__revision__ = 0
|
||||
except (IndexError, UnboundLocalError): # [bad-except-order, bad-except-order]
|
||||
__revision__ = 0
|
||||
|
||||
try: # [bad-except-order]
|
||||
__revision__ += 1
|
||||
except:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
__revision__ += 1
|
||||
except TypeError:
|
||||
__revision__ = 0
|
||||
except:
|
||||
__revision__ = 0
|
||||
|
||||
try:
|
||||
__revision__ += 1
|
||||
except Exception:
|
||||
pass
|
||||
except:
|
||||
pass
|
@@ -0,0 +1,5 @@
|
||||
bad-except-order:9::Bad except clauses order (Exception is an ancestor class of TypeError)
|
||||
bad-except-order:16::Bad except clauses order (LookupError is an ancestor class of IndexError)
|
||||
bad-except-order:23::Bad except clauses order (LookupError is an ancestor class of IndexError)
|
||||
bad-except-order:23::Bad except clauses order (NameError is an ancestor class of UnboundLocalError)
|
||||
bad-except-order:26::Bad except clauses order (empty except clause should always appear last)
|
@@ -0,0 +1,24 @@
|
||||
"""Check that raise ... from .. uses a proper exception context """
|
||||
|
||||
# pylint: disable=unreachable, import-error, multiple-imports
|
||||
|
||||
import socket, unknown
|
||||
|
||||
__revision__ = 0
|
||||
|
||||
class ExceptionSubclass(Exception):
|
||||
""" subclass """
|
||||
|
||||
def test():
|
||||
""" docstring """
|
||||
raise IndexError from 1 # [bad-exception-context]
|
||||
raise IndexError from None
|
||||
raise IndexError from ZeroDivisionError
|
||||
raise IndexError from object() # [bad-exception-context]
|
||||
raise IndexError from ExceptionSubclass
|
||||
raise IndexError from socket.error
|
||||
raise IndexError() from None
|
||||
raise IndexError() from ZeroDivisionError
|
||||
raise IndexError() from ZeroDivisionError()
|
||||
raise IndexError() from object() # [bad-exception-context]
|
||||
raise IndexError() from unknown
|
@@ -0,0 +1,2 @@
|
||||
[testoptions]
|
||||
min_pyver=3.0
|
@@ -0,0 +1,3 @@
|
||||
bad-exception-context:14:test:Exception context set to something which is not an exception, nor None
|
||||
bad-exception-context:17:test:Exception context set to something which is not an exception, nor None
|
||||
bad-exception-context:23:test:Exception context set to something which is not an exception, nor None
|
@@ -0,0 +1,19 @@
|
||||
# pylint: disable=missing-docstring, pointless-statement
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
def totoo():
|
||||
print('malindented') # [bad-indentation]
|
||||
|
||||
def tutuu():
|
||||
print('good indentation')
|
||||
|
||||
def titii():
|
||||
1 # and this. # [bad-indentation]
|
||||
|
||||
def tataa(kdict):
|
||||
for key in ['1', '2', '3']:
|
||||
key = key.lower()
|
||||
|
||||
if key in kdict:
|
||||
del kdict[key]
|
@@ -0,0 +1,2 @@
|
||||
bad-indentation:6::Bad indentation. Found 1 spaces, expected 4
|
||||
bad-indentation:12::Bad indentation. Found 5 spaces, expected 4
|
@@ -0,0 +1,5 @@
|
||||
"""errors-only is not usable as an inline option"""
|
||||
# +1: [bad-inline-option]
|
||||
# pylint: errors-only
|
||||
|
||||
CONST = "This is not a pylint: inline option."
|
@@ -0,0 +1,2 @@
|
||||
[Messages Control]
|
||||
enable=I
|
@@ -0,0 +1 @@
|
||||
bad-inline-option:3::Unable to consider inline option 'errors-only'
|
@@ -0,0 +1,37 @@
|
||||
"""Warnings for using open() with an invalid mode string."""
|
||||
|
||||
open('foo.bar', 'w', 2)
|
||||
open('foo.bar', 'rw') # [bad-open-mode]
|
||||
open(name='foo.bar', buffering=10, mode='rw') # [bad-open-mode]
|
||||
open(mode='rw', name='foo.bar') # [bad-open-mode]
|
||||
open('foo.bar', 'U+')
|
||||
open('foo.bar', 'rb+')
|
||||
open('foo.bar', 'Uw') # [bad-open-mode]
|
||||
open('foo.bar', 2) # [bad-open-mode]
|
||||
open('foo.bar', buffering=2)
|
||||
WRITE_MODE = 'w'
|
||||
open('foo.bar', 'U' + WRITE_MODE + 'z') # [bad-open-mode]
|
||||
open('foo.bar', 'br') # [bad-open-mode]
|
||||
open('foo.bar', 'wU') # [bad-open-mode]
|
||||
open('foo.bar', 'r+b')
|
||||
open('foo.bar', 'r+')
|
||||
open('foo.bar', 'w+')
|
||||
open('foo.bar', 'xb') # [bad-open-mode]
|
||||
open('foo.bar', 'rx') # [bad-open-mode]
|
||||
open('foo.bar', 'Ur')
|
||||
open('foo.bar', 'rU')
|
||||
open('foo.bar', 'rUb')
|
||||
open('foo.bar', 'rUb+')
|
||||
open('foo.bar', 'rU+b')
|
||||
open('foo.bar', 'r+Ub')
|
||||
open('foo.bar', '+rUb') # [bad-open-mode]
|
||||
open('foo.bar', 'ab+')
|
||||
open('foo.bar', 'a+b')
|
||||
open('foo.bar', 'aU') # [bad-open-mode]
|
||||
open('foo.bar', 'U+b')
|
||||
open('foo.bar', '+Ub')
|
||||
open('foo.bar', 'b+U')
|
||||
open('foo.bar', 'Urb+')
|
||||
open('foo.bar', 'Ur+b')
|
||||
open('foo.bar', 'Ubr') # [bad-open-mode]
|
||||
open('foo.bar', 'Ut') # [bad-open-mode]
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user