def add_message(
        self,
        msg_descr,
        line=None,
        node=None,
        args=None,
        confidence=UNDEFINED,
        col_offset=None,
    ):
        """Adds a message given by ID or name.

        If provided, the message string is expanded using args.

        AST checkers must provide the node argument (but may optionally
        provide line if the line number is different), raw and token checkers
        must provide the line argument.
        """
        message_definitions = self.msgs_store.get_message_definitions(msg_descr)
        for message_definition in message_definitions:
            self.add_one_message(
                message_definition, line, node, args, confidence, col_offset
            )

def add_message ( self , msg_descr , line = None , node = None , args = None , confidence = UNDEFINED , col_offset = None , ) : message_definitions = self . msgs_store . get_message_definitions ( msg_descr ) for message_definition in message_definitions : self . add_one_message ( message_definition , line , node , args , confidence , col_offset )


def print_full_documentation(self, stream=None):
        """output a full documentation in ReST format"""
        if not stream:
            stream = sys.stdout

        print("Pylint global options and switches", file=stream)
        print("----------------------------------", file=stream)
        print("", file=stream)
        print("Pylint provides global options and switches.", file=stream)
        print("", file=stream)

        by_checker = {}
        for checker in self.get_checkers():
            if checker.name == "master":
                if checker.options:
                    for section, options in checker.options_by_section():
                        if section is None:
                            title = "General options"
                        else:
                            title = "%s options" % section.capitalize()
                        print(title, file=stream)
                        print("~" * len(title), file=stream)
                        _rest_format_section(stream, None, options)
                        print("", file=stream)
            else:
                name = checker.name
                try:
                    by_checker[name]["options"] += checker.options_and_values()
                    by_checker[name]["msgs"].update(checker.msgs)
                    by_checker[name]["reports"] += checker.reports
                except KeyError:
                    by_checker[name] = {
                        "options": list(checker.options_and_values()),
                        "msgs": dict(checker.msgs),
                        "reports": list(checker.reports),
                    }

        print("Pylint checkers' options and switches", file=stream)
        print("-------------------------------------", file=stream)
        print("", file=stream)
        print("Pylint checkers can provide three set of features:", file=stream)
        print("", file=stream)
        print("* options that control their execution,", file=stream)
        print("* messages that they can raise,", file=stream)
        print("* reports that they can generate.", file=stream)
        print("", file=stream)
        print("Below is a list of all checkers and their features.", file=stream)
        print("", file=stream)

        for checker, info in sorted(by_checker.items()):
            self._print_checker_doc(checker, info, stream=stream)


def _print_checker_doc(checker_name, info, stream=None):
        """Helper method for print_full_documentation.

        Also used by doc/exts/pylint_extensions.py.
        """
        if not stream:
            stream = sys.stdout

        doc = info.get("doc")
        module = info.get("module")
        msgs = info.get("msgs")
        options = info.get("options")
        reports = info.get("reports")

        checker_title = "%s checker" % (checker_name.replace("_", " ").title())

        if module:
            # Provide anchor to link against
            print(".. _%s:\n" % module, file=stream)
        print(checker_title, file=stream)
        print("~" * len(checker_title), file=stream)
        print("", file=stream)
        if module:
            print("This checker is provided by ``%s``." % module, file=stream)
        print("Verbatim name of the checker is ``%s``." % checker_name, file=stream)
        print("", file=stream)
        if doc:
            # Provide anchor to link against
            title = "{} Documentation".format(checker_title)
            print(title, file=stream)
            print("^" * len(title), file=stream)
            print(cleandoc(doc), file=stream)
            print("", file=stream)
        if options:
            title = "{} Options".format(checker_title)
            print(title, file=stream)
            print("^" * len(title), file=stream)
            _rest_format_section(stream, None, options)
            print("", file=stream)
        if msgs:
            title = "{} Messages".format(checker_title)
            print(title, file=stream)
            print("^" * len(title), file=stream)
            for msgid, msg in sorted(
                msgs.items(), key=lambda kv: (_MSG_ORDER.index(kv[0][0]), kv[1])
            ):
                msg = build_message_definition(checker_name, msgid, msg)
                print(msg.format_help(checkerref=False), file=stream)
            print("", file=stream)
        if reports:
            title = "{} Reports".format(checker_title)
            print(title, file=stream)
            print("^" * len(title), file=stream)
            for report in reports:
                print(":%s: %s" % report[:2], file=stream)
            print("", file=stream)
        print("", file=stream)

Helper method for print_full_documentation .


def _get_indent_length(line):
    """Return the length of the indentation on the given token's line."""
    result = 0
    for char in line:
        if char == " ":
            result += 1
        elif char == "\t":
            result += _TAB_LENGTH
        else:
            break
    return result

def
_get_indent_length
(
line
)
:
result
=
0
for
char
in
line
:
if
char
==
" "
:
result
+=
1
elif
char
==
"\t"
:
result
+=
_TAB_LENGTH
else
:
break
return
result

Return the length of the indentation on the given token s line .


def _get_indent_hint_line(bar_positions, bad_position):
    """Return a line with |s for each of the positions in the given lists."""
    if not bar_positions:
        return ("", "")
    # TODO tabs should not be replaced by some random (8) number of spaces
    bar_positions = [_get_indent_length(indent) for indent in bar_positions]
    bad_position = _get_indent_length(bad_position)
    delta_message = ""
    markers = [(pos, "|") for pos in bar_positions]
    if len(markers) == 1:
        # if we have only one marker we'll provide an extra hint on how to fix
        expected_position = markers[0][0]
        delta = abs(expected_position - bad_position)
        direction = "add" if expected_position > bad_position else "remove"
        delta_message = _CONTINUATION_HINT_MESSAGE % (
            direction,
            delta,
            "s" if delta > 1 else "",
        )
    markers.append((bad_position, "^"))
    markers.sort()
    line = [" "] * (markers[-1][0] + 1)
    for position, marker in markers:
        line[position] = marker
    return ("".join(line), delta_message)

Return a line with |s for each of the positions in the given lists .


def token_indent(self, idx):
        """Get an indentation string for hanging indentation, consisting of the line-indent plus
        a number of spaces to fill up to the column of this token.

        e.g. the token indent for foo
        in "<TAB><TAB>print(foo)"
        is "<TAB><TAB>      "
        """
        line_indent = self.line_indent(idx)
        return line_indent + " " * (self.start_col(idx) - len(line_indent))

def
token_indent
(
self
,
idx
)
:
line_indent
=
self
.
line_indent
(
idx
)
return
line_indent
+
" "
*
(
self
.
start_col
(
idx
)
len
(
line_indent
)
)

Get an indentation string for hanging indentation consisting of the line - indent plus a number of spaces to fill up to the column of this token .


def handle_line_start(self, pos):
        """Record the first non-junk token at the start of a line."""
        if self._line_start > -1:
            return

        check_token_position = pos
        if self._tokens.token(pos) == _ASYNC_TOKEN:
            check_token_position += 1
        self._is_block_opener = (
            self._tokens.token(check_token_position) in _CONTINUATION_BLOCK_OPENERS
        )
        self._line_start = pos

def handle_line_start ( self , pos ) : if self . _line_start > - 1 : return check_token_position = pos if self . _tokens . token ( pos ) == _ASYNC_TOKEN : check_token_position += 1 self . _is_block_opener = ( self . _tokens . token ( check_token_position ) in _CONTINUATION_BLOCK_OPENERS ) self . _line_start = pos

Record the first non - junk token at the start of a line .


def get_valid_indentations(self, idx):
        """Returns the valid offsets for the token at the given position."""
        # The closing brace on a dict or the 'for' in a dict comprehension may
        # reset two indent levels because the dict value is ended implicitly
        stack_top = -1
        if (
            self._tokens.token(idx) in ("}", "for")
            and self._cont_stack[-1].token == ":"
        ):
            stack_top = -2
        indent = self._cont_stack[stack_top]
        if self._tokens.token(idx) in _CLOSING_BRACKETS:
            valid_indentations = indent.valid_outdent_strings
        else:
            valid_indentations = indent.valid_continuation_strings
        return indent, valid_indentations.copy()

Returns the valid offsets for the token at the given position .


def _hanging_indent_after_bracket(self, bracket, position):
        """Extracts indentation information for a hanging indent

        Case of hanging indent after a bracket (including parenthesis)

        :param str bracket: bracket in question
        :param int position: Position of bracket in self._tokens

        :returns: the state and valid positions for hanging indentation
        :rtype: _ContinuedIndent
        """
        indentation = self._tokens.line_indent(position)
        if (
            self._is_block_opener
            and self._continuation_string == self._block_indent_string
        ):
            return _ContinuedIndent(
                HANGING_BLOCK,
                bracket,
                position,
                _Indentations(indentation + self._continuation_string, indentation),
                _BeforeBlockIndentations(
                    indentation + self._continuation_string,
                    indentation + self._continuation_string * 2,
                ),
            )
        if bracket == ":":
            # If the dict key was on the same line as the open brace, the new
            # correct indent should be relative to the key instead of the
            # current indent level
            paren_align = self._cont_stack[-1].valid_outdent_strings
            next_align = self._cont_stack[-1].valid_continuation_strings.copy()
            next_align_keys = list(next_align.keys())
            next_align[next_align_keys[0] + self._continuation_string] = True
            # Note that the continuation of
            # d = {
            #       'a': 'b'
            #            'c'
            # }
            # is handled by the special-casing for hanging continued string indents.
            return _ContinuedIndent(
                HANGING_DICT_VALUE, bracket, position, paren_align, next_align
            )
        return _ContinuedIndent(
            HANGING,
            bracket,
            position,
            _Indentations(indentation, indentation + self._continuation_string),
            _Indentations(indentation + self._continuation_string),
        )


def _continuation_inside_bracket(self, bracket, position):
        """Extracts indentation information for a continued indent."""
        indentation = self._tokens.line_indent(position)
        token_indent = self._tokens.token_indent(position)
        next_token_indent = self._tokens.token_indent(position + 1)
        if (
            self._is_block_opener
            and next_token_indent == indentation + self._block_indent_string
        ):
            return _ContinuedIndent(
                CONTINUED_BLOCK,
                bracket,
                position,
                _Indentations(token_indent),
                _BeforeBlockIndentations(
                    next_token_indent, next_token_indent + self._continuation_string
                ),
            )
        return _ContinuedIndent(
            CONTINUED,
            bracket,
            position,
            _Indentations(token_indent, next_token_indent),
            _Indentations(next_token_indent),
        )

def _continuation_inside_bracket ( self , bracket , position ) : indentation = self . _tokens . line_indent ( position ) token_indent = self . _tokens . token_indent ( position ) next_token_indent = self . _tokens . token_indent ( position + 1 ) if ( self . _is_block_opener and next_token_indent == indentation + self . _block_indent_string ) : return _ContinuedIndent ( CONTINUED_BLOCK , bracket , position , _Indentations ( token_indent ) , _BeforeBlockIndentations ( next_token_indent , next_token_indent + self . _continuation_string ) , ) return _ContinuedIndent ( CONTINUED , bracket , position , _Indentations ( token_indent , next_token_indent ) , _Indentations ( next_token_indent ) , )

Extracts indentation information for a continued indent .


def push_token(self, token, position):
        """Pushes a new token for continued indentation on the stack.

        Tokens that can modify continued indentation offsets are:
          * opening brackets
          * 'lambda'
          * : inside dictionaries

        push_token relies on the caller to filter out those
        interesting tokens.

        :param int token: The concrete token
        :param int position: The position of the token in the stream.
        """
        if _token_followed_by_eol(self._tokens, position):
            self._cont_stack.append(self._hanging_indent_after_bracket(token, position))
        else:
            self._cont_stack.append(self._continuation_inside_bracket(token, position))

def push_token ( self , token , position ) : if _token_followed_by_eol ( self . _tokens , position ) : self . _cont_stack . append ( self . _hanging_indent_after_bracket ( token , position ) ) else : self . _cont_stack . append ( self . _continuation_inside_bracket ( token , position ) )

Pushes a new token for continued indentation on the stack .


def new_line(self, tokens, line_end, line_start):
        """a new line has been encountered, process it if necessary"""
        if _last_token_on_line_is(tokens, line_end, ";"):
            self.add_message("unnecessary-semicolon", line=tokens.start_line(line_end))

        line_num = tokens.start_line(line_start)
        line = tokens.line(line_start)
        if tokens.type(line_start) not in _JUNK_TOKENS:
            self._lines[line_num] = line.split("\n")[0]
        self.check_lines(line, line_num)

def new_line ( self , tokens , line_end , line_start ) : if _last_token_on_line_is ( tokens , line_end , ";" ) : self . add_message ( "unnecessary-semicolon" , line = tokens . start_line ( line_end ) ) line_num = tokens . start_line ( line_start ) line = tokens . line ( line_start ) if tokens . type ( line_start ) not in _JUNK_TOKENS : self . _lines [ line_num ] = line . split ( "\n" ) [ 0 ] self . check_lines ( line , line_num )

a new line has been encountered process it if necessary


def _check_keyword_parentheses(self, tokens, start):
        """Check that there are not unnecessary parens after a keyword.

        Parens are unnecessary if there is exactly one balanced outer pair on a
        line, and it is followed by a colon, and contains no commas (i.e. is not a
        tuple).

        Args:
        tokens: list of Tokens; the entire list of Tokens.
        start: int; the position of the keyword in the token list.
        """
        # If the next token is not a paren, we're fine.
        if self._inside_brackets(":") and tokens[start][1] == "for":
            self._pop_token()
        if tokens[start + 1][1] != "(":
            return

        found_and_or = False
        depth = 0
        keyword_token = str(tokens[start][1])
        line_num = tokens[start][2][0]

        for i in range(start, len(tokens) - 1):
            token = tokens[i]

            # If we hit a newline, then assume any parens were for continuation.
            if token[0] == tokenize.NL:
                return

            if token[1] == "(":
                depth += 1
            elif token[1] == ")":
                depth -= 1
                if depth:
                    continue
                # ')' can't happen after if (foo), since it would be a syntax error.
                if tokens[i + 1][1] in (":", ")", "]", "}", "in") or tokens[i + 1][
                    0
                ] in (tokenize.NEWLINE, tokenize.ENDMARKER, tokenize.COMMENT):
                    # The empty tuple () is always accepted.
                    if i == start + 2:
                        return
                    if keyword_token == "not":
                        if not found_and_or:
                            self.add_message(
                                "superfluous-parens", line=line_num, args=keyword_token
                            )
                    elif keyword_token in ("return", "yield"):
                        self.add_message(
                            "superfluous-parens", line=line_num, args=keyword_token
                        )
                    elif keyword_token not in self._keywords_with_parens:
                        if not found_and_or:
                            self.add_message(
                                "superfluous-parens", line=line_num, args=keyword_token
                            )
                return
            elif depth == 1:
                # This is a tuple, which is always acceptable.
                if token[1] == ",":
                    return
                # 'and' and 'or' are the only boolean operators with lower precedence
                # than 'not', so parens are only required when they are found.
                if token[1] in ("and", "or"):
                    found_and_or = True
                # A yield inside an expression must always be in parentheses,
                # quit early without error.
                elif token[1] == "yield":
                    return
                # A generator expression always has a 'for' token in it, and
                # the 'for' token is only legal inside parens when it is in a
                # generator expression.  The parens are necessary here, so bail
                # without an error.
                elif token[1] == "for":
                    return

Check that there are not unnecessary parens after a keyword .


def _has_valid_type_annotation(self, tokens, i):
        """Extended check of PEP-484 type hint presence"""
        if not self._inside_brackets("("):
            return False
        # token_info
        # type string start end line
        #  0      1     2    3    4
        bracket_level = 0
        for token in tokens[i - 1 :: -1]:
            if token[1] == ":":
                return True
            if token[1] == "(":
                return False
            if token[1] == "]":
                bracket_level += 1
            elif token[1] == "[":
                bracket_level -= 1
            elif token[1] == ",":
                if not bracket_level:
                    return False
            elif token[1] in (".", "..."):
                continue
            elif token[0] not in (tokenize.NAME, tokenize.STRING, tokenize.NL):
                return False
        return False

def
_has_valid_type_annotation
(
self
,
tokens
,
i
)
:
if
not
self
.
_inside_brackets
(
"("
)
:
return
False
# token_info
# type string start end line
#  0      1     2    3    4
bracket_level
=
0
for
token
in
tokens
[
i
1
:
:
1
]
:
if
token
[
1
]
==
":"
:
return
True
if
token
[
1
]
==
"("
:
return
False
if
token
[
1
]
==
"]"
:
bracket_level
+=
1
elif
token
[
1
]
==
"["
:
bracket_level
-=
1
elif
token
[
1
]
==
","
:
if
not
bracket_level
:
return
False
elif
token
[
1
]
in
(
"."
,
"..."
)
:
continue
elif
token
[
0
]
not
in
(
tokenize
.
NAME
,
tokenize
.
STRING
,
tokenize
.
NL
)
:
return
False
return
False

Extended check of PEP - 484 type hint presence


def _check_equals_spacing(self, tokens, i):
        """Check the spacing of a single equals sign."""
        if self._has_valid_type_annotation(tokens, i):
            self._check_space(tokens, i, (_MUST, _MUST))
        elif self._inside_brackets("(") or self._inside_brackets("lambda"):
            self._check_space(tokens, i, (_MUST_NOT, _MUST_NOT))
        else:
            self._check_space(tokens, i, (_MUST, _MUST))

def _check_equals_spacing ( self , tokens , i ) : if self . _has_valid_type_annotation ( tokens , i ) : self . _check_space ( tokens , i , ( _MUST , _MUST ) ) elif self . _inside_brackets ( "(" ) or self . _inside_brackets ( "lambda" ) : self . _check_space ( tokens , i , ( _MUST_NOT , _MUST_NOT ) ) else : self . _check_space ( tokens , i , ( _MUST , _MUST ) )

Check the spacing of a single equals sign .


def _check_surrounded_by_space(self, tokens, i):
        """Check that a binary operator is surrounded by exactly one space."""
        self._check_space(tokens, i, (_MUST, _MUST))

def _check_surrounded_by_space ( self , tokens , i ) : self . _check_space ( tokens , i , ( _MUST , _MUST ) )

Check that a binary operator is surrounded by exactly one space .


def visit_default(self, node):
        """check the node line number and check it if not yet done"""
        if not node.is_statement:
            return
        if not node.root().pure_python:
            return  # XXX block visit of child nodes
        prev_sibl = node.previous_sibling()
        if prev_sibl is not None:
            prev_line = prev_sibl.fromlineno
        else:
            # The line on which a finally: occurs in a try/finally
            # is not directly represented in the AST. We infer it
            # by taking the last line of the body and adding 1, which
            # should be the line of finally:
            if (
                isinstance(node.parent, nodes.TryFinally)
                and node in node.parent.finalbody
            ):
                prev_line = node.parent.body[0].tolineno + 1
            else:
                prev_line = node.parent.statement().fromlineno
        line = node.fromlineno
        assert line, node
        if prev_line == line and self._visited_lines.get(line) != 2:
            self._check_multi_statement_line(node, line)
            return
        if line in self._visited_lines:
            return
        try:
            tolineno = node.blockstart_tolineno
        except AttributeError:
            tolineno = node.tolineno
        assert tolineno, node
        lines = []
        for line in range(line, tolineno + 1):
            self._visited_lines[line] = 1
            try:
                lines.append(self._lines[line].rstrip())
            except KeyError:
                lines.append("")


def _check_multi_statement_line(self, node, line):
        """Check for lines containing multiple statements."""
        # Do not warn about multiple nested context managers
        # in with statements.
        if isinstance(node, nodes.With):
            return
        # For try... except... finally..., the two nodes
        # appear to be on the same line due to how the AST is built.
        if isinstance(node, nodes.TryExcept) and isinstance(
            node.parent, nodes.TryFinally
        ):
            return
        if (
            isinstance(node.parent, nodes.If)
            and not node.parent.orelse
            and self.config.single_line_if_stmt
        ):
            return
        if (
            isinstance(node.parent, nodes.ClassDef)
            and len(node.parent.body) == 1
            and self.config.single_line_class_stmt
        ):
            return
        self.add_message("multiple-statements", node=node)
        self._visited_lines[line] = 2

Check for lines containing multiple statements .


def check_lines(self, lines, i):
        """check lines have less than a maximum number of characters
        """
        max_chars = self.config.max_line_length
        ignore_long_line = self.config.ignore_long_lines

        def check_line(line, i):
            if not line.endswith("\n"):
                self.add_message("missing-final-newline", line=i)
            else:
                # exclude \f (formfeed) from the rstrip
                stripped_line = line.rstrip("\t\n\r\v ")
                if not stripped_line and _EMPTY_LINE in self.config.no_space_check:
                    # allow empty lines
                    pass
                elif line[len(stripped_line) :] not in ("\n", "\r\n"):
                    self.add_message(
                        "trailing-whitespace", line=i, col_offset=len(stripped_line)
                    )
                # Don't count excess whitespace in the line length.
                line = stripped_line
            mobj = OPTION_RGX.search(line)
            if mobj and "=" in line:
                front_of_equal, _, back_of_equal = mobj.group(1).partition("=")
                if front_of_equal.strip() == "disable":
                    if "line-too-long" in {
                        _msg_id.strip() for _msg_id in back_of_equal.split(",")
                    }:
                        return None
                    line = line.rsplit("#", 1)[0].rstrip()

            if len(line) > max_chars and not ignore_long_line.search(line):
                self.add_message("line-too-long", line=i, args=(len(line), max_chars))
            return i + 1

        unsplit_ends = {
            "\v",
            "\x0b",
            "\f",
            "\x0c",
            "\x1c",
            "\x1d",
            "\x1e",
            "\x85",
            "\u2028",
            "\u2029",
        }
        unsplit = []
        for line in lines.splitlines(True):
            if line[-1] in unsplit_ends:
                unsplit.append(line)
                continue

            if unsplit:
                unsplit.append(line)
                line = "".join(unsplit)
                unsplit = []

            i = check_line(line, i)
            if i is None:
                break

        if unsplit:
            check_line("".join(unsplit), i)


def check_indent_level(self, string, expected, line_num):
        """return the indent level of the string
        """
        indent = self.config.indent_string
        if indent == "\\t":  # \t is not interpreted in the configuration file
            indent = "\t"
        level = 0
        unit_size = len(indent)
        while string[:unit_size] == indent:
            string = string[unit_size:]
            level += 1
        suppl = ""
        while string and string[0] in " \t":
            if string[0] != indent[0]:
                if string[0] == "\t":
                    args = ("tab", "space")
                else:
                    args = ("space", "tab")
                self.add_message("mixed-indentation", args=args, line=line_num)
                return level
            suppl += string[0]
            string = string[1:]
        if level != expected or suppl:
            i_type = "spaces"
            if indent[0] == "\t":
                i_type = "tabs"
            self.add_message(
                "bad-indentation",
                line=line_num,
                args=(level * unit_size + len(suppl), i_type, expected * unit_size),
            )
        return None


def _in_iterating_context(node):
    """Check if the node is being used as an iterator.

    Definition is taken from lib2to3.fixer_util.in_special_context().
    """
    parent = node.parent
    # Since a call can't be the loop variant we only need to know if the node's
    # parent is a 'for' loop to know it's being used as the iterator for the
    # loop.
    if isinstance(parent, astroid.For):
        return True
    # Need to make sure the use of the node is in the iterator part of the
    # comprehension.
    if isinstance(parent, astroid.Comprehension):
        if parent.iter == node:
            return True
    # Various built-ins can take in an iterable or list and lead to the same
    # value.
    elif isinstance(parent, astroid.Call):
        if isinstance(parent.func, astroid.Name):
            parent_scope = parent.func.lookup(parent.func.name)[0]
            if _is_builtin(parent_scope) and parent.func.name in _ACCEPTS_ITERATOR:
                return True
        elif isinstance(parent.func, astroid.Attribute):
            if parent.func.attrname in ATTRIBUTES_ACCEPTS_ITERATOR:
                return True

        inferred = utils.safe_infer(parent.func)
        if inferred:
            if inferred.qname() in _BUILTIN_METHOD_ACCEPTS_ITERATOR:
                return True
            root = inferred.root()
            if root and root.name == "itertools":
                return True
    # If the call is in an unpacking, there's no need to warn,
    # since it can be considered iterating.
    elif isinstance(parent, astroid.Assign) and isinstance(
        parent.targets[0], (astroid.List, astroid.Tuple)
    ):
        if len(parent.targets[0].elts) > 1:
            return True
    # If the call is in a containment check, we consider that to
    # be an iterating context
    elif (
        isinstance(parent, astroid.Compare)
        and len(parent.ops) == 1
        and parent.ops[0][0] == "in"
    ):
        return True
    # Also if it's an `yield from`, that's fair
    elif isinstance(parent, astroid.YieldFrom):
        return True
    if isinstance(parent, astroid.Starred):
        return True
    return False

Check if the node is being used as an iterator .


def _is_conditional_import(node):
    """Checks if an import node is in the context of a conditional.
    """
    parent = node.parent
    return isinstance(
        parent, (astroid.TryExcept, astroid.ExceptHandler, astroid.If, astroid.IfExp)
    )

def _is_conditional_import ( node ) : parent = node . parent return isinstance ( parent , ( astroid . TryExcept , astroid . ExceptHandler , astroid . If , astroid . IfExp ) )

Checks if an import node is in the context of a conditional .


def visit_name(self, node):
        """Detect when a "bad" built-in is referenced."""
        found_node, _ = node.lookup(node.name)
        if not _is_builtin(found_node):
            return
        if node.name not in self._bad_builtins:
            return
        if node_ignores_exception(node) or isinstance(
            find_try_except_wrapper_node(node), astroid.ExceptHandler
        ):
            return

        message = node.name.lower() + "-builtin"
        self.add_message(message, node=node)

def visit_name ( self , node ) : found_node , _ = node . lookup ( node . name ) if not _is_builtin ( found_node ) : return if node . name not in self . _bad_builtins : return if node_ignores_exception ( node ) or isinstance ( find_try_except_wrapper_node ( node ) , astroid . ExceptHandler ) : return message = node . name . lower ( ) + "-builtin" self . add_message ( message , node = node )

Detect when a bad built - in is referenced .


def visit_subscript(self, node):
        """ Look for indexing exceptions. """
        try:
            for inferred in node.value.infer():
                if not isinstance(inferred, astroid.Instance):
                    continue
                if utils.inherit_from_std_ex(inferred):
                    self.add_message("indexing-exception", node=node)
        except astroid.InferenceError:
            return

def visit_subscript ( self , node ) : try : for inferred in node . value . infer ( ) : if not isinstance ( inferred , astroid . Instance ) : continue if utils . inherit_from_std_ex ( inferred ) : self . add_message ( "indexing-exception" , node = node ) except astroid . InferenceError : return


def visit_attribute(self, node):
        """Look for removed attributes"""
        if node.attrname == "xreadlines":
            self.add_message("xreadlines-attribute", node=node)
            return

        exception_message = "message"
        try:
            for inferred in node.expr.infer():
                if isinstance(inferred, astroid.Instance) and utils.inherit_from_std_ex(
                    inferred
                ):
                    if node.attrname == exception_message:

                        # Exceptions with .message clearly defined are an exception
                        if exception_message in inferred.instance_attrs:
                            continue
                        self.add_message("exception-message-attribute", node=node)
                if isinstance(inferred, astroid.Module):
                    self._warn_if_deprecated(
                        node, inferred.name, {node.attrname}, report_on_modules=False
                    )
        except astroid.InferenceError:
            return


def visit_excepthandler(self, node):
        """Visit an except handler block and check for exception unpacking."""

        def _is_used_in_except_block(node):
            scope = node.scope()
            current = node
            while (
                current
                and current != scope
                and not isinstance(current, astroid.ExceptHandler)
            ):
                current = current.parent
            return isinstance(current, astroid.ExceptHandler) and current.type != node

        if isinstance(node.name, (astroid.Tuple, astroid.List)):
            self.add_message("unpacking-in-except", node=node)
            return

        if not node.name:
            return

        # Find any names
        scope = node.parent.scope()
        scope_names = scope.nodes_of_class(astroid.Name, skip_klass=astroid.FunctionDef)
        scope_names = list(scope_names)
        potential_leaked_names = [
            scope_name
            for scope_name in scope_names
            if scope_name.name == node.name.name
            and scope_name.lineno > node.lineno
            and not _is_used_in_except_block(scope_name)
        ]
        reassignments_for_same_name = {
            assign_name.lineno
            for assign_name in scope.nodes_of_class(
                astroid.AssignName, skip_klass=astroid.FunctionDef
            )
            if assign_name.name == node.name.name
        }
        for leaked_name in potential_leaked_names:
            if any(
                node.lineno < elem < leaked_name.lineno
                for elem in reassignments_for_same_name
            ):
                continue
            self.add_message("exception-escape", node=leaked_name)

def
visit_excepthandler
(
self
,
node
)
:
def
_is_used_in_except_block
(
node
)
:
scope
=
node
.
scope
(
)
current
=
node
while
(
current
and
current
!=
scope
and
not
isinstance
(
current
,
astroid
.
ExceptHandler
)
)
:
current
=
current
.
parent
return
isinstance
(
current
,
astroid
.
ExceptHandler
)
and
current
.
type
!=
node
if
isinstance
(
node
.
name
,
(
astroid
.
Tuple
,
astroid
.
List
)
)
:
self
.
add_message
(
"unpacking-in-except"
,
node
=
node
)
return
if
not
node
.
name
:
return
# Find any names
scope
=
node
.
parent
.
scope
(
)
scope_names
=
scope
.
nodes_of_class
(
astroid
.
Name
,
skip_klass
=
astroid
.
FunctionDef
)
scope_names
=
list
(
scope_names
)
potential_leaked_names
=
[
scope_name
for
scope_name
in
scope_names
if
scope_name
.
name
==
node
.
name
.
name
and
scope_name
.
lineno
>
node
.
lineno
and
not
_is_used_in_except_block
(
scope_name
)
]
reassignments_for_same_name
=
{
assign_name
.
lineno
for
assign_name
in
scope
.
nodes_of_class
(
astroid
.
AssignName
,
skip_klass
=
astroid
.
FunctionDef
)
if
assign_name
.
name
==
node
.
name
.
name
}
for
leaked_name
in
potential_leaked_names
:
if
any
(
node
.
lineno
<
elem
<
leaked_name
.
lineno
for
elem
in
reassignments_for_same_name
)
:
continue
self
.
add_message
(
"exception-escape"
,
node
=
leaked_name
)

Visit an except handler block and check for exception unpacking .


def visit_raise(self, node):
        """Visit a raise statement and check for raising
        strings or old-raise-syntax.
        """

        # Ignore empty raise.
        if node.exc is None:
            return
        expr = node.exc
        if self._check_raise_value(node, expr):
            return
        try:
            value = next(astroid.unpack_infer(expr))
        except astroid.InferenceError:
            return
        self._check_raise_value(node, value)

def
visit_raise
(
self
,
node
)
:
# Ignore empty raise.
if
node
.
exc
is
:
return
expr
=
node
.
exc
if
self
.
_check_raise_value
(
node
,
expr
)
:
return
try
:
value
=
next
(
astroid
.
unpack_infer
(
expr
)
)
except
astroid
.
InferenceError
:
return
self
.
_check_raise_value
(
node
,
value
)

Visit a raise statement and check for raising strings or old - raise - syntax .


def find_pylintrc():
    """search the pylint rc file and return its path if it find it, else None
    """
    # is there a pylint rc file in the current directory ?
    if os.path.exists("pylintrc"):
        return os.path.abspath("pylintrc")
    if os.path.exists(".pylintrc"):
        return os.path.abspath(".pylintrc")
    if os.path.isfile("__init__.py"):
        curdir = os.path.abspath(os.getcwd())
        while os.path.isfile(os.path.join(curdir, "__init__.py")):
            curdir = os.path.abspath(os.path.join(curdir, ".."))
            if os.path.isfile(os.path.join(curdir, "pylintrc")):
                return os.path.join(curdir, "pylintrc")
            if os.path.isfile(os.path.join(curdir, ".pylintrc")):
                return os.path.join(curdir, ".pylintrc")
    if "PYLINTRC" in os.environ and os.path.exists(os.environ["PYLINTRC"]):
        pylintrc = os.environ["PYLINTRC"]
    else:
        user_home = os.path.expanduser("~")
        if user_home in ("~", "/root"):
            pylintrc = ".pylintrc"
        else:
            pylintrc = os.path.join(user_home, ".pylintrc")
            if not os.path.isfile(pylintrc):
                pylintrc = os.path.join(user_home, ".config", "pylintrc")
    if not os.path.isfile(pylintrc):
        if os.path.isfile("/etc/pylintrc"):
            pylintrc = "/etc/pylintrc"
        else:
            pylintrc = None
    return pylintrc

search the pylint rc file and return its path if it find it else None


def _validate(value, optdict, name=""):
    """return a validated value for an option according to its type

    optional argument name is only used for error message formatting
    """
    try:
        _type = optdict["type"]
    except KeyError:
        # FIXME
        return value
    return _call_validator(_type, optdict, name, value)

def
_validate
(
value
,
optdict
,
name
=
""
)
:
try
:
_type
=
optdict
[
"type"
]
except
KeyError
:
# FIXME
return
value
return
_call_validator
(
_type
,
optdict
,
name
,
value
)


def _expand_default(self, option):
    """Patch OptionParser.expand_default with custom behaviour

    This will handle defaults to avoid overriding values in the
    configuration file.
    """
    if self.parser is None or not self.default_tag:
        return option.help
    optname = option._long_opts[0][2:]
    try:
        provider = self.parser.options_manager._all_options[optname]
    except KeyError:
        value = None
    else:
        optdict = provider.get_option_def(optname)
        optname = provider.option_attrname(optname, optdict)
        value = getattr(provider.config, optname, optdict)
        value = utils._format_option_value(optdict, value)
    if value is optparse.NO_DEFAULT or not value:
        value = self.NO_DEFAULT_VALUE
    return option.help.replace(self.default_tag, str(value))

def _expand_default ( self , option ) : if self . parser is None or not self . default_tag : return option . help optname = option . _long_opts [ 0 ] [ 2 : ] try : provider = self . parser . options_manager . _all_options [ optname ] except KeyError : value = None else : optdict = provider . get_option_def ( optname ) optname = provider . option_attrname ( optname , optdict ) value = getattr ( provider . config , optname , optdict ) value = utils . _format_option_value ( optdict , value ) if value is optparse . NO_DEFAULT or not value : value = self . NO_DEFAULT_VALUE return option . help . replace ( self . default_tag , str ( value ) )

Patch OptionParser . expand_default with custom behaviour


def _match_long_opt(self, opt):
        """Disable abbreviations."""
        if opt not in self._long_opt:
            raise optparse.BadOptionError(opt)
        return opt

def _match_long_opt ( self , opt ) : if opt not in self . _long_opt : raise optparse . BadOptionError ( opt ) return opt


def register_options_provider(self, provider, own_group=True):
        """register an options provider"""
        assert provider.priority <= 0, "provider's priority can't be >= 0"
        for i in range(len(self.options_providers)):
            if provider.priority > self.options_providers[i].priority:
                self.options_providers.insert(i, provider)
                break
        else:
            self.options_providers.append(provider)
        non_group_spec_options = [
            option for option in provider.options if "group" not in option[1]
        ]
        groups = getattr(provider, "option_groups", ())
        if own_group and non_group_spec_options:
            self.add_option_group(
                provider.name.upper(),
                provider.__doc__,
                non_group_spec_options,
                provider,
            )
        else:
            for opt, optdict in non_group_spec_options:
                self.add_optik_option(provider, self.cmdline_parser, opt, optdict)
        for gname, gdoc in groups:
            gname = gname.upper()
            goptions = [
                option
                for option in provider.options
                if option[1].get("group", "").upper() == gname
            ]
            self.add_option_group(gname, gdoc, goptions, provider)

def
register_options_provider
(
self
,
provider
,
own_group
=
True
)
:
assert
provider
.
priority
<=
0
,
"provider's priority can't be >= 0"
for
i
in
range
(
len
(
self
.
options_providers
)
)
:
if
provider
.
priority
>
self
.
options_providers
[
i
]
.
priority
:
self
.
options_providers
.
insert
(
i
,
provider
)
break
else
:
self
.
options_providers
.
append
(
provider
)
non_group_spec_options
=
[
option
for
option
in
provider
.
options
if
"group"
not
in
option
[
1
]
]
groups
=
getattr
(
provider
,
"option_groups"
,
(
)
)
if
own_group
and
non_group_spec_options
:
self
.
add_option_group
(
provider
.
name
.
upper
(
)
,
provider
.
__doc__
,
non_group_spec_options
,
provider
,
)
else
:
for
opt
,
optdict
in
non_group_spec_options
:
self
.
add_optik_option
(
provider
,
self
.
cmdline_parser
,
opt
,
optdict
)
for
gname
,
gdoc
in
groups
:
gname
=
gname
.
upper
(
)
goptions
=
[
option
for
option
in
provider
.
options
if
option
[
1
]
.
get
(
"group"
,
""
)
.
upper
(
)
==
gname
]
self
.
add_option_group
(
gname
,
gdoc
,
goptions
,
provider
)


def cb_set_provider_option(self, option, opt, value, parser):
        """optik callback for option setting"""
        if opt.startswith("--"):
            # remove -- on long option
            opt = opt[2:]
        else:
            # short option, get its long equivalent
            opt = self._short_options[opt[1:]]
        # trick since we can't set action='store_true' on options
        if value is None:
            value = 1
        self.global_set_option(opt, value)


def global_set_option(self, opt, value):
        """set option on the correct option provider"""
        self._all_options[opt].set_option(opt, value)

def global_set_option ( self , opt , value ) : self . _all_options [ opt ] . set_option ( opt , value )


def generate_config(self, stream=None, skipsections=(), encoding=None):
        """write a configuration file according to the current configuration
        into the given stream or stdout
        """
        options_by_section = {}
        sections = []
        for provider in self.options_providers:
            for section, options in provider.options_by_section():
                if section is None:
                    section = provider.name
                if section in skipsections:
                    continue
                options = [
                    (n, d, v)
                    for (n, d, v) in options
                    if d.get("type") is not None and not d.get("deprecated")
                ]
                if not options:
                    continue
                if section not in sections:
                    sections.append(section)
                alloptions = options_by_section.setdefault(section, [])
                alloptions += options
        stream = stream or sys.stdout
        printed = False
        for section in sections:
            if printed:
                print("\n", file=stream)
            utils.format_section(
                stream, section.upper(), sorted(options_by_section[section])
            )
            printed = True

def generate_config ( self , stream = None , skipsections = ( ) , encoding = None ) : options_by_section = { } sections = [ ] for provider in self . options_providers : for section , options in provider . options_by_section ( ) : if section is None : section = provider . name if section in skipsections : continue options = [ ( n , d , v ) for ( n , d , v ) in options if d . get ( "type" ) is not None and not d . get ( "deprecated" ) ] if not options : continue if section not in sections : sections . append ( section ) alloptions = options_by_section . setdefault ( section , [ ] ) alloptions += options stream = stream or sys . stdout printed = False for section in sections : if printed : print ( "\n" , file = stream ) utils . format_section ( stream , section . upper ( ) , sorted ( options_by_section [ section ] ) ) printed = True


def load_config_file(self):
        """dispatch values previously read from a configuration file to each
        options provider)
        """
        parser = self.cfgfile_parser
        for section in parser.sections():
            for option, value in parser.items(section):
                try:
                    self.global_set_option(option, value)
                except (KeyError, optparse.OptionError):
                    # TODO handle here undeclared options appearing in the config file
                    continue

dispatch values previously read from a configuration file to each options provider )


def load_command_line_configuration(self, args=None):
        """Override configuration according to command line parameters

        return additional arguments
        """
        with _patch_optparse():
            if args is None:
                args = sys.argv[1:]
            else:
                args = list(args)
            (options, args) = self.cmdline_parser.parse_args(args=args)
            for provider in self._nocallback_options:
                config = provider.config
                for attr in config.__dict__.keys():
                    value = getattr(options, attr, None)
                    if value is None:
                        continue
                    setattr(config, attr, value)
            return args

def load_command_line_configuration ( self , args = None ) : with _patch_optparse ( ) : if args is None : args = sys . argv [ 1 : ] else : args = list ( args ) ( options , args ) = self . cmdline_parser . parse_args ( args = args ) for provider in self . _nocallback_options : config = provider . config for attr in config . __dict__ . keys ( ) : value = getattr ( options , attr , None ) if value is None : continue setattr ( config , attr , value ) return args


def add_help_section(self, title, description, level=0):
        """add a dummy option section for help purpose """
        group = optparse.OptionGroup(
            self.cmdline_parser, title=title.capitalize(), description=description
        )
        group.level = level
        self._maxlevel = max(self._maxlevel, level)
        self.cmdline_parser.add_option_group(group)

def add_help_section ( self , title , description , level = 0 ) : group = optparse . OptionGroup ( self . cmdline_parser , title = title . capitalize ( ) , description = description ) group . level = level self . _maxlevel = max ( self . _maxlevel , level ) self . cmdline_parser . add_option_group ( group )


def help(self, level=0):
        """return the usage string for available options """
        self.cmdline_parser.formatter.output_level = level
        with _patch_optparse():
            return self.cmdline_parser.format_help()

def help ( self , level = 0 ) : self . cmdline_parser . formatter . output_level = level with _patch_optparse ( ) : return self . cmdline_parser . format_help ( )


def load_defaults(self):
        """initialize the provider using default values"""
        for opt, optdict in self.options:
            action = optdict.get("action")
            if action != "callback":
                # callback action have no default
                if optdict is None:
                    optdict = self.get_option_def(opt)
                default = optdict.get("default")
                self.set_option(opt, default, action, optdict)

def
load_defaults
(
self
)
:
for
opt
,
optdict
in
self
.
options
:
action
=
optdict
.
get
(
"action"
)
if
action
!=
"callback"
:
# callback action have no default
if
optdict
is
:
optdict
=
self
.
get_option_def
(
opt
)
default
=
optdict
.
get
(
"default"
)
self
.
set_option
(
opt
,
default
,
action
,
optdict
)


def option_attrname(self, opt, optdict=None):
        """get the config attribute corresponding to opt"""
        if optdict is None:
            optdict = self.get_option_def(opt)
        return optdict.get("dest", opt.replace("-", "_"))

def option_attrname ( self , opt , optdict = None ) : if optdict is None : optdict = self . get_option_def ( opt ) return optdict . get ( "dest" , opt . replace ( "-" , "_" ) )


def get_option_def(self, opt):
        """return the dictionary defining an option given its name"""
        assert self.options
        for option in self.options:
            if option[0] == opt:
                return option[1]
        raise optparse.OptionError(
            "no such option %s in section %r" % (opt, self.name), opt
        )

def
get_option_def
(
self
,
opt
)
:
assert
self
.
options
for
option
in
self
.
options
:
if
option
[
0
]
==
opt
:
return
option
[
1
]
raise
optparse
.
OptionError
(
"no such option %s in section %r"
%
(
opt
,
self
.
name
)
,
opt
)


def options_by_section(self):
        """return an iterator on options grouped by section

        (section, [list of (optname, optdict, optvalue)])
        """
        sections = {}
        for optname, optdict in self.options:
            sections.setdefault(optdict.get("group"), []).append(
                (optname, optdict, self.option_value(optname))
            )
        if None in sections:
            yield None, sections.pop(None)
        for section, options in sorted(sections.items()):
            yield section.upper(), options

def options_by_section ( self ) : sections = { } for optname , optdict in self . options : sections . setdefault ( optdict . get ( "group" ) , [ ] ) . append ( ( optname , optdict , self . option_value ( optname ) ) ) if None in sections : yield None , sections . pop ( None ) for section , options in sorted ( sections . items ( ) ) : yield section . upper ( ) , options


def is_method_call(func, types=(), methods=()):
    """Determines if a BoundMethod node represents a method call.

    Args:
      func (astroid.BoundMethod): The BoundMethod AST node to check.
      types (Optional[String]): Optional sequence of caller type names to restrict check.
      methods (Optional[String]): Optional sequence of method names to restrict check.

    Returns:
      bool: true if the node represents a method call for the given type and
      method names, False otherwise.
    """
    return (
        isinstance(func, astroid.BoundMethod)
        and isinstance(func.bound, astroid.Instance)
        and (func.bound.name in types if types else True)
        and (func.name in methods if methods else True)
    )

def is_method_call ( func , types = ( ) , methods = ( ) ) : return ( isinstance ( func , astroid . BoundMethod ) and isinstance ( func . bound , astroid . Instance ) and ( func . bound . name in types if types else True ) and ( func . name in methods if methods else True ) )

Determines if a BoundMethod node represents a method call .


def is_complex_format_str(node):
    """Checks if node represents a string with complex formatting specs.

    Args:
        node (astroid.node_classes.NodeNG): AST node to check
    Returns:
        bool: True if inferred string uses complex formatting, False otherwise
    """
    inferred = utils.safe_infer(node)
    if inferred is None or not isinstance(inferred.value, str):
        return True
    try:
        parsed = list(string.Formatter().parse(inferred.value))
    except ValueError:
        # This format string is invalid
        return False
    for _, _, format_spec, _ in parsed:
        if format_spec:
            return True
    return False

def
is_complex_format_str
(
node
)
:
inferred
=
utils
.
safe_infer
(
node
)
if
inferred
is
or
not
isinstance
(
inferred
.
value
,
str
)
:
return
True
try
:
parsed
=
list
(
string
.
Formatter
(
)
.
parse
(
inferred
.
value
)
)
except
ValueError
:
# This format string is invalid
return
False
for
_
,
_
,
format_spec
,
_
in
parsed
:
if
format_spec
:
return
True
return
False

Checks if node represents a string with complex formatting specs .


def visit_module(self, node):  # pylint: disable=unused-argument
        """Clears any state left in this checker from last module checked."""
        # The code being checked can just as easily "import logging as foo",
        # so it is necessary to process the imports and store in this field
        # what name the logging module is actually given.
        self._logging_names = set()
        logging_mods = self.config.logging_modules

        self._format_style = self.config.logging_format_style
        self._logging_modules = set(logging_mods)
        self._from_imports = {}
        for logging_mod in logging_mods:
            parts = logging_mod.rsplit(".", 1)
            if len(parts) > 1:
                self._from_imports[parts[0]] = parts[1]

Clears any state left in this checker from last module checked .


def visit_importfrom(self, node):
        """Checks to see if a module uses a non-Python logging module."""
        try:
            logging_name = self._from_imports[node.modname]
            for module, as_name in node.names:
                if module == logging_name:
                    self._logging_names.add(as_name or module)
        except KeyError:
            pass

def visit_importfrom ( self , node ) : try : logging_name = self . _from_imports [ node . modname ] for module , as_name in node . names : if module == logging_name : self . _logging_names . add ( as_name or module ) except KeyError : pass

Checks to see if a module uses a non - Python logging module .


def visit_import(self, node):
        """Checks to see if this module uses Python's built-in logging."""
        for module, as_name in node.names:
            if module in self._logging_modules:
                self._logging_names.add(as_name or module)

def visit_import ( self , node ) : for module , as_name in node . names : if module in self . _logging_modules : self . _logging_names . add ( as_name or module )

Checks to see if this module uses Python s built - in logging .


def visit_call(self, node):
        """Checks calls to logging methods."""

        def is_logging_name():
            return (
                isinstance(node.func, astroid.Attribute)
                and isinstance(node.func.expr, astroid.Name)
                and node.func.expr.name in self._logging_names
            )

        def is_logger_class():
            try:
                for inferred in node.func.infer():
                    if isinstance(inferred, astroid.BoundMethod):
                        parent = inferred._proxied.parent
                        if isinstance(parent, astroid.ClassDef) and (
                            parent.qname() == "logging.Logger"
                            or any(
                                ancestor.qname() == "logging.Logger"
                                for ancestor in parent.ancestors()
                            )
                        ):
                            return True, inferred._proxied.name
            except astroid.exceptions.InferenceError:
                pass
            return False, None

        if is_logging_name():
            name = node.func.attrname
        else:
            result, name = is_logger_class()
            if not result:
                return
        self._check_log_method(node, name)

def visit_call ( self , node ) : def is_logging_name ( ) : return ( isinstance ( node . func , astroid . Attribute ) and isinstance ( node . func . expr , astroid . Name ) and node . func . expr . name in self . _logging_names ) def is_logger_class ( ) : try : for inferred in node . func . infer ( ) : if isinstance ( inferred , astroid . BoundMethod ) : parent = inferred . _proxied . parent if isinstance ( parent , astroid . ClassDef ) and ( parent . qname ( ) == "logging.Logger" or any ( ancestor . qname ( ) == "logging.Logger" for ancestor in parent . ancestors ( ) ) ) : return True , inferred . _proxied . name except astroid . exceptions . InferenceError : pass return False , None if is_logging_name ( ) : name = node . func . attrname else : result , name = is_logger_class ( ) if not result : return self . _check_log_method ( node , name )


def _check_format_string(self, node, format_arg):
        """Checks that format string tokens match the supplied arguments.

        Args:
          node (astroid.node_classes.NodeNG): AST node to be checked.
          format_arg (int): Index of the format string in the node arguments.
        """
        num_args = _count_supplied_tokens(node.args[format_arg + 1 :])
        if not num_args:
            # If no args were supplied the string is not interpolated and can contain
            # formatting characters - it's used verbatim. Don't check any further.
            return
        format_string = node.args[format_arg].value
        if not isinstance(format_string, str):
            # If the log format is constant non-string (e.g. logging.debug(5)),
            # ensure there are no arguments.
            required_num_args = 0
        else:
            try:
                if self._format_style == "old":
                    keyword_args, required_num_args, _, _ = utils.parse_format_string(
                        format_string
                    )
                    if keyword_args:
                        # Keyword checking on logging strings is complicated by
                        # special keywords - out of scope.
                        return
                elif self._format_style == "new":
                    keyword_arguments, implicit_pos_args, explicit_pos_args = utils.parse_format_method_string(
                        format_string
                    )

                    keyword_args_cnt = len(
                        set(k for k, l in keyword_arguments if not isinstance(k, int))
                    )
                    required_num_args = (
                        keyword_args_cnt + implicit_pos_args + explicit_pos_args
                    )
            except utils.UnsupportedFormatCharacter as ex:
                char = format_string[ex.index]
                self.add_message(
                    "logging-unsupported-format",
                    node=node,
                    args=(char, ord(char), ex.index),
                )
                return
            except utils.IncompleteFormatString:
                self.add_message("logging-format-truncated", node=node)
                return
        if num_args > required_num_args:
            self.add_message("logging-too-many-args", node=node)
        elif num_args < required_num_args:
            self.add_message("logging-too-few-args", node=node)

Checks that format string tokens match the supplied arguments .


def in_loop(node):
    """return True if the node is inside a kind of for loop"""
    parent = node.parent
    while parent is not None:
        if isinstance(
            parent,
            (
                astroid.For,
                astroid.ListComp,
                astroid.SetComp,
                astroid.DictComp,
                astroid.GeneratorExp,
            ),
        ):
            return True
        parent = parent.parent
    return False

def in_loop ( node ) : parent = node . parent while parent is not None : if isinstance ( parent , ( astroid . For , astroid . ListComp , astroid . SetComp , astroid . DictComp , astroid . GeneratorExp , ) , ) : return True parent = parent . parent return False


def _get_break_loop_node(break_node):
    """
    Returns the loop node that holds the break node in arguments.

    Args:
        break_node (astroid.Break): the break node of interest.

    Returns:
        astroid.For or astroid.While: the loop node holding the break node.
    """
    loop_nodes = (astroid.For, astroid.While)
    parent = break_node.parent
    while not isinstance(parent, loop_nodes) or break_node in getattr(
        parent, "orelse", []
    ):
        break_node = parent
        parent = parent.parent
        if parent is None:
            break
    return parent

def _get_break_loop_node ( break_node ) : loop_nodes = ( astroid . For , astroid . While ) parent = break_node . parent while not isinstance ( parent , loop_nodes ) or break_node in getattr ( parent , "orelse" , [ ] ) : break_node = parent parent = parent . parent if parent is None : break return parent

Returns the loop node that holds the break node in arguments .


def _loop_exits_early(loop):
    """
    Returns true if a loop may ends up in a break statement.

    Args:
        loop (astroid.For, astroid.While): the loop node inspected.

    Returns:
        bool: True if the loop may ends up in a break statement, False otherwise.
    """
    loop_nodes = (astroid.For, astroid.While)
    definition_nodes = (astroid.FunctionDef, astroid.ClassDef)
    inner_loop_nodes = [
        _node
        for _node in loop.nodes_of_class(loop_nodes, skip_klass=definition_nodes)
        if _node != loop
    ]
    return any(
        _node
        for _node in loop.nodes_of_class(astroid.Break, skip_klass=definition_nodes)
        if _get_break_loop_node(_node) not in inner_loop_nodes
    )

def _loop_exits_early ( loop ) : loop_nodes = ( astroid . For , astroid . While ) definition_nodes = ( astroid . FunctionDef , astroid . ClassDef ) inner_loop_nodes = [ _node for _node in loop . nodes_of_class ( loop_nodes , skip_klass = definition_nodes ) if _node != loop ] return any ( _node for _node in loop . nodes_of_class ( astroid . Break , skip_klass = definition_nodes ) if _get_break_loop_node ( _node ) not in inner_loop_nodes )

Returns true if a loop may ends up in a break statement .


def _get_properties(config):
    """Returns a tuple of property classes and names.

    Property classes are fully qualified, such as 'abc.abstractproperty' and
    property names are the actual names, such as 'abstract_property'.
    """
    property_classes = {BUILTIN_PROPERTY}
    property_names = set()  # Not returning 'property', it has its own check.
    if config is not None:
        property_classes.update(config.property_classes)
        property_names.update(
            (prop.rsplit(".", 1)[-1] for prop in config.property_classes)
        )
    return property_classes, property_names

Returns a tuple of property classes and names .


def _determine_function_name_type(node, config=None):
    """Determine the name type whose regex the a function's name should match.

    :param node: A function node.
    :type node: astroid.node_classes.NodeNG
    :param config: Configuration from which to pull additional property classes.
    :type config: :class:`optparse.Values`

    :returns: One of ('function', 'method', 'attr')
    :rtype: str
    """
    property_classes, property_names = _get_properties(config)
    if not node.is_method():
        return "function"
    if node.decorators:
        decorators = node.decorators.nodes
    else:
        decorators = []
    for decorator in decorators:
        # If the function is a property (decorated with @property
        # or @abc.abstractproperty), the name type is 'attr'.
        if isinstance(decorator, astroid.Name) or (
            isinstance(decorator, astroid.Attribute)
            and decorator.attrname in property_names
        ):
            infered = utils.safe_infer(decorator)
            if infered and infered.qname() in property_classes:
                return "attr"
        # If the function is decorated using the prop_method.{setter,getter}
        # form, treat it like an attribute as well.
        elif isinstance(decorator, astroid.Attribute) and decorator.attrname in (
            "setter",
            "deleter",
        ):
            return "attr"
    return "method"

Determine the name type whose regex the a function s name should match .


def report_by_type_stats(sect, stats, _):
    """make a report of

    * percentage of different types documented
    * percentage of different types with a bad name
    """
    # percentage of different types documented and/or with a bad name
    nice_stats = {}
    for node_type in ("module", "class", "method", "function"):
        try:
            total = stats[node_type]
        except KeyError:
            raise exceptions.EmptyReportError()
        nice_stats[node_type] = {}
        if total != 0:
            try:
                documented = total - stats["undocumented_" + node_type]
                percent = (documented * 100.0) / total
                nice_stats[node_type]["percent_documented"] = "%.2f" % percent
            except KeyError:
                nice_stats[node_type]["percent_documented"] = "NC"
            try:
                percent = (stats["badname_" + node_type] * 100.0) / total
                nice_stats[node_type]["percent_badname"] = "%.2f" % percent
            except KeyError:
                nice_stats[node_type]["percent_badname"] = "NC"
    lines = ("type", "number", "old number", "difference", "%documented", "%badname")
    for node_type in ("module", "class", "method", "function"):
        new = stats[node_type]
        lines += (
            node_type,
            str(new),
            "NC",
            "NC",
            nice_stats[node_type].get("percent_documented", "0"),
            nice_stats[node_type].get("percent_badname", "0"),
        )
    sect.append(reporter_nodes.Table(children=lines, cols=6, rheaders=1))


def redefined_by_decorator(node):
    """return True if the object is a method redefined via decorator.

    For example:
        @property
        def x(self): return self._x
        @x.setter
        def x(self, value): self._x = value
    """
    if node.decorators:
        for decorator in node.decorators.nodes:
            if (
                isinstance(decorator, astroid.Attribute)
                and getattr(decorator.expr, "name", None) == node.name
            ):
                return True
    return False

def redefined_by_decorator ( node ) : if node . decorators : for decorator in node . decorators . nodes : if ( isinstance ( decorator , astroid . Attribute ) and getattr ( decorator . expr , "name" , None ) == node . name ) : return True return False

return True if the object is a method redefined via decorator .


def _is_one_arg_pos_call(call):
    """Is this a call with exactly 1 argument,
    where that argument is positional?
    """
    return isinstance(call, astroid.Call) and len(call.args) == 1 and not call.keywords

def _is_one_arg_pos_call ( call ) : return isinstance ( call , astroid . Call ) and len ( call . args ) == 1 and not call . keywords

Is this a call with exactly 1 argument where that argument is positional?


def visit_starred(self, node):
        """Check that a Starred expression is used in an assignment target."""
        if isinstance(node.parent, astroid.Call):
            # f(*args) is converted to Call(args=[Starred]), so ignore
            # them for this check.
            return
        if PY35 and isinstance(
            node.parent, (astroid.List, astroid.Tuple, astroid.Set, astroid.Dict)
        ):
            # PEP 448 unpacking.
            return

        stmt = node.statement()
        if not isinstance(stmt, astroid.Assign):
            return

        if stmt.value is node or stmt.value.parent_of(node):
            self.add_message("star-needs-assignment-target", node=node)

Check that a Starred expression is used in an assignment target .


def _check_nonlocal_and_global(self, node):
        """Check that a name is both nonlocal and global."""

        def same_scope(current):
            return current.scope() is node

        from_iter = itertools.chain.from_iterable
        nonlocals = set(
            from_iter(
                child.names
                for child in node.nodes_of_class(astroid.Nonlocal)
                if same_scope(child)
            )
        )

        if not nonlocals:
            return

        global_vars = set(
            from_iter(
                child.names
                for child in node.nodes_of_class(astroid.Global)
                if same_scope(child)
            )
        )
        for name in nonlocals.intersection(global_vars):
            self.add_message("nonlocal-and-global", args=(name,), node=node)

def _check_nonlocal_and_global ( self , node ) : def same_scope ( current ) : return current . scope ( ) is node from_iter = itertools . chain . from_iterable nonlocals = set ( from_iter ( child . names for child in node . nodes_of_class ( astroid . Nonlocal ) if same_scope ( child ) ) ) if not nonlocals : return global_vars = set ( from_iter ( child . names for child in node . nodes_of_class ( astroid . Global ) if same_scope ( child ) ) ) for name in nonlocals . intersection ( global_vars ) : self . add_message ( "nonlocal-and-global" , args = ( name , ) , node = node )

Check that a name is both nonlocal and global .


def visit_call(self, node):
        """ Check instantiating abstract class with
        abc.ABCMeta as metaclass.
        """
        try:
            for inferred in node.func.infer():
                self._check_inferred_class_is_abstract(inferred, node)
        except astroid.InferenceError:
            return

def visit_call ( self , node ) : try : for inferred in node . func . infer ( ) : self . _check_inferred_class_is_abstract ( inferred , node ) except astroid . InferenceError : return

Check instantiating abstract class with abc . ABCMeta as metaclass .


def _check_else_on_loop(self, node):
        """Check that any loop with an else clause has a break statement."""
        if node.orelse and not _loop_exits_early(node):
            self.add_message(
                "useless-else-on-loop",
                node=node,
                # This is not optimal, but the line previous
                # to the first statement in the else clause
                # will usually be the one that contains the else:.
                line=node.orelse[0].lineno - 1,
            )

Check that any loop with an else clause has a break statement .


def _check_in_loop(self, node, node_name):
        """check that a node is inside a for or while loop"""
        _node = node.parent
        while _node:
            if isinstance(_node, (astroid.For, astroid.While)):
                if node not in _node.orelse:
                    return

            if isinstance(_node, (astroid.ClassDef, astroid.FunctionDef)):
                break
            if (
                isinstance(_node, astroid.TryFinally)
                and node in _node.finalbody
                and isinstance(node, astroid.Continue)
            ):
                self.add_message("continue-in-finally", node=node)

            _node = _node.parent

        self.add_message("not-in-loop", node=node, args=node_name)

def _check_in_loop ( self , node , node_name ) : _node = node . parent while _node : if isinstance ( _node , ( astroid . For , astroid . While ) ) : if node not in _node . orelse : return if isinstance ( _node , ( astroid . ClassDef , astroid . FunctionDef ) ) : break if ( isinstance ( _node , astroid . TryFinally ) and node in _node . finalbody and isinstance ( node , astroid . Continue ) ) : self . add_message ( "continue-in-finally" , node = node ) _node = _node . parent self . add_message ( "not-in-loop" , node = node , args = node_name )


def open(self):
        """initialize visit variables and statistics
        """
        self._tryfinallys = []
        self.stats = self.linter.add_stats(module=0, function=0, method=0, class_=0)

def open ( self ) : self . _tryfinallys = [ ] self . stats = self . linter . add_stats ( module = 0 , function = 0 , method = 0 , class_ = 0 )


def visit_expr(self, node):
        """check for various kind of statements without effect"""
        expr = node.value
        if isinstance(expr, astroid.Const) and isinstance(expr.value, str):
            # treat string statement in a separated message
            # Handle PEP-257 attribute docstrings.
            # An attribute docstring is defined as being a string right after
            # an assignment at the module level, class level or __init__ level.
            scope = expr.scope()
            if isinstance(
                scope, (astroid.ClassDef, astroid.Module, astroid.FunctionDef)
            ):
                if isinstance(scope, astroid.FunctionDef) and scope.name != "__init__":
                    pass
                else:
                    sibling = expr.previous_sibling()
                    if (
                        sibling is not None
                        and sibling.scope() is scope
                        and isinstance(sibling, (astroid.Assign, astroid.AnnAssign))
                    ):
                        return
            self.add_message("pointless-string-statement", node=node)
            return

        # Ignore if this is :
        # * a direct function call
        # * the unique child of a try/except body
        # * a yieldd statement
        # * an ellipsis (which can be used on Python 3 instead of pass)
        # warn W0106 if we have any underlying function call (we can't predict
        # side effects), else pointless-statement
        if isinstance(
            expr, (astroid.Yield, astroid.Await, astroid.Ellipsis, astroid.Call)
        ) or (
            isinstance(node.parent, astroid.TryExcept) and node.parent.body == [node]
        ):
            return
        if any(expr.nodes_of_class(astroid.Call)):
            self.add_message(
                "expression-not-assigned", node=node, args=expr.as_string()
            )
        else:
            self.add_message("pointless-statement", node=node)


def visit_lambda(self, node):
        """check whether or not the lambda is suspicious
        """
        # if the body of the lambda is a call expression with the same
        # argument list as the lambda itself, then the lambda is
        # possibly unnecessary and at least suspicious.
        if node.args.defaults:
            # If the arguments of the lambda include defaults, then a
            # judgment cannot be made because there is no way to check
            # that the defaults defined by the lambda are the same as
            # the defaults defined by the function called in the body
            # of the lambda.
            return
        call = node.body
        if not isinstance(call, astroid.Call):
            # The body of the lambda must be a function call expression
            # for the lambda to be unnecessary.
            return
        if isinstance(node.body.func, astroid.Attribute) and isinstance(
            node.body.func.expr, astroid.Call
        ):
            # Chained call, the intermediate call might
            # return something else (but we don't check that, yet).
            return

        call_site = CallSite.from_call(call)
        ordinary_args = list(node.args.args)
        new_call_args = list(self._filter_vararg(node, call.args))
        if node.args.kwarg:
            if self._has_variadic_argument(call.kwargs, node.args.kwarg):
                return

        if node.args.vararg:
            if self._has_variadic_argument(call.starargs, node.args.vararg):
                return
        elif call.starargs:
            return

        if call.keywords:
            # Look for additional keyword arguments that are not part
            # of the lambda's signature
            lambda_kwargs = {keyword.name for keyword in node.args.defaults}
            if len(lambda_kwargs) != len(call_site.keyword_arguments):
                # Different lengths, so probably not identical
                return
            if set(call_site.keyword_arguments).difference(lambda_kwargs):
                return

        # The "ordinary" arguments must be in a correspondence such that:
        # ordinary_args[i].name == call.args[i].name.
        if len(ordinary_args) != len(new_call_args):
            return
        for arg, passed_arg in zip(ordinary_args, new_call_args):
            if not isinstance(passed_arg, astroid.Name):
                return
            if arg.name != passed_arg.name:
                return

        self.add_message("unnecessary-lambda", line=node.fromlineno, node=node)


def visit_assert(self, node):
        """check the use of an assert statement on a tuple."""
        if (
            node.fail is None
            and isinstance(node.test, astroid.Tuple)
            and len(node.test.elts) == 2
        ):
            self.add_message("assert-on-tuple", node=node)

def visit_assert ( self , node ) : if ( node . fail is None and isinstance ( node . test , astroid . Tuple ) and len ( node . test . elts ) == 2 ) : self . add_message ( "assert-on-tuple" , node = node )

check the use of an assert statement on a tuple .


def visit_dict(self, node):
        """check duplicate key in dictionary"""
        keys = set()
        for k, _ in node.items:
            if isinstance(k, astroid.Const):
                key = k.value
                if key in keys:
                    self.add_message("duplicate-key", node=node, args=key)
                keys.add(key)

def visit_dict ( self , node ) : keys = set ( ) for k , _ in node . items : if isinstance ( k , astroid . Const ) : key = k . value if key in keys : self . add_message ( "duplicate-key" , node = node , args = key ) keys . add ( key )


def _check_unreachable(self, node):
        """check unreachable code"""
        unreach_stmt = node.next_sibling()
        if unreach_stmt is not None:
            self.add_message("unreachable", node=unreach_stmt)

def _check_unreachable ( self , node ) : unreach_stmt = node . next_sibling ( ) if unreach_stmt is not None : self . add_message ( "unreachable" , node = unreach_stmt )


def _check_not_in_finally(self, node, node_name, breaker_classes=()):
        """check that a node is not inside a finally clause of a
        try...finally statement.
        If we found before a try...finally bloc a parent which its type is
        in breaker_classes, we skip the whole check."""
        # if self._tryfinallys is empty, we're not an in try...finally block
        if not self._tryfinallys:
            return
        # the node could be a grand-grand...-children of the try...finally
        _parent = node.parent
        _node = node
        while _parent and not isinstance(_parent, breaker_classes):
            if hasattr(_parent, "finalbody") and _node in _parent.finalbody:
                self.add_message("lost-exception", node=node, args=node_name)
                return
            _node = _parent
            _parent = _node.parent

check that a node is not inside a finally clause of a try ... finally statement . If we found before a try ... finally bloc a parent which its type is in breaker_classes we skip the whole check .


def _check_reversed(self, node):
        """ check that the argument to `reversed` is a sequence """
        try:
            argument = utils.safe_infer(utils.get_argument_from_call(node, position=0))
        except utils.NoSuchArgumentError:
            pass
        else:
            if argument is astroid.Uninferable:
                return
            if argument is None:
                # Nothing was infered.
                # Try to see if we have iter().
                if isinstance(node.args[0], astroid.Call):
                    try:
                        func = next(node.args[0].func.infer())
                    except astroid.InferenceError:
                        return
                    if getattr(
                        func, "name", None
                    ) == "iter" and utils.is_builtin_object(func):
                        self.add_message("bad-reversed-sequence", node=node)
                return

            if isinstance(argument, (astroid.List, astroid.Tuple)):
                return

            if isinstance(argument, astroid.Instance):
                if argument._proxied.name == "dict" and utils.is_builtin_object(
                    argument._proxied
                ):
                    self.add_message("bad-reversed-sequence", node=node)
                    return
                if any(
                    ancestor.name == "dict" and utils.is_builtin_object(ancestor)
                    for ancestor in argument._proxied.ancestors()
                ):
                    # Mappings aren't accepted by reversed(), unless
                    # they provide explicitly a __reversed__ method.
                    try:
                        argument.locals[REVERSED_PROTOCOL_METHOD]
                    except KeyError:
                        self.add_message("bad-reversed-sequence", node=node)
                    return

            if hasattr(argument, "getattr"):
                # everything else is not a proper sequence for reversed()
                for methods in REVERSED_METHODS:
                    for meth in methods:
                        try:
                            argument.getattr(meth)
                        except astroid.NotFoundError:
                            break
                    else:
                        break
                else:
                    self.add_message("bad-reversed-sequence", node=node)
            else:
                self.add_message("bad-reversed-sequence", node=node)

check that the argument to reversed is a sequence


def visit_assignname(self, node):
        """check module level assigned names"""
        self._check_assign_to_new_keyword_violation(node.name, node)
        frame = node.frame()
        assign_type = node.assign_type()
        if isinstance(assign_type, astroid.Comprehension):
            self._check_name("inlinevar", node.name, node)
        elif isinstance(frame, astroid.Module):
            if isinstance(assign_type, astroid.Assign) and not in_loop(assign_type):
                if isinstance(utils.safe_infer(assign_type.value), astroid.ClassDef):
                    self._check_name("class", node.name, node)
                else:
                    if not _redefines_import(node):
                        # Don't emit if the name redefines an import
                        # in an ImportError except handler.
                        self._check_name("const", node.name, node)
            elif isinstance(assign_type, astroid.ExceptHandler):
                self._check_name("variable", node.name, node)
        elif isinstance(frame, astroid.FunctionDef):
            # global introduced variable aren't in the function locals
            if node.name in frame and node.name not in frame.argnames():
                if not _redefines_import(node):
                    self._check_name("variable", node.name, node)
        elif isinstance(frame, astroid.ClassDef):
            if not list(frame.local_attr_ancestors(node.name)):
                self._check_name("class_attribute", node.name, node)


def _check_name(self, node_type, name, node, confidence=interfaces.HIGH):
        """check for a name using the type's regexp"""

        def _should_exempt_from_invalid_name(node):
            if node_type == "variable":
                inferred = utils.safe_infer(node)
                if isinstance(inferred, astroid.ClassDef):
                    return True
            return False

        if utils.is_inside_except(node):
            clobbering, _ = utils.clobber_in_except(node)
            if clobbering:
                return
        if name in self.config.good_names:
            return
        if name in self.config.bad_names:
            self.stats["badname_" + node_type] += 1
            self.add_message("blacklisted-name", node=node, args=name)
            return
        regexp = self._name_regexps[node_type]
        match = regexp.match(name)

        if _is_multi_naming_match(match, node_type, confidence):
            name_group = self._find_name_group(node_type)
            bad_name_group = self._bad_names.setdefault(name_group, {})
            warnings = bad_name_group.setdefault(match.lastgroup, [])
            warnings.append((node, node_type, name, confidence))

        if match is None and not _should_exempt_from_invalid_name(node):
            self._raise_name_warning(node, node_type, name, confidence)

def _check_name ( self , node_type , name , node , confidence = interfaces . HIGH ) : def _should_exempt_from_invalid_name ( node ) : if node_type == "variable" : inferred = utils . safe_infer ( node ) if isinstance ( inferred , astroid . ClassDef ) : return True return False if utils . is_inside_except ( node ) : clobbering , _ = utils . clobber_in_except ( node ) if clobbering : return if name in self . config . good_names : return if name in self . config . bad_names : self . stats [ "badname_" + node_type ] += 1 self . add_message ( "blacklisted-name" , node = node , args = name ) return regexp = self . _name_regexps [ node_type ] match = regexp . match ( name ) if _is_multi_naming_match ( match , node_type , confidence ) : name_group = self . _find_name_group ( node_type ) bad_name_group = self . _bad_names . setdefault ( name_group , { } ) warnings = bad_name_group . setdefault ( match . lastgroup , [ ] ) warnings . append ( ( node , node_type , name , confidence ) ) if match is None and not _should_exempt_from_invalid_name ( node ) : self . _raise_name_warning ( node , node_type , name , confidence )

check for a name using the type s regexp


def _check_docstring(
        self, node_type, node, report_missing=True, confidence=interfaces.HIGH
    ):
        """check the node has a non empty docstring"""
        docstring = node.doc
        if docstring is None:
            if not report_missing:
                return
            lines = utils.get_node_last_lineno(node) - node.lineno

            if node_type == "module" and not lines:
                # If the module has no body, there's no reason
                # to require a docstring.
                return
            max_lines = self.config.docstring_min_length

            if node_type != "module" and max_lines > -1 and lines < max_lines:
                return
            self.stats["undocumented_" + node_type] += 1
            if (
                node.body
                and isinstance(node.body[0], astroid.Expr)
                and isinstance(node.body[0].value, astroid.Call)
            ):
                # Most likely a string with a format call. Let's see.
                func = utils.safe_infer(node.body[0].value.func)
                if isinstance(func, astroid.BoundMethod) and isinstance(
                    func.bound, astroid.Instance
                ):
                    # Strings in Python 3, others in Python 2.
                    if PY3K and func.bound.name == "str":
                        return
                    if func.bound.name in ("str", "unicode", "bytes"):
                        return
            self.add_message(
                "missing-docstring", node=node, args=(node_type,), confidence=confidence
            )
        elif not docstring.strip():
            self.stats["undocumented_" + node_type] += 1
            self.add_message(
                "empty-docstring", node=node, args=(node_type,), confidence=confidence
            )


def _check_literal_comparison(self, literal, node):
        """Check if we compare to a literal, which is usually what we do not want to do."""
        nodes = (astroid.List, astroid.Tuple, astroid.Dict, astroid.Set)
        is_other_literal = isinstance(literal, nodes)
        is_const = False
        if isinstance(literal, astroid.Const):
            if isinstance(literal.value, bool) or literal.value is None:
                # Not interested in this values.
                return
            is_const = isinstance(literal.value, (bytes, str, int, float))

        if is_const or is_other_literal:
            self.add_message("literal-comparison", node=node)

def
_check_literal_comparison
(
self
,
literal
,
node
)
:
nodes
=
(
astroid
.
List
,
astroid
.
Tuple
,
astroid
.
Dict
,
astroid
.
Set
)
is_other_literal
=
isinstance
(
literal
,
nodes
)
is_const
=
False
if
isinstance
(
literal
,
astroid
.
Const
)
:
if
isinstance
(
literal
.
value
,
bool
)
or
literal
.
value
is
:
# Not interested in this values.
return
is_const
=
isinstance
(
literal
.
value
,
(
bytes
,
str
,
int
,
float
)
)
if
is_const
or
is_other_literal
:
self
.
add_message
(
"literal-comparison"
,
node
=
node
)

Check if we compare to a literal which is usually what we do not want to do .


def _subgraph(self, node, name, extra_blocks=()):
        """create the subgraphs representing any `if` and `for` statements"""
        if self.graph is None:
            # global loop
            self.graph = PathGraph(node)
            self._subgraph_parse(node, node, extra_blocks)
            self.graphs["%s%s" % (self.classname, name)] = self.graph
            self.reset()
        else:
            self._append_node(node)
            self._subgraph_parse(node, node, extra_blocks)

def
_subgraph
(
self
,
node
,
name
,
extra_blocks
=
(
)
)
:
if
self
.
graph
is
:
# global loop
self
.
graph
=
PathGraph
(
node
)
self
.
_subgraph_parse
(
node
,
node
,
extra_blocks
)
self
.
graphs
[
"%s%s"
%
(
self
.
classname
,
name
)
]
=
self
.
graph
self
.
reset
(
)
else
:
self
.
_append_node
(
node
)
self
.
_subgraph_parse
(
node
,
node
,
extra_blocks
)

create the subgraphs representing any if and for statements


def _subgraph_parse(
        self, node, pathnode, extra_blocks
    ):  # pylint: disable=unused-argument
        """parse the body and any `else` block of `if` and `for` statements"""
        loose_ends = []
        self.tail = node
        self.dispatch_list(node.body)
        loose_ends.append(self.tail)
        for extra in extra_blocks:
            self.tail = node
            self.dispatch_list(extra.body)
            loose_ends.append(self.tail)
        if node.orelse:
            self.tail = node
            self.dispatch_list(node.orelse)
            loose_ends.append(self.tail)
        else:
            loose_ends.append(node)
        if node:
            bottom = "%s" % self._bottom_counter
            self._bottom_counter += 1
            for le in loose_ends:
                self.graph.connect(le, bottom)
            self.tail = bottom

def
_subgraph_parse
(
self
,
node
,
pathnode
,
extra_blocks
)
:
# pylint: disable=unused-argument
loose_ends
=
[
]
self
.
tail
=
node
self
.
dispatch_list
(
node
.
body
)
loose_ends
.
append
(
self
.
tail
)
for
extra
in
extra_blocks
:
self
.
tail
=
node
self
.
dispatch_list
(
extra
.
body
)
loose_ends
.
append
(
self
.
tail
)
if
node
.
orelse
:
self
.
tail
=
node
self
.
dispatch_list
(
node
.
orelse
)
loose_ends
.
append
(
self
.
tail
)
else
:
loose_ends
.
append
(
node
)
if
node
:
bottom
=
"%s"
%
self
.
_bottom_counter
self
.
_bottom_counter
+=
1
for
le
in
loose_ends
:
self
.
graph
.
connect
(
le
,
bottom
)
self
.
tail
=
bottom

parse the body and any else block of if and for statements


def visit_module(self, node):
        """visit an astroid.Module node to check too complex rating and
        add message if is greather than max_complexity stored from options"""
        visitor = PathGraphingAstVisitor()
        for child in node.body:
            visitor.preorder(child, visitor)
        for graph in visitor.graphs.values():
            complexity = graph.complexity()
            node = graph.root
            if hasattr(node, "name"):
                node_name = "'%s'" % node.name
            else:
                node_name = "This '%s'" % node.__class__.__name__.lower()
            if complexity <= self.config.max_complexity:
                continue
            self.add_message(
                "too-complex", node=node, confidence=HIGH, args=(node_name, complexity)
            )

def
visit_module
(
self
,
node
)
:
visitor
=
PathGraphingAstVisitor
(
)
for
child
in
node
.
body
:
visitor
.
preorder
(
child
,
visitor
)
for
graph
in
visitor
.
graphs
.
values
(
)
:
complexity
=
graph
.
complexity
(
)
node
=
graph
.
root
if
hasattr
(
node
,
"name"
)
:
node_name
=
"'%s'"
%
node
.
name
else
:
node_name
=
"This '%s'"
%
node
.
__class__
.
__name__
.
lower
(
)
if
complexity
<=
self
.
config
.
max_complexity
:
continue
self
.
add_message
(
"too-complex"
,
node
=
node
,
confidence
=
HIGH
,
args
=
(
node_name
,
complexity
)
)

visit an astroid . Module node to check too complex rating and add message if is greather than max_complexity stored from options


def add_checker(self, checker):
        """walk to the checker's dir and collect visit and leave methods"""
        # XXX : should be possible to merge needed_checkers and add_checker
        vcids = set()
        lcids = set()
        visits = self.visit_events
        leaves = self.leave_events
        for member in dir(checker):
            cid = member[6:]
            if cid == "default":
                continue
            if member.startswith("visit_"):
                v_meth = getattr(checker, member)
                # don't use visit_methods with no activated message:
                if self._is_method_enabled(v_meth):
                    visits[cid].append(v_meth)
                    vcids.add(cid)
            elif member.startswith("leave_"):
                l_meth = getattr(checker, member)
                # don't use leave_methods with no activated message:
                if self._is_method_enabled(l_meth):
                    leaves[cid].append(l_meth)
                    lcids.add(cid)
        visit_default = getattr(checker, "visit_default", None)
        if visit_default:
            for cls in nodes.ALL_NODE_CLASSES:
                cid = cls.__name__.lower()
                if cid not in vcids:
                    visits[cid].append(visit_default)

walk to the checker s dir and collect visit and leave methods


def walk(self, astroid):
        """call visit events of astroid checkers for the given node, recurse on
        its children, then leave events.
        """
        cid = astroid.__class__.__name__.lower()

        # Detect if the node is a new name for a deprecated alias.
        # In this case, favour the methods for the deprecated
        # alias if any,  in order to maintain backwards
        # compatibility.
        visit_events = self.visit_events.get(cid, ())
        leave_events = self.leave_events.get(cid, ())

        if astroid.is_statement:
            self.nbstatements += 1
        # generate events for this node on each checker
        for cb in visit_events or ():
            cb(astroid)
        # recurse on children
        for child in astroid.get_children():
            self.walk(child)
        for cb in leave_events or ():
            cb(astroid)

call visit events of astroid checkers for the given node recurse on its children then leave events .


def add_relationship(self, from_object, to_object, relation_type, name=None):
        """create a relation ship
        """
        rel = Relationship(from_object, to_object, relation_type, name)
        self.relationships.setdefault(relation_type, []).append(rel)

def add_relationship ( self , from_object , to_object , relation_type , name = None ) : rel = Relationship ( from_object , to_object , relation_type , name ) self . relationships . setdefault ( relation_type , [ ] ) . append ( rel )


def get_relationship(self, from_object, relation_type):
        """return a relation ship or None
        """
        for rel in self.relationships.get(relation_type, ()):
            if rel.from_object is from_object:
                return rel
        raise KeyError(relation_type)

def get_relationship ( self , from_object , relation_type ) : for rel in self . relationships . get ( relation_type , ( ) ) : if rel . from_object is from_object : return rel raise KeyError ( relation_type )


def get_attrs(self, node):
        """return visible attributes, possibly with class name"""
        attrs = []
        properties = [
            (n, m)
            for n, m in node.items()
            if isinstance(m, astroid.FunctionDef) and decorated_with_property(m)
        ]
        for node_name, associated_nodes in (
            list(node.instance_attrs_type.items())
            + list(node.locals_type.items())
            + properties
        ):
            if not self.show_attr(node_name):
                continue
            names = self.class_names(associated_nodes)
            if names:
                node_name = "%s : %s" % (node_name, ", ".join(names))
            attrs.append(node_name)
        return sorted(attrs)

def
get_attrs
(
self
,
node
)
:
attrs
=
[
]
properties
=
[
(
n
,
m
)
for
n
,
m
in
node
.
items
(
)
if
isinstance
(
m
,
astroid
.
FunctionDef
)
and
decorated_with_property
(
m
)
]
for
node_name
,
associated_nodes
in
(
list
(
node
.
instance_attrs_type
.
items
(
)
)
+
list
(
node
.
locals_type
.
items
(
)
)
+
properties
)
:
if
not
self
.
show_attr
(
node_name
)
:
continue
names
=
self
.
class_names
(
associated_nodes
)
if
names
:
node_name
=
"%s : %s"
%
(
node_name
,
", "
.
join
(
names
)
)
attrs
.
append
(
node_name
)
return
sorted
(
attrs
)

return visible attributes possibly with class name


def get_methods(self, node):
        """return visible methods"""
        methods = [
            m
            for m in node.values()
            if isinstance(m, astroid.FunctionDef)
            and not decorated_with_property(m)
            and self.show_attr(m.name)
        ]
        return sorted(methods, key=lambda n: n.name)

def get_methods ( self , node ) : methods = [ m for m in node . values ( ) if isinstance ( m , astroid . FunctionDef ) and not decorated_with_property ( m ) and self . show_attr ( m . name ) ] return sorted ( methods , key = lambda n : n . name )