# scope_profiler.profile_io

*module*

Pick the right reader or writer for a profile path.

scope-profiler writes and reads a run in three shapes: the HDF5 file that is
the default output, the JSON document of :mod:`scope_profiler.json_export`,
and the standalone HTML report of :mod:`scope_profiler.html_report` (which is
write-only - a report is a rendering of a run, not a copy of it).

Everything that takes a profile path from a user goes through
:func:`read_profile` rather than :func:`~scope_profiler.h5reader.read_h5`, so
a ``.json`` file works anywhere a ``.h5`` file does. The format is chosen by
the file name, the same rule ``scope-profiler run -o`` follows.

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

## scope_profiler.profile_io.FORMAT_HDF5

*attribute* · *module attribute*

```python
FORMAT_HDF5 = 'hdf5'
```

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

## scope_profiler.profile_io.FORMAT_HTML

*attribute* · *module attribute*

```python
FORMAT_HTML = 'html'
```

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

## scope_profiler.profile_io.FORMAT_JSON

*attribute* · *module attribute*

```python
FORMAT_JSON = 'json'
```

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

## scope_profiler.profile_io.HTML_SUFFIXES

*attribute* · *module attribute*

```python
HTML_SUFFIXES = ('.html', '.htm')
```

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

## scope_profiler.profile_io.load

*function*

```python
def load(path, verbose: bool = False) -> ProfilingResults
```

Load a profile for post-processing, whatever format it is in.

The one entry point for reading a run back::

    import scope_profiler

    results = scope_profiler.load("profiling_data.h5")
    results.print_summary()

HDF5 and JSON profiles are both accepted, and the format is taken from
the file's contents rather than its name (see
:func:`sniff_profile_format`), so the caller does not have to know which
of :func:`~scope_profiler.h5reader.read_h5` and
:func:`~scope_profiler.json_export.read_json` it wanted. Those remain
available for reading a file whose format is already known.

Parameters
----------
path : str | Path
    The profile to read.
verbose : bool, optional
    Print progress while reading (default: False).

Returns
-------
ProfilingResults
    The run's profiling data, with all durations in seconds.

Raises
------
FileNotFoundError
    If ``path`` does not exist.
ValueError
    If ``path`` is an HTML report. A report is a rendering of a run, not
    a copy of it, so there is nothing to read back.

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

## scope_profiler.profile_io.profile_format

*function*

```python
def profile_format(path) -> str
```

Which of the three formats ``path`` names.

Anything that is not recognisably JSON or HTML is HDF5: that is the
default output format, and it is written under whatever name the user
asked for, extension or not.

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

## scope_profiler.profile_io.read_profile

*function*

```python
def read_profile(file_path, verbose: bool = False) -> ProfilingResults
```

Read a profile from HDF5 or JSON, whichever the name says it is.

Dispatches on the file name; :func:`load` dispatches on the contents and
is the better default for a file that already exists.

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

## scope_profiler.profile_io.read_profile_summary

*function*

```python
def read_profile_summary(file_path, **kwargs) -> ProfilingResults
```

Read a profile, skipping per-call timestamps where the format can.

Only HDF5 can be read partially: its per-call columns are separate
datasets, so a summary-only read never touches them. A JSON document is
parsed as a whole either way, so this falls back to the full read for one
- the caller gets a result set that answers strictly more, never less.

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

## scope_profiler.profile_io.sniff_profile_format

*function*

```python
def sniff_profile_format(path) -> str
```

Which format the *contents* of ``path`` are in.

:func:`profile_format` goes by the file name, which is all that can be
known before a file exists. For a file that does exist the contents are
the better authority: a run written as ``profile.dat``, or a JSON profile
someone renamed to ``.h5``, still reads correctly.

Falls back to :func:`profile_format` when the leading bytes match nothing
known, so an unrecognisable file is still treated as HDF5 and produces
h5py's own error rather than one invented here.

Raises
------
FileNotFoundError
    If ``path`` does not exist.

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

## scope_profiler.profile_io.write_profile

*function*

```python
def write_profile(results, file_path, **kwargs) -> Path
```

Write ``results`` to ``file_path`` in the format its name asks for.

Parameters
----------
results : ProfilingResults
    The run to write.
file_path : str | Path
    Destination. ``.json``/``.json.gz`` writes a JSON profile,
    ``.html`` an HTML report, and anything else an HDF5 file.
**kwargs
    Passed to the format's own writer.

Returns
-------
Path
    The file written.

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