2024-07-09 10:32:37 +00:00
|
|
|
"""
|
|
|
|
Test fixtures primarily for doctests for adapters
|
|
|
|
"""
|
|
|
|
|
2024-07-09 07:27:22 +00:00
|
|
|
import re
|
|
|
|
import textwrap
|
2024-07-09 10:32:37 +00:00
|
|
|
from doctest import ELLIPSIS, NORMALIZE_WHITESPACE
|
|
|
|
from typing import Generator
|
|
|
|
|
|
|
|
import yaml
|
|
|
|
from sybil import Document, Example, Region, Sybil
|
2024-07-09 07:27:22 +00:00
|
|
|
from sybil.parsers.codeblock import PythonCodeBlockParser
|
|
|
|
from sybil.parsers.doctest import DocTestParser
|
2024-07-09 10:32:37 +00:00
|
|
|
|
2024-07-09 07:27:22 +00:00
|
|
|
from nwb_linkml import adapters
|
|
|
|
|
|
|
|
# Test adapter generation examples
|
|
|
|
|
|
|
|
ADAPTER_START = re.compile(r"\.\.\s*adapter::")
|
|
|
|
ADAPTER_END = re.compile(r"\n\s*\n")
|
|
|
|
|
|
|
|
NWB_KEYS = re.compile(r"(^\s*datasets:\s*\n)|^groups:")
|
|
|
|
|
|
|
|
|
|
|
|
def _strip_nwb(nwb: str) -> str:
|
|
|
|
# strip 'datasets:' keys and decoration left in for readability/context
|
|
|
|
nwb = re.sub(NWB_KEYS, "", nwb)
|
2024-07-09 10:26:45 +00:00
|
|
|
nwb = re.sub(r"^-", " ", nwb)
|
2024-07-09 07:27:22 +00:00
|
|
|
nwb = textwrap.dedent(nwb)
|
|
|
|
return nwb
|
|
|
|
|
|
|
|
|
2024-07-09 10:32:37 +00:00
|
|
|
def test_adapter_block(example: Example) -> None:
|
2024-07-09 07:27:22 +00:00
|
|
|
"""
|
|
|
|
The linkml generated from a nwb example input should match
|
|
|
|
that provided in the docstring.
|
|
|
|
|
|
|
|
See adapters/dataset.py for example usage of .. adapter:: directive
|
|
|
|
"""
|
|
|
|
cls_name, nwb, linkml_expected = example.parsed
|
|
|
|
|
|
|
|
# get adapter and generate
|
|
|
|
adapter_cls = getattr(adapters, cls_name)
|
|
|
|
adapter = adapter_cls(cls=nwb)
|
|
|
|
res = adapter.build()
|
|
|
|
|
|
|
|
# compare
|
|
|
|
generated = yaml.safe_load(res.as_linkml())
|
|
|
|
expected = yaml.safe_load(linkml_expected)
|
|
|
|
assert generated == expected
|
|
|
|
|
|
|
|
|
2024-07-09 10:32:37 +00:00
|
|
|
def parse_adapter_blocks(document: Document) -> Generator[Region, None, None]:
|
|
|
|
"""
|
|
|
|
Parse blocks with adapter directives, yield to test with :func:`.test_adapter_block`
|
|
|
|
"""
|
2024-07-09 07:27:22 +00:00
|
|
|
for start_match, end_match, source in document.find_region_sources(ADAPTER_START, ADAPTER_END):
|
|
|
|
# parse
|
2024-07-09 10:32:37 +00:00
|
|
|
sections = re.split(r":\w+?:", source, flags=re.MULTILINE)
|
2024-07-09 07:27:22 +00:00
|
|
|
sections = [textwrap.dedent(section).strip() for section in sections]
|
|
|
|
|
|
|
|
sections[1] = _strip_nwb(sections[1])
|
|
|
|
|
|
|
|
yield Region(start_match.start(), end_match.end(), sections, test_adapter_block)
|
|
|
|
|
|
|
|
|
|
|
|
adapter_parser = Sybil(
|
2024-07-09 10:32:37 +00:00
|
|
|
parsers=[parse_adapter_blocks],
|
2024-07-09 07:27:22 +00:00
|
|
|
patterns=["adapters/*.py"],
|
|
|
|
)
|
|
|
|
|
|
|
|
doctest_parser = Sybil(
|
|
|
|
parsers=[DocTestParser(optionflags=ELLIPSIS + NORMALIZE_WHITESPACE), PythonCodeBlockParser()],
|
|
|
|
patterns=["*.py"],
|
|
|
|
)
|
|
|
|
|
|
|
|
pytest_collect_file = (adapter_parser + doctest_parser).pytest()
|