1010import pathlib
1111import sys
1212import traceback
13- from typing import (
14- TYPE_CHECKING ,
15- Any ,
16- Dict ,
17- Generator ,
18- Literal ,
19- TypedDict ,
20- )
13+ from typing import TYPE_CHECKING , Any , Dict , Generator , Literal , TypedDict
2114
2215import pytest
2316
@@ -265,7 +258,7 @@ def pytest_report_teststatus(report, config): # noqa: ARG001
265258 if SYMLINK_PATH :
266259 cwd = SYMLINK_PATH
267260
268- if report .when == "call" :
261+ if report .when == "call" or ( report . when == "setup" and report . skipped ) :
269262 traceback = None
270263 message = None
271264 report_value = "skipped"
@@ -278,19 +271,8 @@ def pytest_report_teststatus(report, config): # noqa: ARG001
278271 node_path = map_id_to_path [report .nodeid ]
279272 except KeyError :
280273 node_path = cwd
281-
274+ # Calculate the absolute test id and use this as the ID moving forward.
282275 absolute_node_id = get_absolute_test_id (report .nodeid , node_path )
283- parent_test_name = report .nodeid .split ("::" )[- 1 ]
284- if report .head_line and report .head_line != parent_test_name :
285- # add parent node to collected_tests_so_far to not double report
286- collected_tests_so_far .append (absolute_node_id )
287- # If the report has a head_line, then it is a pytest-subtest
288- # and we need to adjust the nodeid to reflect the subtest.
289- if report_value == "failure" :
290- report_value = "subtest-failure"
291- elif report_value == "success" :
292- report_value = "subtest-success"
293- absolute_node_id = absolute_node_id + "**{" + report .head_line + "}**"
294276 if absolute_node_id not in collected_tests_so_far :
295277 collected_tests_so_far .append (absolute_node_id )
296278 item_result = create_test_outcome (
@@ -453,7 +435,11 @@ def pytest_sessionfinish(session, exitstatus):
453435 if is_coverage_run == "True" :
454436 # load the report and build the json result to return
455437 import coverage
456- from coverage import exceptions
438+
439+ try :
440+ from coverage .exceptions import NoSource
441+ except ImportError :
442+ from coverage .misc import NoSource
457443
458444 cov = coverage .Coverage ()
459445 cov .load ()
@@ -464,16 +450,16 @@ def pytest_sessionfinish(session, exitstatus):
464450 # remove files omitted per coverage report config if any
465451 omit_files = cov .config .report_omit
466452 if omit_files :
467- omit_files = set ( omit_files )
468- # convert to absolute paths, check against file set
469- omit_files = { os . fspath ( pathlib . Path ( file ). absolute ()) for file in omit_files }
470- print ( "Files to omit from reporting" , omit_files )
471- file_set = file_set - omit_files
453+ print ( "Plugin info[vscode-pytest]: Omit files/rules: " , omit_files )
454+ for pattern in omit_files :
455+ for file in list ( file_set ):
456+ if pathlib . Path ( file ). match ( pattern ):
457+ file_set . remove ( file )
472458
473459 for file in file_set :
474460 try :
475461 analysis = cov .analysis2 (file )
476- except exceptions . NoSource :
462+ except NoSource :
477463 # as per issue 24308 this best way to handle this edge case
478464 continue
479465 lines_executable = {int (line_no ) for line_no in analysis [1 ]}
@@ -502,7 +488,7 @@ def build_test_tree(session: pytest.Session) -> TestNode:
502488 """
503489 session_node = create_session_node (session )
504490 session_children_dict : dict [str , TestNode ] = {}
505- file_nodes_dict : dict [Any , TestNode ] = {}
491+ file_nodes_dict : dict [str , TestNode ] = {}
506492 class_nodes_dict : dict [str , TestNode ] = {}
507493 function_nodes_dict : dict [str , TestNode ] = {}
508494
@@ -551,11 +537,13 @@ def build_test_tree(session: pytest.Session) -> TestNode:
551537 function_test_node ["children" ].append (test_node )
552538 # Check if the parent node of the function is file, if so create/add to this file node.
553539 if isinstance (test_case .parent , pytest .File ):
540+ # calculate the parent path of the test case
541+ parent_path = get_node_path (test_case .parent )
554542 try :
555- parent_test_case = file_nodes_dict [test_case . parent ]
543+ parent_test_case = file_nodes_dict [os . fspath ( parent_path ) ]
556544 except KeyError :
557- parent_test_case = create_file_node (test_case . parent )
558- file_nodes_dict [test_case . parent ] = parent_test_case
545+ parent_test_case = create_file_node (parent_path )
546+ file_nodes_dict [os . fspath ( parent_path ) ] = parent_test_case
559547 if function_test_node not in parent_test_case ["children" ]:
560548 parent_test_case ["children" ].append (function_test_node )
561549 # If the parent is not a file, it is a class, add the function node as the test node to handle subsequent nesting.
@@ -587,22 +575,24 @@ def build_test_tree(session: pytest.Session) -> TestNode:
587575 else :
588576 ERRORS .append (f"Test class { case_iter } has no parent" )
589577 break
578+ parent_path = get_node_path (parent_module )
590579 # Create a file node that has the last class as a child.
591580 try :
592- test_file_node : TestNode = file_nodes_dict [parent_module ]
581+ test_file_node : TestNode = file_nodes_dict [os . fspath ( parent_path ) ]
593582 except KeyError :
594- test_file_node = create_file_node (parent_module )
595- file_nodes_dict [parent_module ] = test_file_node
583+ test_file_node = create_file_node (parent_path )
584+ file_nodes_dict [os . fspath ( parent_path ) ] = test_file_node
596585 # Check if the class is already a child of the file node.
597586 if test_class_node is not None and test_class_node not in test_file_node ["children" ]:
598587 test_file_node ["children" ].append (test_class_node )
599588 elif not hasattr (test_case , "callspec" ):
600589 # This includes test cases that are pytest functions or a doctests.
590+ parent_path = get_node_path (test_case .parent )
601591 try :
602- parent_test_case = file_nodes_dict [test_case . parent ]
592+ parent_test_case = file_nodes_dict [os . fspath ( parent_path ) ]
603593 except KeyError :
604- parent_test_case = create_file_node (test_case . parent )
605- file_nodes_dict [test_case . parent ] = parent_test_case
594+ parent_test_case = create_file_node (parent_path )
595+ file_nodes_dict [os . fspath ( parent_path ) ] = parent_test_case
606596 parent_test_case ["children" ].append (test_node )
607597 created_files_folders_dict : dict [str , TestNode ] = {}
608598 for file_node in file_nodes_dict .values ():
@@ -760,18 +750,17 @@ def create_parameterized_function_node(
760750 }
761751
762752
763- def create_file_node (file_module : Any ) -> TestNode :
764- """Creates a file node from a pytest file module .
753+ def create_file_node (calculated_node_path : pathlib . Path ) -> TestNode :
754+ """Creates a file node from a path which has already been calculated using the get_node_path function .
765755
766756 Keyword arguments:
767- file_module -- the pytest file module .
757+ calculated_node_path -- the pytest file path .
768758 """
769- node_path = get_node_path (file_module )
770759 return {
771- "name" : node_path .name ,
772- "path" : node_path ,
760+ "name" : calculated_node_path .name ,
761+ "path" : calculated_node_path ,
773762 "type_" : "file" ,
774- "id_" : os .fspath (node_path ),
763+ "id_" : os .fspath (calculated_node_path ),
775764 "children" : [],
776765 }
777766
@@ -930,7 +919,7 @@ def send_message(
930919
931920 if __writer is None :
932921 try :
933- __writer = open (TEST_RUN_PIPE , "w" , encoding = "utf-8" , newline = " \r \n " ) # noqa: SIM115, PTH123
922+ __writer = open (TEST_RUN_PIPE , "wb " ) # noqa: SIM115, PTH123
934923 except Exception as error :
935924 error_msg = f"Error attempting to connect to extension named pipe { TEST_RUN_PIPE } [vscode-pytest]: { error } "
936925 print (error_msg , file = sys .stderr )
@@ -950,9 +939,16 @@ def send_message(
950939 data = json .dumps (rpc , cls = cls_encoder )
951940 try :
952941 if __writer :
953- request = f"""content-length: { len (data )} \n content-type: application/json\n \n { data } """
954- __writer .write (request )
955- __writer .flush ()
942+ request = (
943+ f"""content-length: { len (data )} \r \n content-type: application/json\r \n \r \n { data } """
944+ )
945+ size = 4096
946+ encoded = request .encode ("utf-8" )
947+ bytes_written = 0
948+ while bytes_written < len (encoded ):
949+ segment = encoded [bytes_written : bytes_written + size ]
950+ bytes_written += __writer .write (segment )
951+ __writer .flush ()
956952 else :
957953 print (
958954 f"Plugin error connection error[vscode-pytest], writer is None \n [vscode-pytest] data: \n { data } \n " ,
0 commit comments