Skip to content

Data Models

Entity

crategraph.core.models.Entity dataclass

An immutable node in the graph.

types is stored as a tuple so the frozen contract extends to the type list. properties is a plain dict for ergonomics — treat it as read-only; mutating it will change graph state in place.

Source code in crategraph/core/models.py
@dataclass(frozen=True)
class Entity:
    """An immutable node in the graph.

    ``types`` is stored as a tuple so the frozen contract extends to the
    type list.  ``properties`` is a plain dict for ergonomics — treat it
    as read-only; mutating it will change graph state in place.
    """

    id: str
    types: tuple[str, ...] = ()
    properties: dict[str, Any] = field(default_factory=dict)
    source: str | None = None

    def __post_init__(self) -> None:
        if not isinstance(self.types, tuple):
            object.__setattr__(self, "types", tuple(self.types))

    @property
    def type(self) -> str:
        """Display string joining all types (e.g. ``'PublishedResource, Report'``)."""
        return ", ".join(self.types) if self.types else "Unknown"

    @property
    def name(self) -> str:
        """Best display name: ``name`` property, falling back to ``id``."""
        return str(self.properties.get("name", self.id))

    @property
    def label(self) -> str:
        """Human label via the shared ``name -> title -> id`` fallback, always a string."""
        return _derive_label(self)

    @property
    def has_data(self) -> bool:
        """Whether this entity is a data entity (file or directory).

        Returns ``True`` if the entity has ``File`` or ``Dataset`` in its
        types, per the RO-Crate specification.  The root Dataset entity
        is excluded (identified by the ``_is_root`` property flag set
        during loading).
        """
        if self.properties.get("_is_root"):
            return False
        return "File" in self.types or "Dataset" in self.types

    def __repr__(self) -> str:
        return f"Entity({self.type!r}, {self.name!r}, id={self.id!r})"

    def _repr_html_(self) -> str:
        """Compact HTML representation for Jupyter notebooks."""
        return f"<pre>{_escape_html(repr(self))}</pre>"

has_data property

Whether this entity is a data entity (file or directory).

Returns True if the entity has File or Dataset in its types, per the RO-Crate specification. The root Dataset entity is excluded (identified by the _is_root property flag set during loading).

label property

Human label via the shared name -> title -> id fallback, always a string.

name property

Best display name: name property, falling back to id.

type property

Display string joining all types (e.g. 'PublishedResource, Report').

Relationship

crategraph.core.models.Relationship dataclass

An immutable directed edge in the graph.

Relationships with an id were reified nodes in the source format (e.g. @type: Relationship items in an RO-Crate). Inline references (e.g. preparedBy: {"@id": "..."})) have id=None.

properties is a plain dict for ergonomics — treat it as read-only; mutating it will change graph state in place.

Source code in crategraph/core/models.py
@dataclass(frozen=True)
class Relationship:
    """An immutable directed edge in the graph.

    Relationships with an ``id`` were reified nodes in the source format
    (e.g. ``@type: Relationship`` items in an RO-Crate).  Inline references
    (e.g. ``preparedBy: {"@id": "..."}``)) have ``id=None``.

    ``properties`` is a plain dict for ergonomics — treat it as read-only;
    mutating it will change graph state in place.
    """

    source: str
    target: str
    type: str
    properties: dict[str, Any] = field(default_factory=dict)
    id: str | None = None

    def __repr__(self) -> str:
        return f"Relationship({self.source!r} --{self.type}--> {self.target!r})"

FileInfo

crategraph.core.models.FileInfo dataclass

Result of inspecting a data file.

Source code in crategraph/core/models.py
@dataclass(frozen=True)
class FileInfo:
    """Result of inspecting a data file."""

    path: str
    content: str
    title: str | None
    size_bytes: int
    media_type: str | None

    def __repr__(self) -> str:
        name = Path(self.path).name
        return f"FileInfo({name!r}, {self.size_bytes} bytes)"

    def _repr_html_(self) -> str:
        name = _escape_html(Path(self.path).name)
        parts = [f"<b>{name}</b>"]
        if self.media_type:
            parts.append(f" ({_escape_html(self.media_type)})")
        parts.append(f" — {self.size_bytes:,} bytes")
        header = "".join(parts)
        content = _escape_html(self.content[:2000])
        return (
            f"<div style='font-family:monospace; font-size:13px'>"
            f"<div style='margin-bottom:4px'>{header}</div>"
            f"<pre style='white-space:pre-wrap; max-height:400px; "
            f"overflow-y:auto; padding:8px; background:#f5f5f5; "
            f"border-radius:4px'>{content}</pre>"
            f"</div>"
        )

ViewInfo

crategraph.core.models.ViewInfo dataclass

Result of viewing a data file — rich HTML preview.

Source code in crategraph/core/models.py
@dataclass(frozen=True)
class ViewInfo:
    """Result of viewing a data file — rich HTML preview."""

    path: str
    html: str
    """Raw HTML — callers are responsible for escaping all data-sourced
    content before including it here. This field is rendered unescaped
    by ``_repr_html_``."""
    title: str | None
    size_bytes: int
    media_type: str | None

    def __repr__(self) -> str:
        name = Path(self.path).name
        return f"ViewInfo({name!r}, {self.size_bytes} bytes)"

    def _repr_html_(self) -> str:
        name = _escape_html(Path(self.path).name)
        parts = [f"<b>{name}</b>"]
        if self.media_type:
            parts.append(f" ({_escape_html(self.media_type)})")
        parts.append(f" — {self.size_bytes:,} bytes")
        header = "".join(parts)
        return (
            f"<div style='font-family:monospace; font-size:13px'>"
            f"<div style='margin-bottom:4px'>{header}</div>"
            f"<div style='max-height:500px; overflow-y:auto'>{self.html}</div>"
            f"</div>"
        )

html instance-attribute

Raw HTML — callers are responsible for escaping all data-sourced content before including it here. This field is rendered unescaped by _repr_html_.

SelectOptions

crategraph.core.models.SelectOptions

Bases: BaseModel

Parameters for structural filtering via Graph.select().

Source code in crategraph/core/models.py
class SelectOptions(BaseModel):
    """Parameters for structural filtering via ``Graph.select()``."""

    entity_types: list[str] | None = None
    relationship_types: list[str] | None = None
    time_range: tuple[int, int] | None = None
    min_connections: int | None = None
    max_connections: int | None = None
    source: str | None = None
    id: str | None = None

ValidationReport

crategraph.core.models.ValidationReport

Bases: BaseModel

Result of running a validator against a graph.

Source code in crategraph/core/models.py
class ValidationReport(BaseModel):
    """Result of running a validator against a graph."""

    issues: list[ValidationIssue]

    @property
    def is_valid(self) -> bool:
        """A report is valid when it contains no error-level issues."""
        return not any(i.severity == "error" for i in self.issues)

is_valid property

A report is valid when it contains no error-level issues.

ValidationIssue

crategraph.core.models.ValidationIssue

Bases: BaseModel

A single issue found during validation.

Source code in crategraph/core/models.py
class ValidationIssue(BaseModel):
    """A single issue found during validation."""

    severity: Literal["error", "warning", "info"]
    entity_id: str | None = None
    message: str