| 454 | |
| 455 | |
| 456 | class LogXML: |
| 457 | def __init__( |
| 458 | self, |
| 459 | logfile, |
| 460 | prefix: str | None, |
| 461 | suite_name: str = "pytest", |
| 462 | logging: str = "no", |
| 463 | report_duration: str = "total", |
| 464 | family="xunit1", |
| 465 | log_passing_tests: bool = True, |
| 466 | ) -> None: |
| 467 | logfile = os.path.expanduser(os.path.expandvars(logfile)) |
| 468 | self.logfile = os.path.normpath(os.path.abspath(logfile)) |
| 469 | self.prefix = prefix |
| 470 | self.suite_name = suite_name |
| 471 | self.logging = logging |
| 472 | self.log_passing_tests = log_passing_tests |
| 473 | self.report_duration = report_duration |
| 474 | self.family = family |
| 475 | self.stats: dict[str, int] = dict.fromkeys( |
| 476 | ["error", "passed", "failure", "skipped"], 0 |
| 477 | ) |
| 478 | self.node_reporters: dict[tuple[str | TestReport, object], _NodeReporter] = {} |
| 479 | self.node_reporters_ordered: list[_NodeReporter] = [] |
| 480 | self.global_properties: list[tuple[str, str]] = [] |
| 481 | |
| 482 | # List of reports that failed on call but teardown is pending. |
| 483 | self.open_reports: list[TestReport] = [] |
| 484 | self.cnt_double_fail_tests = 0 |
| 485 | |
| 486 | # Replaces convenience family with real family. |
| 487 | if self.family == "legacy": |
| 488 | self.family = "xunit1" |
| 489 | |
| 490 | def finalize(self, report: TestReport) -> None: |
| 491 | nodeid = getattr(report, "nodeid", report) |
| 492 | # Local hack to handle xdist report order. |
| 493 | workernode = getattr(report, "node", None) |
| 494 | reporter = self.node_reporters.pop((nodeid, workernode)) |
| 495 | |
| 496 | for propname, propvalue in report.user_properties: |
| 497 | reporter.add_property(propname, str(propvalue)) |
| 498 | |
| 499 | if reporter is not None: |
| 500 | reporter.finalize() |
| 501 | |
| 502 | def node_reporter(self, report: TestReport | str) -> _NodeReporter: |
| 503 | nodeid: str | TestReport = getattr(report, "nodeid", report) |
| 504 | # Local hack to handle xdist report order. |
| 505 | workernode = getattr(report, "node", None) |
| 506 | |
| 507 | key = nodeid, workernode |
| 508 | |
| 509 | if key in self.node_reporters: |
| 510 | # TODO: breaks for --dist=each |
| 511 | return self.node_reporters[key] |
| 512 | |
| 513 | reporter = _NodeReporter(nodeid, self) |
no outgoing calls