Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic helper tool #11

Merged
merged 1 commit into from
Apr 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
57 changes: 57 additions & 0 deletions nwb_healthstatus/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from pathlib import Path
import click
import pynwb
from .base import get_cases_in_namespace

DEFAULT_SAMPLES_PATH = str(Path.home() / ".cache" / "nwb-healthstatus")

@click.group()
def main():
pass

@main.group()
def sample():
pass

@sample.command()
#@click.option("-e", "--environment")
@click.option("--overwrite", is_flag=True)
@click.option("--samples-path", type=click.Path(file_okay=False), default=DEFAULT_SAMPLES_PATH)
@click.argument("casefile", type=click.Path(exists=True, dir_okay=False), nargs=-1)
def create(casefile, overwrite, samples_path):
sample_dir = Path(samples_path)
for path in casefile:
p = Path(path)
producer = p.resolve().parent.name
namespace = {}
exec(p.read_text(), namespace)
for casecls in get_cases_in_namespace(namespace):
case = casecls()
filepath = sample_dir / producer / case.FILENAME
filepath.parent.mkdir(parents=True, exist_ok=True)
if overwrite or not filepath.exists():
nwbfile = case.create()
with pynwb.NWBHDF5IO(str(filepath), "w") as io:
io.write(nwbfile) # , cache_spec=cache_spec)

@sample.command()
#@click.option("-e", "--environment")
@click.option("--samples-path", type=click.Path(exists=True, file_okay=False), default=DEFAULT_SAMPLES_PATH)
@click.argument("casefile", type=click.Path(exists=True, dir_okay=False), nargs=-1)
def test(casefile, samples_path):
sample_dir = Path(samples_path)
for path in casefile:
p = Path(path)
producer = p.resolve().parent.name
namespace = {}
exec(p.read_text(), namespace)
for casecls in get_cases_in_namespace(namespace):
case = casecls()
filepath = sample_dir / producer / case.FILENAME
with pynwb.NWBHDF5IO(str(filepath), mode='r') as io:
## TODO: Capture and display possible warnings
obj = io.read()
case.test(obj)

if __name__ == "__main__":
main()
51 changes: 51 additions & 0 deletions nwb_healthstatus/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from abc import ABC, abstractmethod
from functools import reduce
from inspect import isclass
from operator import or_
from types import ModuleType
from typing import ClassVar, Iterator, Set, Type
from hdmf.container import Container
import pynwb

class SampleCase(ABC):
#: Set of extensions needed by the sample case
EXTENSIONS: ClassVar[Set[str]]

#: Basename for the sample file created by the case
FILENAME: ClassVar[str]

@abstractmethod
def create(self) -> pynwb.NWBFile:
""" Creates a sample NWB file """
...

@abstractmethod
def test(self, data: Container) -> None:
"""
Takes the data read from a sample file and asserts that it contains
what it should
"""
...

@classmethod
def __subclasshook__(cls, C):
if (
cls is SampleCase
and {"EXTENSIONS", "FILENAME", "create", "test"}
<= reduce(or_, (B.__dict__.keys() for B in C.__mro__))
):
return True
return NotImplemented


def get_cases_in_module(module: ModuleType) -> Iterator[Type[SampleCase]]:
for name in dir(module):
obj = getattr(module, name)
if isclass(obj) and issubclass(obj, SampleCase):
yield obj


def get_cases_in_namespace(namespace: dict) -> Iterator[Type[SampleCase]]:
for obj in namespace.values():
if isclass(obj) and issubclass(obj, SampleCase):
yield obj
43 changes: 10 additions & 33 deletions nwb_healthstatus/producers/core/simple1.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import hdmf
import pynwb
import datetime
import pynwb

metadata = dict(
session_description= 'my first synthetic recording',
Expand All @@ -13,36 +12,14 @@
session_id='LONELYMTN'
)

def create():
return pynwb.NWBFile(**metadata)


def test_basic(nwbfile):
# TODO: make it more specific to this example
for f, v in metadata.items():
assert getattr(nwbfile, f) == v, f"{f}: {getattr(nwbfile, f)!r} vs. {v!r}"


if __name__ == '__main__':
base_filename = 'core_simple1'
env_details = {
'nwb': pynwb.__version__,
'hdmf': hdmf.__version__,
}
suffix = '_'.join('{}:{}'.format(*i) for i in env_details.items())

filename = f'/tmp/{base_filename}_{suffix}'

### this would be executed once for some combinations of hdmf/pynwb
### version and stored indefinetely somewhere
nwbfile = create()
with pynwb.NWBHDF5IO(filename + '.nwb', "w") as io:
io.write(nwbfile) # , cache_spec=cache_spec)
# todo dump into '.yaml' the details of the spec
class Simple1:
EXTENSIONS = set()
FILENAME = "simple1.nwb"

### CI run would load the file and give it away for testing
with pynwb.NWBHDF5IO(filename + '.nwb', mode='r') as io:
## capture and display possible warnings
obj = io.read()
def create(self):
return pynwb.NWBFile(**metadata)

test_basic(obj)
def test(self, nwbfile):
# TODO: make it more specific to this example
for f, v in metadata.items():
assert getattr(nwbfile, f) == v, f"{f}: {getattr(nwbfile, f)!r} vs. {v!r}"
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
click
hdmf
pynwb