Skip to content

Commit 33d341b

Browse files
authored
feat: Add CIViC to CategoricalFusion object translator (#236)
1 parent 6137480 commit 33d341b

File tree

8 files changed

+390
-25
lines changed

8 files changed

+390
-25
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ dependencies = [
3030
"ga4gh.vrs ==2.*",
3131
"biocommons.seqrepo",
3232
"gene-normalizer ~=0.9.0",
33-
"cool-seq-tool ~=0.13.0",
33+
"civicpy ~=4.0",
34+
"cool-seq-tool ~=0.13.0"
3435
]
3536
dynamic=["version"]
3637

src/fusor/fusion_caller_models.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from enum import Enum
55
from typing import Literal
66

7+
from civicpy.civic import ExonCoordinate, MolecularProfile
78
from pydantic import BaseModel, ConfigDict, Field
89

910

@@ -21,13 +22,26 @@ class Caller(str, Enum):
2122
GENIE = "GENIE"
2223

2324

25+
class KnowledgebaseList(str, Enum):
26+
"""Define supported knowledgebases"""
27+
28+
CIVIC = "CIVIC"
29+
30+
2431
class FusionCaller(ABC, BaseModel):
2532
"""ABC for fusion callers"""
2633

2734
type: Caller
2835
model_config = ConfigDict(extra="allow")
2936

3037

38+
class FusionKnowledgebase(ABC, BaseModel):
39+
"""ABC for Fusion Knowledgebases"""
40+
41+
type: KnowledgebaseList
42+
model_config = ConfigDict(extra="allow")
43+
44+
3145
class JAFFA(FusionCaller):
3246
"""Define parameters for JAFFA model"""
3347

@@ -247,3 +261,22 @@ class Genie(FusionCaller):
247261
reading_frame: str = Field(
248262
..., description="The reading frame status of the fusion"
249263
)
264+
265+
266+
class CIVIC(FusionKnowledgebase):
267+
"""Define parameters for CIVIC model"""
268+
269+
type: Literal[KnowledgebaseList.CIVIC] = KnowledgebaseList.CIVIC
270+
model_config = ConfigDict(arbitrary_types_allowed=True)
271+
vicc_compliant_name: str = Field(
272+
..., description="The VICC compliant name for the fusion"
273+
)
274+
five_prime_end_exon_coords: ExonCoordinate | None = Field(
275+
..., description="Data for the end exon of 5' fusion partner"
276+
)
277+
three_prime_start_exon_coords: ExonCoordinate | None = Field(
278+
..., description="Data for the start exon 3' fusion partner"
279+
)
280+
molecular_profiles: list[MolecularProfile] | None = Field(
281+
..., description="The molecular profiles associated with the fusion"
282+
)

src/fusor/fusor.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Annotated
66

77
from bioutils.accessions import coerce_namespace
8+
from civicpy.civic import MolecularProfile
89
from cool_seq_tool.app import CoolSeqTool
910
from cool_seq_tool.schemas import CoordinateType, Strand
1011
from ga4gh.core import ga4gh_identify
@@ -126,6 +127,7 @@ def fusion(self, fusion_type: FusionType | None = None, **kwargs) -> Fusion:
126127
categorical_attributes = any(
127128
[
128129
"critical_functional_domains" in kwargs,
130+
"civic_molecular_profiles" in kwargs,
129131
self._contains_element_type(
130132
kwargs, StructuralElementType.MULTIPLE_POSSIBLE_GENES_ELEMENT
131133
),
@@ -162,6 +164,7 @@ def categorical_fusion(
162164
regulatory_element: RegulatoryElement | None = None,
163165
critical_functional_domains: list[FunctionalDomain] | None = None,
164166
reading_frame_preserved: bool | None = None,
167+
civic_molecular_profiles: list[MolecularProfile] | None = None,
165168
) -> CategoricalFusion:
166169
"""Construct a categorical fusion object
167170
@@ -170,6 +173,7 @@ def categorical_fusion(
170173
:param critical_functional_domains: lost or preserved functional domains
171174
:param reading_frame_preserved: ``True`` if reading frame is preserved.
172175
``False`` otherwise
176+
:param civic_molecular_profiles: A list of MolecularProfile objects
173177
:return: CategoricalFusion if construction successful
174178
:raise: FUSORParametersException if given incorrect fusion properties
175179
"""
@@ -179,6 +183,7 @@ def categorical_fusion(
179183
criticalFunctionalDomains=critical_functional_domains,
180184
readingFramePreserved=reading_frame_preserved,
181185
regulatoryElement=regulatory_element,
186+
civic_molecular_profiles=civic_molecular_profiles,
182187
)
183188
except ValidationError as e:
184189
error_message = get_error_message(e)

src/fusor/harvester.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
from pathlib import Path
66
from typing import ClassVar
77

8+
from civicpy.civic import FusionVariant
9+
from pydantic import BaseModel, ConfigDict
10+
811
from fusor.fusion_caller_models import (
12+
CIVIC,
913
JAFFA,
1014
Arriba,
1115
Cicero,
@@ -162,3 +166,26 @@ class GenieHarvester(FusionCallerHarvester):
162166
}
163167
delimeter = "\t"
164168
fusion_caller = Genie
169+
170+
171+
class CIVICHarvester(BaseModel):
172+
"""Class for harvesting CIViC Fusion objects"""
173+
174+
fusions_list: list[FusionVariant]
175+
model_config = ConfigDict(arbitrary_types_allowed=True)
176+
177+
def load_records(self) -> list[CIVIC]:
178+
"""Extract data from CIVIC fusion objects
179+
180+
:return A list of CIVIC objects
181+
"""
182+
processed_fusions = []
183+
for fusion in self.fusions_list:
184+
params = {
185+
"vicc_compliant_name": fusion.vicc_compliant_name,
186+
"five_prime_end_exon_coords": fusion.five_prime_end_exon_coordinates,
187+
"three_prime_start_exon_coords": fusion.three_prime_start_exon_coordinates,
188+
"molecular_profiles": fusion.molecular_profiles,
189+
}
190+
processed_fusions.append(CIVIC(**params))
191+
return processed_fusions

src/fusor/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from enum import Enum
55
from typing import Annotated, Any, Literal
66

7+
from civicpy.civic import MolecularProfile
78
from cool_seq_tool.schemas import Strand
89
from ga4gh.core.models import MappableConcept
910
from ga4gh.vrs.models import (
@@ -833,8 +834,10 @@ class CategoricalFusion(AbstractFusion):
833834
type: Literal[FUSORTypes.CATEGORICAL_FUSION] = FUSORTypes.CATEGORICAL_FUSION
834835
criticalFunctionalDomains: list[FunctionalDomain] | None = None
835836
structure: list[CategoricalFusionElement]
837+
civicMolecularProfiles: list[MolecularProfile] | None = None
836838

837839
model_config = ConfigDict(
840+
arbitrary_types_allowed=True,
838841
json_schema_extra={
839842
"example": {
840843
"type": "CategoricalFusion",

0 commit comments

Comments
 (0)