mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
make lint: use config file and plugin for pylint
Our custom implementation of pylint checker is often broken by incompatible change on pylint side. Using supported solutions (config file, pylint plugins) should avoid this issue. The plugin adds missing (dynamic) member to classes in abstract syntax tree generated for pylint, instead of just ignoring missing members and all sub-members. This should improve pylint detection of typos and missing members in api. env and test config. make-lint python script has been removed, to run pylint execute 'make lint' https://fedorahosted.org/freeipa/ticket/5615 Reviewed-By: David Kupka <dkupka@redhat.com> Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
210
pylint_plugins.py
Normal file
210
pylint_plugins.py
Normal file
@@ -0,0 +1,210 @@
|
||||
#
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import copy
|
||||
import sys
|
||||
|
||||
from astroid import MANAGER
|
||||
from astroid import scoped_nodes
|
||||
|
||||
|
||||
def register(linter):
|
||||
pass
|
||||
|
||||
|
||||
def _warning_already_exists(cls, member):
|
||||
print(
|
||||
"WARNING: member '{member}' in '{cls}' already exists".format(
|
||||
cls="{}.{}".format(cls.root().name, cls.name), member=member),
|
||||
file=sys.stderr
|
||||
)
|
||||
|
||||
|
||||
def fake_class(name_or_class_obj, members=()):
|
||||
if isinstance(name_or_class_obj, scoped_nodes.Class):
|
||||
cl = name_or_class_obj
|
||||
else:
|
||||
cl = scoped_nodes.Class(name_or_class_obj, None)
|
||||
|
||||
for m in members:
|
||||
if isinstance(m, str):
|
||||
if m in cl.locals:
|
||||
_warning_already_exists(cl, m)
|
||||
else:
|
||||
cl.locals[m] = [scoped_nodes.Class(m, None)]
|
||||
elif isinstance(m, dict):
|
||||
for key, val in m.items():
|
||||
assert isinstance(key, str), "key must be string"
|
||||
if key in cl.locals:
|
||||
_warning_already_exists(cl, key)
|
||||
fake_class(cl.locals[key], val)
|
||||
else:
|
||||
cl.locals[key] = [fake_class(key, val)]
|
||||
else:
|
||||
# here can be used any astroid type
|
||||
if m.name in cl.locals:
|
||||
_warning_already_exists(cl, m.name)
|
||||
else:
|
||||
cl.locals[m.name] = [copy.copy(m)]
|
||||
return cl
|
||||
|
||||
|
||||
fake_backend = {'Backend': [
|
||||
{'wsgi_dispatch': ['mount']},
|
||||
]}
|
||||
|
||||
NAMESPACE_ATTRS = ['Command', 'Object', 'Method', fake_backend, 'Updater',
|
||||
'Advice']
|
||||
fake_api_env = {'env': [
|
||||
'host',
|
||||
'realm',
|
||||
'session_auth_duration',
|
||||
'session_duration_type',
|
||||
]}
|
||||
|
||||
# this is due ipaserver.rpcserver.KerberosSession where api is undefined
|
||||
fake_api = {'api': [fake_api_env] + NAMESPACE_ATTRS}
|
||||
|
||||
_LOGGING_ATTRS = ['debug', 'info', 'warning', 'error', 'exception',
|
||||
'critical', 'warn']
|
||||
LOGGING_ATTRS = [
|
||||
{'log': _LOGGING_ATTRS},
|
||||
] + _LOGGING_ATTRS
|
||||
|
||||
# 'class': ['generated', 'properties']
|
||||
ipa_class_members = {
|
||||
# Python standard library & 3rd party classes
|
||||
'socket._socketobject': ['sendall'],
|
||||
|
||||
# IPA classes
|
||||
'ipalib.base.NameSpace': [
|
||||
'add',
|
||||
'mod',
|
||||
'del',
|
||||
'show',
|
||||
'find'
|
||||
],
|
||||
'ipalib.cli.Collector': ['__options'],
|
||||
'ipalib.config.Env': [
|
||||
{'__d': ['get']},
|
||||
{'__done': ['add']},
|
||||
'xmlrpc_uri',
|
||||
'validate_api',
|
||||
'startup_traceback',
|
||||
'verbose'
|
||||
] + LOGGING_ATTRS,
|
||||
'ipalib.parameters.Param': [
|
||||
'cli_name',
|
||||
'cli_short_name',
|
||||
'label',
|
||||
'default',
|
||||
'doc',
|
||||
'required',
|
||||
'multivalue',
|
||||
'primary_key',
|
||||
'normalizer',
|
||||
'default_from',
|
||||
'autofill',
|
||||
'query',
|
||||
'attribute',
|
||||
'include',
|
||||
'exclude',
|
||||
'flags',
|
||||
'hint',
|
||||
'alwaysask',
|
||||
'sortorder',
|
||||
'csv',
|
||||
'option_group',
|
||||
],
|
||||
'ipalib.parameters.Bool': [
|
||||
'truths',
|
||||
'falsehoods'],
|
||||
'ipalib.parameters.Data': [
|
||||
'minlength',
|
||||
'maxlength',
|
||||
'length',
|
||||
'pattern',
|
||||
'pattern_errmsg',
|
||||
],
|
||||
'ipalib.parameters.Str': ['noextrawhitespace'],
|
||||
'ipalib.parameters.Password': ['confirm'],
|
||||
'ipalib.parameters.File': ['stdin_if_missing'],
|
||||
'ipalib.plugins.dns.DNSRecord': [
|
||||
'validatedns',
|
||||
'normalizedns',
|
||||
],
|
||||
'ipalib.parameters.Enum': ['values'],
|
||||
'ipalib.parameters.Number': [
|
||||
'minvalue',
|
||||
'maxvalue',
|
||||
],
|
||||
'ipalib.parameters.Decimal': [
|
||||
'precision',
|
||||
'exponential',
|
||||
'numberclass',
|
||||
],
|
||||
'ipalib.parameters.DNSNameParam': [
|
||||
'only_absolute',
|
||||
'only_relative',
|
||||
],
|
||||
'ipalib.plugable.API': [
|
||||
fake_api_env,
|
||||
] + NAMESPACE_ATTRS + LOGGING_ATTRS,
|
||||
'ipalib.plugable.Plugin': [
|
||||
'Object',
|
||||
'Method',
|
||||
'Updater',
|
||||
'Advice',
|
||||
] + LOGGING_ATTRS,
|
||||
'ipalib.session.AuthManager': LOGGING_ATTRS,
|
||||
'ipalib.session.SessionAuthManager': LOGGING_ATTRS,
|
||||
'ipalib.session.SessionManager': LOGGING_ATTRS,
|
||||
'ipaserver.install.ldapupdate.LDAPUpdate': LOGGING_ATTRS,
|
||||
'ipaserver.rpcserver.KerberosSession': [
|
||||
fake_api,
|
||||
] + LOGGING_ATTRS,
|
||||
'ipatests.test_integration.base.IntegrationTest': [
|
||||
'domain',
|
||||
{'master': [
|
||||
{'config': [
|
||||
{'dirman_password': dir(str)},
|
||||
{'admin_password': dir(str)},
|
||||
{'admin_name': dir(str)},
|
||||
{'dns_forwarder': dir(str)},
|
||||
{'test_dir': dir(str)},
|
||||
{'ad_admin_name': dir(str)},
|
||||
{'ad_admin_password': dir(str)},
|
||||
{'domain_level': dir(str)},
|
||||
]},
|
||||
{'domain': [
|
||||
{'realm': dir(str)},
|
||||
{'name': dir(str)},
|
||||
]},
|
||||
'hostname',
|
||||
'ip',
|
||||
'collect_log',
|
||||
{'run_command': [
|
||||
{'stdout_text': dir(str)},
|
||||
'stderr_text',
|
||||
'returncode',
|
||||
]},
|
||||
{'transport': ['put_file']},
|
||||
'put_file_contents',
|
||||
'get_file_contents',
|
||||
]},
|
||||
'replicas',
|
||||
'clients',
|
||||
'ad_domains',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def fix_ipa_classes(cls):
|
||||
class_name_with_module = "{}.{}".format(cls.root().name, cls.name)
|
||||
if class_name_with_module in ipa_class_members:
|
||||
fake_class(cls, ipa_class_members[class_name_with_module])
|
||||
|
||||
MANAGER.register_transform(scoped_nodes.Class, fix_ipa_classes)
|
||||
Reference in New Issue
Block a user