summaryrefslogtreecommitdiffstats
path: root/pylint_plugins.py
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2016-01-15 16:58:38 +0100
committerMartin Basti <mbasti@redhat.com>2016-02-11 11:06:39 +0100
commit2ce8921fe69ed58871f8e33e3899ad80dcc28c0e (patch)
treec91786320fca02c4ce473ef9e6197aa610cde0fc /pylint_plugins.py
parent5ac3a3cee534a16db86c541b9beff4939f03410e (diff)
downloadfreeipa-2ce8921fe69ed58871f8e33e3899ad80dcc28c0e.tar.gz
freeipa-2ce8921fe69ed58871f8e33e3899ad80dcc28c0e.tar.xz
freeipa-2ce8921fe69ed58871f8e33e3899ad80dcc28c0e.zip
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>
Diffstat (limited to 'pylint_plugins.py')
-rw-r--r--pylint_plugins.py210
1 files changed, 210 insertions, 0 deletions
diff --git a/pylint_plugins.py b/pylint_plugins.py
new file mode 100644
index 000000000..f64c426fd
--- /dev/null
+++ b/pylint_plugins.py
@@ -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']
+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)