Skip to content

Commit 23e7d2b

Browse files
committed
WIP typing
1 parent eab4280 commit 23e7d2b

File tree

17 files changed

+157
-55
lines changed

17 files changed

+157
-55
lines changed

server/pyproject.toml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,22 @@ where = ["src"]
7777

7878
[tool.mypy]
7979
plugins = [
80-
"sqlalchemy.ext.mypy.plugin"
80+
"sqlalchemy.ext.mypy.plugin",
81+
"pydantic.mypy"
8182
]
8283
show_error_codes = "True"
84+
# follow_imports = "silent"
85+
# warn_redundant_casts = true
86+
# warn_unused_ignores = true
87+
# disallow_any_generics = true
88+
# check_untyped_defs = true
89+
# no_implicit_reexport = true
8390
#strict = "True"
84-
exclude = [
85-
"scimodom.utils.models.py"
86-
]
91+
92+
# [tool.pydantic-mypy]
93+
# init_forbid_extra = true
94+
# init_typed = true
95+
# warn_required_dynamic_aliases = true
8796

8897
[tool.pytest.ini_options]
8998
testpaths = ["tests"]

server/src/scimodom/api/dataset.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
from dataclasses import dataclass
3-
from typing import Iterable
3+
from typing import Generator, Iterable, Sequence
44

55
from flask import Blueprint
66
from flask_cors import cross_origin
@@ -110,7 +110,7 @@ class _CompareContext:
110110
class Ctx:
111111
bedtools_service: BedToolsService
112112
a_records: Iterable[ComparisonRecord]
113-
b_records_list: list[Iterable[ComparisonRecord]]
113+
b_records_list: Sequence[Iterable[ComparisonRecord]]
114114
is_strand: bool
115115

116116
def __init__(self):
@@ -170,7 +170,9 @@ def __enter__(self) -> Ctx:
170170
is_strand=self._is_strand,
171171
)
172172

173-
def _get_comparison_records_from_db(self, dataset_ids):
173+
def _get_comparison_records_from_db(
174+
self, dataset_ids
175+
) -> Generator[ComparisonRecord, None, None]:
174176
for dataset_id in dataset_ids:
175177
for data in self._data_service.get_by_dataset(dataset_id):
176178
yield ComparisonRecord(
@@ -185,8 +187,10 @@ def _get_comparison_records_from_db(self, dataset_ids):
185187
frequency=data.frequency,
186188
)
187189

188-
def _get_comparison_records_from_file(self):
189-
dummy_values = {"eufid": "upload "}
190+
def _get_comparison_records_from_file(
191+
self,
192+
) -> Generator[ComparisonRecord, None, None]:
193+
dummy_values: dict[str, str | int] = {"eufid": "upload "}
190194
if self._is_euf:
191195
importer = EufImporter(
192196
stream=self._tmp_file_handle, source=self._upload_name

server/src/scimodom/api/helpers.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,18 @@ def validate_request_size(max_size) -> None:
169169
raise ClientResponseException(413, f"File too large (max. {max_size} bytes)")
170170

171171

172-
def get_valid_taxa_id(raw: str) -> int:
173-
utilities_service = get_utilities_service()
174-
taxa_ids = [d["id"] for d in utilities_service.get_taxa()]
172+
def get_valid_taxa_id() -> int:
173+
taxa_id = request.args.get("taxaId", type=int)
174+
if taxa_id is None:
175+
raise ClientResponseException(400, "Invalid Taxa ID")
176+
_validate_taxa_id(taxa_id)
177+
return taxa_id
178+
179+
180+
def get_valid_taxa_id_from_string(raw: str) -> int:
175181
try:
176182
taxa_id = int(raw)
177-
if taxa_id not in taxa_ids:
178-
raise ClientResponseException(404, "Unrecognized Taxa ID")
183+
_validate_taxa_id(taxa_id)
179184
return taxa_id
180185
except ValueError:
181186
raise ClientResponseException(400, "Invalid Taxa ID")
@@ -197,8 +202,14 @@ def get_valid_targets_type(raw: str) -> TargetsFileType:
197202

198203
def get_valid_coords(taxa_id: int, context: int = 0) -> tuple[str, int, int, Strand]:
199204
chrom = request.args.get("chrom", type=str)
205+
if chrom is None:
206+
raise ClientResponseException(400, "Invalid chrom")
200207
start = request.args.get("start", type=int)
208+
if start is None:
209+
raise ClientResponseException(400, "Invalid start")
201210
end = request.args.get("end", type=int)
211+
if end is None:
212+
raise ClientResponseException(400, "Invalid end")
202213
strand = request.args.get("strand", default=".", type=str)
203214

204215
assembly_service = get_assembly_service()
@@ -285,3 +296,10 @@ def _is_valid_identifier(identifier, length):
285296
elif len(identifier) != length:
286297
return False
287298
return True
299+
300+
301+
def _validate_taxa_id(taxa_id: int) -> None:
302+
utilities_service = get_utilities_service()
303+
taxa_ids = [d["id"] for d in utilities_service.get_taxa()]
304+
if taxa_id not in taxa_ids:
305+
raise ClientResponseException(404, "Unrecognized Taxa ID")

server/src/scimodom/api/modification.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def get_modifications_as_csv(by_gene):
100100
def get_modification_sitewise():
101101
"""Get information related to a modification site."""
102102
try:
103-
taxa_id = get_valid_taxa_id(request.args.get("taxaId"))
103+
taxa_id = get_valid_taxa_id()
104104
chrom, start, end, _ = get_valid_coords(taxa_id)
105105
except ClientResponseException as e:
106106
return e.response_tuple
@@ -118,7 +118,7 @@ def get_modification_sitewise():
118118
def get_genomic_sequence_context(context):
119119
"""Get sequence context for a modification site."""
120120
try:
121-
taxa_id = get_valid_taxa_id(request.args.get("taxaId"))
121+
taxa_id = get_valid_taxa_id()
122122
coords = get_valid_coords(taxa_id, context=int(context))
123123
except ClientResponseException as e:
124124
return e.response_tuple
@@ -168,7 +168,7 @@ class Ctx:
168168
def __init__(self, target_type: str):
169169
self._target_type = get_valid_targets_type(target_type)
170170
self._is_strand = True
171-
self._taxa_id = get_valid_taxa_id(request.args.get("taxaId"))
171+
self._taxa_id = get_valid_taxa_id()
172172
self._coords = get_valid_coords(self._taxa_id)
173173

174174
def __enter__(self) -> Ctx:
@@ -222,7 +222,7 @@ def _get_modifications_for_request(by_gene):
222222
gene_or_chrom = _get_gene_or_chrom_required()
223223
return modification_service.get_modifications_by_gene(
224224
annotation_source=_get_annotation_source(),
225-
taxa_id=get_valid_taxa_id(request.args.get("taxaId")),
225+
taxa_id=get_valid_taxa_id(),
226226
gene_filter=gene_or_chrom.gene_filter,
227227
chrom=gene_or_chrom.chrom_filter,
228228
chrom_start=gene_or_chrom.chrom_start_filter,
@@ -237,7 +237,7 @@ def _get_modifications_for_request(by_gene):
237237
modification_id=get_non_negative_int("modification"),
238238
organism_id=get_non_negative_int("organism"),
239239
technology_ids=_get_technology_ids(),
240-
taxa_id=get_valid_taxa_id(request.args.get("taxaId")),
240+
taxa_id=get_valid_taxa_id(),
241241
gene_filter=_get_gene_filters(),
242242
chrom=request.args.get("chrom", type=str),
243243
chrom_start=get_optional_non_negative_int("chromStart"),

server/src/scimodom/api/utilities.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from scimodom.api.helpers import (
66
get_valid_logo,
7-
get_valid_taxa_id,
7+
get_valid_taxa_id_from_string,
88
ClientResponseException,
99
validate_rna_type,
1010
)
@@ -93,7 +93,7 @@ def get_features(rna_type):
9393
def get_chroms(taxa_id: str):
9494
assembly_service = get_assembly_service()
9595
try:
96-
taxa_id_as_int = get_valid_taxa_id(taxa_id)
96+
taxa_id_as_int = get_valid_taxa_id_from_string(taxa_id)
9797
return assembly_service.get_chroms(taxa_id_as_int)
9898
except ClientResponseException as e:
9999
return e.response_tuple
@@ -108,7 +108,7 @@ def get_chroms(taxa_id: str):
108108
def get_assemblies(taxa_id):
109109
utilities_service = get_utilities_service()
110110
try:
111-
taxa_id_as_int = get_valid_taxa_id(taxa_id)
111+
taxa_id_as_int = get_valid_taxa_id_from_string(taxa_id)
112112
return utilities_service.get_assemblies(taxa_id_as_int)
113113
except ClientResponseException as e:
114114
return e.response_tuple

server/src/scimodom/cli/project.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,14 @@ def create_project_template(
162162
sources = []
163163
for dv, pv in zip(doi, pmid):
164164
if dv == "null":
165-
dv = None
165+
dv_dto = None
166+
else:
167+
dv_dto = dv
166168
if pv == 0:
167-
pv = None
168-
source = ProjectSourceDto(doi=dv, pmid=pv)
169+
pv_dto = None
170+
else:
171+
pv_dto = pv
172+
source = ProjectSourceDto(doi=dv_dto, pmid=pv_dto)
169173
sources.append(source)
170174

171175
project_template = ProjectTemplate(

server/src/scimodom/services/annotation/gtrnadb.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ def create_annotation(self, taxa_id: int, **kwargs) -> None:
8282
fasta_file = annotation_paths["fa"].annotation_file
8383
# TODO
8484
# seqids = self._assembly_service.get_seqids(annotation.taxa_id)
85-
seqids = []
85+
# ?
86+
# seqids = []
8687

8788
logger.info(
8889
f"Setting up GtRNAdb {annotation.release} for {annotation.taxa_id}..."

server/src/scimodom/services/assembly.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
from functools import cache
44
from posixpath import join as urljoin
5-
from typing import Any
5+
from typing import Any, Sequence
66

77
from sqlalchemy import select, func
88
from sqlalchemy.exc import NoResultFound
@@ -86,7 +86,7 @@ def get_assembly_by_id(self, assembly_id: int) -> Assembly:
8686
except NoResultFound:
8787
raise AssemblyNotFoundError(f"No such assembly with ID: {assembly_id}.")
8888

89-
def get_assemblies_by_taxa(self, taxa_id: int) -> list[Assembly]:
89+
def get_assemblies_by_taxa(self, taxa_id: int) -> Sequence[Assembly]:
9090
"""Retrieve all assemblies for a given organism.
9191
9292
:param taxa_id: Taxonomy ID

server/src/scimodom/services/exporter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
Annotation,
2020
AnnotationVersion,
2121
)
22-
from scimodom.utils.specs.euf import EUF
22+
from scimodom.utils.specs.euf import EUF_VERSION
2323

2424
logger = logging.getLogger(__name__)
2525

@@ -34,7 +34,7 @@ class NoSuchDataset(Exception):
3434

3535
class Exporter:
3636
BAD_FILE_NAME_CHARACTERS_REGEXP = re.compile(r"[^a-zA-Z0-9(),._-]")
37-
VERSION = EUF["versions"][-1]
37+
VERSION = EUF_VERSION
3838

3939
def __init__(self, session: Session):
4040
self._session = session

server/src/scimodom/services/file.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def open_file_for_reading(path: str | Path) -> TextIO:
113113
return open(path, "r")
114114

115115
@staticmethod
116-
def count_lines(path: str | Path):
116+
def count_lines(path: str | Path) -> int:
117117
count = 0
118118
with open(path) as fp:
119119
while True:
@@ -124,7 +124,7 @@ def count_lines(path: str | Path):
124124

125125
# Import
126126

127-
def check_import_file(self, name: str):
127+
def check_import_file(self, name: str) -> bool:
128128
return Path(self._import_path, name).is_file()
129129

130130
def open_import_file(self, name: str):
@@ -182,7 +182,7 @@ def get_gene_cache(self, selection_ids: Iterable[int]) -> list[str]:
182182
:returns: The genes of the selection
183183
:rtype: list[str]
184184
"""
185-
result = set()
185+
result: set = set()
186186
for selection_id in selection_ids:
187187
path = Path(self._get_gene_cache_dir(), str(selection_id))
188188
with open(path) as fh:
@@ -237,7 +237,9 @@ def open_sunburst_cache(self, name: str) -> TextIO:
237237
file_path = Path(self._get_sunburst_cache_dir(), f"{name}.json")
238238
return open(file_path)
239239

240-
def update_sunburst_cache(self, name: str, generator: Generator[str, None, None]):
240+
def update_sunburst_cache(
241+
self, name: str, generator: Generator[str, None, None]
242+
) -> None:
241243
final_file_path = Path(self._get_sunburst_cache_dir(), f"{name}.json")
242244
try:
243245
temporary_file_path = None
@@ -335,10 +337,10 @@ def delete_project_request_file(self, request_uuid) -> None:
335337
def _get_project_metadata_dir(self) -> Path:
336338
return Path(self._data_path, self.METADATA_DEST)
337339

338-
def _get_project_request_file_path(self, request_uuid):
340+
def _get_project_request_file_path(self, request_uuid) -> Path:
339341
return Path(self._get_project_request_dir(), f"{request_uuid}.json")
340342

341-
def _get_project_request_dir(self):
343+
def _get_project_request_dir(self) -> Path:
342344
return Path(self._get_project_metadata_dir(), self.REQUEST_DEST)
343345

344346
# Assembly
@@ -488,7 +490,7 @@ def _get_current_assembly_name_from_taxa_id(self, taxa_id: int) -> str:
488490

489491
# uploaded files
490492

491-
def upload_tmp_file(self, stream, max_file_size):
493+
def upload_tmp_file(self, stream, max_file_size) -> str:
492494
fp, path = mkstemp(dir=self._upload_path)
493495
close(fp)
494496
file_id = basename(path)
@@ -509,7 +511,9 @@ def check_tmp_upload_file_id(self, file_id: str) -> bool:
509511
path = join(self._upload_path, file_id)
510512
return isfile(path)
511513

512-
def _stream_to_file(self, data_stream, path, max_size, overwrite_is_ok=False):
514+
def _stream_to_file(
515+
self, data_stream, path, max_size, overwrite_is_ok=False
516+
) -> None:
513517
if exists(path) and not overwrite_is_ok:
514518
raise Exception(
515519
f"FileService._stream_to_file(): Refusing to overwrite existing file: '{path}'!"
@@ -555,7 +559,7 @@ def create_or_update_bam_file(
555559
name: str,
556560
data_stream: IO[bytes],
557561
max_size: Optional[int],
558-
):
562+
) -> None:
559563
try:
560564
bam_file = self.get_bam_file(dataset, name)
561565
self._update_bam_file(bam_file, data_stream, max_size)
@@ -581,7 +585,7 @@ def get_bam_file_list(self, dataset: Dataset) -> List[Dict[str, Any]]:
581585
).all()
582586
return [self._get_bam_file_info(i) for i in items]
583587

584-
def remove_bam_file(self, bam_file: BamFile):
588+
def remove_bam_file(self, bam_file: BamFile) -> None:
585589
path = self._get_bam_file_path(bam_file)
586590
try:
587591
unlink(path)
@@ -591,7 +595,7 @@ def remove_bam_file(self, bam_file: BamFile):
591595
self._session.commit()
592596

593597
@staticmethod
594-
def _handle_upload_error(exception, path):
598+
def _handle_upload_error(exception, path) -> None:
595599
logger.warning(
596600
f"Failed to create file '{path}': {str(exception)} - discarding file."
597601
)
@@ -601,10 +605,10 @@ def _handle_upload_error(exception, path):
601605
logger.warning(f"Failed to delete '{path}': {str(unlink_e)}.")
602606
raise exception
603607

604-
def _get_bam_files_parent_dir(self):
608+
def _get_bam_files_parent_dir(self) -> Path:
605609
return Path(self._data_path, self.BAM_DEST)
606610

607-
def _update_bam_file(self, bam_file, data_stream, max_size):
611+
def _update_bam_file(self, bam_file, data_stream, max_size) -> None:
608612
tmp_path = self._get_bam_file_tmp_path(bam_file)
609613
path = self._get_bam_file_path(bam_file)
610614
self._stream_to_file(data_stream, tmp_path, max_size)
@@ -621,18 +625,18 @@ def _update_bam_file(self, bam_file, data_stream, max_size):
621625
self._session.delete(bam_file)
622626
raise exc
623627

624-
def _get_bam_file_tmp_path(self, bam_file):
628+
def _get_bam_file_tmp_path(self, bam_file) -> str:
625629
return join(
626630
self._get_bam_files_parent_dir().as_posix(),
627631
f"tmp.{bam_file.storage_file_name}",
628632
)
629633

630-
def _get_bam_file_path(self, bam_file):
634+
def _get_bam_file_path(self, bam_file) -> str:
631635
return join(
632636
self._get_bam_files_parent_dir().as_posix(), bam_file.storage_file_name
633637
)
634638

635-
def _create_bam_file(self, dataset, name, data_stream, max_size):
639+
def _create_bam_file(self, dataset, name, data_stream, max_size) -> None:
636640
bam_file = BamFile(
637641
dataset_id=dataset.id,
638642
original_file_name=name,
@@ -643,7 +647,7 @@ def _create_bam_file(self, dataset, name, data_stream, max_size):
643647
self._session.add(bam_file)
644648
self._session.commit()
645649

646-
def _get_bam_file_info(self, bam_file):
650+
def _get_bam_file_info(self, bam_file) -> dict[str, Any]:
647651
path = self._get_bam_file_path(bam_file)
648652
stat_info = stat(path)
649653
return {

0 commit comments

Comments
 (0)