| 645 | self.suite_start = timing.Instant() |
| 646 | |
| 647 | def pytest_sessionfinish(self) -> None: |
| 648 | dirname = os.path.dirname(os.path.abspath(self.logfile)) |
| 649 | class="cm"># exist_ok avoids filesystem race conditions between checking path existence and requesting creation |
| 650 | os.makedirs(dirname, exist_ok=True) |
| 651 | |
| 652 | with open(self.logfile, class="st">"w", encoding=class="st">"utf-8") as logfile: |
| 653 | duration = self.suite_start.elapsed() |
| 654 | |
| 655 | numtests = ( |
| 656 | self.stats[class="st">"passed"] |
| 657 | + self.stats[class="st">"failure"] |
| 658 | + self.stats[class="st">"skipped"] |
| 659 | + self.stats[class="st">"error"] |
| 660 | - self.cnt_double_fail_tests |
| 661 | ) |
| 662 | logfile.write(&class="cm">#x27;<?xml version=class="st">"1.0" encoding=class="st">"utf-8"?>') |
| 663 | |
| 664 | suite_node = ET.Element( |
| 665 | class="st">"testsuite", |
| 666 | name=self.suite_name, |
| 667 | errors=str(self.stats[class="st">"error"]), |
| 668 | failures=str(self.stats[class="st">"failure"]), |
| 669 | skipped=str(self.stats[class="st">"skipped"]), |
| 670 | tests=str(numtests), |
| 671 | time=fclass="st">"{duration.seconds:.3f}", |
| 672 | timestamp=self.suite_start.as_utc().astimezone().isoformat(), |
| 673 | hostname=platform.node(), |
| 674 | ) |
| 675 | global_properties = self._get_global_properties_node() |
| 676 | if global_properties is not None: |
| 677 | suite_node.append(global_properties) |
| 678 | for node_reporter in self.node_reporters_ordered: |
| 679 | suite_node.append(node_reporter.to_xml()) |
| 680 | testsuites = ET.Element(class="st">"testsuites") |
| 681 | testsuites.set(class="st">"name", class="st">"pytest tests") |
| 682 | testsuites.append(suite_node) |
| 683 | logfile.write(ET.tostring(testsuites, encoding=class="st">"unicode")) |
| 684 | |
| 685 | def pytest_terminal_summary( |
| 686 | self, terminalreporter: TerminalReporter, config: pytest.Config |