summaryrefslogtreecommitdiffstats
path: root/tools/pylint/plugins/cim_provider_checker.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pylint/plugins/cim_provider_checker.py')
-rw-r--r--tools/pylint/plugins/cim_provider_checker.py149
1 files changed, 149 insertions, 0 deletions
diff --git a/tools/pylint/plugins/cim_provider_checker.py b/tools/pylint/plugins/cim_provider_checker.py
new file mode 100644
index 0000000..253cb9d
--- /dev/null
+++ b/tools/pylint/plugins/cim_provider_checker.py
@@ -0,0 +1,149 @@
+# -*- encoding: utf-8 -*-
+# Software Management Providers
+#
+# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Authors: Michal Minar <miminar@redhat.com>
+"""
+Pylint checker for CIM provider modules and classes.
+"""
+
+import re
+from logilab.astng import node_classes # pylint: disable=W0403
+from logilab.astng import scoped_nodes # pylint: disable=W0403
+from pylint.interfaces import IASTNGChecker
+from pylint.checkers import BaseChecker
+
+_RE_PROVIDER_CLASS_NAME = re.compile(
+ r'^(?P<prefix>[A-Z][a-zA-Z0-9]*)_(?P<name>[A-Z][a-zA-Z]*)$')
+_RE_PROVIDER_MODULE_NAME = re.compile(
+ r'^((?P<parent>.*)\.)?(?P<basename>(?P<prefix>[A-Z][a-zA-Z0-9]*)'
+ r'_(?P<name>[A-Z][a-zA-Z]*))$')
+_RE_COMMON_MODULE_NAME = re.compile(
+ r'^([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)$')
+
+def supress_cim_provider_messages(linter, node):
+ """
+ Supress some warnings for CIMProvider2 subclass.
+ @param node is a subclass of CIMProvider2
+ """
+ assert isinstance(node, scoped_nodes.Class)
+ if ( 'Values' in node
+ and isinstance(node['Values'], scoped_nodes.Class)):
+ linter.disable('R0903', scope='module', line=node['Values'].lineno)
+ linter.disable('C0111', scope='module', line=node['Values'].lineno)
+ for child in node['Values'].get_children():
+ if not isinstance(child, scoped_nodes.Class):
+ continue
+ linter.disable('R0903', scope='module', line=child.lineno)
+ linter.disable('C0111', scope='module', line=child.lineno)
+
+class CIMProviderChecker(BaseChecker):
+ """
+ Checks for compliance to naming conventions for python cim providers.
+ """
+
+ __implements__ = IASTNGChecker
+
+ name = 'cim_provider'
+ msgs = {
+ 'C9904': ('Invalid provider class name %s',
+ "Class name representing cim provider should be in inform "
+ "<prefix>_<name>. Where <prefix> and <name> should be both "
+ "written in CamelCase."),
+ 'C9905': ('Invalid provider module name %s',
+ "Module containing cim provider(s) should be named as "
+ "<prefix>_<name>. Where both <prefix> and <name> are "
+ "CamelCased strings."),
+ 'C9906': ('Prefixes of module and class does not match: %s != %s',
+ "Module prefix has to match provider class prefix."),
+ 'E9907': ("Missing get_providers function in module %s",
+ "Provider module must contain get_providers function."),
+ 'W9908': ("get_providers in module %s is not a function",
+ "get_providers should be a callable function."),
+ 'W9909': ("Missing provider name \"%s\" in providers dictionary.",
+ "Function get_providers returns providers association"
+ " dictionary, that must include all module's provider"
+ " classes."),
+ 'C9910': ("Prefix different from LMI: %s",
+ "All OpenLMI CIM classes have LMI_ ORGID prefix."),
+ 'C9911': ("Invalid module name: %s",
+ "All modules, that does not declare cim provider class"
+ " should be named according to this regexp:"
+ " '^(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$'."),
+ }
+
+ # this is important so that your checker is executed before others
+ priority = -2
+
+ def visit_class(self, node):
+ """
+ Check every class, which inherits from
+ pywbem.cim_provider2.CIMProvider2.
+ """
+ if "CIMProvider2" in [a.name for a in node.ancestors()]:
+ clsm = _RE_PROVIDER_CLASS_NAME.match(node.name)
+ if not clsm:
+ self.add_message('C9904', node=node, args=node.name)
+ parent = node.parent
+ while not isinstance(parent, scoped_nodes.Module):
+ parent = parent.parent
+ modm = _RE_PROVIDER_MODULE_NAME.match(parent.name)
+ if not modm:
+ self.add_message('C9905', node=node, args=parent.name)
+ if not clsm:
+ return
+ if clsm.group('prefix') != modm.group('prefix'):
+ self.add_message('C9906', node=node,
+ args=(modm.group('prefix'), clsm.group('prefix')))
+ if clsm.group('prefix') != 'LMI':
+ self.add_message('C9910', node=node, args=clsm.group('prefix'))
+ if not 'get_providers' in parent.keys():
+ self.add_message('E9907', node=parent, args=parent.name)
+ return
+ getprovs = parent['get_providers']
+ if not isinstance(getprovs, scoped_nodes.Function):
+ self.add_message('W9908', node=getprovs, args=parent.name)
+ ret = getprovs.last_child()
+ if not isinstance(ret, node_classes.Return):
+ return
+ dictionary = ret.get_children().next()
+ if not isinstance(dictionary, node_classes.Dict):
+ return
+ if not node.name in [i[0].value for i in dictionary.items]:
+ self.add_message('W9909', node=getprovs, args=node.name)
+ supress_cim_provider_messages(self.linter, node)
+
+ def visit_module(self, node):
+ """
+ Check for invalid module name.
+ """
+ modm = _RE_PROVIDER_MODULE_NAME.match(node.name)
+ if modm:
+ if not _RE_COMMON_MODULE_NAME.match(node.name):
+ for child in node.get_children():
+ if ( isinstance(child, scoped_nodes.Class)
+ and 'CIMProvider2' in [
+ a.name for a in child.ancestors()]):
+ break
+ else:
+ self.add_message('C9911', node=node, args=node.name)
+
+def register(linter):
+ """required method to auto register our checker"""
+ linter.register_checker(CIMProviderChecker(linter))
+