def _check_accessed_members(self, node, accessed):
        """check that accessed members are defined"""
        # XXX refactor, probably much simpler now that E0201 is in type checker
        excs = ("AttributeError", "Exception", "BaseException")
        for attr, nodes in accessed.items():
            try:
                # is it a class attribute ?
                node.local_attr(attr)
                # yes, stop here
                continue
            except astroid.NotFoundError:
                pass
            # is it an instance attribute of a parent class ?
            try:
                next(node.instance_attr_ancestors(attr))
                # yes, stop here
                continue
            except StopIteration:
                pass
            # is it an instance attribute ?
            try:
                defstmts = node.instance_attr(attr)
            except astroid.NotFoundError:
                pass
            else:
                # filter out augment assignment nodes
                defstmts = [stmt for stmt in defstmts if stmt not in nodes]
                if not defstmts:
                    # only augment assignment for this node, no-member should be
                    # triggered by the typecheck checker
                    continue
                # filter defstmts to only pick the first one when there are
                # several assignments in the same scope
                scope = defstmts[0].scope()
                defstmts = [
                    stmt
                    for i, stmt in enumerate(defstmts)
                    if i == 0 or stmt.scope() is not scope
                ]
                # if there are still more than one, don't attempt to be smarter
                # than we can be
                if len(defstmts) == 1:
                    defstmt = defstmts[0]
                    # check that if the node is accessed in the same method as
                    # it's defined, it's accessed after the initial assignment
                    frame = defstmt.frame()
                    lno = defstmt.fromlineno
                    for _node in nodes:
                        if (
                            _node.frame() is frame
                            and _node.fromlineno < lno
                            and not astroid.are_exclusive(
                                _node.statement(), defstmt, excs
                            )
                        ):
                            self.add_message(
                                "access-member-before-definition",
                                node=_node,
                                args=(attr, lno),
                            )

def _check_accessed_members ( self , node , accessed ) : excs = ( "AttributeError" , "Exception" , "BaseException" ) for attr , nodes in accessed . items ( ) : try : node . local_attr ( attr ) continue except astroid . NotFoundError : pass try : next ( node . instance_attr_ancestors ( attr ) ) continue except StopIteration : pass try : defstmts = node . instance_attr ( attr ) except astroid . NotFoundError : pass else : defstmts = [ stmt for stmt in defstmts if stmt not in nodes ] if not defstmts : continue scope = defstmts [ 0 ] . scope ( ) defstmts = [ stmt for i , stmt in enumerate ( defstmts ) if i == 0 or stmt . scope ( ) is not scope ] if len ( defstmts ) == 1 : defstmt = defstmts [ 0 ] frame = defstmt . frame ( ) lno = defstmt . fromlineno for _node in nodes : if ( _node . frame ( ) is frame and _node . fromlineno < lno and not astroid . are_exclusive ( _node . statement ( ) , defstmt , excs ) ) : self . add_message ( "access-member-before-definition" , node = _node , args = ( attr , lno ) , )


def _check_bases_classes(self, node):
        """check that the given class node implements abstract methods from
        base classes
        """

        def is_abstract(method):
            return method.is_abstract(pass_is_abstract=False)

        # check if this class abstract
        if class_is_abstract(node):
            return

        methods = sorted(
            unimplemented_abstract_methods(node, is_abstract).items(),
            key=lambda item: item[0],
        )
        for name, method in methods:
            owner = method.parent.frame()
            if owner is node:
                continue
            # owner is not this class, it must be a parent class
            # check that the ancestor's method is not abstract
            if name in node.locals:
                # it is redefined as an attribute or with a descriptor
                continue
            self.add_message("abstract-method", node=node, args=(name, owner.name))

def _check_bases_classes ( self , node ) : def is_abstract ( method ) : return method . is_abstract ( pass_is_abstract = False ) if class_is_abstract ( node ) : return methods = sorted ( unimplemented_abstract_methods ( node , is_abstract ) . items ( ) , key = lambda item : item [ 0 ] , ) for name , method in methods : owner = method . parent . frame ( ) if owner is node : continue if name in node . locals : continue self . add_message ( "abstract-method" , node = node , args = ( name , owner . name ) )


def _check_signature(self, method1, refmethod, class_type, cls):
        """check that the signature of the two given methods match
        """
        if not (
            isinstance(method1, astroid.FunctionDef)
            and isinstance(refmethod, astroid.FunctionDef)
        ):
            self.add_message(
                "method-check-failed", args=(method1, refmethod), node=method1
            )
            return

        instance = cls.instantiate_class()
        method1 = function_to_method(method1, instance)
        refmethod = function_to_method(refmethod, instance)

        # Don't care about functions with unknown argument (builtins).
        if method1.args.args is None or refmethod.args.args is None:
            return

        # Ignore private to class methods.
        if is_attr_private(method1.name):
            return
        # Ignore setters, they have an implicit extra argument,
        # which shouldn't be taken in consideration.
        if method1.decorators:
            for decorator in method1.decorators.nodes:
                if (
                    isinstance(decorator, astroid.Attribute)
                    and decorator.attrname == "setter"
                ):
                    return

        if _different_parameters(
            refmethod, method1, dummy_parameter_regex=self._dummy_rgx
        ):
            self.add_message(
                "arguments-differ", args=(class_type, method1.name), node=method1
            )
        elif len(method1.args.defaults) < len(refmethod.args.defaults):
            self.add_message(
                "signature-differs", args=(class_type, method1.name), node=method1
            )

def _check_signature ( self , method1 , refmethod , class_type , cls ) : if not ( isinstance ( method1 , astroid . FunctionDef ) and isinstance ( refmethod , astroid . FunctionDef ) ) : self . add_message ( "method-check-failed" , args = ( method1 , refmethod ) , node = method1 ) return instance = cls . instantiate_class ( ) method1 = function_to_method ( method1 , instance ) refmethod = function_to_method ( refmethod , instance ) if method1 . args . args is None or refmethod . args . args is None : return if is_attr_private ( method1 . name ) : return if method1 . decorators : for decorator in method1 . decorators . nodes : if ( isinstance ( decorator , astroid . Attribute ) and decorator . attrname == "setter" ) : return if _different_parameters ( refmethod , method1 , dummy_parameter_regex = self . _dummy_rgx ) : self . add_message ( "arguments-differ" , args = ( class_type , method1 . name ) , node = method1 ) elif len ( method1 . args . defaults ) < len ( refmethod . args . defaults ) : self . add_message ( "signature-differs" , args = ( class_type , method1 . name ) , node = method1 )


def _is_mandatory_method_param(self, node):
        """Check if astroid.Name corresponds to first attribute variable name

        Name is `self` for method, `cls` for classmethod and `mcs` for metaclass.
        """
        return (
            self._first_attrs
            and isinstance(node, astroid.Name)
            and node.name == self._first_attrs[-1]
        )

def _is_mandatory_method_param ( self , node ) : return ( self . _first_attrs and isinstance ( node , astroid . Name ) and node . name == self . _first_attrs [ - 1 ] )

Check if astroid . Name corresponds to first attribute variable name


def _is_raising(body: typing.List) -> bool:
    """Return true if the given statement node raise an exception"""
    for node in body:
        if isinstance(node, astroid.Raise):
            return True
    return False

def _is_raising ( body : typing . List ) -> bool : for node in body : if isinstance ( node , astroid . Raise ) : return True return False


def _check_bad_exception_context(self, node):
        """Verify that the exception context is properly set.

        An exception context can be only `None` or an exception.
        """
        cause = utils.safe_infer(node.cause)
        if cause in (astroid.Uninferable, None):
            return

        if isinstance(cause, astroid.Const):
            if cause.value is not None:
                self.add_message("bad-exception-context", node=node)
        elif not isinstance(cause, astroid.ClassDef) and not utils.inherit_from_std_ex(
            cause
        ):
            self.add_message("bad-exception-context", node=node)

def _check_bad_exception_context ( self , node ) : cause = utils . safe_infer ( node . cause ) if cause in ( astroid . Uninferable , None ) : return if isinstance ( cause , astroid . Const ) : if cause . value is not None : self . add_message ( "bad-exception-context" , node = node ) elif not isinstance ( cause , astroid . ClassDef ) and not utils . inherit_from_std_ex ( cause ) : self . add_message ( "bad-exception-context" , node = node )

Verify that the exception context is properly set .


def visit_functiondef(self, node):
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(astroid.Call):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue

            expr = stmt.func
            if not isinstance(expr, astroid.Attribute):
                continue

            call = expr.expr
            # skip the test if using super
            if not (
                isinstance(call, astroid.Call)
                and isinstance(call.func, astroid.Name)
                and call.func.name == "super"
            ):
                continue

            if not klass.newstyle and has_known_bases(klass):
                # super should not be used on an old style class
                continue
            else:
                # super first arg should be the class
                if not call.args:
                    if sys.version_info[0] == 3:
                        # unless Python 3
                        continue
                    else:
                        self.add_message("missing-super-argument", node=call)
                        continue

                # calling super(type(self), self) can lead to recursion loop
                # in derived classes
                arg0 = call.args[0]
                if (
                    isinstance(arg0, astroid.Call)
                    and isinstance(arg0.func, astroid.Name)
                    and arg0.func.name == "type"
                ):
                    self.add_message("bad-super-call", node=call, args=("type",))
                    continue

                # calling super(self.__class__, self) can lead to recursion loop
                # in derived classes
                if (
                    len(call.args) >= 2
                    and isinstance(call.args[1], astroid.Name)
                    and call.args[1].name == "self"
                    and isinstance(arg0, astroid.Attribute)
                    and arg0.attrname == "__class__"
                ):
                    self.add_message(
                        "bad-super-call", node=call, args=("self.__class__",)
                    )
                    continue

                try:
                    supcls = call.args and next(call.args[0].infer(), None)
                except astroid.InferenceError:
                    continue

                if klass is not supcls:
                    name = None
                    # if supcls is not Uninferable, then supcls was infered
                    # and use its name. Otherwise, try to look
                    # for call.args[0].name
                    if supcls:
                        name = supcls.name
                    elif call.args and hasattr(call.args[0], "name"):
                        name = call.args[0].name
                    if name:
                        self.add_message("bad-super-call", node=call, args=(name,))

def visit_functiondef ( self , node ) : if not node . is_method ( ) : return klass = node . parent . frame ( ) for stmt in node . nodes_of_class ( astroid . Call ) : if node_frame_class ( stmt ) != node_frame_class ( node ) : continue expr = stmt . func if not isinstance ( expr , astroid . Attribute ) : continue call = expr . expr if not ( isinstance ( call , astroid . Call ) and isinstance ( call . func , astroid . Name ) and call . func . name == "super" ) : continue if not klass . newstyle and has_known_bases ( klass ) : continue else : if not call . args : if sys . version_info [ 0 ] == 3 : continue else : self . add_message ( "missing-super-argument" , node = call ) continue arg0 = call . args [ 0 ] if ( isinstance ( arg0 , astroid . Call ) and isinstance ( arg0 . func , astroid . Name ) and arg0 . func . name == "type" ) : self . add_message ( "bad-super-call" , node = call , args = ( "type" , ) ) continue if ( len ( call . args ) >= 2 and isinstance ( call . args [ 1 ] , astroid . Name ) and call . args [ 1 ] . name == "self" and isinstance ( arg0 , astroid . Attribute ) and arg0 . attrname == "__class__" ) : self . add_message ( "bad-super-call" , node = call , args = ( "self.__class__" , ) ) continue try : supcls = call . args and next ( call . args [ 0 ] . infer ( ) , None ) except astroid . InferenceError : continue if klass is not supcls : name = None if supcls : name = supcls . name elif call . args and hasattr ( call . args [ 0 ] , "name" ) : name = call . args [ 0 ] . name if name : self . add_message ( "bad-super-call" , node = call , args = ( name , ) )


def display_reports(self, layout):
        """display results encapsulated in the layout tree"""
        self.section = 0
        if hasattr(layout, "report_id"):
            layout.children[0].children[0].data += " (%s)" % layout.report_id
        self._display(layout)

def
display_reports
(
self
,
layout
)
:
self
.
section
=
0
if
hasattr
(
layout
,
"report_id"
)
:
layout
.
children
[
0
]
.
children
[
0
]
.
data
+=
" (%s)"
%
layout
.
report_id
self
.
_display
(
layout
)


def _is_typing_namedtuple(node: astroid.ClassDef) -> bool:
    """Check if a class node is a typing.NamedTuple class"""
    for base in node.ancestors():
        if base.qname() == TYPING_NAMEDTUPLE:
            return True
    return False

def _is_typing_namedtuple ( node : astroid . ClassDef ) -> bool : for base in node . ancestors ( ) : if base . qname ( ) == TYPING_NAMEDTUPLE : return True return False

Check if a class node is a typing . NamedTuple class


def _is_enum_class(node: astroid.ClassDef) -> bool:
    """Check if a class definition defines an Enum class.

    :param node: The class node to check.
    :type node: astroid.ClassDef

    :returns: True if the given node represents an Enum class. False otherwise.
    :rtype: bool
    """
    for base in node.bases:
        try:
            inferred_bases = base.inferred()
        except astroid.InferenceError:
            continue

        for ancestor in inferred_bases:
            if not isinstance(ancestor, astroid.ClassDef):
                continue

            if ancestor.name == "Enum" and ancestor.root().name == "enum":
                return True

    return False

def _is_enum_class ( node : astroid . ClassDef ) -> bool : for base in node . bases : try : inferred_bases = base . inferred ( ) except astroid . InferenceError : continue for ancestor in inferred_bases : if not isinstance ( ancestor , astroid . ClassDef ) : continue if ancestor . name == "Enum" and ancestor . root ( ) . name == "enum" : return True return False

Check if a class definition defines an Enum class .


def _is_dataclass(node: astroid.ClassDef) -> bool:
    """Check if a class definition defines a Python 3.7+ dataclass

    :param node: The class node to check.
    :type node: astroid.ClassDef

    :returns: True if the given node represents a dataclass class. False otherwise.
    :rtype: bool
    """
    if not node.decorators:
        return False

    root_locals = node.root().locals
    for decorator in node.decorators.nodes:
        if isinstance(decorator, astroid.Call):
            decorator = decorator.func
        if not isinstance(decorator, (astroid.Name, astroid.Attribute)):
            continue
        if isinstance(decorator, astroid.Name):
            name = decorator.name
        else:
            name = decorator.attrname
        if name == DATACLASS_DECORATOR and DATACLASS_DECORATOR in root_locals:
            return True
    return False

def _is_dataclass ( node : astroid . ClassDef ) -> bool : if not node . decorators : return False root_locals = node . root ( ) . locals for decorator in node . decorators . nodes : if isinstance ( decorator , astroid . Call ) : decorator = decorator . func if not isinstance ( decorator , ( astroid . Name , astroid . Attribute ) ) : continue if isinstance ( decorator , astroid . Name ) : name = decorator . name else : name = decorator . attrname if name == DATACLASS_DECORATOR and DATACLASS_DECORATOR in root_locals : return True return False

Check if a class definition defines a Python 3 . 7 + dataclass


def open(self):
        """initialize visit variables"""
        self.stats = self.linter.add_stats()
        self._returns = []
        self._branches = defaultdict(int)
        self._stmts = []

def open ( self ) : self . stats = self . linter . add_stats ( ) self . _returns = [ ] self . _branches = defaultdict ( int ) self . _stmts = [ ]


def visit_classdef(self, node):
        """check size of inheritance hierarchy and number of instance attributes
        """
        nb_parents = len(list(node.ancestors()))
        if nb_parents > self.config.max_parents:
            self.add_message(
                "too-many-ancestors",
                node=node,
                args=(nb_parents, self.config.max_parents),
            )

        if len(node.instance_attrs) > self.config.max_attributes:
            self.add_message(
                "too-many-instance-attributes",
                node=node,
                args=(len(node.instance_attrs), self.config.max_attributes),
            )

def visit_classdef ( self , node ) : nb_parents = len ( list ( node . ancestors ( ) ) ) if nb_parents > self . config . max_parents : self . add_message ( "too-many-ancestors" , node = node , args = ( nb_parents , self . config . max_parents ) , ) if len ( node . instance_attrs ) > self . config . max_attributes : self . add_message ( "too-many-instance-attributes" , node = node , args = ( len ( node . instance_attrs ) , self . config . max_attributes ) , )


def leave_classdef(self, node):
        """check number of public methods"""
        my_methods = sum(
            1 for method in node.mymethods() if not method.name.startswith("_")
        )

        # Does the class contain less than n public methods ?
        # This checks only the methods defined in the current class,
        # since the user might not have control over the classes
        # from the ancestors. It avoids some false positives
        # for classes such as unittest.TestCase, which provides
        # a lot of assert methods. It doesn't make sense to warn
        # when the user subclasses TestCase to add his own tests.
        if my_methods > self.config.max_public_methods:
            self.add_message(
                "too-many-public-methods",
                node=node,
                args=(my_methods, self.config.max_public_methods),
            )

        # Stop here for exception, metaclass, interface classes and other
        # classes for which we don't need to count the methods.
        if (
            node.type != "class"
            or _is_enum_class(node)
            or _is_dataclass(node)
            or _is_typing_namedtuple(node)
        ):
            return

        # Does the class contain more than n public methods ?
        # This checks all the methods defined by ancestors and
        # by the current class.
        all_methods = _count_methods_in_class(node)
        if all_methods < self.config.min_public_methods:
            self.add_message(
                "too-few-public-methods",
                node=node,
                args=(all_methods, self.config.min_public_methods),
            )

def leave_classdef ( self , node ) : my_methods = sum ( 1 for method in node . mymethods ( ) if not method . name . startswith ( "_" ) ) if my_methods > self . config . max_public_methods : self . add_message ( "too-many-public-methods" , node = node , args = ( my_methods , self . config . max_public_methods ) , ) if ( node . type != "class" or _is_enum_class ( node ) or _is_dataclass ( node ) or _is_typing_namedtuple ( node ) ) : return all_methods = _count_methods_in_class ( node ) if all_methods < self . config . min_public_methods : self . add_message ( "too-few-public-methods" , node = node , args = ( all_methods , self . config . min_public_methods ) , )


def visit_if(self, node):
        """increments the branches counter and checks boolean expressions"""
        self._check_boolean_expressions(node)
        branches = 1
        # don't double count If nodes coming from some 'elif'
        if node.orelse and (len(node.orelse) > 1 or not isinstance(node.orelse[0], If)):
            branches += 1
        self._inc_branch(node, branches)
        self._inc_all_stmts(branches)

def visit_if ( self , node ) : self . _check_boolean_expressions ( node ) branches = 1 if node . orelse and ( len ( node . orelse ) > 1 or not isinstance ( node . orelse [ 0 ] , If ) ) : branches += 1 self . _inc_branch ( node , branches ) self . _inc_all_stmts ( branches )


def _check_boolean_expressions(self, node):
        """Go through "if" node `node` and counts its boolean expressions

        if the "if" node test is a BoolOp node
        """
        condition = node.test
        if not isinstance(condition, BoolOp):
            return
        nb_bool_expr = _count_boolean_expressions(condition)
        if nb_bool_expr > self.config.max_bool_expr:
            self.add_message(
                "too-many-boolean-expressions",
                node=condition,
                args=(nb_bool_expr, self.config.max_bool_expr),
            )

def _check_boolean_expressions ( self , node ) : condition = node . test if not isinstance ( condition , BoolOp ) : return nb_bool_expr = _count_boolean_expressions ( condition ) if nb_bool_expr > self . config . max_bool_expr : self . add_message ( "too-many-boolean-expressions" , node = condition , args = ( nb_bool_expr , self . config . max_bool_expr ) , )

Go through if node node and counts its boolean expressions


def _check_docstring(self, node):
        """check the node has any spelling errors"""
        docstring = node.doc
        if not docstring:
            return

        start_line = node.lineno + 1

        # Go through lines of docstring
        for idx, line in enumerate(docstring.splitlines()):
            self._check_spelling("wrong-spelling-in-docstring", line, start_line + idx)

def _check_docstring ( self , node ) : docstring = node . doc if not docstring : return start_line = node . lineno + 1 for idx , line in enumerate ( docstring . splitlines ( ) ) : self . _check_spelling ( "wrong-spelling-in-docstring" , line , start_line + idx )


def format(self, template):
        """Format the message according to the given template.

        The template format is the one of the format method :
        cf. http://docs.python.org/2/library/string.html#formatstrings
        """
        # For some reason, _asdict on derived namedtuples does not work with
        # Python 3.4. Needs some investigation.
        return template.format(**dict(zip(self._fields, self)))

def format ( self , template ) : return template . format ( ** dict ( zip ( self . _fields , self ) ) )

Format the message according to the given template .


def _is_trailing_comma(tokens, index):
    """Check if the given token is a trailing comma

    :param tokens: Sequence of modules tokens
    :type tokens: list[tokenize.TokenInfo]
    :param int index: Index of token under check in tokens
    :returns: True if the token is a comma which trails an expression
    :rtype: bool
    """
    token = tokens[index]
    if token.exact_type != tokenize.COMMA:
        return False
    # Must have remaining tokens on the same line such as NEWLINE
    left_tokens = itertools.islice(tokens, index + 1, None)
    same_line_remaining_tokens = list(
        itertools.takewhile(
            lambda other_token, _token=token: other_token.start[0] == _token.start[0],
            left_tokens,
        )
    )
    # Note: If the newline is tokenize.NEWLINE and not tokenize.NL
    # then the newline denotes the end of expression
    is_last_element = all(
        other_token.type in (tokenize.NEWLINE, tokenize.COMMENT)
        for other_token in same_line_remaining_tokens
    )
    if not same_line_remaining_tokens or not is_last_element:
        return False

    def get_curline_index_start():
        """Get the index denoting the start of the current line"""
        for subindex, token in enumerate(reversed(tokens[:index])):
            # See Lib/tokenize.py and Lib/token.py in cpython for more info
            if token.type in (tokenize.NEWLINE, tokenize.NL):
                return index - subindex
        return 0

    curline_start = get_curline_index_start()
    expected_tokens = {"return", "yield"}
    for prevtoken in tokens[curline_start:index]:
        if "=" in prevtoken.string or prevtoken.string in expected_tokens:
            return True
    return False

def _is_trailing_comma ( tokens , index ) : token = tokens [ index ] if token . exact_type != tokenize . COMMA : return False left_tokens = itertools . islice ( tokens , index + 1 , None ) same_line_remaining_tokens = list ( itertools . takewhile ( lambda other_token , _token = token : other_token . start [ 0 ] == _token . start [ 0 ] , left_tokens , ) ) is_last_element = all ( other_token . type in ( tokenize . NEWLINE , tokenize . COMMENT ) for other_token in same_line_remaining_tokens ) if not same_line_remaining_tokens or not is_last_element : return False def get_curline_index_start ( ) : for subindex , token in enumerate ( reversed ( tokens [ : index ] ) ) : if token . type in ( tokenize . NEWLINE , tokenize . NL ) : return index - subindex return 0 curline_start = get_curline_index_start ( ) expected_tokens = { "return" , "yield" } for prevtoken in tokens [ curline_start : index ] : if "=" in prevtoken . string or prevtoken . string in expected_tokens : return True return False


def _is_actual_elif(self, node):
        """Check if the given node is an actual elif

        This is a problem we're having with the builtin ast module,
        which splits `elif` branches into a separate if statement.
        Unfortunately we need to know the exact type in certain
        cases.
        """
        if isinstance(node.parent, astroid.If):
            orelse = node.parent.orelse
            # current if node must directly follow an "else"
            if orelse and orelse == [node]:
                if (node.lineno, node.col_offset) in self._elifs:
                    return True
        return False

def _is_actual_elif ( self , node ) : if isinstance ( node . parent , astroid . If ) : orelse = node . parent . orelse if orelse and orelse == [ node ] : if ( node . lineno , node . col_offset ) in self . _elifs : return True return False


def _check_simplifiable_if(self, node):
        """Check if the given if node can be simplified.

        The if statement can be reduced to a boolean expression
        in some cases. For instance, if there are two branches
        and both of them return a boolean value that depends on
        the result of the statement's test, then this can be reduced
        to `bool(test)` without losing any functionality.
        """

        if self._is_actual_elif(node):
            # Not interested in if statements with multiple branches.
            return
        if len(node.orelse) != 1 or len(node.body) != 1:
            return

        # Check if both branches can be reduced.
        first_branch = node.body[0]
        else_branch = node.orelse[0]
        if isinstance(first_branch, astroid.Return):
            if not isinstance(else_branch, astroid.Return):
                return
            first_branch_is_bool = self._is_bool_const(first_branch)
            else_branch_is_bool = self._is_bool_const(else_branch)
            reduced_to = "'return bool(test)'"
        elif isinstance(first_branch, astroid.Assign):
            if not isinstance(else_branch, astroid.Assign):
                return

            # Check if we assign to the same value
            first_branch_targets = [
                target.name
                for target in first_branch.targets
                if isinstance(target, astroid.AssignName)
            ]
            else_branch_targets = [
                target.name
                for target in else_branch.targets
                if isinstance(target, astroid.AssignName)
            ]
            if not first_branch_targets or not else_branch_targets:
                return
            if sorted(first_branch_targets) != sorted(else_branch_targets):
                return

            first_branch_is_bool = self._is_bool_const(first_branch)
            else_branch_is_bool = self._is_bool_const(else_branch)
            reduced_to = "'var = bool(test)'"
        else:
            return

        if not first_branch_is_bool or not else_branch_is_bool:
            return
        if not first_branch.value.value:
            # This is a case that can't be easily simplified and
            # if it can be simplified, it will usually result in a
            # code that's harder to understand and comprehend.
            # Let's take for instance `arg and arg <= 3`. This could theoretically be
            # reduced to `not arg or arg > 3`, but the net result is that now the
            # condition is harder to understand, because it requires understanding of
            # an extra clause:
            #   * first, there is the negation of truthness with `not arg`
            #   * the second clause is `arg > 3`, which occurs when arg has a
            #     a truth value, but it implies that `arg > 3` is equivalent
            #     with `arg and arg > 3`, which means that the user must
            #     think about this assumption when evaluating `arg > 3`.
            #     The original form is easier to grasp.
            return

        self.add_message("simplifiable-if-statement", node=node, args=(reduced_to,))

def
_check_simplifiable_if
(
self
,
node
)
:
if
self
.
_is_actual_elif
(
node
)
:
return
if
len
(
node
.
orelse
)
!=
1
or
len
(
node
.
body
)
!=
1
:
return
first_branch
=
node
.
body
[
0
]
else_branch
=
node
.
orelse
[
0
]
if
isinstance
(
first_branch
,
astroid
.
Return
)
:
if
not
isinstance
(
else_branch
,
astroid
.
Return
)
:
return
first_branch_is_bool
=
self
.
_is_bool_const
(
first_branch
)
else_branch_is_bool
=
self
.
_is_bool_const
(
else_branch
)
reduced_to
=
"'return bool(test)'"
elif
isinstance
(
first_branch
,
astroid
.
Assign
)
:
if
not
isinstance
(
else_branch
,
astroid
.
Assign
)
:
return
first_branch_targets
=
[
target
.
name
for
target
in
first_branch
.
targets
if
isinstance
(
target
,
astroid
.
AssignName
)
]
else_branch_targets
=
[
target
.
name
for
target
in
else_branch
.
targets
if
isinstance
(
target
,
astroid
.
AssignName
)
]
if
not
first_branch_targets
or
not
else_branch_targets
:
return
if
sorted
(
first_branch_targets
)
!=
sorted
(
else_branch_targets
)
:
return
first_branch_is_bool
=
self
.
_is_bool_const
(
first_branch
)
else_branch_is_bool
=
self
.
_is_bool_const
(
else_branch
)
reduced_to
=
"'var = bool(test)'"
else
:
return
if
not
first_branch_is_bool
or
not
else_branch_is_bool
:
return
if
not
first_branch
.
value
.
value
:
return
self
.
add_message
(
"simplifiable-if-statement"
,
node
=
node
,
args
=
(
reduced_to
,
)
)

Check if the given if node can be simplified .


def _check_stop_iteration_inside_generator(self, node):
        """Check if an exception of type StopIteration is raised inside a generator"""
        frame = node.frame()
        if not isinstance(frame, astroid.FunctionDef) or not frame.is_generator():
            return
        if utils.node_ignores_exception(node, StopIteration):
            return
        if not node.exc:
            return
        exc = utils.safe_infer(node.exc)
        if exc is None or exc is astroid.Uninferable:
            return
        if self._check_exception_inherit_from_stopiteration(exc):
            self.add_message("stop-iteration-return", node=node)


def _check_exception_inherit_from_stopiteration(exc):
        """Return True if the exception node in argument inherit from StopIteration"""
        stopiteration_qname = "{}.StopIteration".format(utils.EXCEPTIONS_MODULE)
        return any(_class.qname() == stopiteration_qname for _class in exc.mro())


def _check_raising_stopiteration_in_generator_next_call(self, node):
        """Check if a StopIteration exception is raised by the call to next function

        If the next value has a default value, then do not add message.

        :param node: Check to see if this Call node is a next function
        :type node: :class:`astroid.node_classes.Call`
        """

        def _looks_like_infinite_iterator(param):
            inferred = utils.safe_infer(param)
            if inferred:
                return inferred.qname() in KNOWN_INFINITE_ITERATORS
            return False

        if isinstance(node.func, astroid.Attribute):
            # A next() method, which is now what we want.
            return

        inferred = utils.safe_infer(node.func)
        if getattr(inferred, "name", "") == "next":
            frame = node.frame()
            # The next builtin can only have up to two
            # positional arguments and no keyword arguments
            has_sentinel_value = len(node.args) > 1
            if (
                isinstance(frame, astroid.FunctionDef)
                and frame.is_generator()
                and not has_sentinel_value
                and not utils.node_ignores_exception(node, StopIteration)
                and not _looks_like_infinite_iterator(node.args[0])
            ):
                self.add_message("stop-iteration-return", node=node)


def _check_nested_blocks(self, node):
        """Update and check the number of nested blocks
        """
        # only check block levels inside functions or methods
        if not isinstance(node.scope(), astroid.FunctionDef):
            return
        # messages are triggered on leaving the nested block. Here we save the
        # stack in case the current node isn't nested in the previous one
        nested_blocks = self._nested_blocks[:]
        if node.parent == node.scope():
            self._nested_blocks = [node]
        else:
            # go through ancestors from the most nested to the less
            for ancestor_node in reversed(self._nested_blocks):
                if ancestor_node == node.parent:
                    break
                self._nested_blocks.pop()
            # if the node is an elif, this should not be another nesting level
            if isinstance(node, astroid.If) and self._is_actual_elif(node):
                if self._nested_blocks:
                    self._nested_blocks.pop()
            self._nested_blocks.append(node)

        # send message only once per group of nested blocks
        if len(nested_blocks) > len(self._nested_blocks):
            self._emit_nested_blocks_message_if_needed(nested_blocks)

def _check_nested_blocks ( self , node ) : if not isinstance ( node . scope ( ) , astroid . FunctionDef ) : return nested_blocks = self . _nested_blocks [ : ] if node . parent == node . scope ( ) : self . _nested_blocks = [ node ] else : for ancestor_node in reversed ( self . _nested_blocks ) : if ancestor_node == node . parent : break self . _nested_blocks . pop ( ) if isinstance ( node , astroid . If ) and self . _is_actual_elif ( node ) : if self . _nested_blocks : self . _nested_blocks . pop ( ) self . _nested_blocks . append ( node ) if len ( nested_blocks ) > len ( self . _nested_blocks ) : self . _emit_nested_blocks_message_if_needed ( nested_blocks )


def _duplicated_isinstance_types(node):
        """Get the duplicated types from the underlying isinstance calls.

        :param astroid.BoolOp node: Node which should contain a bunch of isinstance calls.
        :returns: Dictionary of the comparison objects from the isinstance calls,
                  to duplicate values from consecutive calls.
        :rtype: dict
        """
        duplicated_objects = set()
        all_types = collections.defaultdict(set)

        for call in node.values:
            if not isinstance(call, astroid.Call) or len(call.args) != 2:
                continue

            inferred = utils.safe_infer(call.func)
            if not inferred or not utils.is_builtin_object(inferred):
                continue

            if inferred.name != "isinstance":
                continue

            isinstance_object = call.args[0].as_string()
            isinstance_types = call.args[1]

            if isinstance_object in all_types:
                duplicated_objects.add(isinstance_object)

            if isinstance(isinstance_types, astroid.Tuple):
                elems = [
                    class_type.as_string() for class_type in isinstance_types.itered()
                ]
            else:
                elems = [isinstance_types.as_string()]
            all_types[isinstance_object].update(elems)

        # Remove all keys which not duplicated
        return {
            key: value for key, value in all_types.items() if key in duplicated_objects
        }

def _duplicated_isinstance_types ( node ) : duplicated_objects = set ( ) all_types = collections . defaultdict ( set ) for call in node . values : if not isinstance ( call , astroid . Call ) or len ( call . args ) != 2 : continue inferred = utils . safe_infer ( call . func ) if not inferred or not utils . is_builtin_object ( inferred ) : continue if inferred . name != "isinstance" : continue isinstance_object = call . args [ 0 ] . as_string ( ) isinstance_types = call . args [ 1 ] if isinstance_object in all_types : duplicated_objects . add ( isinstance_object ) if isinstance ( isinstance_types , astroid . Tuple ) : elems = [ class_type . as_string ( ) for class_type in isinstance_types . itered ( ) ] else : elems = [ isinstance_types . as_string ( ) ] all_types [ isinstance_object ] . update ( elems ) return { key : value for key , value in all_types . items ( ) if key in duplicated_objects }

Get the duplicated types from the underlying isinstance calls .


def _check_consider_merging_isinstance(self, node):
        """Check isinstance calls which can be merged together."""
        if node.op != "or":
            return

        first_args = self._duplicated_isinstance_types(node)
        for duplicated_name, class_names in first_args.items():
            names = sorted(name for name in class_names)
            self.add_message(
                "consider-merging-isinstance",
                node=node,
                args=(duplicated_name, ", ".join(names)),
            )

def
_check_consider_merging_isinstance
(
self
,
node
)
:
if
node
.
op
!=
"or"
:
return
first_args
=
self
.
_duplicated_isinstance_types
(
node
)
for
duplicated_name
,
class_names
in
first_args
.
items
(
)
:
names
=
sorted
(
name
for
name
in
class_names
)
self
.
add_message
(
"consider-merging-isinstance"
,
node
=
node
,
args
=
(
duplicated_name
,
", "
.
join
(
names
)
)
,
)

Check isinstance calls which can be merged together .


def _check_chained_comparison(self, node):
        """Check if there is any chained comparison in the expression.

        Add a refactoring message if a boolOp contains comparison like a < b and b < c,
        which can be chained as a < b < c.

        Care is taken to avoid simplifying a < b < c and b < d.
        """
        if node.op != "and" or len(node.values) < 2:
            return

        def _find_lower_upper_bounds(comparison_node, uses):
            left_operand = comparison_node.left
            for operator, right_operand in comparison_node.ops:
                for operand in (left_operand, right_operand):
                    value = None
                    if isinstance(operand, astroid.Name):
                        value = operand.name
                    elif isinstance(operand, astroid.Const):
                        value = operand.value

                    if value is None:
                        continue

                    if operator in ("<", "<="):
                        if operand is left_operand:
                            uses[value]["lower_bound"].add(comparison_node)
                        elif operand is right_operand:
                            uses[value]["upper_bound"].add(comparison_node)
                    elif operator in (">", ">="):
                        if operand is left_operand:
                            uses[value]["upper_bound"].add(comparison_node)
                        elif operand is right_operand:
                            uses[value]["lower_bound"].add(comparison_node)
                left_operand = right_operand

        uses = collections.defaultdict(
            lambda: {"lower_bound": set(), "upper_bound": set()}
        )
        for comparison_node in node.values:
            if isinstance(comparison_node, astroid.Compare):
                _find_lower_upper_bounds(comparison_node, uses)

        for _, bounds in uses.items():
            num_shared = len(bounds["lower_bound"].intersection(bounds["upper_bound"]))
            num_lower_bounds = len(bounds["lower_bound"])
            num_upper_bounds = len(bounds["upper_bound"])
            if num_shared < num_lower_bounds and num_shared < num_upper_bounds:
                self.add_message("chained-comparison", node=node)
                break

def _check_chained_comparison ( self , node ) : if node . op != "and" or len ( node . values ) < 2 : return def _find_lower_upper_bounds ( comparison_node , uses ) : left_operand = comparison_node . left for operator , right_operand in comparison_node . ops : for operand in ( left_operand , right_operand ) : value = None if isinstance ( operand , astroid . Name ) : value = operand . name elif isinstance ( operand , astroid . Const ) : value = operand . value if value is None : continue if operator in ( "<" , "<=" ) : if operand is left_operand : uses [ value ] [ "lower_bound" ] . add ( comparison_node ) elif operand is right_operand : uses [ value ] [ "upper_bound" ] . add ( comparison_node ) elif operator in ( ">" , ">=" ) : if operand is left_operand : uses [ value ] [ "upper_bound" ] . add ( comparison_node ) elif operand is right_operand : uses [ value ] [ "lower_bound" ] . add ( comparison_node ) left_operand = right_operand uses = collections . defaultdict ( lambda : { "lower_bound" : set ( ) , "upper_bound" : set ( ) } ) for comparison_node in node . values : if isinstance ( comparison_node , astroid . Compare ) : _find_lower_upper_bounds ( comparison_node , uses ) for _ , bounds in uses . items ( ) : num_shared = len ( bounds [ "lower_bound" ] . intersection ( bounds [ "upper_bound" ] ) ) num_lower_bounds = len ( bounds [ "lower_bound" ] ) num_upper_bounds = len ( bounds [ "upper_bound" ] ) if num_shared < num_lower_bounds and num_shared < num_upper_bounds : self . add_message ( "chained-comparison" , node = node ) break

Check if there is any chained comparison in the expression .


def _is_and_or_ternary(node):
        """
        Returns true if node is 'condition and true_value or false_value' form.

        All of: condition, true_value and false_value should not be a complex boolean expression
        """
        return (
            isinstance(node, astroid.BoolOp)
            and node.op == "or"
            and len(node.values) == 2
            and isinstance(node.values[0], astroid.BoolOp)
            and not isinstance(node.values[1], astroid.BoolOp)
            and node.values[0].op == "and"
            and not isinstance(node.values[0].values[1], astroid.BoolOp)
            and len(node.values[0].values) == 2
        )

def _is_and_or_ternary ( node ) : return ( isinstance ( node , astroid . BoolOp ) and node . op == "or" and len ( node . values ) == 2 and isinstance ( node . values [ 0 ] , astroid . BoolOp ) and not isinstance ( node . values [ 1 ] , astroid . BoolOp ) and node . values [ 0 ] . op == "and" and not isinstance ( node . values [ 0 ] . values [ 1 ] , astroid . BoolOp ) and len ( node . values [ 0 ] . values ) == 2 )

Returns true if node is condition and true_value or false_value form .


def _check_consistent_returns(self, node):
        """Check that all return statements inside a function are consistent.

        Return statements are consistent if:
            - all returns are explicit and if there is no implicit return;
            - all returns are empty and if there is, possibly, an implicit return.

        Args:
            node (astroid.FunctionDef): the function holding the return statements.

        """
        # explicit return statements are those with a not None value
        explicit_returns = [
            _node for _node in self._return_nodes[node.name] if _node.value is not None
        ]
        if not explicit_returns:
            return
        if len(explicit_returns) == len(
            self._return_nodes[node.name]
        ) and self._is_node_return_ended(node):
            return
        self.add_message("inconsistent-return-statements", node=node)

def _check_consistent_returns ( self , node ) : explicit_returns = [ _node for _node in self . _return_nodes [ node . name ] if _node . value is not None ] if not explicit_returns : return if len ( explicit_returns ) == len ( self . _return_nodes [ node . name ] ) and self . _is_node_return_ended ( node ) : return self . add_message ( "inconsistent-return-statements" , node = node )

Check that all return statements inside a function are consistent .


def _is_node_return_ended(self, node):
        """Check if the node ends with an explicit return statement.

        Args:
            node (astroid.NodeNG): node to be checked.

        Returns:
            bool: True if the node ends with an explicit statement, False otherwise.

        """
        #  Recursion base case
        if isinstance(node, astroid.Return):
            return True
        if isinstance(node, astroid.Call):
            try:
                funcdef_node = node.func.inferred()[0]
                if self._is_function_def_never_returning(funcdef_node):
                    return True
            except astroid.InferenceError:
                pass
        # Avoid the check inside while loop as we don't know
        #  if they will be completed
        if isinstance(node, astroid.While):
            return True
        if isinstance(node, astroid.Raise):
            # a Raise statement doesn't need to end with a return statement
            # but if the exception raised is handled, then the handler has to
            # ends with a return statement
            if not node.exc:
                # Ignore bare raises
                return True
            if not utils.is_node_inside_try_except(node):
                # If the raise statement is not inside a try/except statement
                #  then the exception is raised and cannot be caught. No need
                #  to infer it.
                return True
            exc = utils.safe_infer(node.exc)
            if exc is None or exc is astroid.Uninferable:
                return False
            exc_name = exc.pytype().split(".")[-1]
            handlers = utils.get_exception_handlers(node, exc_name)
            handlers = list(handlers) if handlers is not None else []
            if handlers:
                # among all the handlers handling the exception at least one
                # must end with a return statement
                return any(
                    self._is_node_return_ended(_handler) for _handler in handlers
                )
            # if no handlers handle the exception then it's ok
            return True
        if isinstance(node, astroid.If):
            # if statement is returning if there are exactly two return statements in its
            #  children : one for the body part, the other for the orelse part
            # Do not check if inner function definition are return ended.
            is_orelse_returning = any(
                self._is_node_return_ended(_ore)
                for _ore in node.orelse
                if not isinstance(_ore, astroid.FunctionDef)
            )
            is_if_returning = any(
                self._is_node_return_ended(_ifn)
                for _ifn in node.body
                if not isinstance(_ifn, astroid.FunctionDef)
            )
            return is_if_returning and is_orelse_returning
        #  recurses on the children of the node except for those which are except handler
        # because one cannot be sure that the handler will really be used
        return any(
            self._is_node_return_ended(_child)
            for _child in node.get_children()
            if not isinstance(_child, astroid.ExceptHandler)
        )

def _is_node_return_ended ( self , node ) : if isinstance ( node , astroid . Return ) : return True if isinstance ( node , astroid . Call ) : try : funcdef_node = node . func . inferred ( ) [ 0 ] if self . _is_function_def_never_returning ( funcdef_node ) : return True except astroid . InferenceError : pass if isinstance ( node , astroid . While ) : return True if isinstance ( node , astroid . Raise ) : if not node . exc : return True if not utils . is_node_inside_try_except ( node ) : return True exc = utils . safe_infer ( node . exc ) if exc is None or exc is astroid . Uninferable : return False exc_name = exc . pytype ( ) . split ( "." ) [ - 1 ] handlers = utils . get_exception_handlers ( node , exc_name ) handlers = list ( handlers ) if handlers is not None else [ ] if handlers : return any ( self . _is_node_return_ended ( _handler ) for _handler in handlers ) return True if isinstance ( node , astroid . If ) : is_orelse_returning = any ( self . _is_node_return_ended ( _ore ) for _ore in node . orelse if not isinstance ( _ore , astroid . FunctionDef ) ) is_if_returning = any ( self . _is_node_return_ended ( _ifn ) for _ifn in node . body if not isinstance ( _ifn , astroid . FunctionDef ) ) return is_if_returning and is_orelse_returning return any ( self . _is_node_return_ended ( _child ) for _child in node . get_children ( ) if not isinstance ( _child , astroid . ExceptHandler ) )

Check if the node ends with an explicit return statement .


def visit_for(self, node):
        """Emit a convention whenever range and len are used for indexing."""
        # Verify that we have a `range([start], len(...), [stop])` call and
        # that the object which is iterated is used as a subscript in the
        # body of the for.

        # Is it a proper range call?
        if not isinstance(node.iter, astroid.Call):
            return
        if not self._is_builtin(node.iter.func, "range"):
            return
        if len(node.iter.args) == 2 and not _is_constant_zero(node.iter.args[0]):
            return
        if len(node.iter.args) > 2:
            return

        # Is it a proper len call?
        if not isinstance(node.iter.args[-1], astroid.Call):
            return
        second_func = node.iter.args[-1].func
        if not self._is_builtin(second_func, "len"):
            return
        len_args = node.iter.args[-1].args
        if not len_args or len(len_args) != 1:
            return
        iterating_object = len_args[0]
        if not isinstance(iterating_object, astroid.Name):
            return
        # If we're defining __iter__ on self, enumerate won't work
        scope = node.scope()
        if iterating_object.name == "self" and scope.name == "__iter__":
            return

        # Verify that the body of the for loop uses a subscript
        # with the object that was iterated. This uses some heuristics
        # in order to make sure that the same object is used in the
        # for body.
        for child in node.body:
            for subscript in child.nodes_of_class(astroid.Subscript):
                if not isinstance(subscript.value, astroid.Name):
                    continue
                if not isinstance(subscript.slice, astroid.Index):
                    continue
                if not isinstance(subscript.slice.value, astroid.Name):
                    continue
                if subscript.slice.value.name != node.target.name:
                    continue
                if iterating_object.name != subscript.value.name:
                    continue
                if subscript.value.scope() != node.scope():
                    # Ignore this subscript if it's not in the same
                    # scope. This means that in the body of the for
                    # loop, another scope was created, where the same
                    # name for the iterating object was used.
                    continue
                self.add_message("consider-using-enumerate", node=node)
                return

def visit_for ( self , node ) : if not isinstance ( node . iter , astroid . Call ) : return if not self . _is_builtin ( node . iter . func , "range" ) : return if len ( node . iter . args ) == 2 and not _is_constant_zero ( node . iter . args [ 0 ] ) : return if len ( node . iter . args ) > 2 : return if not isinstance ( node . iter . args [ - 1 ] , astroid . Call ) : return second_func = node . iter . args [ - 1 ] . func if not self . _is_builtin ( second_func , "len" ) : return len_args = node . iter . args [ - 1 ] . args if not len_args or len ( len_args ) != 1 : return iterating_object = len_args [ 0 ] if not isinstance ( iterating_object , astroid . Name ) : return scope = node . scope ( ) if iterating_object . name == "self" and scope . name == "__iter__" : return for child in node . body : for subscript in child . nodes_of_class ( astroid . Subscript ) : if not isinstance ( subscript . value , astroid . Name ) : continue if not isinstance ( subscript . slice , astroid . Index ) : continue if not isinstance ( subscript . slice . value , astroid . Name ) : continue if subscript . slice . value . name != node . target . name : continue if iterating_object . name != subscript . value . name : continue if subscript . value . scope ( ) != node . scope ( ) : continue self . add_message ( "consider-using-enumerate" , node = node ) return

Emit a convention whenever range and len are used for indexing .


def _check_graphviz_available(output_format):
    """check if we need graphviz for different output format"""
    try:
        subprocess.call(["dot", "-V"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except OSError:
        print(
            "The output format '%s' is currently not available.\n"
            "Please install 'Graphviz' to have other output formats "
            "than 'dot' or 'vcg'." % output_format
        )
        sys.exit(32)


def run(self, args):
        """checking arguments and run project"""
        if not args:
            print(self.help())
            return 1
        # insert current working directory to the python path to recognize
        # dependencies to local modules even if cwd is not in the PYTHONPATH
        sys.path.insert(0, os.getcwd())
        try:
            project = project_from_files(
                args,
                project_name=self.config.project,
                black_list=self.config.black_list,
            )
            linker = Linker(project, tag=True)
            handler = DiadefsHandler(self.config)
            diadefs = handler.get_diadefs(project, linker)
        finally:
            sys.path.pop(0)

        if self.config.output_format == "vcg":
            writer.VCGWriter(self.config).write(diadefs)
        else:
            writer.DotWriter(self.config).write(diadefs)
        return 0

def run ( self , args ) : if not args : print ( self . help ( ) ) return 1 sys . path . insert ( 0 , os . getcwd ( ) ) try : project = project_from_files ( args , project_name = self . config . project , black_list = self . config . black_list , ) linker = Linker ( project , tag = True ) handler = DiadefsHandler ( self . config ) diadefs = handler . get_diadefs ( project , linker ) finally : sys . path . pop ( 0 ) if self . config . output_format == "vcg" : writer . VCGWriter ( self . config ) . write ( diadefs ) else : writer . DotWriter ( self . config ) . write ( diadefs ) return 0


def write_packages(self, diagram):
        """write a package diagram"""
        # sorted to get predictable (hence testable) results
        for i, obj in enumerate(sorted(diagram.modules(), key=lambda x: x.title)):
            self.printer.emit_node(i, label=self.get_title(obj), shape="box")
            obj.fig_id = i
        # package dependencies
        for rel in diagram.get_relationships("depends"):
            self.printer.emit_edge(
                rel.from_object.fig_id, rel.to_object.fig_id, **self.pkg_edges
            )

def write_packages ( self , diagram ) : for i , obj in enumerate ( sorted ( diagram . modules ( ) , key = lambda x : x . title ) ) : self . printer . emit_node ( i , label = self . get_title ( obj ) , shape = "box" ) obj . fig_id = i for rel in diagram . get_relationships ( "depends" ) : self . printer . emit_edge ( rel . from_object . fig_id , rel . to_object . fig_id , ** self . pkg_edges )


def write_classes(self, diagram):
        """write a class diagram"""
        # sorted to get predictable (hence testable) results
        for i, obj in enumerate(sorted(diagram.objects, key=lambda x: x.title)):
            self.printer.emit_node(i, **self.get_values(obj))
            obj.fig_id = i
        # inheritance links
        for rel in diagram.get_relationships("specialization"):
            self.printer.emit_edge(
                rel.from_object.fig_id, rel.to_object.fig_id, **self.inh_edges
            )
        # implementation links
        for rel in diagram.get_relationships("implements"):
            self.printer.emit_edge(
                rel.from_object.fig_id, rel.to_object.fig_id, **self.imp_edges
            )
        # generate associations
        for rel in diagram.get_relationships("association"):
            self.printer.emit_edge(
                rel.from_object.fig_id,
                rel.to_object.fig_id,
                label=rel.name,
                **self.association_edges
            )

def write_classes ( self , diagram ) : for i , obj in enumerate ( sorted ( diagram . objects , key = lambda x : x . title ) ) : self . printer . emit_node ( i , ** self . get_values ( obj ) ) obj . fig_id = i for rel in diagram . get_relationships ( "specialization" ) : self . printer . emit_edge ( rel . from_object . fig_id , rel . to_object . fig_id , ** self . inh_edges ) for rel in diagram . get_relationships ( "implements" ) : self . printer . emit_edge ( rel . from_object . fig_id , rel . to_object . fig_id , ** self . imp_edges ) for rel in diagram . get_relationships ( "association" ) : self . printer . emit_edge ( rel . from_object . fig_id , rel . to_object . fig_id , label = rel . name , ** self . association_edges )


def set_printer(self, file_name, basename):
        """initialize DotWriter and add options for layout.
        """
        layout = dict(rankdir="BT")
        self.printer = DotBackend(basename, additional_param=layout)
        self.file_name = file_name

def set_printer ( self , file_name , basename ) : layout = dict ( rankdir = "BT" ) self . printer = DotBackend ( basename , additional_param = layout ) self . file_name = file_name

initialize DotWriter and add options for layout .


def set_printer(self, file_name, basename):
        """initialize VCGWriter for a UML graph"""
        self.graph_file = open(file_name, "w+")
        self.printer = VCGPrinter(self.graph_file)
        self.printer.open_graph(
            title=basename,
            layoutalgorithm="dfs",
            late_edge_labels="yes",
            port_sharing="no",
            manhattan_edges="yes",
        )
        self.printer.emit_node = self.printer.node
        self.printer.emit_edge = self.printer.edge

def set_printer ( self , file_name , basename ) : self . graph_file = open ( file_name , "w+" ) self . printer = VCGPrinter ( self . graph_file ) self . printer . open_graph ( title = basename , layoutalgorithm = "dfs" , late_edge_labels = "yes" , port_sharing = "no" , manhattan_edges = "yes" , ) self . printer . emit_node = self . printer . node self . printer . emit_edge = self . printer . edge


def may_be_emitted(self):
        """return True if message may be emitted using the current interpreter"""
        if self.minversion is not None and self.minversion > sys.version_info:
            return False
        if self.maxversion is not None and self.maxversion <= sys.version_info:
            return False
        return True

def may_be_emitted ( self ) : if self . minversion is not None and self . minversion > sys . version_info : return False if self . maxversion is not None and self . maxversion <= sys . version_info : return False return True


def format_help(self, checkerref=False):
        """return the help string for the given message id"""
        desc = self.descr
        if checkerref:
            desc += " This message belongs to the %s checker." % self.checker.name
        title = self.msg
        if self.symbol:
            msgid = "%s (%s)" % (self.symbol, self.msgid)
        else:
            msgid = self.msgid
        if self.minversion or self.maxversion:
            restr = []
            if self.minversion:
                restr.append("< %s" % ".".join([str(n) for n in self.minversion]))
            if self.maxversion:
                restr.append(">= %s" % ".".join([str(n) for n in self.maxversion]))
            restr = " or ".join(restr)
            if checkerref:
                desc += " It can't be emitted when using Python %s." % restr
            else:
                desc += " This message can't be emitted when using Python %s." % restr
        desc = normalize_text(" ".join(desc.split()), indent="  ")
        if title != "%s":
            title = title.splitlines()[0]

            return ":%s: *%s*\n%s" % (msgid, title.rstrip(" "), desc)
        return ":%s:\n%s" % (msgid, desc)


def _get_env():
    """Extracts the environment PYTHONPATH and appends the current sys.path to
    those."""
    env = dict(os.environ)
    env["PYTHONPATH"] = os.pathsep.join(sys.path)
    return env

def _get_env ( ) : env = dict ( os . environ ) env [ "PYTHONPATH" ] = os . pathsep . join ( sys . path ) return env

Extracts the environment PYTHONPATH and appends the current sys . path to those .


def lint(filename, options=()):
    """Pylint the given file.

    When run from emacs we will be in the directory of a file, and passed its
    filename.  If this file is part of a package and is trying to import other
    modules from within its own package or another package rooted in a directory
    below it, pylint will classify it as a failed import.

    To get around this, we traverse down the directory tree to find the root of
    the package this module is in.  We then invoke pylint from this directory.

    Finally, we must correct the filenames in the output generated by pylint so
    Emacs doesn't become confused (it will expect just the original filename,
    while pylint may extend it with extra directories if we've traversed down
    the tree)
    """
    # traverse downwards until we are out of a python package
    full_path = osp.abspath(filename)
    parent_path = osp.dirname(full_path)
    child_path = osp.basename(full_path)

    while parent_path != "/" and osp.exists(osp.join(parent_path, "__init__.py")):
        child_path = osp.join(osp.basename(parent_path), child_path)
        parent_path = osp.dirname(parent_path)

    # Start pylint
    # Ensure we use the python and pylint associated with the running epylint
    run_cmd = "import sys; from pylint.lint import Run; Run(sys.argv[1:])"
    cmd = (
        [sys.executable, "-c", run_cmd]
        + [
            "--msg-template",
            "{path}:{line}: {category} ({msg_id}, {symbol}, {obj}) {msg}",
            "-r",
            "n",
            child_path,
        ]
        + list(options)
    )
    process = Popen(
        cmd, stdout=PIPE, cwd=parent_path, env=_get_env(), universal_newlines=True
    )

    for line in process.stdout:
        # remove pylintrc warning
        if line.startswith("No config file found"):
            continue

        # modify the file name thats output to reverse the path traversal we made
        parts = line.split(":")
        if parts and parts[0] == child_path:
            line = ":".join([filename] + parts[1:])
        print(line, end=" ")

    process.wait()
    return process.returncode


def py_run(command_options="", return_std=False, stdout=None, stderr=None):
    """Run pylint from python

    ``command_options`` is a string containing ``pylint`` command line options;
    ``return_std`` (boolean) indicates return of created standard output
    and error (see below);
    ``stdout`` and ``stderr`` are 'file-like' objects in which standard output
    could be written.

    Calling agent is responsible for stdout/err management (creation, close).
    Default standard output and error are those from sys,
    or standalone ones (``subprocess.PIPE``) are used
    if they are not set and ``return_std``.

    If ``return_std`` is set to ``True``, this function returns a 2-uple
    containing standard output and error related to created process,
    as follows: ``(stdout, stderr)``.

    To silently run Pylint on a module, and get its standard output and error:
        >>> (pylint_stdout, pylint_stderr) = py_run( 'module_name.py', True)
    """
    # Detect if we use Python as executable or not, else default to `python`
    executable = sys.executable if "python" in sys.executable else "python"

    # Create command line to call pylint
    epylint_part = [executable, "-c", "from pylint import epylint;epylint.Run()"]
    options = shlex.split(command_options, posix=not sys.platform.startswith("win"))
    cli = epylint_part + options

    # Providing standard output and/or error if not set
    if stdout is None:
        if return_std:
            stdout = PIPE
        else:
            stdout = sys.stdout
    if stderr is None:
        if return_std:
            stderr = PIPE
        else:
            stderr = sys.stderr
    # Call pylint in a subprocess
    process = Popen(
        cli,
        shell=False,
        stdout=stdout,
        stderr=stderr,
        env=_get_env(),
        universal_newlines=True,
    )
    proc_stdout, proc_stderr = process.communicate()
    # Return standard output and error
    if return_std:
        return StringIO(proc_stdout), StringIO(proc_stderr)
    return None


def _get_cycles(graph_dict, path, visited, result, vertice):
    """recursive function doing the real work for get_cycles"""
    if vertice in path:
        cycle = [vertice]
        for node in path[::-1]:
            if node == vertice:
                break
            cycle.insert(0, node)
        # make a canonical representation
        start_from = min(cycle)
        index = cycle.index(start_from)
        cycle = cycle[index:] + cycle[0:index]
        # append it to result if not already in
        if cycle not in result:
            result.append(cycle)
        return
    path.append(vertice)
    try:
        for node in graph_dict[vertice]:
            # don't check already visited nodes again
            if node not in visited:
                _get_cycles(graph_dict, path, visited, result, node)
                visited.add(node)
    except KeyError:
        pass
    path.pop()

def _get_cycles ( graph_dict , path , visited , result , vertice ) : if vertice in path : cycle = [ vertice ] for node in path [ : : - 1 ] : if node == vertice : break cycle . insert ( 0 , node ) start_from = min ( cycle ) index = cycle . index ( start_from ) cycle = cycle [ index : ] + cycle [ 0 : index ] if cycle not in result : result . append ( cycle ) return path . append ( vertice ) try : for node in graph_dict [ vertice ] : if node not in visited : _get_cycles ( graph_dict , path , visited , result , node ) visited . add ( node ) except KeyError : pass path . pop ( )


def get_source(self):
        """returns self._source"""
        if self._source is None:
            self.emit("}\n")
            self._source = "\n".join(self.lines)
            del self.lines
        return self._source

def get_source ( self ) : if self . _source is None : self . emit ( "}\n" ) self . _source = "\n" . join ( self . lines ) del self . lines return self . _source


def generate(self, outputfile=None, dotfile=None, mapfile=None):
        """Generates a graph file.

        :param str outputfile: filename and path [defaults to graphname.png]
        :param str dotfile: filename and path [defaults to graphname.dot]
        :param str mapfile: filename and path

        :rtype: str
        :return: a path to the generated file
        """
        import subprocess  # introduced in py 2.4

        name = self.graphname
        if not dotfile:
            # if 'outputfile' is a dot file use it as 'dotfile'
            if outputfile and outputfile.endswith(".dot"):
                dotfile = outputfile
            else:
                dotfile = "%s.dot" % name
        if outputfile is not None:
            storedir, _, target = target_info_from_filename(outputfile)
            if target != "dot":
                pdot, dot_sourcepath = tempfile.mkstemp(".dot", name)
                os.close(pdot)
            else:
                dot_sourcepath = osp.join(storedir, dotfile)
        else:
            target = "png"
            pdot, dot_sourcepath = tempfile.mkstemp(".dot", name)
            ppng, outputfile = tempfile.mkstemp(".png", name)
            os.close(pdot)
            os.close(ppng)
        pdot = codecs.open(dot_sourcepath, "w", encoding="utf8")
        pdot.write(self.source)
        pdot.close()
        if target != "dot":
            use_shell = sys.platform == "win32"
            if mapfile:
                subprocess.call(
                    [
                        self.renderer,
                        "-Tcmapx",
                        "-o",
                        mapfile,
                        "-T",
                        target,
                        dot_sourcepath,
                        "-o",
                        outputfile,
                    ],
                    shell=use_shell,
                )
            else:
                subprocess.call(
                    [self.renderer, "-T", target, dot_sourcepath, "-o", outputfile],
                    shell=use_shell,
                )
            os.unlink(dot_sourcepath)
        return outputfile

def generate ( self , outputfile = None , dotfile = None , mapfile = None ) : import subprocess name = self . graphname if not dotfile : if outputfile and outputfile . endswith ( ".dot" ) : dotfile = outputfile else : dotfile = "%s.dot" % name if outputfile is not None : storedir , _ , target = target_info_from_filename ( outputfile ) if target != "dot" : pdot , dot_sourcepath = tempfile . mkstemp ( ".dot" , name ) os . close ( pdot ) else : dot_sourcepath = osp . join ( storedir , dotfile ) else : target = "png" pdot , dot_sourcepath = tempfile . mkstemp ( ".dot" , name ) ppng , outputfile = tempfile . mkstemp ( ".png" , name ) os . close ( pdot ) os . close ( ppng ) pdot = codecs . open ( dot_sourcepath , "w" , encoding = "utf8" ) pdot . write ( self . source ) pdot . close ( ) if target != "dot" : use_shell = sys . platform == "win32" if mapfile : subprocess . call ( [ self . renderer , "-Tcmapx" , "-o" , mapfile , "-T" , target , dot_sourcepath , "-o" , outputfile , ] , shell = use_shell , ) else : subprocess . call ( [ self . renderer , "-T" , target , dot_sourcepath , "-o" , outputfile ] , shell = use_shell , ) os . unlink ( dot_sourcepath ) return outputfile


def _rest_format_section(stream, section, options, doc=None):
    """format an options section using as ReST formatted output"""
    if section:
        print("%s\n%s" % (section, "'" * len(section)), file=stream)
    if doc:
        print(normalize_text(doc, line_len=79, indent=""), file=stream)
        print(file=stream)
    for optname, optdict, value in options:
        help_opt = optdict.get("help")
        print(":%s:" % optname, file=stream)
        if help_opt:
            help_opt = normalize_text(help_opt, line_len=79, indent="  ")
            print(help_opt, file=stream)
        if value:
            value = str(_format_option_value(optdict, value))
            print(file=stream)
            print("  Default: ``%s``" % value.replace("`` ", "```` ``"), file=stream)

def
_rest_format_section
(
stream
,
section
,
options
,
doc
=
)
:
if
section
:
print
(
"%s\n%s"
%
(
section
,
"'"
*
len
(
section
)
)
,
file
=
stream
)
if
doc
:
print
(
normalize_text
(
doc
,
line_len
=
79
,
indent
=
""
)
,
file
=
stream
)
print
(
file
=
stream
)
for
optname
,
optdict
,
value
in
options
:
help_opt
=
optdict
.
get
(
"help"
)
print
(
":%s:"
%
optname
,
file
=
stream
)
if
help_opt
:
help_opt
=
normalize_text
(
help_opt
,
line_len
=
79
,
indent
=
"  "
)
print
(
help_opt
,
file
=
stream
)
if
value
:
value
=
str
(
_format_option_value
(
optdict
,
value
)
)
print
(
file
=
stream
)
print
(
"  Default: ``%s``"
%
value
.
replace
(
"`` "
,
"```` ``"
)
,
file
=
stream
)


def _register_by_id_managed_msg(self, msgid, line, is_disabled=True):
        """If the msgid is a numeric one, then register it to inform the user
        it could furnish instead a symbolic msgid."""
        try:
            message_definitions = self.msgs_store.get_message_definitions(msgid)
            for message_definition in message_definitions:
                if msgid == message_definition.msgid:
                    MessagesHandlerMixIn.__by_id_managed_msgs.append(
                        (
                            self.current_name,
                            message_definition.msgid,
                            message_definition.symbol,
                            line,
                            is_disabled,
                        )
                    )
        except UnknownMessageError:
            pass

def _register_by_id_managed_msg ( self , msgid , line , is_disabled = True ) : try : message_definitions = self . msgs_store . get_message_definitions ( msgid ) for message_definition in message_definitions : if msgid == message_definition . msgid : MessagesHandlerMixIn . __by_id_managed_msgs . append ( ( self . current_name , message_definition . msgid , message_definition . symbol , line , is_disabled , ) ) except UnknownMessageError : pass

If the msgid is a numeric one then register it to inform the user it could furnish instead a symbolic msgid .


def disable(self, msgid, scope="package", line=None, ignore_unknown=False):
        """don't output message of the given id"""
        self._set_msg_status(
            msgid, enable=False, scope=scope, line=line, ignore_unknown=ignore_unknown
        )
        self._register_by_id_managed_msg(msgid, line)

def disable ( self , msgid , scope = "package" , line = None , ignore_unknown = False ) : self . _set_msg_status ( msgid , enable = False , scope = scope , line = line , ignore_unknown = ignore_unknown ) self . _register_by_id_managed_msg ( msgid , line )


def enable(self, msgid, scope="package", line=None, ignore_unknown=False):
        """reenable message of the given id"""
        self._set_msg_status(
            msgid, enable=True, scope=scope, line=line, ignore_unknown=ignore_unknown
        )
        self._register_by_id_managed_msg(msgid, line, is_disabled=False)

def enable ( self , msgid , scope = "package" , line = None , ignore_unknown = False ) : self . _set_msg_status ( msgid , enable = True , scope = scope , line = line , ignore_unknown = ignore_unknown ) self . _register_by_id_managed_msg ( msgid , line , is_disabled = False )


def _message_symbol(self, msgid):
        """Get the message symbol of the given message id

        Return the original message id if the message does not
        exist.
        """
        try:
            return [md.symbol for md in self.msgs_store.get_message_definitions(msgid)]
        except UnknownMessageError:
            return msgid

def _message_symbol ( self , msgid ) : try : return [ md . symbol for md in self . msgs_store . get_message_definitions ( msgid ) ] except UnknownMessageError : return msgid


def is_message_enabled(self, msg_descr, line=None, confidence=None):
        """return true if the message associated to the given message id is
        enabled

        msgid may be either a numeric or symbolic message id.
        """
        if self.config.confidence and confidence:
            if confidence.name not in self.config.confidence:
                return False
        try:
            message_definitions = self.msgs_store.get_message_definitions(msg_descr)
            msgids = [md.msgid for md in message_definitions]
        except UnknownMessageError:
            # The linter checks for messages that are not registered
            # due to version mismatch, just treat them as message IDs
            # for now.
            msgids = [msg_descr]
        for msgid in msgids:
            if self.is_one_message_enabled(msgid, line):
                return True
        return False

def is_message_enabled ( self , msg_descr , line = None , confidence = None ) : if self . config . confidence and confidence : if confidence . name not in self . config . confidence : return False try : message_definitions = self . msgs_store . get_message_definitions ( msg_descr ) msgids = [ md . msgid for md in message_definitions ] except UnknownMessageError : msgids = [ msg_descr ] for msgid in msgids : if self . is_one_message_enabled ( msgid , line ) : return True return False


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)

def
_get_indent_hint_line
(
bar_positions
,
bad_position
)
:
if
not
bar_positions
:
return
(
""
,
""
)
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
:
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()

def get_valid_indentations ( self , idx ) : 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 _hanging_indent_after_bracket ( self , bracket , position ) : 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 == ":" : 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 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