diff --git a/alembic/versions/00dab0f5f498_add_external_links_property_to_.py b/alembic/versions/00dab0f5f498_add_external_links_property_to_.py new file mode 100644 index 00000000..01c25ad4 --- /dev/null +++ b/alembic/versions/00dab0f5f498_add_external_links_property_to_.py @@ -0,0 +1,33 @@ +"""add external links property to experiments + +Revision ID: 00dab0f5f498 +Revises: b22b450d409c +Create Date: 2025-12-16 12:06:15.265947 + +""" + +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from alembic import op + +# revision identifiers, used by Alembic. +revision = "00dab0f5f498" +down_revision = "b22b450d409c" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "experiments", + sa.Column("external_links", postgresql.JSONB(astext_type=sa.Text()), nullable=False, server_default="{}"), + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("experiments", "external_links") + # ### end Alembic commands ### diff --git a/src/mavedb/models/experiment.py b/src/mavedb/models/experiment.py index 846ab00a..22014a59 100644 --- a/src/mavedb/models/experiment.py +++ b/src/mavedb/models/experiment.py @@ -73,6 +73,7 @@ class Experiment(Base): abstract_text = Column(String, nullable=False) method_text = Column(String, nullable=False) extra_metadata = Column(JSONB, nullable=False) + external_links = Column(JSONB, nullable=False, default={}) private = Column(Boolean, nullable=False, default=True) approved = Column(Boolean, nullable=False, default=False) diff --git a/src/mavedb/view_models/collection.py b/src/mavedb/view_models/collection.py index 9761686d..e83de288 100644 --- a/src/mavedb/view_models/collection.py +++ b/src/mavedb/view_models/collection.py @@ -1,5 +1,5 @@ from datetime import date -from typing import Any, Sequence, Optional +from typing import Any, Optional, Sequence from pydantic import Field, model_validator @@ -132,3 +132,14 @@ class Collection(SavedCollection): # NOTE: Coupled to ContributionRole enum class AdminCollection(Collection): pass + + +# Properties to return for official collections +class OfficialCollection(BaseModel): + badge_name: str + name: str + urn: str + + class Config: + arbitrary_types_allowed = True + from_attributes = True diff --git a/src/mavedb/view_models/components/external_link.py b/src/mavedb/view_models/components/external_link.py new file mode 100644 index 00000000..43c5d28e --- /dev/null +++ b/src/mavedb/view_models/components/external_link.py @@ -0,0 +1,15 @@ +from typing import Optional + +from mavedb.view_models.base.base import BaseModel + + +class ExternalLink(BaseModel): + """ + Represents an external hyperlink for view models. + + Attributes: + url (Optional[str]): Fully qualified URL for the external resource. + May be None if no link is available or applicable. + """ + + url: Optional[str] = None diff --git a/src/mavedb/view_models/experiment.py b/src/mavedb/view_models/experiment.py index b05766ff..c75e3bde 100644 --- a/src/mavedb/view_models/experiment.py +++ b/src/mavedb/view_models/experiment.py @@ -1,18 +1,20 @@ from datetime import date from typing import Any, Collection, Optional, Sequence -from pydantic import field_validator, model_validator, ValidationInfo +from pydantic import ValidationInfo, field_validator, model_validator +from mavedb.lib.validation import urn_re from mavedb.lib.validation.exceptions import ValidationError from mavedb.lib.validation.transform import ( transform_experiment_set_to_urn, - transform_score_set_list_to_urn_list, transform_record_publication_identifiers, + transform_score_set_list_to_urn_list, ) -from mavedb.lib.validation import urn_re from mavedb.lib.validation.utilities import is_null from mavedb.view_models import record_type_validator, set_record_type from mavedb.view_models.base.base import BaseModel +from mavedb.view_models.collection import OfficialCollection +from mavedb.view_models.components.external_link import ExternalLink from mavedb.view_models.contributor import Contributor, ContributorCreate from mavedb.view_models.doi_identifier import ( DoiIdentifier, @@ -37,16 +39,6 @@ from mavedb.view_models.user import SavedUser, User -class OfficialCollection(BaseModel): - badge_name: str - name: str - urn: str - - class Config: - arbitrary_types_allowed = True - from_attributes = True - - class ExperimentBase(BaseModel): title: str short_description: str @@ -115,6 +107,7 @@ class SavedExperiment(ExperimentBase): contributors: list[Contributor] keywords: Sequence[SavedExperimentControlledKeyword] score_set_urns: list[str] + external_links: dict[str, ExternalLink] _record_type_factory = record_type_validator()(set_record_type) diff --git a/src/mavedb/view_models/score_set.py b/src/mavedb/view_models/score_set.py index 9f53cf64..e6f20af9 100644 --- a/src/mavedb/view_models/score_set.py +++ b/src/mavedb/view_models/score_set.py @@ -19,6 +19,8 @@ from mavedb.models.enums.processing_state import ProcessingState from mavedb.view_models import record_type_validator, set_record_type from mavedb.view_models.base.base import BaseModel +from mavedb.view_models.collection import OfficialCollection +from mavedb.view_models.components.external_link import ExternalLink from mavedb.view_models.contributor import Contributor, ContributorCreate from mavedb.view_models.doi_identifier import ( DoiIdentifier, @@ -49,20 +51,6 @@ UnboundedRange = tuple[Union[float, None], Union[float, None]] -class ExternalLink(BaseModel): - url: Optional[str] = None - - -class OfficialCollection(BaseModel): - badge_name: str - name: str - urn: str - - class Config: - arbitrary_types_allowed = True - from_attributes = True - - class ScoreSetBase(BaseModel): """Base class for score set view models.""" diff --git a/tests/conftest.py b/tests/conftest.py index c79c033e..b11f728c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ import logging # noqa: F401 +import sys from datetime import datetime from unittest import mock -import sys import email_validator import pytest @@ -11,35 +11,33 @@ from sqlalchemy.pool import NullPool from mavedb.db.base import Base +from mavedb.models import * # noqa: F403 +from mavedb.models.experiment import Experiment from mavedb.models.experiment_set import ExperimentSet -from mavedb.models.score_set_publication_identifier import ScoreSetPublicationIdentifierAssociation -from mavedb.models.user import User, UserRole, Role from mavedb.models.license import License -from mavedb.models.taxonomy import Taxonomy -from mavedb.models.publication_identifier import PublicationIdentifier -from mavedb.models.experiment import Experiment -from mavedb.models.variant import Variant from mavedb.models.mapped_variant import MappedVariant +from mavedb.models.publication_identifier import PublicationIdentifier from mavedb.models.score_set import ScoreSet - -from mavedb.models import * # noqa: F403 - +from mavedb.models.score_set_publication_identifier import ScoreSetPublicationIdentifierAssociation +from mavedb.models.taxonomy import Taxonomy +from mavedb.models.user import Role, User, UserRole +from mavedb.models.variant import Variant from tests.helpers.constants import ( ADMIN_USER, EXTRA_USER, - TEST_LICENSE, + TEST_BRNICH_SCORE_CALIBRATION, TEST_INACTIVE_LICENSE, + TEST_LICENSE, + TEST_PATHOGENICITY_SCORE_CALIBRATION, + TEST_PUBMED_IDENTIFIER, TEST_SAVED_TAXONOMY, TEST_USER, - VALID_VARIANT_URN, - VALID_SCORE_SET_URN, - VALID_EXPERIMENT_URN, - VALID_EXPERIMENT_SET_URN, - TEST_PUBMED_IDENTIFIER, TEST_VALID_POST_MAPPED_VRS_ALLELE_VRS2_X, TEST_VALID_PRE_MAPPED_VRS_ALLELE_VRS2_X, - TEST_BRNICH_SCORE_CALIBRATION, - TEST_PATHOGENICITY_SCORE_CALIBRATION, + VALID_EXPERIMENT_SET_URN, + VALID_EXPERIMENT_URN, + VALID_SCORE_SET_URN, + VALID_VARIANT_URN, ) sys.path.append(".") @@ -56,7 +54,7 @@ assert pytest_postgresql.factories # Allow the @test domain name through our email validator. -email_validator.SPECIAL_USE_DOMAIN_NAMES.remove("test") +email_validator.TEST_ENVIRONMENT = True @pytest.fixture() diff --git a/tests/helpers/constants.py b/tests/helpers/constants.py index 1a219f17..2bb66ce8 100644 --- a/tests/helpers/constants.py +++ b/tests/helpers/constants.py @@ -540,6 +540,7 @@ "primaryPublicationIdentifiers": [], "secondaryPublicationIdentifiers": [], "rawReadIdentifiers": [], + "externalLinks": {}, # keys to be set after receiving response "urn": None, "experimentSetUrn": None, @@ -580,6 +581,7 @@ "primaryPublicationIdentifiers": [], "secondaryPublicationIdentifiers": [], "rawReadIdentifiers": [], + "externalLinks": {}, # keys to be set after receiving response "urn": None, "experimentSetUrn": None, @@ -630,6 +632,7 @@ "primaryPublicationIdentifiers": [], "secondaryPublicationIdentifiers": [], "rawReadIdentifiers": [], + "externalLinks": {}, # keys to be set after receiving response "urn": None, "experimentSetUrn": None,