# scope_profiler.astro_site

*module*

Astro/Starlight content for a catalogue of profiling runs.

``scope-profiler site MANIFEST -o DOCS`` reads a YAML manifest that lists cases
(each a set of profiling files) and writes the pages and chart data of a
catalogue into an Astro project, where the site's own build turns them into a
website. Nothing here renders HTML: a page is an MDX file of components plus a
JSON data file holding what it shows (the models of
:mod:`scope_profiler.report_model`, the same ones the HTML report is drawn
from), and charts are the plot-data JSON the HTML report embeds, drawn in the
browser by ``@scope-profiler/plotly``.

The manifest::

    title: Profiling catalogue
    description: Runs of my code.
    base: /my-catalogue          # the site's base path: "/" plus the repo name
    defaults: {scaling: strong, speedup_x: auto}
    cases:
      - id: poisson              # default: the slug of the title
        title: Poisson solver
        description: Strong scaling of the solver.
        group: Solvers           # optional: nests the case in a sidebar group
        tags: [cpu, scaling]
        scaling: strong          # strong, weak, both or none
        metadata: minimal        # or "all": publish every metadata field
        info: {commit: 843a82cd}
        runs:
          - {path: data/np1.h5, label: 1 rank}
          - {path: "data/np*.h5"}   # globs, relative to the manifest

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L1-L1)

## scope_profiler.astro_site.COMPONENTS

*attribute* · *module attribute*

```python
COMPONENTS = Path('src/components/report')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L60-L60)

## scope_profiler.astro_site.CONTENT_DIR

*attribute* · *module attribute*

```python
CONTENT_DIR = Path('src/content/docs/catalogue')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L57-L57)

## scope_profiler.astro_site.FIGURE_SUFFIXES

*attribute* · *module attribute*

```python
FIGURE_SUFFIXES = (*IMAGE_SUFFIXES, '.pdf')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L152-L152)

## scope_profiler.astro_site.HOTSPOTS

*attribute* · *module attribute*

```python
HOTSPOTS = 15
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L114-L114)

## scope_profiler.astro_site.IMAGE_SUFFIXES

*attribute* · *module attribute*

```python
IMAGE_SUFFIXES = ('.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L151-L151)

## scope_profiler.astro_site.LANGUAGES

*attribute* · *module attribute*

```python
LANGUAGES = {'.py': 'python', '.yml': 'yaml', '.yaml': 'yaml', '.json': 'json', '.toml': 'toml', '.sh': 'bash', '.bash': 'bash', '.md': 'markdown', '.ini': 'ini', '.cfg': 'ini', '.c': 'c', '.h': 'c', '.cpp': 'cpp', '.hpp': 'cpp', '.f90': 'fortran', '.f': 'fortran', '.jl': 'julia', '.m': 'matlab', '.sbatch': 'bash', '.slurm': 'bash'}
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L88-L109)

## scope_profiler.astro_site.MARKER

*attribute* · *module attribute*

```python
MARKER = '.scope-profiler-site'
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L54-L54)

## scope_profiler.astro_site.MAX_CHART_BYTES

*attribute* · *module attribute*

```python
MAX_CHART_BYTES = 8000000
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L112-L112)

## scope_profiler.astro_site.MAX_COPIED_FILE_BYTES

*attribute* · *module attribute*

```python
MAX_COPIED_FILE_BYTES = 20000000
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L85-L85)

## scope_profiler.astro_site.MAX_SHOWN_FILE_BYTES

*attribute* · *module attribute*

```python
MAX_SHOWN_FILE_BYTES = 200000
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L84-L84)

## scope_profiler.astro_site.METADATA_KEYS

*attribute* · *module attribute*

```python
METADATA_KEYS = ('timestamp', 'platform', 'chip_information', 'python_version', 'scope_profiler_version', 'omp_num_threads', 'mpi_size', 'total_cores', 'num_nodes')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L66-L76)

## scope_profiler.astro_site.PUBLIC_DIR

*attribute* · *module attribute*

```python
PUBLIC_DIR = Path('public/catalogue')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L58-L58)

## scope_profiler.astro_site.REFERENCE_RUNS

*attribute* · *module attribute*

```python
REFERENCE_RUNS = 4
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L80-L80)

## scope_profiler.astro_site.SCALING_CHOICES

*attribute* · *module attribute*

```python
SCALING_CHOICES = ('strong', 'weak', 'both', 'none')
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L62-L62)

## scope_profiler.astro_site.Case

*class* · *dataclass*

```python
class Case
```

A set of runs shown together; ``runs`` is the latest execution's when it has several.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L189-L210)

### scope_profiler.astro_site.Case.charts

*attribute* · *class attribute* · *instance attribute*

```python
charts: bool = True
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L205-L205)

### scope_profiler.astro_site.Case.code

*attribute* · *class attribute* · *instance attribute*

```python
code: tuple[CodeSpec, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L210-L210)

### scope_profiler.astro_site.Case.description

*attribute* · *class attribute* · *instance attribute*

```python
description: str = ''
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L196-L196)

### scope_profiler.astro_site.Case.exclude

*attribute* · *class attribute* · *instance attribute*

```python
exclude: tuple[str, ...] | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L203-L203)

### scope_profiler.astro_site.Case.executions

*attribute* · *class attribute* · *instance attribute*

```python
executions: tuple[Execution, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L208-L208)

### scope_profiler.astro_site.Case.files

*attribute* · *class attribute* · *instance attribute*

```python
files: tuple[Path, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L207-L207)

### scope_profiler.astro_site.Case.group

*attribute* · *class attribute* · *instance attribute*

```python
group: str | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L197-L197)

### scope_profiler.astro_site.Case.id

*attribute* · *instance attribute*

```python
id: str
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L193-L193)

### scope_profiler.astro_site.Case.images

*attribute* · *class attribute* · *instance attribute*

```python
images: tuple[Path, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L209-L209)

### scope_profiler.astro_site.Case.include

*attribute* · *class attribute* · *instance attribute*

```python
include: tuple[str, ...] | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L202-L202)

### scope_profiler.astro_site.Case.info

*attribute* · *class attribute* · *instance attribute*

```python
info: dict = field(default_factory=dict)
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L201-L201)

### scope_profiler.astro_site.Case.metadata

*attribute* · *class attribute* · *instance attribute*

```python
metadata: str = 'minimal'
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L206-L206)

### scope_profiler.astro_site.Case.ranks

*attribute* · *class attribute* · *instance attribute*

```python
ranks: tuple[int, ...] | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L204-L204)

### scope_profiler.astro_site.Case.runs

*attribute* · *instance attribute*

```python
runs: tuple[RunSpec, ...]
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L195-L195)

### scope_profiler.astro_site.Case.scaling

*attribute* · *class attribute* · *instance attribute*

```python
scaling: str = 'strong'
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L199-L199)

### scope_profiler.astro_site.Case.speedup_x

*attribute* · *class attribute* · *instance attribute*

```python
speedup_x: str = 'auto'
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L200-L200)

### scope_profiler.astro_site.Case.tags

*attribute* · *class attribute* · *instance attribute*

```python
tags: tuple[str, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L198-L198)

### scope_profiler.astro_site.Case.title

*attribute* · *instance attribute*

```python
title: str
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L194-L194)

## scope_profiler.astro_site.CodeSpec

*class* · *dataclass*

```python
class CodeSpec
```

Code shown at the bottom of a case: a file of the manifest's tree, a link, or both.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L169-L175)

### scope_profiler.astro_site.CodeSpec.label

*attribute* · *class attribute* · *instance attribute*

```python
label: str | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L175-L175)

### scope_profiler.astro_site.CodeSpec.path

*attribute* · *class attribute* · *instance attribute*

```python
path: Path | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L173-L173)

### scope_profiler.astro_site.CodeSpec.url

*attribute* · *class attribute* · *instance attribute*

```python
url: str | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L174-L174)

## scope_profiler.astro_site.Execution

*class* · *dataclass*

```python
class Execution
```

One execution of a case that is run again and again (a nightly job): a set of runs.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L178-L186)

### scope_profiler.astro_site.Execution.date

*attribute* · *class attribute* · *instance attribute*

```python
date: str | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L185-L185)

### scope_profiler.astro_site.Execution.id

*attribute* · *instance attribute*

```python
id: str
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L182-L182)

### scope_profiler.astro_site.Execution.info

*attribute* · *class attribute* · *instance attribute*

```python
info: dict = field(default_factory=dict)
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L186-L186)

### scope_profiler.astro_site.Execution.label

*attribute* · *instance attribute*

```python
label: str
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L183-L183)

### scope_profiler.astro_site.Execution.runs

*attribute* · *instance attribute*

```python
runs: tuple[RunSpec, ...]
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L184-L184)

## scope_profiler.astro_site.Manifest

*class* · *dataclass*

```python
class Manifest
```

The parsed catalogue manifest.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L213-L220)

### scope_profiler.astro_site.Manifest.base

*attribute* · *class attribute* · *instance attribute*

```python
base: str | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L220-L220)

### scope_profiler.astro_site.Manifest.cases

*attribute* · *instance attribute*

```python
cases: tuple[Case, ...]
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L218-L218)

### scope_profiler.astro_site.Manifest.description

*attribute* · *class attribute* · *instance attribute*

```python
description: str = ''
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L219-L219)

### scope_profiler.astro_site.Manifest.title

*attribute* · *instance attribute*

```python
title: str
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L217-L217)

## scope_profiler.astro_site.RunSpec

*class* · *dataclass*

```python
class RunSpec
```

One profiling file of a case.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L159-L166)

### scope_profiler.astro_site.RunSpec.files

*attribute* · *class attribute* · *instance attribute*

```python
files: tuple[Path, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L165-L165)

### scope_profiler.astro_site.RunSpec.images

*attribute* · *class attribute* · *instance attribute*

```python
images: tuple[Path, ...] = ()
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L166-L166)

### scope_profiler.astro_site.RunSpec.label

*attribute* · *class attribute* · *instance attribute*

```python
label: str | None = None
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L164-L164)

### scope_profiler.astro_site.RunSpec.path

*attribute* · *instance attribute*

```python
path: Path
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L163-L163)

## scope_profiler.astro_site.SiteError

*class*

```python
class SiteError(ValueError)
```

Bases: `ValueError`

The manifest is invalid, or the site cannot be written.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L155-L156)

## scope_profiler.astro_site.SiteResult

*class* · *dataclass*

```python
class SiteResult
```

What :func:`build_site` wrote.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L223-L230)

### scope_profiler.astro_site.SiteResult.cases

*attribute* · *instance attribute*

```python
cases: int
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L228-L228)

### scope_profiler.astro_site.SiteResult.files

*attribute* · *instance attribute*

```python
files: list[Path]
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L227-L227)

### scope_profiler.astro_site.SiteResult.notes

*attribute* · *class attribute* · *instance attribute*

```python
notes: list[str] = field(default_factory=list)
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L230-L230)

### scope_profiler.astro_site.SiteResult.runs

*attribute* · *instance attribute*

```python
runs: int
```

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L229-L229)

## scope_profiler.astro_site.build_site

*function*

```python
def build_site(manifest: Manifest, output: str | Path = 'docs', *, base: str | None = None, charts: bool = True, clean: bool = True) -> SiteResult
```

Write the catalogue's pages and chart data into the Astro project ``output``.

Pages go to ``src/content/docs/catalogue`` (an MDX file and a JSON data file
per page) and chart data to ``public/catalogue``; both are replaced on every
run, but only when a previous run wrote them (``clean=False`` writes into
them as they are).

``base`` is the site's base path (``/repo`` on GitHub Pages), which the
links between pages need; it defaults to the manifest's ``base``. Raises
:class:`SiteError` without one, for runs that cannot be read, and for
``charts=True`` without ``scope-profiler[pproc]``.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L1392-L1844)

## scope_profiler.astro_site.load_manifest

*function*

```python
def load_manifest(path: str | Path) -> Manifest
```

Read and validate a catalogue manifest.

Run paths are resolved against the manifest's directory and globs are
expanded (in natural order, so ``np2`` precedes ``np10``). Every error names
the case and field it comes from.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L550-L669)

## scope_profiler.astro_site.slugify

*function*

```python
def slugify(text: str) -> str
```

Lower-case ``text`` into a URL- and file-name-safe slug.

[View source](https://github.com/max-models/scope-profiler/blob/devel/src/scope_profiler/astro_site.py#L233-L235)
