# demopkg.utils

*module*

Helpers that operate on reports.

Everything here is a plain function; the module has no `__all__`, so the public
surface comes from the `is_public` heuristics (no leading underscore, not
imported).

## demopkg.utils.SECTION_STYLES

*attribute* · *module attribute*

```python
SECTION_STYLES: dict[str, dict[str, str]] = {'summary': {'colour': '#1b1f2a', 'marker': '*', 'caption': 'Summary, at a glance'}, 'detail': {'colour': '#2a334e', 'marker': '-', 'caption': 'Detail (one row per metric)'}, 'appendix': {'colour': '#f2c641', 'marker': '+', 'caption': 'Appendix [optional, omitted by default]'}, 'footer': {'colour': '#aab2c4', 'marker': '.', 'caption': 'Footer, with the generated-at stamp'}}
```

How each section of a rendered report is presented.

Deliberately long: it is the fixture for a signature whose value is broken
across lines at its brackets and then folded behind a toggle. The captions hold
brackets, commas and quotes so the line-breaker has string literals to step
over.

## demopkg.utils.describe

*function*

```python
def describe(report: Report, **extra: Any) -> str
```

Summarise a report in one line.

**Parameters**

- `report` (`Report`) — The report to describe.
- `**extra` (`Any`) (default: `{}`) — Extra key/value pairs appended to the summary.

**Returns**

- (`str`) — A single line of plain text.

## demopkg.utils.iter_sections

*function*

```python
def iter_sections(report: Report) -> Iterator[str]
```

Walk the sections of a report in render order.

**Parameters**

- `report` (`Report`) — The report to walk.

**Yields**

- (`str`) — Section names, uppercased.

**Examples**

```pycon
>>> list(iter_sections(Report("weekly")))
[]
```

## demopkg.utils.merge_scores

*function*

```python
def merge_scores(left: Report, right: Report) -> dict[str, float]
```

Combine the scores of two reports.

**Parameters**

- `left` (`Report`) — Report whose scores take precedence.
- `right` (`Report`) — Report contributing the remaining scores.

**Returns**

- (`dict[str, float]`) — A new mapping holding both sets of scores.

**Raises**

- `ReportError` — If the two reports disagree on a metric.
- `TypeError` — If either argument is not a report.
- `ValueError` — If either report has no scores.
