From 08c1f24f8216d872dcabcfe377fdc51777a31dac Mon Sep 17 00:00:00 2001 From: Kori Kuzma Date: Thu, 11 Jul 2024 10:15:17 -0400 Subject: [PATCH] refactor!: split gks-common module into domain + entity (#422) * ga4gh.core.models split into ga4gh.core.domain_models and ga4gh.core.entity_models --- src/ga4gh/core/__init__.py | 5 +- src/ga4gh/core/domain_models.py | 142 ++++++++++++++++++ .../core/{models.py => entity_models.py} | 12 +- src/ga4gh/vrs/models.py | 2 +- 4 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 src/ga4gh/core/domain_models.py rename src/ga4gh/core/{models.py => entity_models.py} (97%) diff --git a/src/ga4gh/core/__init__.py b/src/ga4gh/core/__init__.py index 640b2411..53c4edb9 100644 --- a/src/ga4gh/core/__init__.py +++ b/src/ga4gh/core/__init__.py @@ -14,7 +14,7 @@ from .pydantic import ( is_pydantic_instance, is_curie_type, is_ga4gh_identifiable, is_literal, pydantic_copy ) -from . import models as common_models +from . import entity_models, domain_models __all__ = [ "sha512t24u", @@ -37,7 +37,8 @@ "is_ga4gh_identifiable", "is_literal", "pydantic_copy", - "common_models" + "entity_models", + "domain_models" ] try: diff --git a/src/ga4gh/core/domain_models.py b/src/ga4gh/core/domain_models.py new file mode 100644 index 00000000..d6d0918f --- /dev/null +++ b/src/ga4gh/core/domain_models.py @@ -0,0 +1,142 @@ +"""GKS Common Library Domain Entity models + +**This module should not be imported directly.** + +Instead, users should use one of the following: + + * `from ga4gh.core import domain_models`, and refer to models with the + abbreviated name, e.g., `domain_models.Gene` (recommended) + + * `import ga4gh.core`, and refer to models using the fully-qualified + module name, e.g., `ga4gh.core.domain_models.Gene` +""" +from typing import Literal, Union, List +from enum import Enum + +from pydantic import Field, RootModel + +from ga4gh.core.entity_models import _DomainEntity + + +class CommonDomainType(str, Enum): + """Define GKS Common Domain Entity types""" + + PHENOTYPE = "Phenotype" + DISEASE = "Disease" + TRAIT_SET = "TraitSet" + TR_ACTION = "TherapeuticAction" + TR_AGENT = "TherapeuticAgent" + TR_SUB = "TherapeuticSubstituteGroup" + TR_COMB = "CombinationTherapy" + GENE = "Gene" + +class Phenotype(_DomainEntity): + """An observable characteristic or trait of an organism.""" + + type: Literal[CommonDomainType.PHENOTYPE] = Field( + CommonDomainType.PHENOTYPE, + description=f'MUST be "{CommonDomainType.PHENOTYPE.value}".' + ) + + +class Disease(_DomainEntity): + """A particular abnormal condition that negatively affects the structure or function + of all or part of an organism and is not immediately due to any external injury. + """ + + type: Literal[CommonDomainType.DISEASE] = Field( + CommonDomainType.DISEASE, + description=f'MUST be "{CommonDomainType.DISEASE.value}".' + ) + + +class TraitSet(_DomainEntity): + """A set of phenotype and/or disease concepts that together constitute a condition.""" + + type: Literal[CommonDomainType.TRAIT_SET] = Field( + CommonDomainType.TRAIT_SET, + description=f'MUST be "{CommonDomainType.TRAIT_SET.value}".' + ) + traits: List[Union[Disease, Phenotype]] = Field( + ..., + min_length=2 + ) + + +class Condition(RootModel): + """A disease or other medical disorder.""" + + root: Union[TraitSet, Disease, Phenotype] = Field( + ..., + json_schema_extra={'description': 'A disease or other medical disorder.'}, + discriminator='type', + ) + + +class TherapeuticAction(_DomainEntity): + """A therapeutic action taken that is intended to alter or stop a pathologic process.""" + + type: Literal[CommonDomainType.TR_ACTION] = Field( + CommonDomainType.TR_ACTION, + description=f'MUST be "{CommonDomainType.TR_ACTION.value}".' + ) + + +class TherapeuticAgent(_DomainEntity): + """An administered therapeutic agent that is intended to alter or stop a pathologic process.""" + + type: Literal[CommonDomainType.TR_AGENT] = Field( + CommonDomainType.TR_AGENT, + description=f'MUST be "{CommonDomainType.TR_AGENT.value}".' + ) + + +class TherapeuticSubstituteGroup(_DomainEntity): + """A group of therapeutic procedures that may be treated as substitutes for one another.""" + + type: Literal[CommonDomainType.TR_SUB] = Field( + CommonDomainType.TR_SUB, + description=f'MUST be "{CommonDomainType.TR_SUB.value}".' + ) + substitutes: List[Union[TherapeuticAction, TherapeuticAgent]] = Field( + ..., + description='The individual therapeutic procedures that may be treated as substitutes.', + min_length=2 + ) + + +class CombinationTherapy(_DomainEntity): + """A therapeutic procedure that involves multiple different therapeutic procedures + performed in combination. + """ + + type: Literal[CommonDomainType.TR_COMB] = Field( + CommonDomainType.TR_COMB, + description=f'MUST be "{CommonDomainType.TR_COMB.value}".' + ) + components: List[Union[TherapeuticSubstituteGroup, TherapeuticAction, TherapeuticAgent]] = Field( + ..., + description='The individual therapeutic procedure components that constitute the combination therapy.', + min_length=2 + ) + + +class TherapeuticProcedure(RootModel): + """An action or administration of therapeutic agents to produce an effect that is + intended to alter or stop a pathologic process. + """ + + root: Union[CombinationTherapy, TherapeuticSubstituteGroup, TherapeuticAction, TherapeuticAgent] = Field( + ..., + json_schema_extra={'description': 'An action or administration of therapeutic agents to produce an effect that is intended to alter or stop a pathologic process.'}, + discriminator='type', + ) + + +class Gene(_DomainEntity): + """A basic physical and functional unit of heredity.""" + + type: Literal[CommonDomainType.GENE] = Field( + CommonDomainType.GENE, + description=f'MUST be "{CommonDomainType.GENE.value}".' + ) diff --git a/src/ga4gh/core/models.py b/src/ga4gh/core/entity_models.py similarity index 97% rename from src/ga4gh/core/models.py rename to src/ga4gh/core/entity_models.py index f66cc1e4..ea575bf2 100644 --- a/src/ga4gh/core/models.py +++ b/src/ga4gh/core/entity_models.py @@ -1,14 +1,14 @@ -"""GKS Common Library models +"""GKS Common Library Entity models **This module should not be imported directly.** Instead, users should use one of the following: - * `from ga4gh.core import common_models`, and refer to models with the - abbreviated name, e.g., `common_models.Gene` (recommended) + * `from ga4gh.core import entity_models`, and refer to models with the + abbreviated name, e.g., `entity_models.Coding` (recommended) * `import ga4gh.core`, and refer to models using the fully-qualified - module name, e.g., `ga4gh.core.common_models.Gene` + module name, e.g., `ga4gh.core.entity_models.Coding` """ from typing import Any, Dict, Literal, Annotated, Optional, Union, List from enum import Enum @@ -18,10 +18,6 @@ from ga4gh.core import GA4GH_IR_REGEXP -######################################### -# GKS Common Utility Class Definitions -######################################### - class Relation(str, Enum): """A mapping relation between concepts as defined by the Simple Knowledge diff --git a/src/ga4gh/vrs/models.py b/src/ga4gh/vrs/models.py index 147fbef6..ad2e1ae6 100644 --- a/src/ga4gh/vrs/models.py +++ b/src/ga4gh/vrs/models.py @@ -23,7 +23,7 @@ is_ga4gh_identifiable, getattr_in ) -from ga4gh.core.models import IRI, Expression, _DomainEntity +from ga4gh.core.entity_models import IRI, Expression, _DomainEntity def flatten(vals):