Run pylint on tests

Drop support for pylint < 1.0

Enable ignoring unknown attributes on modules (both nose and pytest
use advanced techniques, support for which only made it to pylint
recently)

Fix some bugs revealed by pylint

Do minor refactoring or add pylint:disable directives where the
linter complains.

Reviewed-By: Tomas Babej <tbabej@redhat.com>
This commit is contained in:
Petr Viktorin
2014-12-16 14:45:37 +01:00
committed by Tomas Babej
parent 10fe918acd
commit 61c4ecccc1
16 changed files with 77 additions and 66 deletions

View File

@@ -67,7 +67,7 @@ BuildRequires: python-netaddr
BuildRequires: python-kerberos >= 1.1-14 BuildRequires: python-kerberos >= 1.1-14
BuildRequires: python-rhsm BuildRequires: python-rhsm
BuildRequires: pyOpenSSL BuildRequires: pyOpenSSL
BuildRequires: pylint BuildRequires: pylint >= 1.0
BuildRequires: python-polib BuildRequires: python-polib
BuildRequires: libipa_hbac-python BuildRequires: libipa_hbac-python
BuildRequires: python-memcached BuildRequires: python-memcached

View File

@@ -678,7 +678,7 @@ def po_file_iterate(po_file, get_msgstr, get_msgstr_plural):
return 1 return 1
if not n_entries: if not n_entries:
print >> sys.stderr, "ERROR: no translations found in %s" % (po_filename) print >> sys.stderr, "ERROR: no translations found in %s" % (po_file)
return 1 return 1
if n_fail: if n_fail:

View File

@@ -17,6 +17,9 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# FIXME: Pylint errors
# pylint: disable=no-member
import os import os
import re import re
@@ -43,6 +46,10 @@ class BaseTestLegacyClient(object):
'/etc/nsswitch.conf', '/etc/nsswitch.conf',
paths.SSSD_CONF] paths.SSSD_CONF]
homedir_template = "/home/{domain}/{username}"
required_extra_roles = ()
optional_extra_roles = ()
# Actual test classes need to override these attributes to set the expected # Actual test classes need to override these attributes to set the expected
# values on the UID and GID results, since this varies with the usage of the # values on the UID and GID results, since this varies with the usage of the
# POSIX and non-POSIX ID ranges # POSIX and non-POSIX ID ranges
@@ -407,7 +414,6 @@ class BaseTestLegacyClientPosix(BaseTestLegacyClient,
testuser_gid_regex = '10047' testuser_gid_regex = '10047'
subdomain_testuser_uid_regex = '10142' subdomain_testuser_uid_regex = '10142'
subdomain_testuser_gid_regex = '10147' subdomain_testuser_gid_regex = '10147'
homedir_template = "/home/{domain}/{username}"
posix_trust = True posix_trust = True
def test_remove_trust_with_posix_attributes(self): def test_remove_trust_with_posix_attributes(self):
@@ -421,7 +427,6 @@ class BaseTestLegacyClientNonPosix(BaseTestLegacyClient,
testuser_gid_regex = '(?!10047)(\d+)' testuser_gid_regex = '(?!10047)(\d+)'
subdomain_testuser_uid_regex = '(?!10142)(\d+)' subdomain_testuser_uid_regex = '(?!10142)(\d+)'
subdomain_testuser_gid_regex = '(?!10147)(\d+)' subdomain_testuser_gid_regex = '(?!10147)(\d+)'
homedir_template = '/home/{domain}/{username}'
def test_remove_nonposix_trust(self): def test_remove_nonposix_trust(self):
pass pass

View File

@@ -129,6 +129,12 @@ class CheckConfig(object):
assert_deepequal(self.get_output_dict(), conf.to_dict()) assert_deepequal(self.get_output_dict(), conf.to_dict())
self.check_config(conf) self.check_config(conf)
# Settings to override:
extra_input_dict = {}
extra_input_env = {}
extra_output_dict = {}
extra_output_env = {}
class TestEmptyConfig(CheckConfig): class TestEmptyConfig(CheckConfig):
extra_input_dict = {} extra_input_dict = {}

View File

@@ -21,6 +21,10 @@
Test the `ipalib.backend` module. Test the `ipalib.backend` module.
""" """
# FIXME: Pylint errors
# pylint: disable=no-member
# pylint: disable=maybe-no-member
import threading import threading
from ipatests.util import ClassChecker, raises, create_test_api from ipatests.util import ClassChecker, raises, create_test_api
from ipatests.data import unicode_str from ipatests.data import unicode_str

View File

@@ -21,6 +21,9 @@
Test the `ipalib.errors` module. Test the `ipalib.errors` module.
""" """
# FIXME: Pylint errors
# pylint: disable=no-member
import re import re
import inspect import inspect

View File

@@ -21,8 +21,11 @@
Test the `ipalib.frontend` module. Test the `ipalib.frontend` module.
""" """
from ipatests.util import raises, getitem, no_set, no_del, read_only # FIXME: Pylint errors
from ipatests.util import check_TypeError, ClassChecker, create_test_api # pylint: disable=no-member
from ipatests.util import raises, read_only
from ipatests.util import ClassChecker, create_test_api
from ipatests.util import assert_equal from ipatests.util import assert_equal
from ipalib.constants import TYPE_ERROR from ipalib.constants import TYPE_ERROR
from ipalib.base import NameSpace from ipalib.base import NameSpace
@@ -444,7 +447,7 @@ class test_Command(ClassChecker):
o = my_cmd() o = my_cmd()
o.set_api(api) o.set_api(api)
o.finalize() o.finalize()
e = o(**kw) e = o(**kw) # pylint: disable=not-callable
assert type(e) is dict assert type(e) is dict
assert 'result' in e assert 'result' in e
assert 'option2' in e['result'] assert 'option2' in e['result']

View File

@@ -22,6 +22,9 @@
Test the `ipalib.parameters` module. Test the `ipalib.parameters` module.
""" """
# FIXME: Pylint errors
# pylint: disable=no-member
import datetime import datetime
import re import re
import sys import sys
@@ -219,12 +222,12 @@ class test_Param(ClassChecker):
# Test that ValueError is raised when a kwarg from a subclass # Test that ValueError is raised when a kwarg from a subclass
# conflicts with an attribute: # conflicts with an attribute:
class Subclass(self.cls): class Subclass1(self.cls):
kwargs = self.cls.kwargs + ( kwargs = self.cls.kwargs + (
('convert', callable, None), ('convert', callable, None),
) )
e = raises(ValueError, Subclass, name) e = raises(ValueError, Subclass1, name)
assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass" assert str(e) == "kwarg 'convert' conflicts with attribute on Subclass1"
# Test type validation of keyword arguments: # Test type validation of keyword arguments:
class Subclass(self.cls): class Subclass(self.cls):
@@ -593,6 +596,8 @@ class test_Param(ClassChecker):
type = unicode type = unicode
def __init__(self, name, **kw): def __init__(self, name, **kw):
# (Pylint complains because the superclass is unknowm)
# pylint: disable=bad-super-call, super-on-old-class
self._convert_scalar = PassThrough() self._convert_scalar = PassThrough()
super(Str, self).__init__(name, **kw) super(Str, self).__init__(name, **kw)

View File

@@ -21,6 +21,9 @@
Test the `ipalib.plugable` module. Test the `ipalib.plugable` module.
""" """
# FIXME: Pylint errors
# pylint: disable=no-member
import inspect import inspect
from ipatests.util import raises, no_set, no_del, read_only from ipatests.util import raises, no_set, no_del, read_only
from ipatests.util import getitem, setitem, delitem from ipatests.util import getitem, setitem, delitem
@@ -343,7 +346,7 @@ def test_Registrar():
orig1 = plugin1 orig1 = plugin1
class base1_extended(Base1): class base1_extended(Base1):
pass pass
class plugin1(base1_extended): class plugin1(base1_extended): # pylint: disable=function-redefined
pass pass
e = raises(errors.PluginOverrideError, r, plugin1) e = raises(errors.PluginOverrideError, r, plugin1)
assert e.base == 'Base1' assert e.base == 'Base1'

View File

@@ -128,6 +128,11 @@ class TestCIDict(object):
nose.tools.assert_equal(3, len(self.cidict)) nose.tools.assert_equal(3, len(self.cidict))
self.cidict.clear() self.cidict.clear()
nose.tools.assert_equal(0, len(self.cidict)) nose.tools.assert_equal(0, len(self.cidict))
assert self.cidict == {}
assert self.cidict.keys() == []
assert self.cidict.values() == []
assert self.cidict.items() == []
assert self.cidict._keys == {}
def test_copy(self): def test_copy(self):
copy = self.cidict.copy() copy = self.cidict.copy()
@@ -309,14 +314,6 @@ class TestCIDict(object):
assert sorted(dct.keys()) == sorted(['A', 'b', 'C']) assert sorted(dct.keys()) == sorted(['A', 'b', 'C'])
assert sorted(dct.values()) == [None] * 3 assert sorted(dct.values()) == [None] * 3
def test_clear(self):
self.cidict.clear()
assert self.cidict == {}
assert self.cidict.keys() == []
assert self.cidict.values() == []
assert self.cidict.items() == []
assert self.cidict._keys == {}
class TestTimeParser(object): class TestTimeParser(object):
def test_simple(self): def test_simple(self):

View File

@@ -20,6 +20,9 @@
Test the `pkcs10.py` module. Test the `pkcs10.py` module.
""" """
# FIXME: Pylint errors
# pylint: disable=no-member
import os import os
import sys import sys
import nose import nose

View File

@@ -45,6 +45,10 @@ class MockTextui(list):
class AutomountTest(XMLRPC_test): class AutomountTest(XMLRPC_test):
"""Provides common functionality for automount tests""" """Provides common functionality for automount tests"""
locname = u'testlocation'
tofiles_output = '' # To be overridden
def check_tofiles(self): def check_tofiles(self):
"""Check automountlocation_tofiles output against self.tofiles_output """Check automountlocation_tofiles output against self.tofiles_output
""" """
@@ -111,7 +115,6 @@ class test_automount(AutomountTest):
""" """
Test the `automount` plugin. Test the `automount` plugin.
""" """
locname = u'testlocation'
mapname = u'testmap' mapname = u'testmap'
keyname = u'testkey' keyname = u'testkey'
keyname_rename = u'testkey_rename' keyname_rename = u'testkey_rename'
@@ -320,7 +323,6 @@ class test_automount_direct(AutomountTest):
""" """
Test the `automount` plugin indirect map functionality. Test the `automount` plugin indirect map functionality.
""" """
locname = u'testlocation'
mapname = u'auto.direct2' mapname = u'auto.direct2'
keyname = u'/-' keyname = u'/-'
direct_kw = { 'key' : keyname } direct_kw = { 'key' : keyname }
@@ -386,7 +388,6 @@ class test_automount_indirect(AutomountTest):
""" """
Test the `automount` plugin indirect map functionality. Test the `automount` plugin indirect map functionality.
""" """
locname = u'testlocation'
mapname = u'auto.home' mapname = u'auto.home'
keyname = u'/home' keyname = u'/home'
parentmap = u'auto.master' parentmap = u'auto.master'
@@ -485,7 +486,6 @@ class test_automount_indirect_no_parent(AutomountTest):
""" """
Test the `automount` plugin Indirect map function. Test the `automount` plugin Indirect map function.
""" """
locname = u'testlocation'
mapname = u'auto.home' mapname = u'auto.home'
keyname = u'/home' keyname = u'/home'
mapname2 = u'auto.direct2' mapname2 = u'auto.direct2'

View File

@@ -153,7 +153,7 @@ def test_exc_callback_registration():
@callbacktest_base.register_exc_callback @callbacktest_base.register_exc_callback
def exc_callback(self, keys, options, exc, call_func, *args, **kwargs): def exc_callback_2(self, keys, options, exc, call_func, *args, **kwargs):
"""Callback on super class; doesn't affect the subclass""" """Callback on super class; doesn't affect the subclass"""
messages.append('Superclass registered callback') messages.append('Superclass registered callback')
raise exc raise exc

View File

@@ -29,7 +29,7 @@ from ipalib import api, errors, x509
from ipalib.util import normalize_zone from ipalib.util import normalize_zone
from ipapython.dn import DN from ipapython.dn import DN
from ipapython.dnsutil import DNSName from ipapython.dnsutil import DNSName
from nose.tools import raises, assert_raises from nose.tools import raises, assert_raises # pylint: disable=E0611
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, XMLRPC_test, from ipatests.test_xmlrpc.xmlrpc_test import (Declarative, XMLRPC_test,
fuzzy_uuid, fuzzy_digits, fuzzy_hash, fuzzy_date, fuzzy_issuer, fuzzy_uuid, fuzzy_digits, fuzzy_hash, fuzzy_date, fuzzy_issuer,

View File

@@ -430,7 +430,7 @@ class ClassChecker(object):
def __get_cls(self): def __get_cls(self):
if self.__cls is None: if self.__cls is None:
self.__cls = self._cls self.__cls = self._cls # pylint: disable=E1101
assert inspect.isclass(self.__cls) assert inspect.isclass(self.__cls)
return self.__cls return self.__cls
cls = property(__get_cls) cls = property(__get_cls)
@@ -455,19 +455,6 @@ class ClassChecker(object):
context.__dict__.clear() context.__dict__.clear()
def check_TypeError(value, type_, name, callback, *args, **kw):
"""
Tests a standard TypeError raised with `errors.raise_TypeError`.
"""
e = raises(TypeError, callback, *args, **kw)
assert e.value is value
assert e.type is type_
assert e.name == name
assert type(e.name) is str
assert str(e) == ipalib.errors.TYPE_ERROR % (name, type_, value)
return e
def get_api(**kw): def get_api(**kw):
""" """
Returns (api, home) tuple. Returns (api, home) tuple.
@@ -503,7 +490,7 @@ class PluginTester(object):
def __get_plugin(self): def __get_plugin(self):
if self.__plugin is None: if self.__plugin is None:
self.__plugin = self._plugin self.__plugin = self._plugin # pylint: disable=E1101
assert issubclass(self.__plugin, Plugin) assert issubclass(self.__plugin, Plugin)
return self.__plugin return self.__plugin
plugin = property(__get_plugin) plugin = property(__get_plugin)

View File

@@ -29,24 +29,16 @@ try:
from pylint import checkers from pylint import checkers
from pylint.lint import PyLinter from pylint.lint import PyLinter
from pylint.checkers.typecheck import TypeChecker from pylint.checkers.typecheck import TypeChecker
try: from astroid import Class, Instance, Module, InferenceError
# Pylint 1.0 from pylint.reporters.text import TextReporter
from astroid import Class, Instance, InferenceError
from pylint.reporters.text import TextReporter
have_pylint_1_0 = True
except ImportError:
# Older Pylint
from logilab.astng import Class, Instance, InferenceError
from pylint.reporters.text import ParseableTextReporter
have_pylint_1_0 = False
except ImportError: except ImportError:
print >> sys.stderr, "To use {0}, please install pylint.".format(sys.argv[0]) print >> sys.stderr, "To use {0}, please install pylint.".format(sys.argv[0])
sys.exit(32) sys.exit(32)
# File names to ignore when searching for python source files # File names to ignore when searching for python source files
IGNORE_FILES = ('.*', '*~', '*.in', '*.pyc', '*.pyo') IGNORE_FILES = ('.*', '*~', '*.in', '*.pyc', '*.pyo')
IGNORE_PATHS = ('build', 'rpmbuild', 'dist', 'install/po/test_i18n.py', IGNORE_PATHS = (
'lite-server.py', 'make-lint', 'make-test', 'ipatests') 'build', 'rpmbuild', 'dist', 'install/po/test_i18n.py', 'lite-server.py')
class IPATypeChecker(TypeChecker): class IPATypeChecker(TypeChecker):
NAMESPACE_ATTRS = ['Command', 'Object', 'Method', 'Backend', 'Updater', NAMESPACE_ATTRS = ['Command', 'Object', 'Method', 'Backend', 'Updater',
@@ -54,7 +46,7 @@ class IPATypeChecker(TypeChecker):
LOGGING_ATTRS = ['log', 'debug', 'info', 'warning', 'error', 'exception', LOGGING_ATTRS = ['log', 'debug', 'info', 'warning', 'error', 'exception',
'critical'] 'critical']
# 'class': ['generated', 'properties'] # 'class or module': ['generated', 'properties']
ignore = { ignore = {
# Python standard library & 3rd party classes # Python standard library & 3rd party classes
'krbV.Principal': ['name'], 'krbV.Principal': ['name'],
@@ -65,6 +57,9 @@ class IPATypeChecker(TypeChecker):
'urlparse.ResultMixin': ['scheme', 'netloc', 'path', 'query', 'urlparse.ResultMixin': ['scheme', 'netloc', 'path', 'query',
'fragment', 'username', 'password', 'hostname', 'port'], 'fragment', 'username', 'password', 'hostname', 'port'],
'urlparse.ParseResult': ['params'], 'urlparse.ParseResult': ['params'],
'pytest': ['fixture', 'raises', 'skip', 'yield_fixture', 'mark'],
'nose.tools': ['assert_equal', 'assert_raises'],
'datetime.tzinfo': ['houroffset', 'minoffset', 'utcoffset', 'dst'],
# IPA classes # IPA classes
'ipalib.base.NameSpace': ['add', 'mod', 'del', 'show', 'find'], 'ipalib.base.NameSpace': ['add', 'mod', 'del', 'show', 'find'],
@@ -96,6 +91,8 @@ class IPATypeChecker(TypeChecker):
'ipalib.session.SessionManager': LOGGING_ATTRS, 'ipalib.session.SessionManager': LOGGING_ATTRS,
'ipaserver.install.ldapupdate.LDAPUpdate': LOGGING_ATTRS, 'ipaserver.install.ldapupdate.LDAPUpdate': LOGGING_ATTRS,
'ipaserver.rpcserver.KerberosSession': ['api'] + LOGGING_ATTRS, 'ipaserver.rpcserver.KerberosSession': ['api'] + LOGGING_ATTRS,
'ipatests.test_integration.base.IntegrationTest': [
'domain', 'master', 'replicas', 'clients', 'ad_domains']
} }
def _related_classes(self, klass): def _related_classes(self, klass):
@@ -121,14 +118,16 @@ class IPATypeChecker(TypeChecker):
inferred = [] inferred = []
for owner in inferred: for owner in inferred:
if not isinstance(owner, Class) and type(owner) is not Instance: if isinstance(owner, Module):
continue if node.attrname in self.ignore.get(owner.name, ()):
ignored = self._find_ignored_attrs(owner)
for pattern in ignored:
if fnmatchcase(node.attrname, pattern):
return return
elif isinstance(owner, Class) or type(owner) is Instance:
ignored = self._find_ignored_attrs(owner)
for pattern in ignored:
if fnmatchcase(node.attrname, pattern):
return
super(IPATypeChecker, self).visit_getattr(node) super(IPATypeChecker, self).visit_getattr(node)
class IPALinter(PyLinter): class IPALinter(PyLinter):
@@ -231,13 +230,9 @@ def main():
if options.errors_only: if options.errors_only:
linter.disable_noerror_messages() linter.disable_noerror_messages()
linter.enable('F') linter.enable('F')
if have_pylint_1_0: linter.set_reporter(TextReporter())
linter.set_reporter(TextReporter()) linter.set_option('msg-template',
linter.set_option('msg-template', '{path}:{line}: [{msg_id}({symbol}), {obj}] {msg})')
'{path}:{line}: [{msg_id}({symbol}), {obj}] {msg})')
else:
linter.set_reporter(ParseableTextReporter())
linter.set_option('include-ids', True)
linter.set_option('reports', False) linter.set_option('reports', False)
linter.set_option('persistent', False) linter.set_option('persistent', False)