hyperspy / rosettasciio

Python library for reading and writing scientific data format

Home Page:https://hyperspy.org/rosettasciio

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

failing tests after merging #100

jlaehne opened this issue · comments

Actually, this is after merging #100:
https://github.com/hyperspy/rosettasciio/actions/runs/4742402405

FAILED rsciio/tests/test_pantarhei.py::test_save_load_cycle - box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute scan_generator"
FAILED rsciio/tests/test_tiff.py::test_JEOL_SightX - TypeError: 'NoneType' object is not iterable
Full log
=================================== FAILURES ===================================
_____________________________ test_save_load_cycle _____________________________
[gw0] darwin -- Python 3.8.16 /Users/runner/hostedtoolcache/Python/3.8.16/x64/bin/python

tmp_path = PosixPath('/private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/pytest-of-runner/pytest-0/popen-gw0/test_save_load_cycle3')

    def test_save_load_cycle(tmp_path):
        fname = tmp_path / "test_file.prz"
    
        s = hs.load(my_path / "pantarhei_data" / "panta_rhei_sample_v5.prz")
>       s.save(fname)

rsciio/tests/test_pantarhei.py:85: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/signal.py:3043: in save
    io_save(filename, self, overwrite=overwrite, file_format=file_format, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:921: in save
    importlib.import_module(writer["api"]).file_writer(
rsciio/pantarhei/_api.py:69: in file_writer
    data, meta_data = export_pr(signal=signal)
rsciio/pantarhei/_api.py:276: in export_pr
    meta_data = _metadata_converter_out(metadata, original_metadata)
rsciio/pantarhei/_api.py:373: in _metadata_converter_out
    original_metadata = DTBox(original_metadata, box_dots=True)
box/box.py:286: in box.box.Box.__init__
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute scan_generator"

box/box.py:653: BoxKeyError
_______________________________ test_JEOL_SightX _______________________________
[gw1] darwin -- Python 3.8.16 /Users/runner/hostedtoolcache/Python/3.8.16/x64/bin/python

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
serie = <tifffile.TiffPageSeries 0 uniform>
filename = '/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp0gplw1v1/JEOL-SightX-Ronchigram-dummy.tif'
force_read_resolution = False, lazy = False, memmap = None
RGB_as_structured_array = True, kwds = {}, axes = 'YX'
page = <tifffile.TiffPage 0 @684352>, shape = (556, 556)
dtype = dtype('uint16'), is_rgb = False, names = ['height', 'width']

    def _read_serie(
        tiff,
        serie,
        filename,
        force_read_resolution=False,
        lazy=False,
        memmap=None,
        RGB_as_structured_array=True,
        **kwds,
    ):
        axes = serie.axes
        page = serie.pages[0]
        if hasattr(serie, "shape"):
            shape = serie.shape
            dtype = serie.dtype
        else:
            shape = serie["shape"]
            dtype = serie["dtype"]
    
        is_rgb = page.photometric == TIFF.PHOTOMETRIC.RGB and RGB_as_structured_array
        _logger.debug("Is RGB: %s" % is_rgb)
        if is_rgb:
            axes = axes[:-1]
            names = ["R", "G", "B", "A"]
            lastshape = shape[-1]
            dtype = np.dtype({"names": names[:lastshape], "formats": [dtype] * lastshape})
            shape = shape[:-1]
    
        if Version(tiffversion) >= Version("2020.2.16"):
            op = {tag.name: tag.value for tag in page.tags}
        else:
            op = {key: tag.value for key, tag in page.tags.items()}
    
        names = [axes_label_codes[axis] for axis in axes]
    
        _logger.debug("Tiff tags list: %s" % op)
        _logger.debug("Photometric: %s" % op["PhotometricInterpretation"])
        _logger.debug("is_imagej: {}".format(page.is_imagej))
    
        try:
>           axes = _parse_scale_unit(
                tiff, page, op, shape, force_read_resolution, names, **kwds
            )

rsciio/tiff/_api.py:277: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
page = <tifffile.TiffPage 0 @684352>
op = {'BitsPerSample': 16, 'Compression': <COMPRESSION.NONE: 1>, 'DateTime': '2021/05/18 14:10', 'ImageDescription': '<?xml...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', ...}
shape = (556, 556), force_read_resolution = False, names = ['height', 'width']
kwds = {}

    def _parse_scale_unit(tiff, page, op, shape, force_read_resolution, names, **kwds):
        # Force reading always has priority
        if _is_force_readable(op, force_read_resolution):
            axes = _axes_force_read(op, shape, names)
            return axes
        # Other axes readers can change position if you need to do it
        elif _is_fei(tiff):
            axes = _axes_fei(tiff, op, shape, names)
            return axes
        elif _is_zeiss(tiff):
            axes = _axes_zeiss(tiff, op, shape, names)
            return axes
        elif _is_tvips(tiff):
            axes = _axes_tvips(tiff, op, shape, names)
            return axes
        elif _is_olympus_sis(page):
            axes = _axes_olympus_sis(page, tiff, op, shape, names)
            return axes
        elif _is_jeol_sightx(op):
>           axes = _axes_jeol_sightx(tiff, op, shape, names)

rsciio/tiff/_api.py:859: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
op = {'BitsPerSample': 16, 'Compression': <COMPRESSION.NONE: 1>, 'DateTime': '2021/05/18 14:10', 'ImageDescription': '<?xml...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', ...}
shape = (556, 556), names = ['height', 'width']

    def _axes_jeol_sightx(tiff, op, shape, names):
        # convert xml text to dictionary of tiff op['ImageDescription']
        # convert_xml_to_dict need to remove white spaces before decoding XML
        scales, offsets, units = _axes_defaults()
    
        jeol_xml = "".join(
            [line.strip(" \r\n\t\x01\x00") for line in op["ImageDescription"].split("\n")]
        )
        from rsciio.utils.tools import convert_xml_to_dict
    
>       jeol_dict = convert_xml_to_dict(jeol_xml)

rsciio/tiff/_api.py:543: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

xml_object = <Element 'TemReporter' at 0x13b506cc0>

    def convert_xml_to_dict(xml_object):
        if isinstance(xml_object, str):
            xml_object = ET.fromstring(xml_object)
        op = DTBox(box_dots=True)
>       xml2dtb(xml_object, op)

rsciio/utils/tools.py:182: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'TemReporter' at 0x13b506cc0>
dictree = Box({'TemReporter': {'FormatVersion': '1.0', 'FormatMajorVersion': '1', 'FormatMinorVersion': '0', 'Instruments': 'JEM...itsConverterLUTLimit': 'false'}, 'Measurement': {'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'Measurement' at 0x13b522770>
dictree = Box({'FormatVersion': '1.0', 'FormatMajorVersion': '1', 'FormatMinorVersion': '0', 'Instruments': 'JEM-ARM200F', 'Manu...BitsConverterLUTLimit': 'false'}, 'Measurement': {'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'MeasurementFormat' at 0x13b5226d0>
dictree = Box({'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'SaveMeasureObjectList' at 0x13b5225e0>
dictree = Box({'SaveMeasureObjectList': {'DrawObject': {}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'DrawObject' at 0x13b5229a0>, dictree = Box({'DrawObject': {}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
>               dictree[et.tag].merge_update(et.attrib)

rsciio/utils/tools.py:156: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

box/box.py:846: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

box/box.py:8[38](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:39): 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute {http://www"

box/box.py:653: BoxKeyError

During handling of the above exception, another exception occurred:

    def test_JEOL_SightX():
        files = [
            ("JEOL-SightX-Ronchigram-dummy.tif.gz", 1.0, t.Undefined),
            ("JEOL-SightX-SAED-dummy.tif.gz", 0.2723, "1 / nm"),
            ("JEOL-SightX-TEM-mag-dummy.tif.gz", 1.8208, "nm"),
        ]
        for file in files:
            fname = file[0]
            if fname[-3:] == ".gz":
                import gzip
    
                with tempfile.TemporaryDirectory() as tmp_dir:
                    with gzip.open(os.path.join(MY_PATH2, fname), "rb") as f:
                        content = f.read()
                    fname = os.path.join(tmp_dir, fname[:-3])
                    with open(fname, "wb") as f2:
                        f2.write(content)
>                   s = hs.load(fname)

rsciio/tests/test_tiff.py:878: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:[51](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:52)7: in load
    objects = [load_single_file(filename, lazy=lazy, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:517: in <listcomp>
    objects = [load_single_file(filename, lazy=lazy, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:576: in load_single_file
    return load_with_reader(filename=filename, reader=reader, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:597: in load_with_reader
    file_data_list = importlib.import_module(reader["api"]).file_reader(filename,
rsciio/tiff/_api.py:181: in file_reader
    dict_list = [
rsciio/tiff/_api.py:182: in <listcomp>
    _read_serie(tiff, serie, filename, force_read_resolution, lazy=lazy, **kwds)
rsciio/tiff/_api.py:282: in _read_serie
    axes = _build_axes_dictionaries(shape, names)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

shape = ([55](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:56)6, 5[56](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:57)), names = ['height', 'width'], scales = [None, None]
offsets = None, units = None

    def _build_axes_dictionaries(shape, names=None, scales=None, offsets=None, units=None):
        """Build axes dictionaries from a set of lists"""
        if names is None:
            names = [""] * len(shape)
        if scales is None:
            scales = [1.0] * len(shape)
        if scales is None:
            scales = [0.0] * len(shape)
        if units is None:
            scales = [None] * len(shape)
    
        axes = [
            {
                "size": size,
                "name": str(name),
                "scale": scale,
                "offset": offset,
                "units": unit,
            }
>           for size, name, scale, offset, unit in zip(shape, names, scales, offsets, units)
        ]
E       TypeError: 'NoneType' object is not iterable

rsciio/tiff/_api.py:232: TypeError
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:[57](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:58)9 If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:5[79](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:80) If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:579 If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:579 If this file format is supported, please report this error to the HyperSpy developers.
```=================================== FAILURES ===================================
_____________________________ test_save_load_cycle _____________________________
[gw0] darwin -- Python 3.8.16 /Users/runner/hostedtoolcache/Python/3.8.16/x64/bin/python

tmp_path = PosixPath('/private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/pytest-of-runner/pytest-0/popen-gw0/test_save_load_cycle3')

    def test_save_load_cycle(tmp_path):
        fname = tmp_path / "test_file.prz"
    
        s = hs.load(my_path / "pantarhei_data" / "panta_rhei_sample_v5.prz")
>       s.save(fname)

rsciio/tests/test_pantarhei.py:85: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/signal.py:3043: in save
    io_save(filename, self, overwrite=overwrite, file_format=file_format, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:921: in save
    importlib.import_module(writer["api"]).file_writer(
rsciio/pantarhei/_api.py:69: in file_writer
    data, meta_data = export_pr(signal=signal)
rsciio/pantarhei/_api.py:276: in export_pr
    meta_data = _metadata_converter_out(metadata, original_metadata)
rsciio/pantarhei/_api.py:373: in _metadata_converter_out
    original_metadata = DTBox(original_metadata, box_dots=True)
box/box.py:286: in box.box.Box.__init__
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute scan_generator"

box/box.py:653: BoxKeyError
_______________________________ test_JEOL_SightX _______________________________
[gw1] darwin -- Python 3.8.16 /Users/runner/hostedtoolcache/Python/3.8.16/x64/bin/python

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
serie = <tifffile.TiffPageSeries 0 uniform>
filename = '/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp0gplw1v1/JEOL-SightX-Ronchigram-dummy.tif'
force_read_resolution = False, lazy = False, memmap = None
RGB_as_structured_array = True, kwds = {}, axes = 'YX'
page = <tifffile.TiffPage 0 @684352>, shape = (556, 556)
dtype = dtype('uint16'), is_rgb = False, names = ['height', 'width']

    def _read_serie(
        tiff,
        serie,
        filename,
        force_read_resolution=False,
        lazy=False,
        memmap=None,
        RGB_as_structured_array=True,
        **kwds,
    ):
        axes = serie.axes
        page = serie.pages[0]
        if hasattr(serie, "shape"):
            shape = serie.shape
            dtype = serie.dtype
        else:
            shape = serie["shape"]
            dtype = serie["dtype"]
    
        is_rgb = page.photometric == TIFF.PHOTOMETRIC.RGB and RGB_as_structured_array
        _logger.debug("Is RGB: %s" % is_rgb)
        if is_rgb:
            axes = axes[:-1]
            names = ["R", "G", "B", "A"]
            lastshape = shape[-1]
            dtype = np.dtype({"names": names[:lastshape], "formats": [dtype] * lastshape})
            shape = shape[:-1]
    
        if Version(tiffversion) >= Version("2020.2.16"):
            op = {tag.name: tag.value for tag in page.tags}
        else:
            op = {key: tag.value for key, tag in page.tags.items()}
    
        names = [axes_label_codes[axis] for axis in axes]
    
        _logger.debug("Tiff tags list: %s" % op)
        _logger.debug("Photometric: %s" % op["PhotometricInterpretation"])
        _logger.debug("is_imagej: {}".format(page.is_imagej))
    
        try:
>           axes = _parse_scale_unit(
                tiff, page, op, shape, force_read_resolution, names, **kwds
            )

rsciio/tiff/_api.py:277: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
page = <tifffile.TiffPage 0 @684352>
op = {'BitsPerSample': 16, 'Compression': <COMPRESSION.NONE: 1>, 'DateTime': '2021/05/18 14:10', 'ImageDescription': '<?xml...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', ...}
shape = (556, 556), force_read_resolution = False, names = ['height', 'width']
kwds = {}

    def _parse_scale_unit(tiff, page, op, shape, force_read_resolution, names, **kwds):
        # Force reading always has priority
        if _is_force_readable(op, force_read_resolution):
            axes = _axes_force_read(op, shape, names)
            return axes
        # Other axes readers can change position if you need to do it
        elif _is_fei(tiff):
            axes = _axes_fei(tiff, op, shape, names)
            return axes
        elif _is_zeiss(tiff):
            axes = _axes_zeiss(tiff, op, shape, names)
            return axes
        elif _is_tvips(tiff):
            axes = _axes_tvips(tiff, op, shape, names)
            return axes
        elif _is_olympus_sis(page):
            axes = _axes_olympus_sis(page, tiff, op, shape, names)
            return axes
        elif _is_jeol_sightx(op):
>           axes = _axes_jeol_sightx(tiff, op, shape, names)

rsciio/tiff/_api.py:859: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
op = {'BitsPerSample': 16, 'Compression': <COMPRESSION.NONE: 1>, 'DateTime': '2021/05/18 14:10', 'ImageDescription': '<?xml...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', ...}
shape = (556, 556), names = ['height', 'width']

    def _axes_jeol_sightx(tiff, op, shape, names):
        # convert xml text to dictionary of tiff op['ImageDescription']
        # convert_xml_to_dict need to remove white spaces before decoding XML
        scales, offsets, units = _axes_defaults()
    
        jeol_xml = "".join(
            [line.strip(" \r\n\t\x01\x00") for line in op["ImageDescription"].split("\n")]
        )
        from rsciio.utils.tools import convert_xml_to_dict
    
>       jeol_dict = convert_xml_to_dict(jeol_xml)

rsciio/tiff/_api.py:543: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

xml_object = <Element 'TemReporter' at 0x13b506cc0>

    def convert_xml_to_dict(xml_object):
        if isinstance(xml_object, str):
            xml_object = ET.fromstring(xml_object)
        op = DTBox(box_dots=True)
>       xml2dtb(xml_object, op)

rsciio/utils/tools.py:182: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'TemReporter' at 0x13b506cc0>
dictree = Box({'TemReporter': {'FormatVersion': '1.0', 'FormatMajorVersion': '1', 'FormatMinorVersion': '0', 'Instruments': 'JEM...itsConverterLUTLimit': 'false'}, 'Measurement': {'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'Measurement' at 0x13b522770>
dictree = Box({'FormatVersion': '1.0', 'FormatMajorVersion': '1', 'FormatMinorVersion': '0', 'Instruments': 'JEM-ARM200F', 'Manu...BitsConverterLUTLimit': 'false'}, 'Measurement': {'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'MeasurementFormat' at 0x13b5226d0>
dictree = Box({'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'SaveMeasureObjectList' at 0x13b5225e0>
dictree = Box({'SaveMeasureObjectList': {'DrawObject': {}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'DrawObject' at 0x13b5229a0>, dictree = Box({'DrawObject': {}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
>               dictree[et.tag].merge_update(et.attrib)

rsciio/utils/tools.py:156: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

box/box.py:846: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

box/box.py:8[38](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:39): 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute {http://www"

box/box.py:653: BoxKeyError

During handling of the above exception, another exception occurred:

    def test_JEOL_SightX():
        files = [
            ("JEOL-SightX-Ronchigram-dummy.tif.gz", 1.0, t.Undefined),
            ("JEOL-SightX-SAED-dummy.tif.gz", 0.2723, "1 / nm"),
            ("JEOL-SightX-TEM-mag-dummy.tif.gz", 1.8208, "nm"),
        ]
        for file in files:
            fname = file[0]
            if fname[-3:] == ".gz":
                import gzip
    
                with tempfile.TemporaryDirectory() as tmp_dir:
                    with gzip.open(os.path.join(MY_PATH2, fname), "rb") as f:
                        content = f.read()
                    fname = os.path.join(tmp_dir, fname[:-3])
                    with open(fname, "wb") as f2:
                        f2.write(content)
>                   s = hs.load(fname)

rsciio/tests/test_tiff.py:878: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:[51](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:52)7: in load
    objects = [load_single_file(filename, lazy=lazy, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:517: in <listcomp>
    objects = [load_single_file(filename, lazy=lazy, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:576: in load_single_file
    return load_with_reader(filename=filename, reader=reader, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:597: in load_with_reader
    file_data_list = importlib.import_module(reader["api"]).file_reader(filename,
rsciio/tiff/_api.py:181: in file_reader
    dict_list = [
rsciio/tiff/_api.py:182: in <listcomp>
    _read_serie(tiff, serie, filename, force_read_resolution, lazy=lazy, **kwds)
rsciio/tiff/_api.py:282: in _read_serie
    axes = _build_axes_dictionaries(shape, names)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

shape = ([55](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:56)6, 5[56](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:57)), names = ['height', 'width'], scales = [None, None]
offsets = None, units = None

    def _build_axes_dictionaries(shape, names=None, scales=None, offsets=None, units=None):
        """Build axes dictionaries from a set of lists"""
        if names is None:
            names = [""] * len(shape)
        if scales is None:
            scales = [1.0] * len(shape)
        if scales is None:
            scales = [0.0] * len(shape)
        if units is None:
            scales = [None] * len(shape)
    
        axes = [
            {
                "size": size,
                "name": str(name),
                "scale": scale,
                "offset": offset,
                "units": unit,
            }
>           for size, name, scale, offset, unit in zip(shape, names, scales, offsets, units)
        ]
E       TypeError: 'NoneType' object is not iterable

rsciio/tiff/_api.py:232: TypeError
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:[57](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:58)9 If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:5[79](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:80) If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:579 If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:579 If this file format is supported, please report this error to the HyperSpy developers.=================================== FAILURES ===================================
_____________________________ test_save_load_cycle _____________________________
[gw0] darwin -- Python 3.8.16 /Users/runner/hostedtoolcache/Python/3.8.16/x64/bin/python

tmp_path = PosixPath('/private/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/pytest-of-runner/pytest-0/popen-gw0/test_save_load_cycle3')

    def test_save_load_cycle(tmp_path):
        fname = tmp_path / "test_file.prz"
    
        s = hs.load(my_path / "pantarhei_data" / "panta_rhei_sample_v5.prz")
>       s.save(fname)

rsciio/tests/test_pantarhei.py:85: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/signal.py:3043: in save
    io_save(filename, self, overwrite=overwrite, file_format=file_format, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:921: in save
    importlib.import_module(writer["api"]).file_writer(
rsciio/pantarhei/_api.py:69: in file_writer
    data, meta_data = export_pr(signal=signal)
rsciio/pantarhei/_api.py:276: in export_pr
    meta_data = _metadata_converter_out(metadata, original_metadata)
rsciio/pantarhei/_api.py:373: in _metadata_converter_out
    original_metadata = DTBox(original_metadata, box_dots=True)
box/box.py:286: in box.box.Box.__init__
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute scan_generator"

box/box.py:653: BoxKeyError
_______________________________ test_JEOL_SightX _______________________________
[gw1] darwin -- Python 3.8.16 /Users/runner/hostedtoolcache/Python/3.8.16/x64/bin/python

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
serie = <tifffile.TiffPageSeries 0 uniform>
filename = '/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp0gplw1v1/JEOL-SightX-Ronchigram-dummy.tif'
force_read_resolution = False, lazy = False, memmap = None
RGB_as_structured_array = True, kwds = {}, axes = 'YX'
page = <tifffile.TiffPage 0 @684352>, shape = (556, 556)
dtype = dtype('uint16'), is_rgb = False, names = ['height', 'width']

    def _read_serie(
        tiff,
        serie,
        filename,
        force_read_resolution=False,
        lazy=False,
        memmap=None,
        RGB_as_structured_array=True,
        **kwds,
    ):
        axes = serie.axes
        page = serie.pages[0]
        if hasattr(serie, "shape"):
            shape = serie.shape
            dtype = serie.dtype
        else:
            shape = serie["shape"]
            dtype = serie["dtype"]
    
        is_rgb = page.photometric == TIFF.PHOTOMETRIC.RGB and RGB_as_structured_array
        _logger.debug("Is RGB: %s" % is_rgb)
        if is_rgb:
            axes = axes[:-1]
            names = ["R", "G", "B", "A"]
            lastshape = shape[-1]
            dtype = np.dtype({"names": names[:lastshape], "formats": [dtype] * lastshape})
            shape = shape[:-1]
    
        if Version(tiffversion) >= Version("2020.2.16"):
            op = {tag.name: tag.value for tag in page.tags}
        else:
            op = {key: tag.value for key, tag in page.tags.items()}
    
        names = [axes_label_codes[axis] for axis in axes]
    
        _logger.debug("Tiff tags list: %s" % op)
        _logger.debug("Photometric: %s" % op["PhotometricInterpretation"])
        _logger.debug("is_imagej: {}".format(page.is_imagej))
    
        try:
>           axes = _parse_scale_unit(
                tiff, page, op, shape, force_read_resolution, names, **kwds
            )

rsciio/tiff/_api.py:277: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
page = <tifffile.TiffPage 0 @684352>
op = {'BitsPerSample': 16, 'Compression': <COMPRESSION.NONE: 1>, 'DateTime': '2021/05/18 14:10', 'ImageDescription': '<?xml...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', ...}
shape = (556, 556), force_read_resolution = False, names = ['height', 'width']
kwds = {}

    def _parse_scale_unit(tiff, page, op, shape, force_read_resolution, names, **kwds):
        # Force reading always has priority
        if _is_force_readable(op, force_read_resolution):
            axes = _axes_force_read(op, shape, names)
            return axes
        # Other axes readers can change position if you need to do it
        elif _is_fei(tiff):
            axes = _axes_fei(tiff, op, shape, names)
            return axes
        elif _is_zeiss(tiff):
            axes = _axes_zeiss(tiff, op, shape, names)
            return axes
        elif _is_tvips(tiff):
            axes = _axes_tvips(tiff, op, shape, names)
            return axes
        elif _is_olympus_sis(page):
            axes = _axes_olympus_sis(page, tiff, op, shape, names)
            return axes
        elif _is_jeol_sightx(op):
>           axes = _axes_jeol_sightx(tiff, op, shape, names)

rsciio/tiff/_api.py:859: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

tiff = <tifffile.TiffFile 'JEOL-SightX-Ronchigram-dummy.tif'>
op = {'BitsPerSample': 16, 'Compression': <COMPRESSION.NONE: 1>, 'DateTime': '2021/05/18 14:10', 'ImageDescription': '<?xml...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01', ...}
shape = (556, 556), names = ['height', 'width']

    def _axes_jeol_sightx(tiff, op, shape, names):
        # convert xml text to dictionary of tiff op['ImageDescription']
        # convert_xml_to_dict need to remove white spaces before decoding XML
        scales, offsets, units = _axes_defaults()
    
        jeol_xml = "".join(
            [line.strip(" \r\n\t\x01\x00") for line in op["ImageDescription"].split("\n")]
        )
        from rsciio.utils.tools import convert_xml_to_dict
    
>       jeol_dict = convert_xml_to_dict(jeol_xml)

rsciio/tiff/_api.py:543: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

xml_object = <Element 'TemReporter' at 0x13b506cc0>

    def convert_xml_to_dict(xml_object):
        if isinstance(xml_object, str):
            xml_object = ET.fromstring(xml_object)
        op = DTBox(box_dots=True)
>       xml2dtb(xml_object, op)

rsciio/utils/tools.py:182: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'TemReporter' at 0x13b506cc0>
dictree = Box({'TemReporter': {'FormatVersion': '1.0', 'FormatMajorVersion': '1', 'FormatMinorVersion': '0', 'Instruments': 'JEM...itsConverterLUTLimit': 'false'}, 'Measurement': {'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'Measurement' at 0x13b522770>
dictree = Box({'FormatVersion': '1.0', 'FormatMajorVersion': '1', 'FormatMinorVersion': '0', 'Instruments': 'JEM-ARM200F', 'Manu...BitsConverterLUTLimit': 'false'}, 'Measurement': {'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'MeasurementFormat' at 0x13b5226d0>
dictree = Box({'MeasurementFormat': {'SaveMeasureObjectList': {'DrawObject': {}}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'SaveMeasureObjectList' at 0x13b5225e0>
dictree = Box({'SaveMeasureObjectList': {'DrawObject': {}}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
                dictree[et.tag].merge_update(et.attrib)
            for child in et:
>               xml2dtb(child, dictree[et.tag])

rsciio/utils/tools.py:158: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

et = <Element 'DrawObject' at 0x13b5229a0>, dictree = Box({'DrawObject': {}})

    def xml2dtb(et, dictree):
        if et.text:
            dictree.set_item(et.tag, et.text)
            return
        else:
            dictree.add_node(et.tag)
            if et.attrib:
>               dictree[et.tag].merge_update(et.attrib)

rsciio/utils/tools.py:156: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

box/box.py:846: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???

box/box.py:8[38](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:39): 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

>   ???
E   box.exceptions.BoxKeyError: "'<class 'rsciio.utils.tools.DTBox'>' object has no attribute {http://www"

box/box.py:653: BoxKeyError

During handling of the above exception, another exception occurred:

    def test_JEOL_SightX():
        files = [
            ("JEOL-SightX-Ronchigram-dummy.tif.gz", 1.0, t.Undefined),
            ("JEOL-SightX-SAED-dummy.tif.gz", 0.2723, "1 / nm"),
            ("JEOL-SightX-TEM-mag-dummy.tif.gz", 1.8208, "nm"),
        ]
        for file in files:
            fname = file[0]
            if fname[-3:] == ".gz":
                import gzip
    
                with tempfile.TemporaryDirectory() as tmp_dir:
                    with gzip.open(os.path.join(MY_PATH2, fname), "rb") as f:
                        content = f.read()
                    fname = os.path.join(tmp_dir, fname[:-3])
                    with open(fname, "wb") as f2:
                        f2.write(content)
>                   s = hs.load(fname)

rsciio/tests/test_tiff.py:878: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:[51](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:52)7: in load
    objects = [load_single_file(filename, lazy=lazy, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:517: in <listcomp>
    objects = [load_single_file(filename, lazy=lazy, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:576: in load_single_file
    return load_with_reader(filename=filename, reader=reader, **kwds)
../../../hostedtoolcache/Python/3.8.16/x64/lib/python3.8/site-packages/hyperspy/io.py:597: in load_with_reader
    file_data_list = importlib.import_module(reader["api"]).file_reader(filename,
rsciio/tiff/_api.py:181: in file_reader
    dict_list = [
rsciio/tiff/_api.py:182: in <listcomp>
    _read_serie(tiff, serie, filename, force_read_resolution, lazy=lazy, **kwds)
rsciio/tiff/_api.py:282: in _read_serie
    axes = _build_axes_dictionaries(shape, names)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

shape = ([55](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:56)6, 5[56](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:57)), names = ['height', 'width'], scales = [None, None]
offsets = None, units = None

    def _build_axes_dictionaries(shape, names=None, scales=None, offsets=None, units=None):
        """Build axes dictionaries from a set of lists"""
        if names is None:
            names = [""] * len(shape)
        if scales is None:
            scales = [1.0] * len(shape)
        if scales is None:
            scales = [0.0] * len(shape)
        if units is None:
            scales = [None] * len(shape)
    
        axes = [
            {
                "size": size,
                "name": str(name),
                "scale": scale,
                "offset": offset,
                "units": unit,
            }
>           for size, name, scale, offset, unit in zip(shape, names, scales, offsets, units)
        ]
E       TypeError: 'NoneType' object is not iterable

rsciio/tiff/_api.py:232: TypeError
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:[57](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:58)9 If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:5[79](https://github.com/hyperspy/rosettasciio/actions/runs/4742402403/jobs/8420632911#step:10:80) If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:579 If this file format is supported, please report this error to the HyperSpy developers.
------------------------------ Captured log call -------------------------------
ERROR    hyperspy.io:io.py:579 If this file format is supported, please report this error to the HyperSpy developers.

It is surprising these tests passed on the PR but not since then...

The test_tiff.py::test_JEOL_SightX failure is caused by the formatting of the JEOL xml, for example the schema specification xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" is not handle gracefully by xml.etree.ElementTree and later one cause issue with latest version of python-box when parsing the xml to a DTBox.

Here is an example:

<?xml version="1.0"?>
<TemReporter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <FormatVersion>1.0</FormatVersion>

@nem1234, you already fiddled with the JEOL xml, do have an idea if there a way to remove these easily or parse them correctly?

I'm sorry, but in my environment, I could not reproduce such error yet.
test_tiff.py runs without any error.
python-box = 6.1, et-xmlfile = 1.1.0, rsciio - commit 0ca8be4

Oops, may be sub effect of upgrading python packages, I just got this error.
I'll try to fix it.

Is this solved with #106 @ericpre ?

python-box 6.1.0 does not show this error, but python-box 7.x.x makes error.
python-box 7 does not accept this string as a key.
'{http://www.w3.org/2001/XMLSchema-instance}type'
may be sanitizing '.' with some other characters (_) is needed.