2424from typing import Generator # noqa:F401
2525from typing import List
2626from typing import Tuple # noqa:F401
27+ from unittest import TestCase
2728from unittest import mock
2829from urllib import parse
2930import warnings
4748from tests .utils import snapshot_context as _snapshot_context
4849
4950
51+ try :
52+ from pytest import StashKey
53+ except ImportError :
54+ StashKey = None
55+
56+
5057code_to_pyc = getattr (importlib ._bootstrap_external , "_code_to_timestamp_pyc" )
5158
5259
5360DEFAULT_DDTRACE_SUBPROCESS_TEST_SERVICE_NAME = "ddtrace_subprocess_dir"
5461
62+ # Stash keys for storing original test name and nodeid before Python version suffix is added
63+ # For pytest >= 7.1.0, use StashKey; for older versions, use attribute names
64+ if StashKey :
65+ original_test_name_key = StashKey [str ]()
66+ original_test_nodeid_key = StashKey [str ]()
67+ else :
68+ # Fallback attribute names for pytest < 7.1.0
69+ original_test_name_key = "_ddtrace_original_name"
70+ original_test_nodeid_key = "_ddtrace_original_nodeid"
71+
72+
73+ def get_original_test_name (request_or_item ):
74+ """Get the original test name (before Python version suffix was added).
75+
76+ Works with both pytest >= 7.1.0 (using stash) and older versions (using attributes).
77+
78+ Args:
79+ request_or_item: Either a pytest.FixtureRequest or pytest.Item
80+
81+ Returns:
82+ The original test name string, or the current name if not found
83+ """
84+ if hasattr (request_or_item , "node" ):
85+ # It's a FixtureRequest
86+ item = request_or_item .node
87+ else :
88+ # It's an Item
89+ item = request_or_item
90+
91+ if StashKey :
92+ # pytest >= 7.1.0: use stash
93+ return item .stash .get (original_test_name_key , item .name )
94+ else :
95+ # pytest < 7.1.0: use attribute
96+ return getattr (item , original_test_name_key , item .name )
97+
5598
5699# Hack to try and capture more logging data from pytest failing on `internal` jobs on
57100# pytest shutdown. This is a temporary workaround until we can figure out... why....
@@ -404,7 +447,13 @@ def _subprocess_wrapper():
404447
405448@pytest .hookimpl (tryfirst = True )
406449def pytest_collection_modifyitems (session , config , items ):
407- """Don't let ITR skip tests that use the subprocess marker because coverage collection in subprocesses is broken"""
450+ """
451+ Don't let ITR skip tests that use the subprocess marker
452+ because coverage collection in subprocesses is broken.
453+
454+ Also: add py39 - py314 suffix as parametrization in test names
455+ """
456+ py_tag = f"py{ sys .version_info .major } .{ sys .version_info .minor } "
408457 for item in items :
409458 if item .get_closest_marker ("subprocess" ):
410459 if item .get_closest_marker ("skipif" ):
@@ -413,6 +462,26 @@ def pytest_collection_modifyitems(session, config, items):
413462 unskippable = pytest .mark .skipif (False , reason = "datadog_itr_unskippable" )
414463 item .add_marker (unskippable )
415464
465+ # Store original name and nodeid before modification
466+ if StashKey :
467+ # pytest >= 7.1.0: use stash
468+ item .stash [original_test_name_key ] = item .name
469+ item .stash [original_test_nodeid_key ] = item .nodeid
470+ else :
471+ # pytest < 7.1.0: use attributes
472+ setattr (item , original_test_name_key , item .name )
473+ setattr (item , original_test_nodeid_key , item .nodeid )
474+
475+ name_base = item .name
476+ nodeid_base = item .nodeid
477+
478+ item ._nodeid = f"{ nodeid_base } [{ py_tag } ]"
479+
480+ cls = getattr (item , "cls" , None )
481+ is_unittest = isinstance (cls , type ) and issubclass (cls , TestCase )
482+ if not is_unittest :
483+ item .name = f"{ name_base } [{ py_tag } ]"
484+
416485
417486def pytest_generate_tests (metafunc ):
418487 marker = metafunc .definition .get_closest_marker ("subprocess" )
0 commit comments