Skip to content

Commit

Permalink
build: require python >= 3.10 (#149)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsstevenson authored Jun 24, 2024
1 parent 49cf778 commit eab6746
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 81 deletions.
7 changes: 3 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ classifiers = [
"Topic :: Scientific/Engineering :: Bio-Informatics",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
]
requires-python = ">=3.8"
requires-python = ">=3.10"
description = "Computable object representation and validation for gene fusions"
license = {file = "LICENSE"}
dependencies = [
Expand Down Expand Up @@ -140,11 +138,12 @@ ignore = [

[tool.ruff.lint.per-file-ignores]
# ANN001 - missing-type-function-argument
# ANN102 - missing-type-cls
# ANN2 - missing-return-type
# ANN201 - missing-return-type-undocumented-public-function
# ANN102 - missing-type-cls
# S101 - assert
# B011 - assert-false
# N805 - invalid-first-argument-name-for-method
"tests/*" = ["ANN001", "ANN2", "ANN102", "S101", "B011"]
"src/fusor/models.py" = ["ANN201", "N805", "ANN001", "ANN2"]
"src/fusor/models.py" = ["ANN201", "N805", "ANN001", "ANN2", "ANN102"]
53 changes: 26 additions & 27 deletions src/fusor/fusor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Module for modifying fusion objects."""
import logging
import re
from typing import Dict, List, Optional, Tuple
from urllib.parse import quote

from biocommons.seqrepo import SeqRepo
Expand Down Expand Up @@ -65,9 +64,9 @@ class FUSOR:

def __init__(
self,
seqrepo_data_path: Optional[str] = None,
gene_database: Optional[GeneDatabase] = None,
uta_db_url: Optional[str] = None,
seqrepo_data_path: str | None = None,
gene_database: GeneDatabase | None = None,
uta_db_url: str | None = None,
) -> None:
"""Initialize FUSOR class.
Expand All @@ -88,7 +87,7 @@ def __init__(
self.seqrepo = self.cool_seq_tool.seqrepo_access.sr

@staticmethod
def _contains_element_type(kwargs: Dict, elm_type: StructuralElementType) -> bool:
def _contains_element_type(kwargs: dict, elm_type: StructuralElementType) -> bool:
"""Check if fusion contains element of a specific type. Helper method
for inferring fusion type.
:param Dict kwargs: keyword args given to fusion method
Expand All @@ -97,13 +96,13 @@ def _contains_element_type(kwargs: Dict, elm_type: StructuralElementType) -> boo
False otherwise.
"""
for c in kwargs["structural_elements"]:
if (isinstance(c, Dict) and c.get("type") == elm_type) or (
if (isinstance(c, dict) and c.get("type") == elm_type) or (
isinstance(c, BaseStructuralElement) and c.type == elm_type
):
return True
return False

def fusion(self, fusion_type: Optional[FusionType] = None, **kwargs) -> Fusion:
def fusion(self, fusion_type: FusionType | None = None, **kwargs) -> Fusion:
"""Construct fusion object.
:param Optional[FusionType] fusion_type: explicitly specify fusion type.
Expand Down Expand Up @@ -170,9 +169,9 @@ def fusion(self, fusion_type: Optional[FusionType] = None, **kwargs) -> Fusion:
@staticmethod
def categorical_fusion(
structural_elements: CategoricalFusionElements,
regulatory_element: Optional[RegulatoryElement] = None,
critical_functional_domains: Optional[List[FunctionalDomain]] = None,
r_frame_preserved: Optional[bool] = None,
regulatory_element: RegulatoryElement | None = None,
critical_functional_domains: list[FunctionalDomain] | None = None,
r_frame_preserved: bool | None = None,
) -> CategoricalFusion:
"""Construct a categorical fusion object
:param CategoricalFusionElements structural_elements: elements
Expand Down Expand Up @@ -200,9 +199,9 @@ def categorical_fusion(
@staticmethod
def assayed_fusion(
structural_elements: AssayedFusionElements,
causative_event: Optional[CausativeEvent] = None,
assay: Optional[Assay] = None,
regulatory_element: Optional[RegulatoryElement] = None,
causative_event: CausativeEvent | None = None,
assay: Assay | None = None,
regulatory_element: RegulatoryElement | None = None,
) -> AssayedFusion:
"""Construct an assayed fusion object
:param AssayedFusionElements structural_elements: elements constituting the
Expand All @@ -229,9 +228,9 @@ async def transcript_segment_element(
self,
tx_to_genomic_coords: bool = True,
use_minimal_gene_descr: bool = True,
seq_id_target_namespace: Optional[str] = None,
seq_id_target_namespace: str | None = None,
**kwargs,
) -> Tuple[Optional[TranscriptSegmentElement], Optional[List[str]]]:
) -> tuple[TranscriptSegmentElement | None, list[str] | None]:
"""Create transcript segment element
:param bool tx_to_genomic_coords: `True` if going from transcript
Expand Down Expand Up @@ -325,7 +324,7 @@ async def transcript_segment_element(

def gene_element(
self, gene: str, use_minimal_gene_descr: bool = True
) -> Tuple[Optional[GeneElement], Optional[str]]:
) -> tuple[GeneElement | None, str | None]:
"""Create gene element
:param str gene: Gene
Expand All @@ -347,10 +346,10 @@ def templated_sequence_element(
end: int,
sequence_id: str,
strand: Strand,
label: Optional[str] = None,
label: str | None = None,
add_location_id: bool = False,
residue_mode: ResidueMode = ResidueMode.RESIDUE,
seq_id_target_namespace: Optional[str] = None,
seq_id_target_namespace: str | None = None,
) -> TemplatedSequenceElement:
"""Create templated sequence element
Expand Down Expand Up @@ -389,7 +388,7 @@ def templated_sequence_element(
def linker_element(
sequence: str,
residue_type: CURIE = "SO:0000348",
) -> Tuple[Optional[LinkerElement], Optional[str]]:
) -> tuple[LinkerElement | None, str | None]:
"""Create linker element
:param str sequence: Sequence
Expand Down Expand Up @@ -439,8 +438,8 @@ def functional_domain(
start: int,
end: int,
use_minimal_gene_descr: bool = True,
seq_id_target_namespace: Optional[str] = None,
) -> Tuple[Optional[FunctionalDomain], Optional[str]]:
seq_id_target_namespace: str | None = None,
) -> tuple[FunctionalDomain | None, str | None]:
"""Build functional domain instance.
:param DomainStatus status: Status for domain. Must be either `lost`
Expand Down Expand Up @@ -507,7 +506,7 @@ def regulatory_element(
regulatory_class: RegulatoryClass,
gene: str,
use_minimal_gene_descr: bool = True,
) -> Tuple[Optional[RegulatoryElement], Optional[str]]:
) -> tuple[RegulatoryElement | None, str | None]:
"""Create RegulatoryElement
:param RegulatoryClass regulatory_class: one of {"promoter", "enhancer"}
:param str gene: gene term to fetch normalized descriptor for
Expand Down Expand Up @@ -538,8 +537,8 @@ def _location_descriptor(
start: int,
end: int,
sequence_id: str,
label: Optional[str] = None,
seq_id_target_namespace: Optional[str] = None,
label: str | None = None,
seq_id_target_namespace: str | None = None,
use_location_id: bool = False,
) -> LocationDescriptor:
"""Create location descriptor
Expand Down Expand Up @@ -600,7 +599,7 @@ def add_additional_fields(
self,
fusion: Fusion,
add_all: bool = True,
fields: Optional[List[AdditionalFields]] = None,
fields: list[AdditionalFields] | None = None,
target_namespace: str = "ga4gh",
) -> Fusion:
"""Add additional fields to Fusion object.
Expand Down Expand Up @@ -668,7 +667,7 @@ def add_location_id(self, fusion: Fusion) -> Fusion:
return fusion

@staticmethod
def _location_id(location: Dict) -> CURIE:
def _location_id(location: dict) -> CURIE:
"""Return GA4GH digest for location
:param dict location: VRS Location represented as a dict
Expand Down Expand Up @@ -761,7 +760,7 @@ def add_gene_descriptor(self, fusion: Fusion) -> Fusion:

def _normalized_gene_descriptor(
self, query: str, use_minimal_gene_descr: bool = True
) -> Tuple[Optional[GeneDescriptor], Optional[str]]:
) -> tuple[GeneDescriptor | None, str | None]:
"""Return gene descriptor from normalized response.
:param str query: Gene query
Expand Down
92 changes: 44 additions & 48 deletions src/fusor/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Model for fusion class"""
from abc import ABC
from enum import Enum
from typing import Any, Dict, List, Literal, Optional, Set, Type, Union
from typing import Any, Literal

from ga4gh.vrsatile.pydantic import return_value
from ga4gh.vrsatile.pydantic.vrsatile_models import (
Expand Down Expand Up @@ -63,9 +63,9 @@ class FunctionalDomain(BaseModel):
type: Literal[FUSORTypes.FUNCTIONAL_DOMAIN] = FUSORTypes.FUNCTIONAL_DOMAIN
status: DomainStatus
associated_gene: GeneDescriptor
id: Optional[CURIE] = Field(None, alias="_id")
label: Optional[StrictStr] = None
sequence_location: Optional[LocationDescriptor] = None
id: CURIE | None = Field(None, alias="_id")
label: StrictStr | None = None
sequence_location: LocationDescriptor | None = None

_get_id_val = field_validator("id")(return_value)

Expand Down Expand Up @@ -124,13 +124,13 @@ class TranscriptSegmentElement(BaseStructuralElement):
FUSORTypes.TRANSCRIPT_SEGMENT_ELEMENT
] = FUSORTypes.TRANSCRIPT_SEGMENT_ELEMENT
transcript: CURIE
exon_start: Optional[StrictInt] = None
exon_start_offset: Optional[StrictInt] = 0
exon_end: Optional[StrictInt] = None
exon_end_offset: Optional[StrictInt] = 0
exon_start: StrictInt | None = None
exon_start_offset: StrictInt | None = 0
exon_end: StrictInt | None = None
exon_end_offset: StrictInt | None = 0
gene_descriptor: GeneDescriptor
element_genomic_start: Optional[LocationDescriptor] = None
element_genomic_end: Optional[LocationDescriptor] = None
element_genomic_start: LocationDescriptor | None = None
element_genomic_end: LocationDescriptor | None = None

@model_validator(mode="before")
def check_exons(cls, values):
Expand Down Expand Up @@ -386,9 +386,9 @@ class RegulatoryElement(BaseModel):

type: Literal[FUSORTypes.REGULATORY_ELEMENT] = FUSORTypes.REGULATORY_ELEMENT
regulatory_class: RegulatoryClass
feature_id: Optional[str] = None
associated_gene: Optional[GeneDescriptor] = None
feature_location: Optional[LocationDescriptor] = None
feature_id: str | None = None
associated_gene: GeneDescriptor | None = None
feature_location: LocationDescriptor | None = None

_get_ref_id_val = field_validator("feature_id")(return_value)

Expand Down Expand Up @@ -434,7 +434,7 @@ class FusionType(str, Enum):
ASSAYED_FUSION = FUSORTypes.ASSAYED_FUSION.value

@classmethod
def values(cls) -> Set: # noqa: ANN102
def values(cls) -> set:
"""Provide all possible enum values."""
return {c.value for c in cls}

Expand All @@ -443,15 +443,15 @@ class AbstractFusion(BaseModel, ABC):
"""Define Fusion class"""

type: FusionType
regulatory_element: Optional[RegulatoryElement] = None
structural_elements: List[BaseStructuralElement]
regulatory_element: RegulatoryElement | None = None
structural_elements: list[BaseStructuralElement]

@classmethod
def _access_object_attr(
cls: Type[FusionType],
obj: Union[Dict, BaseModel],
cls,
obj: dict | BaseModel,
attr_name: str,
) -> Optional[Any]: # noqa: ANN401
) -> Any | None: # noqa: ANN401
"""Help enable safe access of object properties while performing
validation for Pydantic class objects. Because the validator could be handling either
existing Pydantic class objects, or candidate dictionaries, we need a flexible
Expand All @@ -476,10 +476,10 @@ def _access_object_attr(

@classmethod
def _fetch_gene_id(
cls: Type[FusionType],
obj: Union[Dict, BaseModel],
cls,
obj: dict | BaseModel,
gene_descriptor_field: str,
) -> Optional[str]:
) -> str | None:
"""Get gene ID if element includes a gene annotation.
:param obj: element to fetch gene from. Might not contain a gene (e.g. it's a
Expand Down Expand Up @@ -591,10 +591,10 @@ class Assay(BaseModelForbidExtra):
"""Information pertaining to the assay used in identifying the fusion."""

type: Literal["Assay"] = "Assay"
assay_name: Optional[StrictStr] = None
assay_id: Optional[CURIE] = None
method_uri: Optional[CURIE] = None
fusion_detection: Optional[Evidence] = None
assay_name: StrictStr | None = None
assay_id: CURIE | None = None
method_uri: CURIE | None = None
fusion_detection: Evidence | None = None

_get_assay_id_val = field_validator("assay_id")(return_value)
_get_method_uri_val = field_validator("method_uri")(return_value)
Expand All @@ -611,14 +611,12 @@ class Assay(BaseModelForbidExtra):
)


AssayedFusionElements = List[
Union[
TranscriptSegmentElement,
GeneElement,
TemplatedSequenceElement,
LinkerElement,
UnknownGeneElement,
]
AssayedFusionElements = list[
TranscriptSegmentElement
| GeneElement
| TemplatedSequenceElement
| LinkerElement
| UnknownGeneElement
]


Expand All @@ -640,7 +638,7 @@ class CausativeEvent(BaseModelForbidExtra):

type: Literal[FUSORTypes.CAUSATIVE_EVENT] = FUSORTypes.CAUSATIVE_EVENT
event_type: EventType
event_description: Optional[StrictStr] = None
event_description: StrictStr | None = None

model_config = ConfigDict(
json_schema_extra={
Expand All @@ -662,8 +660,8 @@ class AssayedFusion(AbstractFusion):

type: Literal[FUSORTypes.ASSAYED_FUSION] = FUSORTypes.ASSAYED_FUSION
structural_elements: AssayedFusionElements
causative_event: Optional[CausativeEvent] = None
assay: Optional[Assay] = None
causative_event: CausativeEvent | None = None
assay: Assay | None = None

model_config = ConfigDict(
json_schema_extra={
Expand Down Expand Up @@ -698,14 +696,12 @@ class AssayedFusion(AbstractFusion):
)


CategoricalFusionElements = List[
Union[
TranscriptSegmentElement,
GeneElement,
TemplatedSequenceElement,
LinkerElement,
MultiplePossibleGenesElement,
]
CategoricalFusionElements = list[
TranscriptSegmentElement
| GeneElement
| TemplatedSequenceElement
| LinkerElement
| MultiplePossibleGenesElement
]


Expand All @@ -717,8 +713,8 @@ class CategoricalFusion(AbstractFusion):
"""

type: Literal[FUSORTypes.CATEGORICAL_FUSION] = FUSORTypes.CATEGORICAL_FUSION
r_frame_preserved: Optional[StrictBool] = None
critical_functional_domains: Optional[List[FunctionalDomain]] = None
r_frame_preserved: StrictBool | None = None
critical_functional_domains: list[FunctionalDomain] | None = None
structural_elements: CategoricalFusionElements

model_config = ConfigDict(
Expand Down Expand Up @@ -808,4 +804,4 @@ class CategoricalFusion(AbstractFusion):
)


Fusion = Union[CategoricalFusion, AssayedFusion]
Fusion = CategoricalFusion | AssayedFusion
Loading

0 comments on commit eab6746

Please sign in to comment.