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)