[PATCH 2/5] Remove our extra pylint checkers.

Chris Lumens clumens at redhat.com
Thu Jun 4 17:16:01 UTC 2015


These are moving off into their own package that can be shared amongst our
various projects, so there's no need to keep them in anaconda.
---
 tests/pylint/eintr.py              |  65 ----------
 tests/pylint/environ.py            | 107 ----------------
 tests/pylint/intl.py               | 148 ----------------------
 tests/pylint/markup.py             | 198 -----------------------------
 tests/pylint/pointless-override.py | 252 -------------------------------------
 5 files changed, 770 deletions(-)
 delete mode 100644 tests/pylint/eintr.py
 delete mode 100644 tests/pylint/environ.py
 delete mode 100644 tests/pylint/intl.py
 delete mode 100644 tests/pylint/markup.py
 delete mode 100644 tests/pylint/pointless-override.py

diff --git a/tests/pylint/eintr.py b/tests/pylint/eintr.py
deleted file mode 100644
index 8fae96c..0000000
--- a/tests/pylint/eintr.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Interuptible system call pylint module
-#
-# Copyright (C) 2014  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): David Shea <dhsea at redhat.com>
-#
-
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages, safe_infer
-from pylint.interfaces import IAstroidChecker
-
-import os
-
-# These are all of the system calls exposed through the os module that are
-# documented in SUSv4 as *may* set EINTR. Some of them probably don't in Linux,
-# but who knows.  lchmod, wait3 and wait4 aren't documented much anywhere but
-# are here just in case.
-interruptible = ("tmpfile", "close", "dup2", "fchmod", "fchown", "fstatvfs",
-                 "fsync", "ftruncate", "open", "read", "write", "fchdir",
-                 "chmod", "chown", "lchmod", "lchown", "statvfs", "wait",
-                 "waitpid", "wait3", "wait4")
-
-class EintrChecker(BaseChecker):
-    __implements__ = (IAstroidChecker,)
-    name = "retry-interruptible"
-    msgs = {"W9930" : ("Found interruptible system call %s",
-                       "interruptible-system-call",
-                       "A system call that may raise EINTR is not wrapped in eintr_retry_call"),
-           }
-
-    @check_messages("interruptible-system-call")
-    def visit_callfunc(self, node):
-        if not isinstance(node, astroid.CallFunc):
-            return
-
-        # Skip anything not a function or not in os.  os redirects most of its
-        # content to an OS-dependent module, named in os.name, so check that
-        # one too.
-        function_node = safe_infer(node.func)
-        if not isinstance(function_node, astroid.Function) or \
-                function_node.root().name not in ("os", os.name):
-            return
-
-        if function_node.name in interruptible:
-            self.add_message("interruptible-system-call", node=node, args=function_node.name)
-
-def register(linter):
-    """required method to auto register this checker """
-    linter.register_checker(EintrChecker(linter))
diff --git a/tests/pylint/environ.py b/tests/pylint/environ.py
deleted file mode 100644
index ffbed49..0000000
--- a/tests/pylint/environ.py
+++ /dev/null
@@ -1,107 +0,0 @@
-# setenv pylint module
-#
-# Copyright (C) 2015  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): David Shea <dshea at redhat.com>
-#
-
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages, safe_infer
-from pylint.interfaces import IAstroidChecker
-
-import os
-
-class EnvironChecker(BaseChecker):
-    __implements__ = (IAstroidChecker,)
-    name = "environ"
-    msgs = {"W9940" : ("Found potentially unsafe modification of environment",
-                       "environment-modify",
-                       "Potentially thread-unsafe modification of environment")}
-
-    def _is_environ(self, node):
-        # Guess whether a node being modified is os.environ
-
-        if isinstance(node, astroid.Getattr):
-            if node.attrname == "environ":
-                expr_node = safe_infer(node.expr)
-                if isinstance(expr_node, astroid.Module) and expr_node.name == "os":
-                    return True
-
-        # If the node being modified is just "environ" assume that it's os.environ
-        if isinstance(node, astroid.Name):
-            if node.name == "environ":
-                return True
-
-        return False
-
-    @check_messages("environment-modify")
-    def visit_assign(self, node):
-        if not isinstance(node, astroid.Assign):
-            return
-
-        # Look for os.environ["WHATEVER"] = something
-        for target in node.targets:
-            if not isinstance(target, astroid.Subscript):
-                continue
-
-            if self._is_environ(target.value):
-                self.add_message("environment-modify", node=node)
-
-    @check_messages("environment-modify")
-    def visit_callfunc(self, node):
-        # Check both for uses of os.putenv and os.setenv and modifying calls
-        # to the os.environ object, such as os.environ.update
-
-        if not isinstance(node, astroid.CallFunc):
-            return
-
-        function_node = safe_infer(node.func)
-        if not isinstance(function_node, (astroid.Function, astroid.BoundMethod)):
-            return
-
-        # If the function is from the os or posix modules, look for calls that
-        # modify the environment
-        if function_node.root().name in ("os", os.name) and \
-                function_node.name in ("putenv", "unsetenv"):
-            self.add_message("environment-modify", node=node)
-
-        # Look for methods bound to the environ dict
-        if isinstance(function_node, astroid.BoundMethod) and \
-                isinstance(function_node.bound, astroid.Dict) and \
-                function_node.bound.root().name in ("os", os.name) and \
-                function_node.bound.name == "environ" and \
-                function_node.name in ("clear", "pop", "popitem", "setdefault", "update"):
-            self.add_message("environment-modify", node=node)
-
-    @check_messages("environment-modify")
-    def visit_delete(self, node):
-        if not isinstance(node, astroid.Delete):
-            return
-
-        # Look for del os.environ["WHATEVER"]
-        for target in node.targets:
-            if not isinstance(target, astroid.Subscript):
-                continue
-
-            if self._is_environ(target.value):
-                self.add_message("environment-modify", node=node)
-
-def register(linter):
-    """required method to auto register this checker """
-    linter.register_checker(EnvironChecker(linter))
diff --git a/tests/pylint/intl.py b/tests/pylint/intl.py
deleted file mode 100644
index ac27bb6..0000000
--- a/tests/pylint/intl.py
+++ /dev/null
@@ -1,148 +0,0 @@
-# I18N-related pylint module
-#
-# Copyright (C) 2013  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): Chris Lumens <clumens at redhat.com>
-#
-
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.strings import StringFormatChecker
-from pylint.checkers.logging import LoggingChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker
-
-from copy import copy
-
-translationMethods = frozenset(["_", "N_", "P_", "C_", "CN_", "CP_"])
-
-# Returns a list of the message strings for a given translation method call
-def _get_message_strings(node):
-    msgstrs = []
-
-    if node.func.name in ("_", "N_") and len(node.args) >= 1:
-        if isinstance(node.args[0], astroid.Const):
-            msgstrs.append(node.args[0].value)
-    elif node.func.name in ("C_", "CN_") and len(node.args) >= 2:
-        if isinstance(node.args[1], astroid.Const):
-            msgstrs.append(node.args[1].value)
-    elif node.func.name == "P_" and len(node.args) >= 2:
-        if isinstance(node.args[0], astroid.Const):
-            msgstrs.append(node.args[0].value)
-        if isinstance(node.args[1], astroid.Const):
-            msgstrs.append(node.args[1].value)
-    elif node.func.name == "CP_" and len(node.args) >= 3:
-        if isinstance(node.args[1], astroid.Const):
-            msgstrs.append(node.args[1].value)
-        if isinstance(node.args[2], astroid.Const):
-            msgstrs.append(node.args[2].value)
-
-    return msgstrs
-
-class IntlChecker(BaseChecker):
-    __implements__ = (IAstroidChecker, )
-    name = "internationalization"
-    msgs = {"W9901": ("Found % in a call to a _() method",
-                      "found-percent-in-_",
-                      "% in a call to one of the _() methods results in incorrect translations"),
-            "W9902": ("Found _ call at module/class level",
-                      "found-_-in-module-class",
-                      "Calling _ at the module or class level results in translations to the wrong language")
-           }
-
-    @check_messages("found-percent-in-_")
-    def visit_binop(self, node):
-        if node.op != "%":
-            return
-
-        curr = node
-        while curr.parent:
-            if isinstance(curr.parent, astroid.CallFunc) and getattr(curr.parent.func, "name", "") in translationMethods:
-                self.add_message("W9901", node=node)
-                break
-
-            curr = curr.parent
-
-    @check_messages("found-_-in-module-class")
-    def visit_callfunc(self, node):
-        # The first test skips internal functions like getattr.
-        if isinstance(node.func, astroid.Name) and node.func.name == "_":
-            if isinstance(node.scope(), astroid.Module) or isinstance(node.scope(), astroid.Class):
-                self.add_message("W9902", node=node)
-
-# Extend LoggingChecker to check translated logging strings
-class IntlLoggingChecker(LoggingChecker):
-    __implements__ = (IAstroidChecker,)
-
-    name = 'intl-logging'
-    msgs = {'W9903': ("Fake message for translated E/W120* checks",
-                      "translated-log",
-                      "This message is not emitted itself, but can be used to control the display of \
-                       logging format messages extended for translated strings")
-           }
-
-    options = ()
-
-    @check_messages('translated-log')
-    def visit_callfunc(self, node):
-        if len(node.args) >= 1 and isinstance(node.args[0], astroid.CallFunc) and \
-                getattr(node.args[0].func, "name", "") in translationMethods:
-            for formatstr in _get_message_strings(node.args[0]):
-                # Both the node and the args need to be copied so we don't replace args
-                # on the original node.
-                copynode = copy(node)
-                copyargs = copy(node.args)
-                copyargs[0] = astroid.Const(formatstr)
-                copynode.args = copyargs
-                LoggingChecker.visit_callfunc(self, copynode)
-
-    def __init__(self, *args, **kwargs):
-        LoggingChecker.__init__(self, *args, **kwargs)
-
-        # Just set logging_modules to 'logging', instead of trying to take a parameter
-        # like LoggingChecker
-        self.config.logging_modules = ('logging',)
-
-# Extend StringFormatChecker to check translated format strings
-class IntlStringFormatChecker(StringFormatChecker):
-    __implements__ = (IAstroidChecker,)
-
-    name = 'intl-string'
-    msgs = {'W9904': ("Fake message for translated E/W130* checks",
-                      "translated-format",
-                      "This message is not emitted itself, but can be used to control the display of \
-                       string format messages extended for translated strings")
-           }
-
-    @check_messages('translated-format')
-    def visit_binop(self, node):
-        if node.op != '%':
-            return
-
-        if isinstance(node.left, astroid.CallFunc) and getattr(node.left.func, "name", "") in translationMethods:
-            for formatstr in _get_message_strings(node.left):
-                # Create a copy of the node with just the message string as the format
-                copynode = copy(node)
-                copynode.left = astroid.Const(formatstr)
-                StringFormatChecker.visit_binop(self, copynode)
-
-def register(linter):
-    """required method to auto register this checker """
-    linter.register_checker(IntlChecker(linter))
-    linter.register_checker(IntlLoggingChecker(linter))
-    linter.register_checker(IntlStringFormatChecker(linter))
diff --git a/tests/pylint/markup.py b/tests/pylint/markup.py
deleted file mode 100644
index 7a93880..0000000
--- a/tests/pylint/markup.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# Pango markup pylint module
-#
-# Copyright (C) 2014  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): David Shea <dhsea at redhat.com>
-#
-
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker
-
-import sys
-import os
-
-import xml.etree.ElementTree as ET
-
-# markup_necessary not used yet
-from pangocheck import markup_nodes, is_markup, markup_match #, markup_necessary
-
-markupMethods = ["set_markup"]
-escapeMethods = ["escape_markup"]
-
-# Used for checking translations
-podicts = None
-
-i18n_funcs = ["_", "N_", "P_", "C_", "CN_", "CP_"]
-i18n_ctxt_funcs = ["C_", "CN_", "CP_"]
-
-class MarkupChecker(BaseChecker):
-    __implements__ = (IAstroidChecker,)
-    name = "pango-markup"
-    msgs = {"W9920" : ("Found invalid pango markup",
-                       "invalid-markup",
-                       "Pango markup could not be parsed"),
-            "W9921" : ("Found pango markup with invalid element %s",
-                       "invalid-markup-element",
-                       "Pango markup contains invalid elements"),
-            "W9922" : ("Found % in markup with unescaped parameters",
-                       "unescaped-markup",
-                       "Parameters passed to % in markup not escaped"),
-            "W9923" : ("Found invalid pango markup in %s translation",
-                       "invalid-translated-markup",
-                       "Translated Pango markup could not be parsed"),
-            "W9924" : ("Found pango markup with invalid element %s in %s translation",
-                       "invalid-translated-markup-element",
-                       "Translated pango markup contains invalid elements"),
-            "W9925" : ("Found mis-translated pango markup for language %s",
-                       "invalid-pango-translation",
-                       "The elements or attributes do not match between a pango markup string and its translation"),
-            "W9926" : ("Found unnecessary pango markup",
-                       "unnecessary-markup",
-                       "Pango markup could be expressed as attribute list"),
-           }
-
-    options = (('translate-markup',
-                {'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
-                 'help' : "Check translations of markup strings"
-                }),
-              )
-
-    # Check a parsed markup string for invalid tags
-    def _validate_pango_markup(self, node, root, lang=None):
-        if root.tag not in markup_nodes:
-            if lang:
-                self.add_message("W9924", node=node, args=(root.tag, lang))
-            else:
-                self.add_message("W9921", node=node, args=(root.tag,))
-        else:
-            for child in root:
-                self._validate_pango_markup(node, child)
-
-    # Attempt to parse a markup string as XML
-    def _validate_pango_markup_string(self, node, string, lang=None):
-        try:
-            # QUIS CUSTODIET IPSOS CUSTODES
-            # pylint: disable=unescaped-markup
-            tree = ET.fromstring("<markup>%s</markup>" % string)
-
-            # Check if the markup is necessary
-            # TODO: Turn this on after it's possible to actually do
-            # anything about it. See https://bugzilla.gnome.org/show_bug.cgi?id=725681
-            #if not markup_necessary(tree):
-            #    self.add_message("W9926", node=node)
-        except ET.ParseError:
-            if lang:
-                self.add_message("W9923", node=node, args=(lang,))
-            else:
-                self.add_message("W9920", node=node)
-        else:
-            # Check that all of the elements are valid for pango
-            self._validate_pango_markup(node, tree)
-
-    def __init__(self, linter=None):
-        BaseChecker.__init__(self, linter)
-
-    @check_messages("invalid-markup", "invalid-markup-element", "unescaped-markup", "invalid-translated-markup", "invalid-translated-markup-element", "invalid-pango-translation", "unnecessary-markup")
-    def visit_const(self, node):
-        if not isinstance(node.value, (bytes, str)):
-            return
-
-        if not is_markup(node.value):
-            return
-
-        self._validate_pango_markup_string(node, node.value)
-
-        # Check translated versions of the string if requested
-        if self.config.translate_markup:
-            global podicts
-
-            # Check if this is a translatable string
-            curr = node
-            i18nFunc = None
-            while curr.parent:
-                if isinstance(curr.parent, astroid.CallFunc) and \
-                        getattr(curr.parent.func, "name", "") in i18n_funcs:
-                    i18nFunc = curr.parent
-                    break
-                curr = curr.parent
-
-            if i18nFunc:
-                # If not done already, import polib and read the translations
-                if not podicts:
-                    try:
-                        from translatepo import translate_all
-                    except ImportError:
-                        print("Unable to load po translation module")
-                        sys.exit(99)
-                    else:
-                        podicts = translate_all(os.path.join(os.environ.get('top_srcdir', '.'), 'po'))
-
-                if i18nFunc.func.name in i18n_ctxt_funcs:
-                    msgctxt = i18nFunc.args[0].value
-                else:
-                    msgctxt = None
-
-                # Loop over all translations for the string
-                for podict in podicts.values():
-                    try:
-                        node_values = podict.get(node.value, msgctxt)
-                    except KeyError:
-                        continue
-
-                    for value in node_values:
-                        self._validate_pango_markup_string(node, value, podict.metadata['Language'])
-
-                        # Check that the markup matches, roughly
-                        if not markup_match(node.value, value):
-                            self.add_message("W9925", node=node, args=(podict.metadata['Language'],))
-
-        # Check if this the left side of a % operation
-        curr = node
-        formatOp = None
-        while curr.parent:
-            if isinstance(curr.parent, astroid.BinOp) and curr.parent.op == "%" and \
-                    curr.parent.left == curr:
-                formatOp = curr.parent
-                break
-            curr = curr.parent
-
-        # Check whether the right side of the % operation is escaped
-        if formatOp:
-            if isinstance(formatOp.right, astroid.CallFunc):
-                if getattr(formatOp.right.func, "name", "") not in escapeMethods:
-                    self.add_message("W9922", node=formatOp.right)
-            # If a tuple, each item in the tuple must be escaped
-            elif isinstance(formatOp.right, astroid.Tuple):
-                for elt in formatOp.right.elts:
-                    if not isinstance(elt, astroid.CallFunc) or\
-                            getattr(elt.func, "name", "") not in escapeMethods:
-                        self.add_message("W9922", node=elt)
-            # If a dictionary, each value must be escaped
-            elif isinstance(formatOp.right, astroid.Dict):
-                for item in formatOp.right.items:
-                    if not isinstance(item[1], astroid.CallFunc) or\
-                            getattr(item[1].func, "name", "") not in escapeMethods:
-                        self.add_message("W9922", node=item[1])
-            else:
-                self.add_message("W9922", node=formatOp)
-
-def register(linter):
-    """required method to auto register this checker """
-    linter.register_checker(MarkupChecker(linter))
diff --git a/tests/pylint/pointless-override.py b/tests/pylint/pointless-override.py
deleted file mode 100644
index d10ba42..0000000
--- a/tests/pylint/pointless-override.py
+++ /dev/null
@@ -1,252 +0,0 @@
-# Pylint checker for pointless class attributes overrides.
-#
-# Copyright (C) 2014  Red Hat, Inc.
-#
-# This copyrighted material is made available to anyone wishing to use,
-# modify, copy, or redistribute it subject to the terms and conditions of
-# the GNU General Public License v.2, or (at your option) any later version.
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY expressed or implied, including the implied warranties of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
-# Public License for more details.  You should have received a copy of the
-# GNU General Public License along with this program; if not, write to the
-# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
-# source code or documentation are not subject to the GNU General Public
-# License and may only be used or replicated with the express permission of
-# Red Hat, Inc.
-#
-# Red Hat Author(s): Anne Mulhern <amulhern at redhat.com>
-#
-
-import abc
-
-from six import add_metaclass
-
-import astroid
-
-from pylint.checkers import BaseChecker
-from pylint.checkers.utils import check_messages
-from pylint.interfaces import IAstroidChecker
-
- at add_metaclass(abc.ABCMeta)
-class PointlessData(object):
-
-    _DEF_CLASS = abc.abstractproperty(doc="Class of interesting definitions.")
-    message_id = abc.abstractproperty(doc="Pylint message identifier.")
-
-    @classmethod
-    @abc.abstractmethod
-    def _retain_node(cls, node, restrict=True):
-        """ Determines whether to retain a node for the analysis.
-
-            :param node: an AST node
-            :type node: astroid.Class
-            :param restrict bool: True if results returned should be restricted
-            :returns: True if the node should be kept, otherwise False
-            :rtype: bool
-
-            Restricted nodes are candidates for being marked as overridden.
-            Only restricted nodes are put into the initial pool of candidates.
-        """
-        raise NotImplementedError()
-
-    @staticmethod
-    @abc.abstractmethod
-    def _extract_value(node):
-        """ Return the node that contains the assignment's value.
-
-            :param node: an AST node
-            :type node: astroid.Class
-            :returns: the node corresponding to the value
-            :rtype: bool
-        """
-        raise NotImplementedError()
-
-    @staticmethod
-    @abc.abstractmethod
-    def _extract_targets(node):
-        """ Generates the names being assigned to.
-
-            :param node: an AST node
-            :type node: astroid.Class
-            :returns: a list of assignment target names
-            :rtype: generator of str
-        """
-        raise NotImplementedError()
-
-    @classmethod
-    def get_data(cls, node, restrict=True):
-        """ Find relevant nodes for this analysis.
-
-            :param node: an AST node
-            :type node: astroid.Class
-            :param restrict bool: True if results returned should be restricted
-
-            :rtype: generator of astroid.Class
-            :returns: a generator of interesting nodes.
-
-            Note that all nodes returned are guaranteed to be instances of
-            some class in self._DEF_CLASS.
-        """
-        nodes = (n for n in node.body if isinstance(n, cls._DEF_CLASS))
-        for n in nodes:
-            if cls._retain_node(n, restrict):
-                for name in cls._extract_targets(n):
-                    yield (name, cls._extract_value(n))
-
-    @classmethod
-    @abc.abstractmethod
-    def check_equal(cls, node, other):
-        """ Check whether the two nodes are considered equal.
-
-            :param node: some ast node
-            :param other: some ast node
-
-            :rtype: bool
-            :returns: True if the nodes are considered equal, otherwise False
-
-            If the method returns True, the nodes are actually equal, but it
-            may return False when the nodes are equal.
-        """
-        raise NotImplementedError()
-
-class PointlessFunctionDefinition(PointlessData):
-    """ Looking for pointless function definitions. """
-
-    _DEF_CLASS = astroid.Function
-    message_id = "W9952"
-
-    @classmethod
-    def _retain_node(cls, node, restrict=True):
-        return not restrict or \
-           (len(node.body) == 1 and isinstance(node.body[0], astroid.Pass))
-
-    @classmethod
-    def check_equal(cls, node, other):
-        return len(node.body) == 1 and isinstance(node.body[0], astroid.Pass) and \
-           len(other.body) == 1 and isinstance(other.body[0], astroid.Pass)
-
-    @staticmethod
-    def _extract_value(node):
-        return node
-
-    @staticmethod
-    def _extract_targets(node):
-        yield node.name
-
-class PointlessAssignment(PointlessData):
-
-    _DEF_CLASS = astroid.Assign
-    message_id = "W9951"
-
-    _VALUE_CLASSES = (
-        astroid.Const,
-        astroid.Dict,
-        astroid.List,
-        astroid.Tuple
-    )
-
-    @classmethod
-    def _retain_node(cls, node, restrict=True):
-        return not restrict or isinstance(node.value, cls._VALUE_CLASSES)
-
-    @classmethod
-    def check_equal(cls, node, other):
-        if not isinstance(node, other.__class__):
-            return False
-        if isinstance(node, astroid.Const):
-            return node.value == other.value
-        if isinstance(node, (astroid.List, astroid.Tuple)):
-            return len(node.elts) == len(other.elts) and \
-               all(cls.check_equal(n, o) for (n, o) in zip(node.elts, other.elts))
-        if isinstance(node, astroid.Dict):
-            return len(node.items) == len(other.items)
-        return False
-
-    @staticmethod
-    def _extract_value(node):
-        return node.value
-
-    @staticmethod
-    def _extract_targets(node):
-        for target in node.targets:
-            yield target.name
-
-class PointlessClassAttributeOverrideChecker(BaseChecker):
-    """ If the nearest definition of the class attribute in the MRO assigns
-        it the same value, then the overriding definition is said to be
-        pointless.
-
-        The algorithm for detecting a pointless attribute override is the following.
-
-        * For each class, C:
-           - For each attribute assignment,
-               name_1 = name_2 ... name_n = l (where l is a literal):
-              * For each n in (n_1, n_2):
-                - Traverse the linearization of the MRO until the first
-                   matching assignment n = l' is identified. If l is equal to l',
-                   then consider that the assignment to l in C is a
-                   pointless override.
-
-        The algorithm for detecting a pointless method override has the same
-        general structure, and the same defects discussed below.
-
-        Note that this analysis is neither sound nor complete. It is unsound
-        under multiple inheritance. Consider the following class hierarchy::
-
-            class A(object):
-                _attrib = False
-
-            class B(A):
-                _attrib = False
-
-            class C(A):
-                _attrib = True
-
-            class D(B,C):
-                pass
-
-        In this  case, starting from B, B._attrib = False would be considered
-        pointless. However, for D the MRO is B, C, A, and removing the assignment
-        B._attrib = False would change the inherited value of D._attrib from
-        False to True.
-
-        The analysis is incomplete because it will find some values unequal when
-        actually they are equal.
-
-        The analysis is both incomplete and unsound because it expects that
-        assignments will always be made by means of the same syntax.
-    """
-
-    __implements__ = (IAstroidChecker,)
-
-    name = "pointless class attribute override checker"
-    msgs = {
-       "W9951":
-       (
-          "Assignment to class attribute %s overrides identical assignment in ancestor.",
-          "pointless-class-attribute-override",
-          "Assignment to class attribute  that overrides assignment in ancestor that assigns identical value has no effect."
-       ),
-       "W9952":
-       (
-          "definition of %s method overrides identical method definition in ancestor",
-          "pointless-method-definition-override",
-          "Overriding empty method definition with another empty method definition has no effect."
-       )
-    }
-
-    @check_messages("W9951", "W9952")
-    def visit_class(self, node):
-        for checker in (PointlessAssignment, PointlessFunctionDefinition):
-            for (name, value) in checker.get_data(node):
-                for a in node.ancestors():
-                    match = next((v for (n, v) in checker.get_data(a, False) if n == name), None)
-                    if match is not None:
-                        if checker.check_equal(value, match):
-                            self.add_message(checker.message_id, node=value, args=(name,))
-                        break
-
-def register(linter):
-    linter.register_checker(PointlessClassAttributeOverrideChecker(linter))
-- 
2.2.2



More information about the anaconda-patches mailing list