| 1576 | |
| 1577 | |
| 1578 | def _folded_skips( |
| 1579 | startpath: Path, |
| 1580 | skipped: Sequence[CollectReport], |
| 1581 | ) -> list[tuple[int, str, int | None, str]]: |
| 1582 | d: dict[tuple[str, int | None, str], list[CollectReport]] = {} |
| 1583 | for event in skipped: |
| 1584 | assert event.longrepr is not None |
| 1585 | assert isinstance(event.longrepr, tuple), (event, event.longrepr) |
| 1586 | assert len(event.longrepr) == 3, (event, event.longrepr) |
| 1587 | fspath, lineno, reason = event.longrepr |
| 1588 | # For consistency, report all fspaths in relative form. |
| 1589 | fspath = bestrelpath(startpath, Path(fspath)) |
| 1590 | keywords = getattr(event, "keywords", {}) |
| 1591 | # Folding reports with global pytestmark variable. |
| 1592 | # This is a workaround, because for now we cannot identify the scope of a skip marker |
| 1593 | # TODO: Revisit after marks scope would be fixed. |
| 1594 | if ( |
| 1595 | event.when == "setup" |
| 1596 | and "skip" in keywords |
| 1597 | and "pytestmark" not in keywords |
| 1598 | ): |
| 1599 | key: tuple[str, int | None, str] = (fspath, None, reason) |
| 1600 | else: |
| 1601 | key = (fspath, lineno, reason) |
| 1602 | d.setdefault(key, []).append(event) |
| 1603 | values: list[tuple[int, str, int | None, str]] = [] |
| 1604 | for key, events in d.items(): |
| 1605 | values.append((len(events), *key)) |
| 1606 | return values |
| 1607 | |
| 1608 | |
| 1609 | _color_for_type = { |