Skip to content

Commit 1d77493

Browse files
author
Bruno Grande
authored
Merge pull request #20 from Sage-Bionetworks-Workflows/bgrande/parsers-reports-cov
Close code coverage for `parsers` and `reports` submodules
2 parents 089b49d + 9c2935d commit 1d77493

17 files changed

+239
-51
lines changed

Pipfile.lock

Lines changed: 34 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

setup.cfg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ testing =
7676
pytest-mock~=3.0
7777
hypothesis~=4.0
7878
nbmake~=1.3
79+
pytest-xdist[psutil]~=3.1
7980

8081
# Dependencies for development (used by Pipenv)
8182
dev =
@@ -108,8 +109,11 @@ console_scripts =
108109
# CAUTION: --cov flags may prohibit setting breakpoints while debugging.
109110
# Comment those flags to avoid this pytest issue.
110111
addopts =
111-
--cov dcqc --cov-report term-missing --cov-report xml
112+
--cov "dcqc" --cov-report "term-missing" --cov-report "xml"
112113
-m "not slow"
114+
# For now, the overhead with parallelizing the small number of tests makes
115+
# them slower (2.49s vs 1.16s). Uncomment when we have more tests.
116+
# --numprocesses "auto"
113117
--verbose
114118
norecursedirs =
115119
dist

src/dcqc/__main__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
from dcqc.main import app
1+
if __name__ == "__main__":
2+
from dcqc.main import app
23

3-
app(prog_name="dcqc")
4+
app(prog_name="dcqc")

src/dcqc/file.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ def register_file_type(self) -> None:
6868
raise ValueError(message)
6969
self._registry[name] = self
7070

71+
@classmethod
72+
def list_file_types(cls) -> list[FileType]:
73+
"""Retrieve all available file type objects.
74+
75+
Returns:
76+
The full list of file type objects.
77+
"""
78+
return list(cls._registry.values())
79+
7180
@classmethod
7281
def get_file_type(cls, file_type: str) -> FileType:
7382
"""Retrieve file type object based on its name.

src/dcqc/parsers.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pathlib import Path
55
from typing import Any, Optional, Type, TypeVar, cast
66

7-
from dcqc.file import File
7+
from dcqc.file import File, FileType
88
from dcqc.mixins import SerializableMixin
99
from dcqc.suites.suite_abc import SuiteABC
1010
from dcqc.target import Target
@@ -85,14 +85,17 @@ def get_class(cls, cls_name: str) -> Type[SerializableMixin]:
8585
suite_classes = SuiteABC.list_subclasses()
8686
suite_cls_map = {cls.__name__: cls for cls in suite_classes}
8787

88-
if cls_name == "File":
89-
return File
90-
elif cls_name == "Target":
88+
file_types = FileType.list_file_types()
89+
file_types_names = {ft.name.lower() for ft in file_types}
90+
91+
if cls_name == "Target":
9192
return Target
9293
elif cls_name in test_cls_map:
9394
return test_cls_map[cls_name]
9495
elif cls_name in suite_cls_map:
9596
return suite_cls_map[cls_name]
97+
elif cls_name.lower() in file_types_names:
98+
return File
9699
else:
97100
message = f"Type ({cls_name}) is not recognized."
98101
raise ValueError(message)
@@ -126,7 +129,7 @@ def parse_objects(cls, path: Path, expected_cls: Type[T]) -> list[T]:
126129
contents = parser.load_json()
127130

128131
if not isinstance(contents, list):
129-
message = f"JSON file ({cls.path}) does not contain a list of objects."
132+
message = f"JSON file ({parser.path}) does not contain a list of objects."
130133
raise ValueError(message)
131134

132135
objects = [cls.from_dict(dictionary) for dictionary in contents]

src/dcqc/reports.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ def __init__(self, paths_relative_to: Optional[Path] = None) -> None:
2020
self._fs: Optional[FS] = None
2121
self._fs_path: Optional[str] = None
2222

23+
# TODO: Move towards an FS mixin for these functions
2324
def _init_fs(self, url) -> tuple[FS, str]:
24-
if self._url != url or self._fs is None or self._fs_path is None:
25-
self._url = url
26-
self._fs, self._fs_path = open_parent_fs(url)
25+
self._url = url
26+
self._fs, self._fs_path = open_parent_fs(url)
2727
return self._fs, self._fs_path
2828

2929
def _create_parent_directories(self, url: str):
@@ -61,11 +61,11 @@ def _generate_single(self, item: SerializableMixin) -> SerializedObject:
6161
# the inputs and outputs: single to single, and many to many.
6262
@overload
6363
def generate(self, items: SerializableMixin) -> SerializedObject:
64-
...
64+
""""""
6565

6666
@overload
6767
def generate(self, items: Iterable[SerializableMixin]) -> list[SerializedObject]:
68-
...
68+
""""""
6969

7070
def generate(self, items):
7171
if isinstance(items, Iterable):
@@ -79,13 +79,13 @@ def generate(self, items):
7979
def save(
8080
self, items: SerializableMixin, url: str, overwrite: bool = False
8181
) -> SerializedObject:
82-
...
82+
""""""
8383

8484
@overload
8585
def save(
8686
self, items: Iterable[SerializableMixin], url: str, overwrite: bool = False
8787
) -> list[SerializedObject]:
88-
...
88+
""""""
8989

9090
def save(self, items, url: str, overwrite: bool = False):
9191
report = self.generate(items)

tests/data/file.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"url": "tests/data/test.txt",
3+
"metadata": {
4+
"md5_checksum": "14758f1afd44c09b7992073ccf00b43d"
5+
},
6+
"type": "TIFF",
7+
"name": "test.txt",
8+
"local_path": "tests/data/test.txt"
9+
}

tests/data/generate.py

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

55
import os
66
import sys
7+
from pathlib import Path
8+
from typing import Sequence
79

810
from dcqc.file import File
911
from dcqc.mixins import SerializableMixin
@@ -15,19 +17,22 @@
1517
# Shared values
1618
data_dir = sys.path[0]
1719
data_dir = os.path.relpath(data_dir)
18-
report = JsonReport()
20+
report = JsonReport(paths_relative_to=Path.cwd())
1921

2022

2123
# Shared functions
22-
def export(obj: SerializableMixin, filename: str):
24+
def export(obj: SerializableMixin | Sequence[SerializableMixin], filename: str):
2325
output_url = os.path.join(data_dir, filename)
2426
report.save(obj, output_url, overwrite=True)
2527

2628

27-
# target.json
29+
# file.json
2830
file_url = os.path.join(data_dir, "test.txt")
2931
metadata = {"file_type": "TIFF", "md5_checksum": "14758f1afd44c09b7992073ccf00b43d"}
3032
file = File(file_url, metadata)
33+
export(file, "file.json")
34+
35+
# target.json
3136
target = Target(file, id="001")
3237
export(target, "target.json")
3338

@@ -44,6 +49,10 @@ def export(obj: SerializableMixin, filename: str):
4449
computed_test.get_status()
4550
export(computed_test, "test.computed.json")
4651

52+
# tests.json
53+
test_list = [internal_test, external_test, computed_test]
54+
export(test_list, "tests.json")
55+
4756
# suite.json
4857
suite_tests = [internal_test, external_test]
4958
required_tests = ["Md5ChecksumTest"]

tests/data/suite.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"md5_checksum": "14758f1afd44c09b7992073ccf00b43d"
1111
},
1212
"type": "TIFF",
13-
"local_path": "tests/data/test.txt",
14-
"name": "test.txt"
13+
"name": "test.txt",
14+
"local_path": "tests/data/test.txt"
1515
}
1616
]
1717
},

tests/data/target.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
"md5_checksum": "14758f1afd44c09b7992073ccf00b43d"
99
},
1010
"type": "TIFF",
11-
"local_path": "tests/data/test.txt",
12-
"name": "test.txt"
11+
"name": "test.txt",
12+
"local_path": "tests/data/test.txt"
1313
}
1414
]
1515
}

0 commit comments

Comments
 (0)