/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")
|