Source code for slash.core.tagging

from sentinels import NOTHING

from ..exceptions import TaggingConflict

_TAGS_NAME = "__slash_tags__"


class Tagger(object):
    def __init__(self, tag_name, tag_value):
        self.tag_name = tag_name
        self.tag_value = tag_value

    def __call__(self, target):
        assert callable(target)
        return tag_test(target, self.tag_name, self.tag_value)

    def __rfloordiv__(self, other):
        from .fixtures.parameters import ParametrizationValue

        return ParametrizationValue(value=other, tags=[(self.tag_name, self.tag_value)])


def tag_test(test, tag_name, tag_value):
    tags = get_tags(test)
    if tags is NO_TAGS:
        tags = Tags()
        setattr(test, _TAGS_NAME, tags)
    if tags.get(tag_name, NOTHING) not in (tag_value, NOTHING):
        raise TaggingConflict("Tag {} is already set on {}".format(tag_name, test))
    tags[tag_name] = tag_value
    return test


[docs]def tag(tag_name, tag_value=NOTHING): """Decorator for tagging tests """ return Tagger(tag_name=tag_name, tag_value=tag_value)
def get_tags(test): return getattr(test, _TAGS_NAME, NO_TAGS) class Tags(object): def __init__(self, tags=None): super(Tags, self).__init__() if tags is None: tags = {} self._tags = tags def __setitem__(self, tag_name, value): self._tags[tag_name] = value def __getitem__(self, tag_name): return self._tags[tag_name] def __contains__(self, tag_name): return tag_name in self._tags has_tag = __contains__ def _check_conflicting_tags(self, other): for ( tag_name, tag_value, ) in other._tags.items(): # pylint: disable=protected-access if self.get(tag_name, NOTHING) not in (tag_value, NOTHING): raise TaggingConflict( "Conflicting tag: {} when adding {}, {}".format( tag_name, self, other ) ) def __add__(self, other): if other is NO_TAGS: return self self._check_conflicting_tags(other) new_tags = self._tags.copy() new_tags.update(other._tags) # pylint: disable=protected-access return Tags(new_tags) def copy(self): return Tags(self._tags.copy()) def update(self, other): if other is NO_TAGS: return self._check_conflicting_tags(other) self._tags.update(other._tags) # pylint: disable=protected-access def get(self, *args, **kwargs): return self._tags.get(*args, **kwargs) def matches_pattern(self, pattern, exact=False): if "=" in pattern: key, predicate = pattern.split("=", 1) value = self._tags.get(key, NOTHING) return value is not NOTHING and str(value) == predicate for key, value in self._tags.items(): if exact: if pattern == key: return True else: if pattern in key: return True return False def __iter__(self): return iter(self._tags) class _NoTags(object): def __contains__(self, tag_name): return False def __add__(self, other): return other has_tag = __contains__ def matches_pattern(self, pattern, **_): # pylint: disable=unused-argument return False def __iter__(self): return iter([]) NO_TAGS = _NoTags()