Source code for pyphi.display.description
"""Declarative, backend-independent description of how to display a result.
A result type's ``_describe()`` returns a ``Description``; a renderer turns it
into ASCII or HTML. This is the single source of truth for *what* to show.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
[docs]
def system_phi_label(config: Any) -> str:
"""The label for a system irreducibility value under ``config``'s formalism.
Under IIT 3.0 the system-level irreducibility value *is* big phi, so it is
labelled ``Φ``. Under IIT 4.0 it is φₛ, and ``Φ`` names a different
quantity — the structure integrated information, the sum of φ over the
Φ-structure's distinctions and relations. Labelling φₛ as Φ under IIT 4.0
reports one quantity as if it were the other.
Parameters
----------
config : ConfigSnapshot or None
The snapshot carried by the result being displayed. ``None`` falls back
to the IIT 4.0 label.
Returns
-------
str
``"Φ"`` under IIT 3.0, ``"φ_s"`` otherwise.
"""
version = getattr(
getattr(getattr(config, "formalism", None), "iit", None), "version", None
)
return "Φ" if version == "IIT_3_0" else "φ_s"
[docs]
def intrinsic_specification_label(config: Any) -> str:
"""The label for a specified state's selectivity-times-informativeness
value under ``config``'s formalism.
Mayner et al. (2026, Eqs. 7 and 9) call it intrinsic specification;
Albantakis et al. (2023, Eqs. 5 and 7) call the same quantity intrinsic
information.
Parameters
----------
config : ConfigSnapshot or None
The snapshot carried by the result being displayed. ``None`` falls back
to ``"Intrinsic specification"``.
Returns
-------
str
``"Intrinsic information"`` under IIT 4.0 as published in 2023,
``"Intrinsic specification"`` otherwise.
"""
version = getattr(
getattr(getattr(config, "formalism", None), "iit", None), "version", None
)
if version == "IIT_4_0_2023":
return "Intrinsic information"
return "Intrinsic specification"
[docs]
@dataclass(frozen=True)
class Row:
"""One aligned key/value line with optional trailing extra fields.
``tone`` is an optional semantic accent (``"cause"`` / ``"effect"``) that
HTML rendering colors; the ASCII backend ignores it.
"""
label: str
value: Any
extra: tuple[tuple[str, Any], ...] = ()
tone: str | None = None
[docs]
@dataclass(frozen=True)
class Table:
"""A tabular list (distinctions, relations, account links).
``overflow`` is the number of rows omitted from ``rows`` (the collection
was larger than the display cap); renderers show a "… N more" indicator.
"""
headers: tuple[str, ...]
rows: tuple[tuple[Any, ...], ...]
overflow: int = 0
grid: bool = False # matrix-style (e.g. a cut grid): tight, center-aligned
# Optional per-column semantic tone for the header cells (HTML colors them).
header_tones: tuple[str | None, ...] = ()
# Optional per-cell semantic tone, aligned with ``rows`` (HTML colors them).
row_tones: tuple[tuple[str | None, ...], ...] = ()
[docs]
@dataclass(frozen=True)
class Inline:
"""A pre-formatted fragment owned by the source type.
``text`` is the ASCII form; ``html`` optionally overrides the HTML form.
"""
text: str
html: str | None = None
[docs]
@dataclass(frozen=True)
class Nested:
"""A child result rendered compactly (one line), never as a recursive box."""
description: Description
Component = Row | Table | Inline | Nested
[docs]
@dataclass(frozen=True)
class Section:
"""A named group rendered with a rule divider.
``rows`` are key/value lines; ``body`` holds richer components.
"""
label: str | None = None
rows: tuple[Row, ...] = ()
body: tuple[Component, ...] = ()
tone: str | None = None
[docs]
@dataclass(frozen=True)
class Description:
"""The full description of a displayable object."""
title: str
subtitle: str | None = None
sections: tuple[Section, ...] = ()
compact: str | None = None
tone: str | None = None
[docs]
def card_label_width(description: Description) -> int:
"""The widest key/value label in a card, in visible characters.
Every key/value section of a card aligns its values to this width, so
values line up down the whole card rather than per section.
"""
labels: list[str] = []
for section in description.sections:
labels.extend(row.label for row in section.rows)
labels.extend(comp.label for comp in section.body if isinstance(comp, Row))
return max((len(label) for label in labels), default=0)