|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
from .conftest import EXAMPLE_DIR_XML_WITH_PARAMS, EXAMPLE_DIR_XML_WO_PARAMS
|
|
|
|
|
|
|
|
|
|
|
|
class DummyDataFunc:
|
|
|
|
def __init__(self, as_bool):
|
|
|
|
self.data = None
|
|
|
|
self.as_bool = as_bool
|
|
|
|
|
|
|
|
def __call__(self, data):
|
|
|
|
self.data = data
|
|
|
|
|
|
|
|
def __bool__(self):
|
|
|
|
return self.as_bool
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_init():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
|
|
|
|
assert target.collected == []
|
|
|
|
assert target._current == {}
|
|
|
|
assert target._data_func is None
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
("tag", "attributes", "expected"),
|
|
|
|
[
|
|
|
|
("UnknownTag", {"ID": "something"}, {}),
|
|
|
|
(
|
|
|
|
"ScanJobResult",
|
|
|
|
{"ID": "scan job 1"},
|
|
|
|
{"Analysis.Name": "scan job 1"},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"AssayResult",
|
|
|
|
{"ID": "C03"},
|
|
|
|
{"Well.Name": "C03", "Well.Row": "C", "Well.Column": 3},
|
|
|
|
),
|
|
|
|
("ChannelConfig1", {}, {"Exposure.Id": 1}),
|
|
|
|
("Spot", {"ID": "456"}, {"Pos.Id": 456}),
|
|
|
|
(
|
|
|
|
"Result",
|
|
|
|
{"Label": "a label", "Type": "Unknown", "Value": "a value"},
|
|
|
|
{"a label": "a value"},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
@pytest.mark.parametrize("additionals", [{}, {"Ignored": "value"}])
|
|
|
|
def test_parser_target_start_simple_attributes(
|
|
|
|
tag, attributes, additionals, expected
|
|
|
|
):
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
attributes.update(additionals)
|
|
|
|
|
|
|
|
target.start(tag, attributes) # stateful operation
|
|
|
|
|
|
|
|
assert target._current == expected
|
|
|
|
assert target._data_func is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_start_timestamp():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
target.start("Timestamp", {})
|
|
|
|
|
|
|
|
assert target._data_func == target._data_timestamp_parser
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_start_image_file_name():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
target.start("ImageFileName", {})
|
|
|
|
|
|
|
|
assert target._data_func == target._data_image_name_parser
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
("data_type", "value", "expected"),
|
|
|
|
[
|
|
|
|
("unknown type", 1, "1"),
|
|
|
|
("System.Int32", "12", 12),
|
|
|
|
("System.UInt32", "23", 23),
|
|
|
|
("System.Double", "4.56", 4.56),
|
|
|
|
("System.Boolean", "true", True),
|
|
|
|
("System.Boolean", "True", True),
|
|
|
|
("System.Boolean", "Xrue", False),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_parser_target_result_attributes_parser(data_type, value, expected):
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
data = {"Label": "some label", "Type": data_type, "Value": value}
|
|
|
|
|
|
|
|
target._result_attributes_parser(data) # stateful operation
|
|
|
|
|
|
|
|
assert target._current == {"some label": expected}
|
|
|
|
assert type(target._current["some label"]) == type(expected)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
("value", "expected"),
|
|
|
|
[
|
|
|
|
(
|
|
|
|
"3/7/2022 5:31:47 PM",
|
|
|
|
datetime(2022, 3, 7, 17, 31, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"03/7/2022 5:31:47 PM",
|
|
|
|
datetime(2022, 3, 7, 17, 31, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"3/07/2022 5:31:47 PM",
|
|
|
|
datetime(2022, 3, 7, 17, 31, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"03/07/2022 5:31:47 PM",
|
|
|
|
datetime(2022, 3, 7, 17, 31, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"3/7/2022 5:3:47 PM",
|
|
|
|
datetime(2022, 3, 7, 17, 3, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"3/7/2022 5:31:4 PM",
|
|
|
|
datetime(2022, 3, 7, 17, 31, 4), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"3/7/2022 5:31:47 pm",
|
|
|
|
datetime(2022, 3, 7, 17, 31, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"3/7/2022 5:31:47 AM",
|
|
|
|
datetime(2022, 3, 7, 5, 31, 47), # noqa: DTZ001
|
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_parser_target_data_timestamp_parser(value, expected):
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
|
|
|
|
target._data_timestamp_parser(value) # stateful operation
|
|
|
|
|
|
|
|
assert target._current == {"Analysis.Datetime": expected}
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_data_image_name_parser():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
|
|
|
|
target._data_image_name_parser(" some file path ") # stateful operation
|
|
|
|
|
|
|
|
assert target._current == {"Analysis.Image": "some file path"}
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_data_does_not_call_function():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
dummy = DummyDataFunc(as_bool=False)
|
|
|
|
target._data_func = dummy
|
|
|
|
|
|
|
|
target.data("some data") # the NotImplementedError is not raised
|
|
|
|
|
|
|
|
assert dummy.data is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_data_does_call_function():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
dummy = DummyDataFunc(as_bool=True)
|
|
|
|
target._data_func = dummy
|
|
|
|
|
|
|
|
target.data("some data") # stateful operation
|
|
|
|
|
|
|
|
assert dummy.data == "some data"
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_data_reacts_on_spot():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
target._current = {"some current": "data values"}
|
|
|
|
|
|
|
|
target.end("Spot") # stateful operation
|
|
|
|
|
|
|
|
assert target.collected == [{"some current": "data values"}]
|
|
|
|
assert target.collected[0] is not target._current
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_data_does_only_react_on_spot():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
target._current = {"some current": "data values"}
|
|
|
|
|
|
|
|
target.end("NonSpotTag") # stateful operation
|
|
|
|
|
|
|
|
assert target.collected == []
|
|
|
|
|
|
|
|
|
|
|
|
def test_parser_target_closed():
|
|
|
|
from sensospot_parser.xml_parser import ParserTarget
|
|
|
|
|
|
|
|
target = ParserTarget()
|
|
|
|
|
|
|
|
target.closed() # stateful operation, must be callable
|
|
|
|
|
|
|
|
|
|
|
|
def test_find_result_xml_file_ok(tmp_path):
|
|
|
|
from sensospot_parser.xml_parser import _find_result_xml_file
|
|
|
|
|
|
|
|
xls_file = tmp_path / "result.xsl"
|
|
|
|
xls_file.touch()
|
|
|
|
xml_file = tmp_path / "result.xml"
|
|
|
|
xml_file.touch()
|
|
|
|
|
|
|
|
result = _find_result_xml_file(tmp_path)
|
|
|
|
|
|
|
|
assert result == xml_file
|
|
|
|
|
|
|
|
|
|
|
|
def test_find_result_xml_file_no_matching_xml_file(tmp_path):
|
|
|
|
from sensospot_parser.xml_parser import _find_result_xml_file
|
|
|
|
|
|
|
|
xls_file = tmp_path / "result.xsl"
|
|
|
|
xls_file.touch()
|
|
|
|
xml_file = tmp_path / "other.xml"
|
|
|
|
xml_file.touch()
|
|
|
|
|
|
|
|
result = _find_result_xml_file(tmp_path)
|
|
|
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_find_result_xml_file_no_xsl_file(tmp_path):
|
|
|
|
from sensospot_parser.xml_parser import _find_result_xml_file
|
|
|
|
|
|
|
|
xml_file = tmp_path / "result.xml"
|
|
|
|
xml_file.touch()
|
|
|
|
|
|
|
|
result = _find_result_xml_file(tmp_path)
|
|
|
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_find_result_xml_file_multiple_xsl_files(tmp_path):
|
|
|
|
from sensospot_parser.xml_parser import _find_result_xml_file
|
|
|
|
|
|
|
|
xls_file = tmp_path / "result.xsl"
|
|
|
|
xls_file.touch()
|
|
|
|
surplus_file = tmp_path / "surplus.xsl"
|
|
|
|
surplus_file.touch()
|
|
|
|
xml_file = tmp_path / "result.xml"
|
|
|
|
xml_file.touch()
|
|
|
|
|
|
|
|
result = _find_result_xml_file(tmp_path)
|
|
|
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_find_result_hidden_xsl_file(tmp_path):
|
|
|
|
from sensospot_parser.xml_parser import _find_result_xml_file
|
|
|
|
|
|
|
|
xls_file = tmp_path / ".result.xsl"
|
|
|
|
xls_file.touch()
|
|
|
|
xml_file = tmp_path / ".result.xml"
|
|
|
|
xml_file.touch()
|
|
|
|
|
|
|
|
result = _find_result_xml_file(tmp_path)
|
|
|
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_xml_file_ok(example_dir):
|
|
|
|
import pandas
|
|
|
|
from sensospot_parser.xml_parser import (
|
|
|
|
_find_result_xml_file,
|
|
|
|
parse_xml_file,
|
|
|
|
)
|
|
|
|
|
|
|
|
folder = example_dir / EXAMPLE_DIR_XML_WO_PARAMS
|
|
|
|
xml_file = _find_result_xml_file(folder)
|
|
|
|
|
|
|
|
result = parse_xml_file(xml_file)
|
|
|
|
|
|
|
|
assert isinstance(result, pandas.DataFrame)
|
|
|
|
assert len(result) == 4 * 4 * 4 * 100
|
|
|
|
assert set(result["Well.Row"]) == set("ABCD")
|
|
|
|
assert set(result["Well.Column"]) == {1, 2, 3, 4}
|
|
|
|
assert set(result["Exposure.Id"]) == {1, 2, 3, 4}
|
|
|
|
assert min(result["Spot.Diameter"]) == 22
|
|
|
|
assert max(result["Spot.Diameter"]) == 34
|
|
|
|
assert "Parameters.Time" not in result
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
("file_name", "message"),
|
|
|
|
[
|
|
|
|
("not_existing.xml", "Xml file does not exist"),
|
|
|
|
("defect.xml", "Could not parse assay results xml file"),
|
|
|
|
("malformed_data.xml", "Malformed data in xml file"),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_parse_xml_file_raies_error(file_name, message, example_dir):
|
|
|
|
from sensospot_parser.xml_parser import parse_xml_file
|
|
|
|
|
|
|
|
xml_file = example_dir / file_name
|
|
|
|
|
|
|
|
with pytest.raises(ValueError) as e: # noqa: PT011
|
|
|
|
parse_xml_file(xml_file)
|
|
|
|
|
|
|
|
assert message in str(e)
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_xml_folder_with_params(example_dir):
|
|
|
|
import pandas
|
|
|
|
from sensospot_parser.xml_parser import parse_xml_folder
|
|
|
|
|
|
|
|
folder = example_dir / EXAMPLE_DIR_XML_WITH_PARAMS
|
|
|
|
|
|
|
|
result = parse_xml_folder(folder)
|
|
|
|
|
|
|
|
assert isinstance(result, pandas.DataFrame)
|
|
|
|
assert len(result) == 4 * 4 * 4 * 100
|
|
|
|
assert not result["Parameters.Time"].hasnans
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_xml_folder_without_params(example_dir):
|
|
|
|
import pandas
|
|
|
|
from sensospot_parser.xml_parser import parse_xml_folder
|
|
|
|
|
|
|
|
folder = example_dir / EXAMPLE_DIR_XML_WO_PARAMS
|
|
|
|
|
|
|
|
result = parse_xml_folder(folder)
|
|
|
|
|
|
|
|
assert isinstance(result, pandas.DataFrame)
|
|
|
|
assert len(result) == 4 * 4 * 4 * 100
|
|
|
|
assert result["Parameters.Time"].hasnans
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_xml_folder_non_existing_xml_file(tmp_path):
|
|
|
|
from sensospot_parser.xml_parser import parse_xml_folder
|
|
|
|
|
|
|
|
with pytest.raises(ValueError) as e: # noqa: PT011
|
|
|
|
parse_xml_folder(tmp_path)
|
|
|
|
|
|
|
|
assert "Could not find assay results xml file" in str(e)
|