Skip to content

Commit c931717

Browse files
andravinclaude
andcommitted
feat(testing): expose pytest marks as tags in Test Explorer
Extract pytest marks (e.g., @pytest.mark.slow, @pytest.mark.integration) during test discovery and expose them as VS Code TestTags with IDs like "mark.slow", "mark.integration". This enables filtering tests by marks in the Test Explorer UI using @python-tests:mark.slow syntax. Changes: - Add tags field to TestItem TypedDict in pytest plugin - Extract marks from test_case.own_markers in create_test_node() - Add tags field to DiscoveredTestItem TypeScript type - Create TestTag objects from marks in populateTestTree() Fixes #20350 Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 72bb721 commit c931717

File tree

3 files changed

+15
-2
lines changed

3 files changed

+15
-2
lines changed

python_files/vscode_pytest/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class TestItem(TestData):
5656

5757
lineno: str
5858
runID: str
59+
tags: list[str]
5960

6061

6162
class TestNode(TestData):
@@ -816,13 +817,22 @@ def create_test_node(
816817
str(test_case.location[1] + 1) if (test_case.location[1] is not None) else ""
817818
)
818819
absolute_test_id = get_absolute_test_id(test_case.nodeid, get_node_path(test_case))
820+
821+
# Extract pytest marks as tags
822+
tags: list[str] = []
823+
if hasattr(test_case, "own_markers"):
824+
for marker in test_case.own_markers:
825+
if marker.name and marker.name != "parametrize":
826+
tags.append(marker.name)
827+
819828
return {
820829
"name": test_case.name,
821830
"path": get_node_path(test_case),
822831
"lineno": test_case_loc,
823832
"type_": "test",
824833
"id_": absolute_test_id,
825834
"runID": absolute_test_id,
835+
"tags": tags,
826836
}
827837

828838

src/client/testing/testController/common/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ export type DiscoveredTestCommon = {
190190
export type DiscoveredTestItem = DiscoveredTestCommon & {
191191
lineno: number | string;
192192
runID: string;
193+
tags?: string[];
193194
};
194195

195196
export type DiscoveredTestNode = DiscoveredTestCommon & {

src/client/testing/testController/common/utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,10 @@ export function populateTestTree(
227227
if (!token?.isCancellationRequested) {
228228
if (isTestItem(child)) {
229229
const testItem = testController.createTestItem(child.id_, child.name, Uri.file(child.path));
230-
testItem.tags = [RunTestTag, DebugTestTag];
230+
231+
// Create tags from pytest marks (if available) and combine with default tags
232+
const pytestMarkTags = (child.tags ?? []).map((tag) => ({ id: `mark.${tag}` }));
233+
testItem.tags = [RunTestTag, DebugTestTag, ...pytestMarkTags];
231234

232235
let range: Range | undefined;
233236
if (child.lineno) {
@@ -242,7 +245,6 @@ export function populateTestTree(
242245
}
243246
testItem.canResolveChildren = false;
244247
testItem.range = range;
245-
testItem.tags = [RunTestTag, DebugTestTag];
246248

247249
testRoot!.children.add(testItem);
248250
// add to our map

0 commit comments

Comments
 (0)