From 478048b685386fbdba295603b547b695ddd980bb Mon Sep 17 00:00:00 2001 From: Aleksandr Brodin Date: Mon, 26 Dec 2022 15:54:06 +0700 Subject: [PATCH 1/2] add pytest -m extention as --allure-tags --- .../label/tags/select_tests_by_tags.rst | 31 ++++++++++ allure-pytest/src/plugin.py | 57 ++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 allure-pytest/examples/label/tags/select_tests_by_tags.rst diff --git a/allure-pytest/examples/label/tags/select_tests_by_tags.rst b/allure-pytest/examples/label/tags/select_tests_by_tags.rst new file mode 100644 index 00000000..ce6c2d53 --- /dev/null +++ b/allure-pytest/examples/label/tags/select_tests_by_tags.rst @@ -0,0 +1,31 @@ +Selecting tests by TAG label +---------------------------- + +You can use following commandline options to specify different sets of tests to execute passing a list of +values as compiled expression: + +--allure-tags + +There are some tests marked with TAG labels: + + >>> import allure + + >>> @allure.tag("some feature", "smoke") + ... def test_feature_smoke(): + ... pass + + >>> @allure.tag("some feature", "load") + ... def test_feature_load(): + ... pass + + + >>> @pytest.mark.some_feature + >>> @pytest.mark.e2e + ... def test_feature_e2e(): + ... pass + + +If you run ``pytest`` with following options: ``$ pytest tests.py --allure-tags="some_feature and (smoke or e2e)" --alluredir=./report`` first +and last tests will be runned. +All spaces in tags in the expression should be replaced with "_". +The function only works with statically assigned tags by @allure.tag marker. \ No newline at end of file diff --git a/allure-pytest/src/plugin.py b/allure-pytest/src/plugin.py index 7ff58f9e..a2c91f48 100644 --- a/allure-pytest/src/plugin.py +++ b/allure-pytest/src/plugin.py @@ -1,8 +1,10 @@ +import attr import argparse import allure import allure_commons import os +import pytest from allure_commons.types import LabelType from allure_commons.logger import AllureFileLogger @@ -15,6 +17,9 @@ from allure_pytest.utils import ALLURE_DESCRIPTION_MARK, ALLURE_DESCRIPTION_HTML_MARK from allure_pytest.utils import ALLURE_LABEL_MARK, ALLURE_LINK_MARK +from typing import AbstractSet +from _pytest.mark import _parse_expression + def pytest_addoption(parser): parser.getgroup("reporting").addoption('--alluredir', @@ -102,6 +107,13 @@ def a_label_type(string): help="""Comma-separated list of IDs. Run tests that have at least one of the specified id labels.""") + parser.getgroup("general").addoption('--allure-tags', + dest="allure_tags", + metavar="TAGS_SET", + default='', + type=str, + help="An alternative for pytest -m key with support allure tags.") + def link_pattern(string): pattern = string.split(':', 1) if not pattern[0]: @@ -202,11 +214,52 @@ def is_planed(item): return items, [] +@attr.s(slots=True, auto_attribs=True) +class AllureTagsMatcher: + own_tags: AbstractSet[str] + + @classmethod + def from_item(cls, item: pytest.Item): + mark_names = { + tag.replace(' ', '_') + for mark in item.iter_markers('allure_label') + for tag in mark.args + if mark.kwargs.get('label_type') == 'tag' + } + mark_names.update( + ( + mark.name for mark in item.iter_markers() + if not mark.args and not mark.kwargs + ) + ) + return cls(mark_names) + + def __call__(self, name: str) -> bool: + return name in self.own_tags + + +def select_by_tags(items: list[pytest.Item], config: pytest.Config) -> None: + if not config.option.allure_tags: + return items, [] + selected: list[pytest.Item] = [] + deselected: list[pytest.Item] = [] + expr = _parse_expression(config.option.allure_tags, "Wrong expression passed to '--allure-tags'") + for item in items: + if expr.evaluate(AllureTagsMatcher.from_item(item)): + selected.append(item) + else: + deselected.append(item) + return selected, deselected + + def pytest_collection_modifyitems(items, config): selected, deselected_by_testcase = select_by_testcase(items, config) selected, deselected_by_labels = select_by_labels(selected, config) + selected, deselected_by_tags = select_by_tags(selected, config) items[:] = selected - if deselected_by_testcase or deselected_by_labels: - config.hook.pytest_deselected(items=[*deselected_by_testcase, *deselected_by_labels]) + if deselected_by_testcase or deselected_by_labels or deselected_by_tags: + config.hook.pytest_deselected( + items=[*deselected_by_testcase, *deselected_by_labels, *deselected_by_tags] + ) From 8dacc4910bb2fc8ea96370c6c65ea9c2c1e0e7a4 Mon Sep 17 00:00:00 2001 From: Aleksandr Brodin Date: Mon, 26 Dec 2022 16:12:16 +0700 Subject: [PATCH 2/2] fix back python compability --- allure-pytest/src/plugin.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/allure-pytest/src/plugin.py b/allure-pytest/src/plugin.py index a2c91f48..5c8f9f7b 100644 --- a/allure-pytest/src/plugin.py +++ b/allure-pytest/src/plugin.py @@ -4,7 +4,6 @@ import allure import allure_commons import os -import pytest from allure_commons.types import LabelType from allure_commons.logger import AllureFileLogger @@ -219,7 +218,7 @@ class AllureTagsMatcher: own_tags: AbstractSet[str] @classmethod - def from_item(cls, item: pytest.Item): + def from_item(cls, item): mark_names = { tag.replace(' ', '_') for mark in item.iter_markers('allure_label') @@ -238,12 +237,11 @@ def __call__(self, name: str) -> bool: return name in self.own_tags -def select_by_tags(items: list[pytest.Item], config: pytest.Config) -> None: +def select_by_tags(items, config) -> None: if not config.option.allure_tags: return items, [] - selected: list[pytest.Item] = [] - deselected: list[pytest.Item] = [] expr = _parse_expression(config.option.allure_tags, "Wrong expression passed to '--allure-tags'") + selected, deselected = [], [] for item in items: if expr.evaluate(AllureTagsMatcher.from_item(item)): selected.append(item)