Fix ParallelTreeManager cannot find nodeids when using xdist

+ pytest parameters + teamcity


Merge-request: IJ-MR-174417
Merged-by: Egor Eliseev <Egor.Eliseev@jetbrains.com>

GitOrigin-RevId: 92838e6f54c142cab795912db2c4fc20e9daca99
This commit is contained in:
YueChen-C
2025-09-03 15:42:01 +00:00
committed by intellij-monorepo-bot
parent ae9fd63d67
commit 4cc8fd2eba
3 changed files with 38 additions and 35 deletions
@@ -1,4 +1,5 @@
# coding=utf-8
import _jb_utils
class ParallelTreeManager(object):
@@ -68,6 +69,6 @@ class ParallelTreeManager(object):
:return: (current_node_id, parent_node_id) or None, None if message must be ignored
"""
try:
return self._branches[tuple(test_name.split("."))]
return self._branches[tuple(_jb_utils.test_to_list(test_name))]
except KeyError:
return None, None
+5 -34
View File
@@ -25,24 +25,6 @@ JB_VERBOSE = "JB_VERBOSE" in os.environ
PROJECT_DIR = os.getenv('PWD', os.getcwd())
def _parse_parametrized(part):
"""
Support nose generators / pytest parameters and other functions that provides names like foo(1,2)
Until https://github.com/JetBrains/teamcity-messages/issues/121, all such tests are provided
with parentheses.
Tests with docstring are reported in similar way but they have space before parenthesis and should be ignored
by this function
"""
match = re.match("^([^\\s)(]+)(\\(.+\\))$", part)
if not match:
return [part]
else:
return [match.group(1), match.group(2)]
class _TreeManagerHolder(object):
def __init__(self):
self.parallel = "JB_USE_PARALLEL_TREE_MANAGER" in os.environ
@@ -184,17 +166,6 @@ class NewTeamcityServiceMessages(_old_service_messages):
self._test_suites[ancestor].was_stopped = True
_old_service_messages.message(self, messageName, **properties)
def _test_to_list(self, test_name):
"""
Splits test name to parts to use it as list.
It most cases dot is used, but runner may provide custom function
"""
parts = test_name.split(".")
result = []
for part in parts:
result += _parse_parametrized(part)
return result
def _fix_setup_teardown_name(self, test_name):
"""
@@ -235,7 +206,7 @@ class NewTeamcityServiceMessages(_old_service_messages):
self._latest_subtest_result = subTestResult
def testStarted(self, testName, captureStandardOutput=None, flowId=None, is_suite=False, metainfo=None):
test_name_as_list = self._test_to_list(testName)
test_name_as_list = _jb_utils.test_to_list(testName)
testName = ".".join(test_name_as_list)
def _write_start_message():
@@ -246,13 +217,13 @@ class NewTeamcityServiceMessages(_old_service_messages):
else:
self.message("testStarted", **args)
commands = _TREE_MANAGER_HOLDER.manager.level_opened(self._test_to_list(testName), _write_start_message)
commands = _TREE_MANAGER_HOLDER.manager.level_opened(test_name_as_list, _write_start_message)
if commands:
self.do_commands(commands)
self.testStarted(testName, captureStandardOutput, is_suite=is_suite, metainfo=metainfo)
def testFailed(self, testName, message='', details='', flowId=None, comparison_failure=None):
testName = ".".join(self._test_to_list(testName))
testName = ".".join(_jb_utils.test_to_list(testName))
if JB_DISABLE_BUFFERING:
self._print_error(details)
details = None
@@ -266,7 +237,7 @@ class NewTeamcityServiceMessages(_old_service_messages):
self.stderr_output_manager.send_message(self.encode(message))
def testFinished(self, testName, testDuration=None, flowId=None, is_suite=False):
test_parts = self._test_to_list(testName)
test_parts = _jb_utils.test_to_list(testName)
testName = ".".join(test_parts)
def _write_finished_message():
@@ -293,7 +264,7 @@ class NewTeamcityServiceMessages(_old_service_messages):
del self._test_suites[testName]
commands = _TREE_MANAGER_HOLDER.manager.level_closed(
self._test_to_list(testName), _write_finished_message)
test_parts, _write_finished_message)
if commands:
self.do_commands(commands)
self.testFinished(testName, testDuration)
+31
View File
@@ -3,6 +3,7 @@
__author__ = 'Ilya.Kazakevich'
import fnmatch
import os
import re
import sys
@@ -138,3 +139,33 @@ class _Py3KUtils(VersionAgnosticUtils):
assert isinstance(option, OptionDescription)
parser.add_argument(option.name, help=option.description, action=option.action)
return parser.parse_args()
def _parse_parametrized(part):
"""
Support nose generators / pytest parameters and other functions that provides names like foo(1,2)
Until https://github.com/JetBrains/teamcity-messages/issues/121, all such tests are provided
with parentheses.
Tests with docstring are reported in similar way but they have space before parenthesis and should be ignored
by this function
"""
match = re.match("^([^\\s)(]+)(\\(.+\\))$", part)
if not match:
return [part]
else:
return [match.group(1), match.group(2)]
def test_to_list(test_name):
"""
Splits test name to parts to use it as list.
It most cases dot is used, but runner may provide custom function
"""
parts = test_name.split(".")
result = []
for part in parts:
result += _parse_parametrized(part)
return result