From e1411530829407ebaf632eeb83c789df7aa3c934 Mon Sep 17 00:00:00 2001 From: sharovd Date: Sat, 17 May 2025 13:37:17 +0400 Subject: [PATCH 1/3] fix: don't convert built-in (reserved) pytest markers to allure tags (#817) --- allure-pytest/src/utils.py | 34 ++-- .../acceptance/label/tag/tag_test.py | 190 ++++++++++++++---- .../pytest_rerunfailures_test.py | 4 +- 3 files changed, 170 insertions(+), 58 deletions(-) diff --git a/allure-pytest/src/utils.py b/allure-pytest/src/utils.py index 1e07cb49..d8e075e5 100644 --- a/allure-pytest/src/utils.py +++ b/allure-pytest/src/utils.py @@ -20,6 +20,15 @@ LabelType.SUB_SUITE ] +MARK_NAMES_TO_IGNORE = { + "usefixtures", + "filterwarnings", + "skip", + "skipif", + "xfail", + "parametrize", +} + def get_marker_value(item, keyword): marker = item.get_closest_marker(keyword) @@ -81,27 +90,14 @@ def format_allure_link(config, url, link_type): def pytest_markers(item): - for keyword in item.keywords.keys(): - if any([keyword.startswith('allure_'), keyword == 'parametrize']): - continue - marker = item.get_closest_marker(keyword) - if marker is None: - continue - - yield mark_to_str(marker) + for mark in item.iter_markers(): + if should_convert_mark_to_tag(mark): + yield mark.name -def mark_to_str(marker): - args = [represent(arg) for arg in marker.args] - kwargs = [f'{key}={represent(value)}' for key, value in marker.kwargs.items()] - if marker.name in ('filterwarnings', 'skip', 'skipif', 'xfail', 'usefixtures', 'tryfirst', 'trylast'): - markstr = f'@pytest.mark.{marker.name}' - else: - markstr = str(marker.name) - if args or kwargs: - parameters = ', '.join(args + kwargs) - markstr = f'{markstr}({parameters})' - return markstr +def should_convert_mark_to_tag(mark): + return mark.name not in MARK_NAMES_TO_IGNORE and \ + not mark.args and not mark.kwargs def allure_package(item): diff --git a/tests/allure_pytest/acceptance/label/tag/tag_test.py b/tests/allure_pytest/acceptance/label/tag/tag_test.py index 3f32475b..bd8779ad 100644 --- a/tests/allure_pytest/acceptance/label/tag/tag_test.py +++ b/tests/allure_pytest/acceptance/label/tag/tag_test.py @@ -5,13 +5,15 @@ from allure_commons_test.label import has_tag -def test_pytest_marker(allure_pytest_runner: AllurePytestRunner): +def test_pytest_simple_markers_are_converted_to_allure_tags( + allure_pytest_runner: AllurePytestRunner +): """ >>> import pytest >>> @pytest.mark.cool ... @pytest.mark.stuff - ... def test_pytest_marker_example(): + ... def test_pytest_simple_markers_are_converted_to_allure_tags_example(): ... pass """ @@ -20,15 +22,63 @@ def test_pytest_marker(allure_pytest_runner: AllurePytestRunner): assert_that( allure_results, has_test_case( - "test_pytest_marker_example", + "test_pytest_simple_markers_are_converted_to_allure_tags_example", has_tag("cool"), has_tag("stuff") ) ) -def test_show_reserved_pytest_markers_full_decorator( - allure_pytest_runner: AllurePytestRunner +def test_pytest_marker_with_args_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.marker('cool', 'stuff') + ... def test_pytest_marker_with_args_is_not_converted_to_allure_tag_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_with_args_is_not_converted_to_allure_tag_example", + not_( + has_tag("marker('cool', 'stuff')") + ) + ) + ) + + +def test_pytest_marker_with_kwargs_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.marker(stuff='cool') + ... def test_pytest_marker_with_kwargs_is_not_converted_to_allure_tag_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_marker_with_kwargs_is_not_converted_to_allure_tag_example", + not_( + has_tag("marker(stuff='cool')") + ) + ) + ) + + +def test_pytest_multiple_simple_and_reserved_markers_to_allure_tags( + allure_pytest_runner: AllurePytestRunner ): """ >>> import pytest @@ -38,7 +88,7 @@ def test_show_reserved_pytest_markers_full_decorator( ... @pytest.mark.parametrize("param", ["foo"]) ... @pytest.mark.skipif(False, reason="reason2") ... @pytest.mark.skipif(False, reason="reason1") - ... def test_show_reserved_pytest_markers_full_decorator_example(param): + ... def test_pytest_multiple_simple_and_reserved_markers_to_allure_tags_example(param): ... pass """ @@ -47,26 +97,54 @@ def test_show_reserved_pytest_markers_full_decorator( assert_that( allure_results, has_test_case( - "test_show_reserved_pytest_markers_full_decorator_example[foo]", + "test_pytest_multiple_simple_and_reserved_markers_to_allure_tags_example[foo]", has_tag("usermark1"), has_tag("usermark2"), - has_tag("@pytest.mark.skipif(False, reason='reason1')"), not_( - has_tag("@pytest.mark.skipif(False, reason='reason2')") + has_tag("skipif(False, reason='reason1')") + ), + not_( + has_tag("skipif(False, reason='reason2')") ), not_( - has_tag("@pytest.mark.parametrize('param', ['foo'])") + has_tag("parametrize('param', ['foo'])") ) ) ) -def test_pytest_xfail_marker(allure_pytest_runner: AllurePytestRunner): +def test_pytest_reserved_marker_usefixtures_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): """ >>> import pytest - >>> @pytest.mark.xfail(reason='this is unexpect pass') - ... def test_pytest_xfail_marker_example(): + >>> @pytest.mark.usefixtures('test_fixture') + ... def test_pytest_reserved_marker_usefixtures_is_not_converted_to_allure_tag_example(): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_reserved_marker_usefixtures_is_not_converted_to_allure_tag_example", + not_( + has_tag("usefixtures('test_fixture')") + ) + ) + ) + + +def test_pytest_reserved_marker_filterwarnings_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.filterwarnings('ignore:val') + ... def test_pytest_reserved_marker_filterwarnings_is_not_converted_to_allure_tag_example(): ... pass """ @@ -75,18 +153,22 @@ def test_pytest_xfail_marker(allure_pytest_runner: AllurePytestRunner): assert_that( allure_results, has_test_case( - "test_pytest_xfail_marker_example", - has_tag("@pytest.mark.xfail(reason='this is unexpect pass')") + "test_pytest_reserved_marker_filterwarnings_is_not_converted_to_allure_tag_example", + not_( + has_tag("filterwarnings('ignore:val')") + ) ) ) -def test_pytest_marker_with_args(allure_pytest_runner: AllurePytestRunner): +def test_pytest_reserved_marker_skip_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): """ >>> import pytest - >>> @pytest.mark.marker('cool', 'stuff') - ... def test_pytest_marker_with_args_example(): + >>> @pytest.mark.skip(reason='reason') + ... def test_pytest_reserved_marker_skip_is_not_converted_to_allure_tag_example(): ... pass """ @@ -95,18 +177,22 @@ def test_pytest_marker_with_args(allure_pytest_runner: AllurePytestRunner): assert_that( allure_results, has_test_case( - "test_pytest_marker_with_args_example", - has_tag("marker('cool', 'stuff')") + "test_pytest_reserved_marker_skip_is_not_converted_to_allure_tag_example", + not_( + has_tag("skip(reason='reason')") + ) ) ) -def test_pytest_marker_with_kwargs(allure_pytest_runner: AllurePytestRunner): +def test_pytest_reserved_marker_skipif_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): """ >>> import pytest - >>> @pytest.mark.marker(stuff='cool') - ... def test_pytest_marker_with_kwargs_example(): + >>> @pytest.mark.skipif(False, reason='reason') + ... def test_pytest_reserved_marker_skipif_is_not_converted_to_allure_tag_example(): ... pass """ @@ -115,20 +201,22 @@ def test_pytest_marker_with_kwargs(allure_pytest_runner: AllurePytestRunner): assert_that( allure_results, has_test_case( - "test_pytest_marker_with_kwargs_example", - has_tag("marker(stuff='cool')") + "test_pytest_reserved_marker_skipif_is_not_converted_to_allure_tag_example", + not_( + has_tag("skipif(False, reason='reason')") + ) ) ) -def test_pytest_marker_with_kwargs_native_encoding( - allure_pytest_runner: AllurePytestRunner +def test_pytest_reserved_marker_xfail_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner ): """ >>> import pytest - >>> @pytest.mark.marker(stuff='я') - ... def test_pytest_marker_with_kwargs_native_encoding_example(): + >>> @pytest.mark.xfail(reason='this is unexpect pass') + ... def test_pytest_reserved_marker_xfail_is_not_converted_to_allure_tag_example(): ... pass """ @@ -137,20 +225,47 @@ def test_pytest_marker_with_kwargs_native_encoding( assert_that( allure_results, has_test_case( - "test_pytest_marker_with_kwargs_native_encoding_example", - has_tag("marker(stuff='я')") + "test_pytest_reserved_marker_xfail_is_not_converted_to_allure_tag_example", + not_( + has_tag("xfail(reason='this is unexpect pass')") + ) + ) + ) + + +def test_pytest_reserved_marker_parametrize_is_not_converted_to_allure_tag( + allure_pytest_runner: AllurePytestRunner +): + """ + >>> import pytest + + >>> @pytest.mark.parametrize("param", ["foo"]) + ... def test_pytest_reserved_marker_parametrize_is_not_converted_to_allure_tag_example(param): + ... pass + """ + + allure_results = allure_pytest_runner.run_docstring() + + assert_that( + allure_results, + has_test_case( + "test_pytest_reserved_marker_parametrize_is_not_converted_to_allure_tag_example[foo]", + not_( + has_tag("parametrize('param', ['foo'])") + ) ) ) -def test_pytest_marker_with_kwargs_utf_encoding( - allure_pytest_runner: AllurePytestRunner +def test_pytest_simple_markers_utf_encoding_are_converted_to_allure_tags( + allure_pytest_runner: AllurePytestRunner ): """ >>> import pytest - >>> @pytest.mark.marker(stuff='я') - ... def test_pytest_marker_with_kwargs_utf_encoding_example(): + >>> @pytest.mark.классная + >>> @pytest.mark.штука + ... def test_pytest_simple_markers_utf_encoding_are_converted_to_allure_tags_example(): ... pass """ @@ -159,7 +274,8 @@ def test_pytest_marker_with_kwargs_utf_encoding( assert_that( allure_results, has_test_case( - "test_pytest_marker_with_kwargs_utf_encoding_example", - has_tag("marker(stuff='я')") + "test_pytest_simple_markers_utf_encoding_are_converted_to_allure_tags_example", + has_tag("классная"), + has_tag("штука") ) ) diff --git a/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py b/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py index b242b488..779657c3 100644 --- a/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py +++ b/tests/allure_pytest/externals/pytest_rerunfailures/pytest_rerunfailures_test.py @@ -65,6 +65,6 @@ def __count_labels(tc, name): assert len(output.test_cases) == 2 assert __count_labels(output.test_cases[0], "suite") == 1 - assert __count_labels(output.test_cases[0], "tag") == 1 + assert __count_labels(output.test_cases[0], "tag") == 0 assert __count_labels(output.test_cases[1], "suite") == 1 - assert __count_labels(output.test_cases[1], "tag") == 1 + assert __count_labels(output.test_cases[1], "tag") == 0 From 26b6a9cea3066bb0e317441c36813cad0f0afc60 Mon Sep 17 00:00:00 2001 From: sharovd Date: Sat, 17 May 2025 13:56:55 +0400 Subject: [PATCH 2/3] fix the issue found by the linter (F401 'allure_commons.utils.represent' imported but unused) --- allure-pytest/src/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/allure-pytest/src/utils.py b/allure-pytest/src/utils.py index d8e075e5..19145510 100644 --- a/allure-pytest/src/utils.py +++ b/allure-pytest/src/utils.py @@ -1,6 +1,6 @@ import pytest from itertools import chain, islice -from allure_commons.utils import represent, SafeFormatter, md5 +from allure_commons.utils import SafeFormatter, md5 from allure_commons.utils import format_exception, format_traceback from allure_commons.model2 import Status from allure_commons.model2 import StatusDetails From c3b3197b0e6c90ac0006c686b36d3153bc5cecd4 Mon Sep 17 00:00:00 2001 From: sharovd Date: Mon, 9 Jun 2025 17:07:46 +0400 Subject: [PATCH 3/3] apply suggestions from code review --- .../acceptance/label/tag/tag_test.py | 78 +++---------------- 1 file changed, 9 insertions(+), 69 deletions(-) diff --git a/tests/allure_pytest/acceptance/label/tag/tag_test.py b/tests/allure_pytest/acceptance/label/tag/tag_test.py index bd8779ad..a738628b 100644 --- a/tests/allure_pytest/acceptance/label/tag/tag_test.py +++ b/tests/allure_pytest/acceptance/label/tag/tag_test.py @@ -1,4 +1,4 @@ -from hamcrest import assert_that, not_ +from hamcrest import assert_that, not_, anything from tests.allure_pytest.pytest_runner import AllurePytestRunner from allure_commons_test.report import has_test_case @@ -47,7 +47,7 @@ def test_pytest_marker_with_args_is_not_converted_to_allure_tag( has_test_case( "test_pytest_marker_with_args_is_not_converted_to_allure_tag_example", not_( - has_tag("marker('cool', 'stuff')") + has_tag(anything()) ) ) ) @@ -71,43 +71,7 @@ def test_pytest_marker_with_kwargs_is_not_converted_to_allure_tag( has_test_case( "test_pytest_marker_with_kwargs_is_not_converted_to_allure_tag_example", not_( - has_tag("marker(stuff='cool')") - ) - ) - ) - - -def test_pytest_multiple_simple_and_reserved_markers_to_allure_tags( - allure_pytest_runner: AllurePytestRunner -): - """ - >>> import pytest - - >>> @pytest.mark.usermark1 - ... @pytest.mark.usermark2 - ... @pytest.mark.parametrize("param", ["foo"]) - ... @pytest.mark.skipif(False, reason="reason2") - ... @pytest.mark.skipif(False, reason="reason1") - ... def test_pytest_multiple_simple_and_reserved_markers_to_allure_tags_example(param): - ... pass - """ - - allure_results = allure_pytest_runner.run_docstring() - - assert_that( - allure_results, - has_test_case( - "test_pytest_multiple_simple_and_reserved_markers_to_allure_tags_example[foo]", - has_tag("usermark1"), - has_tag("usermark2"), - not_( - has_tag("skipif(False, reason='reason1')") - ), - not_( - has_tag("skipif(False, reason='reason2')") - ), - not_( - has_tag("parametrize('param', ['foo'])") + has_tag(anything()) ) ) ) @@ -131,7 +95,7 @@ def test_pytest_reserved_marker_usefixtures_is_not_converted_to_allure_tag( has_test_case( "test_pytest_reserved_marker_usefixtures_is_not_converted_to_allure_tag_example", not_( - has_tag("usefixtures('test_fixture')") + has_tag(anything()) ) ) ) @@ -155,7 +119,7 @@ def test_pytest_reserved_marker_filterwarnings_is_not_converted_to_allure_tag( has_test_case( "test_pytest_reserved_marker_filterwarnings_is_not_converted_to_allure_tag_example", not_( - has_tag("filterwarnings('ignore:val')") + has_tag(anything()) ) ) ) @@ -179,7 +143,7 @@ def test_pytest_reserved_marker_skip_is_not_converted_to_allure_tag( has_test_case( "test_pytest_reserved_marker_skip_is_not_converted_to_allure_tag_example", not_( - has_tag("skip(reason='reason')") + has_tag(anything()) ) ) ) @@ -203,7 +167,7 @@ def test_pytest_reserved_marker_skipif_is_not_converted_to_allure_tag( has_test_case( "test_pytest_reserved_marker_skipif_is_not_converted_to_allure_tag_example", not_( - has_tag("skipif(False, reason='reason')") + has_tag(anything()) ) ) ) @@ -227,7 +191,7 @@ def test_pytest_reserved_marker_xfail_is_not_converted_to_allure_tag( has_test_case( "test_pytest_reserved_marker_xfail_is_not_converted_to_allure_tag_example", not_( - has_tag("xfail(reason='this is unexpect pass')") + has_tag(anything()) ) ) ) @@ -251,31 +215,7 @@ def test_pytest_reserved_marker_parametrize_is_not_converted_to_allure_tag( has_test_case( "test_pytest_reserved_marker_parametrize_is_not_converted_to_allure_tag_example[foo]", not_( - has_tag("parametrize('param', ['foo'])") + has_tag(anything()) ) ) ) - - -def test_pytest_simple_markers_utf_encoding_are_converted_to_allure_tags( - allure_pytest_runner: AllurePytestRunner -): - """ - >>> import pytest - - >>> @pytest.mark.классная - >>> @pytest.mark.штука - ... def test_pytest_simple_markers_utf_encoding_are_converted_to_allure_tags_example(): - ... pass - """ - - allure_results = allure_pytest_runner.run_docstring() - - assert_that( - allure_results, - has_test_case( - "test_pytest_simple_markers_utf_encoding_are_converted_to_allure_tags_example", - has_tag("классная"), - has_tag("штука") - ) - )