This file is indexed.

/usr/lib/python3/dist-packages/behave/tag_expression.py is in python3-behave 1.2.5-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
# -*- coding: utf-8 -*-

import six

class TagExpression(object):
    """
    Tag expression, as logical boolean expression, to select
    (include or exclude) model elements.

    BOOLEAN LOGIC := (or_expr1) and (or_expr2) and ...
    with or_exprN := [not] tag1 or [not] tag2 or ...
    """

    def __init__(self, tag_expressions):
        self.ands = []
        self.limits = {}

        for expr in tag_expressions:
            self.store_and_extract_limits(self.normalized_tags_from_or(expr))

    @staticmethod
    def normalize_tag(tag):
        """
        Normalize a tag for a tag expression:

          * strip whitespace
          * strip '@' char
          * convert '~' (tilde) into '-' (minus sign)

        :param tag:  Tag (as string).
        :return: Normalized tag (as string).
        """
        tag = tag.strip()
        if tag.startswith('@'):
            tag = tag[1:]
        elif tag.startswith('-@') or tag.startswith('~@'):
            tag = '-' + tag[2:]
        elif tag.startswith('~'):
            tag = '-' + tag[1:]
        return tag

    @classmethod
    def normalized_tags_from_or(cls, expr):
        """
        Normalizes all tags in an OR expression (and return it as list).

        :param expr:  OR expression to normalize and split (as string).
        :return: Generator of normalized tags (as string)
        """
        for tag in expr.strip().split(','):
            yield cls.normalize_tag(tag)

    def store_and_extract_limits(self, tags):
        tags_with_negation = []

        for tag in tags:
            negated = tag.startswith('-')
            tag = tag.split(':')
            tag_with_negation = tag.pop(0)
            tags_with_negation.append(tag_with_negation)

            if tag:
                limit = int(tag[0])
                if negated:
                    tag_without_negation = tag_with_negation[1:]
                else:
                    tag_without_negation = tag_with_negation
                limited = tag_without_negation in self.limits
                if limited and self.limits[tag_without_negation] != limit:
                    msg = "Inconsistent tag limits for {0}: {1:d} and {2:d}"
                    msg = msg.format(tag_without_negation,
                                     self.limits[tag_without_negation], limit)
                    raise Exception(msg)
                self.limits[tag_without_negation] = limit

        if tags_with_negation:
            self.ands.append(tags_with_negation)

    def check(self, tags):
        """
        Checks if this tag expression matches the tags of a model element.

        :param tags:  List of tags of a model element.
        :return: True, if tag expression matches. False, otherwise.
        """
        if not self.ands:
            return True

        element_tags = set(tags)

        def test_tag(xtag):
            if xtag.startswith('-'): # -- or xtag.startswith('~'):
                return xtag[1:] not in element_tags
            return xtag in element_tags

        # -- EVALUATE: (or_expr1) and (or_expr2) and ...
        return all(any(test_tag(xtag) for xtag in ors)  for ors in self.ands)

    def __len__(self):
        return len(self.ands)

    def __str__(self):
        """Conversion back into string that represents this tag expression."""
        and_parts = []
        for or_terms in self.ands:
            and_parts.append(",".join(or_terms))
        return " ".join(and_parts)

    if six.PY2:
        __unicode__ = __str__
        __str__ = lambda self: self.__unicode__().encode("utf-8")