Source code for autowisp.database.data_model.error

"""Define the :class:`Error` table: the queryable record of a failure."""

from sqlalchemy import (
    Column,
    Integer,
    String,
    TIMESTAMP,
    ForeignKey,
)

from autowisp.database.data_model.base import DataModelBase

__all__ = ["Error"]


[docs] class Error(DataModelBase): """A persisted pipeline/step/BUI error. Holds the *queryable subset* of an :class:`~autowisp.exceptions. AutoWISPError` -- the fields list views and aggregate queries need, so they never have to open the sidecar. The heavy remainder (full message, complete related-file list, ``details``, traceback) lives in a per-error JSON sidecar referenced by :attr:`sidecar_path`; the two are disjoint, so nothing has to be kept in sync. Artifact links are foreign keys only for artifacts that are genuine database rows -- :attr:`image_id` and :attr:`master_file_id`. DR files and lightcurves are HDF5 files on disk with no row to reference, so they appear (by path) only in the sidecar's related-file list. All links use ``ON DELETE SET NULL`` so an error row stays valid as a historical record even if the artifact or run it referred to is later removed. """ __tablename__ = "error" pipeline_run_id = Column( Integer, ForeignKey("pipeline_run.id", onupdate="CASCADE", ondelete="SET NULL"), nullable=True, doc="The pipeline run during which the error occurred; NULL for " "standalone CLI/BUI errors with no run.", ) component = Column( String(20), nullable=False, doc="Which component raised it: 'step', 'pipeline', or 'bui'.", ) step_name = Column( String(255), nullable=True, doc="The processing step that failed; set for step errors.", ) exception_class = Column( String(255), nullable=False, doc="Concrete exception class name, e.g. 'SolveAstrometryError', " "for filtering all occurrences of a kind of failure.", ) image_id = Column( Integer, ForeignKey("image.id", onupdate="CASCADE", ondelete="SET NULL"), nullable=True, doc="The image the error is about, when a related file maps to a " "known image row.", ) master_file_id = Column( Integer, ForeignKey("master_file.id", onupdate="CASCADE", ondelete="SET NULL"), nullable=True, doc="The master file the error is about, when a related file maps " "to a known master row.", ) subprocess_id = Column( Integer, nullable=True, doc="PID of the multiprocessing worker that raised, when the error " "travelled out of a worker; NULL for main-process errors.", ) user_message = Column( String(2000), nullable=False, doc="Short, jargon-free description for the BUI/CLI. The full " "technical message lives in the sidecar.", ) created = Column( TIMESTAMP, nullable=True, doc="When the failure surfaced (the exception's 'crashed' time).", ) sidecar_path = Column( String(1000), nullable=True, doc="Path to the JSON detail sidecar, relative to the project " "home; NULL if the sidecar write failed (row stays valid).", ) resolved = Column( TIMESTAMP, nullable=True, doc="When a user marked this error resolved; NULL while open. " "Open errors drive the error badge, progress-grid markers, and " "the start-processing gate; resolved errors are kept as history.", ) def __repr__(self): return ( f"Error(id={self.id}, component={self.component!r}, " f"exception_class={self.exception_class!r}, " f"step_name={self.step_name!r})" )