diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py index 43be96ae01e..722afb197ff 100644 --- a/lib/galaxy/model/__init__.py +++ b/lib/galaxy/model/__init__.py @@ -4918,6 +4918,20 @@ class HistoryDatasetAssociation(DatasetInstance, HasTags, Dictifiable, UsesAnnot self.copied_from_history_dataset_association = copied_from_history_dataset_association self.copied_from_library_dataset_dataset_association = copied_from_library_dataset_dataset_association + def __strict_check_before_flush__(self): + if self.extension != "len": + # TODO: Custom builds (with .len extension) do not get a history or a HID. + # These should get some other type of permanent storage, perhaps UserDatasetAssociation ? + # Everything else needs to have a hid and a history + if not self.history and not getattr(self, "history_id", None): + raise Exception(f"HistoryDatasetAssociation {self} without history detected, this is not valid") + elif not self.hid: + raise Exception(f"HistoryDatasetAssociation {self} without hid, this is not valid") + elif self.dataset.file_size is None and self.dataset.state not in self.dataset.no_data_states: + raise Exception( + f"HistoryDatasetAssociation {self} in state {self.dataset.state} with null file size, this is not valid" + ) + @property def user(self): if self.history: @@ -6995,6 +7009,9 @@ class DatasetCollectionElement(Base, Dictifiable, Serializable): self.element_index = element_index self.element_identifier = element_identifier or str(element_index) + def __strict_check_before_flush__(self): + assert self.element_object, "Dataset Collection Element without child entity detected, this is not valid" + @property def element_type(self): if self.hda: diff --git a/lib/galaxy/model/base.py b/lib/galaxy/model/base.py index bcd76da2c6a..6d168846d86 100644 --- a/lib/galaxy/model/base.py +++ b/lib/galaxy/model/base.py @@ -3,6 +3,7 @@ Shared model and mapping code between Galaxy and Tool Shed, trying to generalize to generic database connections. """ import contextlib +import logging import os import threading from contextvars import ContextVar @@ -29,6 +30,8 @@ from galaxy.util.bunch import Bunch if TYPE_CHECKING: from galaxy.model.store import SessionlessContext +log = logging.getLogger(__name__) + # Create a ContextVar with mutable state, this allows sync tasks in the context # of a request (which run within a threadpool) to see changes to the ContextVar # state. See https://github.com/tiangolo/fastapi/issues/953#issuecomment-586006249 @@ -146,23 +149,14 @@ def versioned_objects(iter): def versioned_objects_strict(iter): for obj in iter: + if hasattr(obj, "__strict_check_before_flush__"): + obj.__strict_check_before_flush__() if hasattr(obj, "__create_version__"): - if obj.extension != "len": - # TODO: Custom builds (with .len extension) do not get a history or a HID. - # These should get some other type of permanent storage, perhaps UserDatasetAssociation ? - # Everything else needs to have a hid and a history - if not obj.history and not obj.history_id: - raise Exception(f"HistoryDatasetAssociation {obj} without history detected, this is not valid") - elif not obj.hid: - raise Exception(f"HistoryDatasetAssociation {obj} without hid, this is not valid") - elif obj.dataset.file_size is None and obj.dataset.state not in obj.dataset.no_data_states: - raise Exception( - f"HistoryDatasetAssociation {obj} in state {obj.dataset.state} with null file size, this is not valid" - ) yield obj if os.environ.get("GALAXY_TEST_RAISE_EXCEPTION_ON_HISTORYLESS_HDA"): + log.debug("Using strict flush checks") versioned_objects = versioned_objects_strict # noqa: F811 diff --git a/lib/galaxy_test/driver/driver_util.py b/lib/galaxy_test/driver/driver_util.py index 7a2c47368ec..ffd76175d2b 100644 --- a/lib/galaxy_test/driver/driver_util.py +++ b/lib/galaxy_test/driver/driver_util.py @@ -877,6 +877,8 @@ class GalaxyTestDriver(TestDriver): """Setup various variables used to launch a Galaxy server.""" config_object = self._ensure_config_object(config_object) self.external_galaxy = os.environ.get("GALAXY_TEST_EXTERNAL", None) + if not self.external_galaxy: + os.environ["GALAXY_TEST_STRICT_CHECKS"] = "1" # Allow controlling the log format self.log_format = os.environ.get("GALAXY_TEST_LOG_FORMAT")