From 21c1102b35237201c8cbb9b2fdb433bd2a533358 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 22:09:26 +0000 Subject: [PATCH 1/9] Initial plan From 72fd373f5286bb9d3602c8648bd0217b267d7cc0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 22:32:41 +0000 Subject: [PATCH 2/9] Add lineno to class nodes for pytest discovery - Modified create_class_node() to extract and include line number using inspect.getsourcelines() - Updated TypeScript types to allow optional lineno on DiscoveredTestNode - Modified populateTestTree() to handle lineno for class nodes (not just test items) - Added find_class_line_number() helper function for test expectations - Updated all test expectations to include lineno for class nodes - Added 'function' to DiscoveredTestType enum This enables TestClass items to show the green arrow and be runnable in VS Code's Test Explorer. Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> --- .../expected_discovery_test_output.py | 58 ++++++++++++++++++- python_files/tests/pytestadapter/helpers.py | 20 +++++++ python_files/vscode_pytest/__init__.py | 13 +++++ .../testing/testController/common/types.ts | 3 +- .../testing/testController/common/utils.ts | 15 +++++ 5 files changed, 107 insertions(+), 2 deletions(-) diff --git a/python_files/tests/pytestadapter/expected_discovery_test_output.py b/python_files/tests/pytestadapter/expected_discovery_test_output.py index e00db5d660a3..0641529c0d98 100644 --- a/python_files/tests/pytestadapter/expected_discovery_test_output.py +++ b/python_files/tests/pytestadapter/expected_discovery_test_output.py @@ -1,6 +1,11 @@ import os -from .helpers import TEST_DATA_PATH, find_test_line_number, get_absolute_test_id +from .helpers import ( + TEST_DATA_PATH, + find_class_line_number, + find_test_line_number, + get_absolute_test_id, +) # This file contains the expected output dictionaries for tests discovery and is used in test_discovery.py. @@ -95,6 +100,9 @@ "unittest_pytest_same_file.py::TestExample", unit_pytest_same_file_path, ), + "lineno": find_class_line_number( + "TestExample", unit_pytest_same_file_path + ), }, { "name": "test_true_pytest", @@ -207,6 +215,9 @@ "unittest_folder/test_add.py::TestAddFunction", test_add_path, ), + "lineno": find_class_line_number( + "TestAddFunction", test_add_path + ), }, { "name": "TestDuplicateFunction", @@ -235,6 +246,9 @@ "unittest_folder/test_add.py::TestDuplicateFunction", test_add_path, ), + "lineno": find_class_line_number( + "TestDuplicateFunction", test_add_path + ), }, ], }, @@ -288,6 +302,9 @@ "unittest_folder/test_subtract.py::TestSubtractFunction", test_subtract_path, ), + "lineno": find_class_line_number( + "TestSubtractFunction", test_subtract_path + ), }, { "name": "TestDuplicateFunction", @@ -316,6 +333,9 @@ "unittest_folder/test_subtract.py::TestDuplicateFunction", test_subtract_path, ), + "lineno": find_class_line_number( + "TestDuplicateFunction", test_subtract_path + ), }, ], }, @@ -553,6 +573,9 @@ "parametrize_tests.py::TestClass", parameterize_tests_path, ), + "lineno": find_class_line_number( + "TestClass", parameterize_tests_path + ), "children": [ { "name": "test_adding", @@ -929,6 +952,9 @@ "test_multi_class_nest.py::TestFirstClass", TEST_MULTI_CLASS_NEST_PATH, ), + "lineno": find_class_line_number( + "TestFirstClass", TEST_MULTI_CLASS_NEST_PATH + ), "children": [ { "name": "TestSecondClass", @@ -938,6 +964,9 @@ "test_multi_class_nest.py::TestFirstClass::TestSecondClass", TEST_MULTI_CLASS_NEST_PATH, ), + "lineno": find_class_line_number( + "TestSecondClass", TEST_MULTI_CLASS_NEST_PATH + ), "children": [ { "name": "test_second", @@ -982,6 +1011,9 @@ "test_multi_class_nest.py::TestFirstClass::TestSecondClass2", TEST_MULTI_CLASS_NEST_PATH, ), + "lineno": find_class_line_number( + "TestSecondClass2", TEST_MULTI_CLASS_NEST_PATH + ), "children": [ { "name": "test_second2", @@ -1227,6 +1259,9 @@ "same_function_new_class_param.py::TestNotEmpty", TEST_DATA_PATH / "same_function_new_class_param.py", ), + "lineno": find_class_line_number( + "TestNotEmpty", TEST_DATA_PATH / "same_function_new_class_param.py" + ), }, { "name": "TestEmpty", @@ -1298,6 +1333,9 @@ "same_function_new_class_param.py::TestEmpty", TEST_DATA_PATH / "same_function_new_class_param.py", ), + "lineno": find_class_line_number( + "TestEmpty", TEST_DATA_PATH / "same_function_new_class_param.py" + ), }, ], } @@ -1371,6 +1409,9 @@ "test_param_span_class.py::TestClass1", TEST_DATA_PATH / "test_param_span_class.py", ), + "lineno": find_class_line_number( + "TestClass1", TEST_DATA_PATH / "test_param_span_class.py" + ), }, { "name": "TestClass2", @@ -1427,6 +1468,9 @@ "test_param_span_class.py::TestClass2", TEST_DATA_PATH / "test_param_span_class.py", ), + "lineno": find_class_line_number( + "TestClass2", TEST_DATA_PATH / "test_param_span_class.py" + ), }, ], } @@ -1503,6 +1547,9 @@ "pytest_describe_plugin/describe_only.py::describe_A", describe_only_path, ), + "lineno": find_class_line_number( + "describe_A", describe_only_path + ), } ], } @@ -1586,6 +1633,9 @@ "pytest_describe_plugin/nested_describe.py::describe_list::describe_append", nested_describe_path, ), + "lineno": find_class_line_number( + "describe_append", nested_describe_path + ), }, { "name": "describe_remove", @@ -1614,12 +1664,18 @@ "pytest_describe_plugin/nested_describe.py::describe_list::describe_remove", nested_describe_path, ), + "lineno": find_class_line_number( + "describe_remove", nested_describe_path + ), }, ], "id_": get_absolute_test_id( "pytest_describe_plugin/nested_describe.py::describe_list", nested_describe_path, ), + "lineno": find_class_line_number( + "describe_list", nested_describe_path + ), } ], } diff --git a/python_files/tests/pytestadapter/helpers.py b/python_files/tests/pytestadapter/helpers.py index 4c337585bece..7b822ba071ce 100644 --- a/python_files/tests/pytestadapter/helpers.py +++ b/python_files/tests/pytestadapter/helpers.py @@ -370,6 +370,26 @@ def find_test_line_number(test_name: str, test_file_path) -> str: raise ValueError(error_str) +def find_class_line_number(class_name: str, test_file_path) -> str: + """Function which finds the correct line number for a class definition. + + Args: + class_name: The name of the class to find the line number for. + test_file_path: The path to the test file where the class is located. + """ + # Look for the class definition line (or function for pytest-describe) + with open(test_file_path) as f: # noqa: PTH123 + for i, line in enumerate(f): + # Match "class ClassName" or "class ClassName(" or "class ClassName:" + # Also match "def ClassName(" for pytest-describe blocks + if line.strip().startswith(f"class {class_name}") or line.strip().startswith( + f"class {class_name}(" + ) or line.strip().startswith(f"def {class_name}("): + return str(i + 1) + error_str: str = f"Class {class_name!r} not found on any line in {test_file_path}" + raise ValueError(error_str) + + def get_absolute_test_id(test_id: str, test_path: pathlib.Path) -> str: """Get the absolute test id by joining the testPath with the test_id.""" split_id = test_id.split("::")[1:] diff --git a/python_files/vscode_pytest/__init__.py b/python_files/vscode_pytest/__init__.py index 0eac4a74f4c3..e5e261118e05 100644 --- a/python_files/vscode_pytest/__init__.py +++ b/python_files/vscode_pytest/__init__.py @@ -830,12 +830,25 @@ def create_class_node(class_module: pytest.Class | DescribeBlock) -> TestNode: Keyword arguments: class_module -- the pytest object representing a class module. """ + # Get line number for the class definition + class_line = "" + try: + if hasattr(class_module, "obj"): + import inspect + + _, lineno = inspect.getsourcelines(class_module.obj) + class_line = str(lineno) + except (OSError, TypeError): + # If we can't get the source lines, leave lineno empty + pass + return { "name": class_module.name, "path": get_node_path(class_module), "type_": "class", "children": [], "id_": get_absolute_test_id(class_module.nodeid, get_node_path(class_module)), + "lineno": class_line, } diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index 5c6796905024..6121b3e24442 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -177,7 +177,7 @@ export interface ITestExecutionAdapter { } // Same types as in python_files/unittestadapter/utils.py -export type DiscoveredTestType = 'folder' | 'file' | 'class' | 'test'; +export type DiscoveredTestType = 'folder' | 'file' | 'class' | 'function' | 'test'; export type DiscoveredTestCommon = { path: string; @@ -194,6 +194,7 @@ export type DiscoveredTestItem = DiscoveredTestCommon & { export type DiscoveredTestNode = DiscoveredTestCommon & { children: (DiscoveredTestNode | DiscoveredTestItem)[]; + lineno?: number | string; }; export type DiscoveredTestPayload = { diff --git a/src/client/testing/testController/common/utils.ts b/src/client/testing/testController/common/utils.ts index 0bbf0e449dcd..606865e5ad7e 100644 --- a/src/client/testing/testController/common/utils.ts +++ b/src/client/testing/testController/common/utils.ts @@ -257,6 +257,21 @@ export function populateTestTree( node.canResolveChildren = true; node.tags = [RunTestTag, DebugTestTag]; + + // Set range for class nodes (and other nodes) if lineno is available + let range: Range | undefined; + if ('lineno' in child && child.lineno) { + if (Number(child.lineno) === 0) { + range = new Range(new Position(0, 0), new Position(0, 0)); + } else { + range = new Range( + new Position(Number(child.lineno) - 1, 0), + new Position(Number(child.lineno), 0), + ); + } + node.range = range; + } + testRoot!.children.add(node); } populateTestTree(testController, child, node, resultResolver, token); From 85e6ca88404911da05fdf96971044e7f9bf3adcc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 22:35:05 +0000 Subject: [PATCH 3/9] Fix Python type checking errors and format code - Added NotRequired to imports for optional TypedDict fields - Made lineno an optional field in TestNode TypedDict - Formatted Python files with ruff Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> --- .../expected_discovery_test_output.py | 24 +++++-------------- python_files/tests/pytestadapter/helpers.py | 8 ++++--- python_files/vscode_pytest/__init__.py | 13 +++++++++- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/python_files/tests/pytestadapter/expected_discovery_test_output.py b/python_files/tests/pytestadapter/expected_discovery_test_output.py index 0641529c0d98..b6f0779cf982 100644 --- a/python_files/tests/pytestadapter/expected_discovery_test_output.py +++ b/python_files/tests/pytestadapter/expected_discovery_test_output.py @@ -100,9 +100,7 @@ "unittest_pytest_same_file.py::TestExample", unit_pytest_same_file_path, ), - "lineno": find_class_line_number( - "TestExample", unit_pytest_same_file_path - ), + "lineno": find_class_line_number("TestExample", unit_pytest_same_file_path), }, { "name": "test_true_pytest", @@ -215,9 +213,7 @@ "unittest_folder/test_add.py::TestAddFunction", test_add_path, ), - "lineno": find_class_line_number( - "TestAddFunction", test_add_path - ), + "lineno": find_class_line_number("TestAddFunction", test_add_path), }, { "name": "TestDuplicateFunction", @@ -573,9 +569,7 @@ "parametrize_tests.py::TestClass", parameterize_tests_path, ), - "lineno": find_class_line_number( - "TestClass", parameterize_tests_path - ), + "lineno": find_class_line_number("TestClass", parameterize_tests_path), "children": [ { "name": "test_adding", @@ -952,9 +946,7 @@ "test_multi_class_nest.py::TestFirstClass", TEST_MULTI_CLASS_NEST_PATH, ), - "lineno": find_class_line_number( - "TestFirstClass", TEST_MULTI_CLASS_NEST_PATH - ), + "lineno": find_class_line_number("TestFirstClass", TEST_MULTI_CLASS_NEST_PATH), "children": [ { "name": "TestSecondClass", @@ -1547,9 +1539,7 @@ "pytest_describe_plugin/describe_only.py::describe_A", describe_only_path, ), - "lineno": find_class_line_number( - "describe_A", describe_only_path - ), + "lineno": find_class_line_number("describe_A", describe_only_path), } ], } @@ -1673,9 +1663,7 @@ "pytest_describe_plugin/nested_describe.py::describe_list", nested_describe_path, ), - "lineno": find_class_line_number( - "describe_list", nested_describe_path - ), + "lineno": find_class_line_number("describe_list", nested_describe_path), } ], } diff --git a/python_files/tests/pytestadapter/helpers.py b/python_files/tests/pytestadapter/helpers.py index 7b822ba071ce..25e6187e2efa 100644 --- a/python_files/tests/pytestadapter/helpers.py +++ b/python_files/tests/pytestadapter/helpers.py @@ -382,9 +382,11 @@ def find_class_line_number(class_name: str, test_file_path) -> str: for i, line in enumerate(f): # Match "class ClassName" or "class ClassName(" or "class ClassName:" # Also match "def ClassName(" for pytest-describe blocks - if line.strip().startswith(f"class {class_name}") or line.strip().startswith( - f"class {class_name}(" - ) or line.strip().startswith(f"def {class_name}("): + if ( + line.strip().startswith(f"class {class_name}") + or line.strip().startswith(f"class {class_name}(") + or line.strip().startswith(f"def {class_name}(") + ): return str(i + 1) error_str: str = f"Class {class_name!r} not found on any line in {test_file_path}" raise ValueError(error_str) diff --git a/python_files/vscode_pytest/__init__.py b/python_files/vscode_pytest/__init__.py index e5e261118e05..c4265751a2dd 100644 --- a/python_files/vscode_pytest/__init__.py +++ b/python_files/vscode_pytest/__init__.py @@ -10,7 +10,17 @@ import pathlib import sys import traceback -from typing import TYPE_CHECKING, Any, Dict, Generator, Literal, Protocol, TypedDict, cast +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Generator, + Literal, + NotRequired, + Protocol, + TypedDict, + cast, +) import pytest @@ -52,6 +62,7 @@ class TestNode(TestData): """A general class that handles all test data which contains children.""" children: list[TestNode | TestItem | None] + lineno: NotRequired[str] # Optional field for class/function nodes class VSCodePytestError(Exception): From 25dbb7b1f294be34d5cc76e5e9886c17ec731401 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:13:06 +0000 Subject: [PATCH 4/9] Add lineno to class nodes for unittest discovery - Modified build_test_tree() in pvsc_utils.py to add line numbers to class nodes - Added get_class_line() function to extract class line numbers using inspect - Made lineno an optional field in TestNode TypedDict - Added find_class_line_number() helper for test expectations - Updated expected test outputs to include lineno for class nodes This implements the same functionality for unittest as was done for pytest, enabling TestClass items to show the green arrow and be runnable in VS Code's Test Explorer. Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> --- .../expected_discovery_test_output.py | 33 +++++++++++++++++++ python_files/unittestadapter/pvsc_utils.py | 15 +++++++++ 2 files changed, 48 insertions(+) diff --git a/python_files/tests/unittestadapter/expected_discovery_test_output.py b/python_files/tests/unittestadapter/expected_discovery_test_output.py index 9de0eff8238c..0901f21bfbc2 100644 --- a/python_files/tests/unittestadapter/expected_discovery_test_output.py +++ b/python_files/tests/unittestadapter/expected_discovery_test_output.py @@ -9,6 +9,25 @@ TEST_DATA_PATH = pathlib.Path(__file__).parent / ".data" +def find_class_line_number(class_name: str, test_file_path) -> str: + """Function which finds the correct line number for a class definition. + + Args: + class_name: The name of the class to find the line number for. + test_file_path: The path to the test file where the class is located. + """ + # Look for the class definition line + with pathlib.Path(test_file_path).open() as f: + for i, line in enumerate(f): + # Match "class ClassName" or "class ClassName(" or "class ClassName:" + if line.strip().startswith(f"class {class_name}") or line.strip().startswith( + f"class {class_name}(" + ): + return str(i + 1) + error_str: str = f"Class {class_name!r} not found on any line in {test_file_path}" + raise ValueError(error_str) + + skip_unittest_folder_discovery_output = { "path": os.fspath(TEST_DATA_PATH / "unittest_skip"), "name": "unittest_skip", @@ -49,6 +68,10 @@ ], "id_": os.fspath(TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py") + "\\SimpleTest", + "lineno": find_class_line_number( + "SimpleTest", + TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py", + ), } ], "id_": os.fspath(TEST_DATA_PATH / "unittest_skip" / "unittest_skip_function.py"), @@ -114,6 +137,16 @@ }, ], "id_": complex_tree_file_path + "\\" + "TreeOne", + "lineno": find_class_line_number( + "TreeOne", + pathlib.PurePath( + TEST_DATA_PATH, + "utils_complex_tree", + "test_outer_folder", + "test_inner_folder", + "test_utils_complex_tree.py", + ), + ), } ], "id_": complex_tree_file_path, diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index e9d7bc092992..6447319c8b4e 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -44,6 +44,7 @@ class TestItem(TestData): class TestNode(TestData): children: "List[TestNode | TestItem]" + lineno: NotRequired[str] # Optional field for class nodes class TestExecutionStatus(str, enum.Enum): @@ -101,6 +102,16 @@ def get_test_case(suite): yield from get_test_case(test) +def get_class_line(test_case: unittest.TestCase) -> str: + """Get the line number where a test class is defined.""" + try: + test_class = test_case.__class__ + _sourcelines, lineno = inspect.getsourcelines(test_class) + return str(lineno) + except Exception: + return "*" + + def get_source_line(obj) -> str: """Get the line number of a test case start line.""" try: @@ -249,6 +260,10 @@ def build_test_tree( class_name, file_path, TestNodeTypeEnum.class_, current_node ) + # Add line number to class node if not already present. + if "lineno" not in current_node: + current_node["lineno"] = get_class_line(test_case) + # Get test line number. test_method = getattr(test_case, test_case._testMethodName) # noqa: SLF001 lineno = get_source_line(test_method) From d1828b32c9d21114f9c832af8461a16d61a7ff32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:38:13 +0000 Subject: [PATCH 5/9] Return empty string instead of asterisk when class line cannot be determined Changed get_class_line() to return "" instead of "*" when inspect.getsourcelines() fails, making it consistent with the pytest implementation and leaving the field blank when the line number cannot be determined. Co-authored-by: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> --- python_files/unittestadapter/pvsc_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index 6447319c8b4e..6f6d7f70825b 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -109,7 +109,7 @@ def get_class_line(test_case: unittest.TestCase) -> str: _sourcelines, lineno = inspect.getsourcelines(test_class) return str(lineno) except Exception: - return "*" + return "" def get_source_line(obj) -> str: From e9305563cdeffcad6605ab48ad572b4d6c3bd9d6 Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:47:59 -0800 Subject: [PATCH 6/9] opt for undefined as null value --- python_files/unittestadapter/pvsc_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index 6f6d7f70825b..b336d8e35d98 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -102,14 +102,14 @@ def get_test_case(suite): yield from get_test_case(test) -def get_class_line(test_case: unittest.TestCase) -> str: +def get_class_line(test_case: unittest.TestCase) -> str | None: """Get the line number where a test class is defined.""" try: test_class = test_case.__class__ _sourcelines, lineno = inspect.getsourcelines(test_class) return str(lineno) except Exception: - return "" + return None def get_source_line(obj) -> str: From 0d7a23023adfeee43fae3a88e1a0515c30d4f190 Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:49:48 -0800 Subject: [PATCH 7/9] linting --- python_files/unittestadapter/pvsc_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index b336d8e35d98..9bb22b7bc130 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -262,7 +262,9 @@ def build_test_tree( # Add line number to class node if not already present. if "lineno" not in current_node: - current_node["lineno"] = get_class_line(test_case) + class_lineno = get_class_line(test_case) + if class_lineno is not None: + current_node["lineno"] = class_lineno # Get test line number. test_method = getattr(test_case, test_case._testMethodName) # noqa: SLF001 From 26fd006d4bf25a0d871a1d66e604d64af28ce277 Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:02:27 -0800 Subject: [PATCH 8/9] typing and formatting --- python_files/vscode_pytest/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_files/vscode_pytest/__init__.py b/python_files/vscode_pytest/__init__.py index c4265751a2dd..171132483912 100644 --- a/python_files/vscode_pytest/__init__.py +++ b/python_files/vscode_pytest/__init__.py @@ -16,11 +16,11 @@ Dict, Generator, Literal, - NotRequired, Protocol, TypedDict, cast, ) +from typing_extensions import NotRequired import pytest From 9847b5e86c47381074867375f4645454784963a0 Mon Sep 17 00:00:00 2001 From: eleanorjboyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Fri, 14 Nov 2025 16:06:50 -0800 Subject: [PATCH 9/9] fixes --- python_files/unittestadapter/pvsc_utils.py | 2 +- python_files/vscode_pytest/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python_files/unittestadapter/pvsc_utils.py b/python_files/unittestadapter/pvsc_utils.py index 9bb22b7bc130..d6920592a4d4 100644 --- a/python_files/unittestadapter/pvsc_utils.py +++ b/python_files/unittestadapter/pvsc_utils.py @@ -102,7 +102,7 @@ def get_test_case(suite): yield from get_test_case(test) -def get_class_line(test_case: unittest.TestCase) -> str | None: +def get_class_line(test_case: unittest.TestCase) -> Optional[str]: """Get the line number where a test class is defined.""" try: test_class = test_case.__class__ diff --git a/python_files/vscode_pytest/__init__.py b/python_files/vscode_pytest/__init__.py index 171132483912..91a81bff9a36 100644 --- a/python_files/vscode_pytest/__init__.py +++ b/python_files/vscode_pytest/__init__.py @@ -20,9 +20,9 @@ TypedDict, cast, ) -from typing_extensions import NotRequired import pytest +from typing_extensions import NotRequired if TYPE_CHECKING: from pluggy import Result