Skip to content
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* Deprecated returning NWBFile when using `append_on_disk_nwbfile=True` in `write_imaging_to_nwbfile` and `write_segmentation_to_nwbfile`. Will return None on or after June 2026. [PR #1649](https://github.com/catalystneuro/neuroconv/pull/1649)

## Bug Fixes
* Fixed `TypeError: Object of type type is not JSON serializable` when passing `type` or `callable` objects (e.g. `progress_bar_class`) in `conversion_options`. The validation step now serializes these to their qualified module path for JSON schema validation while passing the original objects through to conversion unchanged. [PR #1667](https://github.com/catalystneuro/neuroconv/pull/1667)
* Fixed `UnicodeDecodeError` on Windows when reading YAML and JSON files containing UTF-8 characters by adding explicit `encoding='utf-8'` parameter to all text file operations. This ensures cross-platform compatibility per PEP 597 recommendations. [PR #1657](https://github.com/catalystneuro/neuroconv/pull/1657)
* Fixed bug in `write_imaging_to_nwbfile` where `nwbfile` was incorrectly passed to `add_imaging_to_nwbfile` instead of the created/loaded nwbfile. [PR #1649](https://github.com/catalystneuro/neuroconv/pull/1649)
* Fixed bug in `write_segmentation_to_nwbfile` where invalid `plane_num` parameter was passed to `add_segmentation_to_nwbfile`. [PR #1649](https://github.com/catalystneuro/neuroconv/pull/1649)
Expand Down
8 changes: 8 additions & 0 deletions src/neuroconv/utils/json_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ class _NWBConversionOptionsEncoder(_GenericNeuroconvEncoder):
Custom JSON encoder for conversion options of the data interfaces and converters (i.e. kwargs).
"""

def default(self, obj):

# Serialize callable objects (e.g. callback functions in progress_bar_options)
if callable(obj):
return f"{obj.__module__}.{obj.__qualname__}"

return super().default(obj)


# This is used in the Guide so we will keep it public.
NWBMetaDataEncoder = _NWBMetaDataEncoder
Expand Down
54 changes: 54 additions & 0 deletions tests/test_minimal/test_interface_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,57 @@ def add_to_nwbfile(self, nwbfile: NWBFile, metadata: dict | None, datetime_optio

nwbfile_path = tmp_path / "converter_test.nwb"
converter.run_conversion(nwbfile_path=nwbfile_path, overwrite=True, conversion_options=conversion_options)


def test_conversion_options_validation_with_type_and_callable(tmp_path):
"""Test that type objects and callables in conversion_options don't break validation.

This is a regression test for https://github.com/catalystneuro/neuroconv/pull/1667.
NWB GUIDE passes progress_bar_class (a type) and callback functions nested inside
iterator_opts dict in conversion_options, which caused TypeError during JSON
serialization in the validation step.
"""

class InterfaceWithIteratorOpts(MockInterface):

def add_to_nwbfile(
self,
nwbfile: NWBFile,
metadata: dict | None,
iterator_opts: dict | None = None,
):
pass

class MyProgressBar:
pass

def my_callback():
pass

iterator_opts = dict(
display_progress=True,
progress_bar_class=MyProgressBar,
progress_bar_options=dict(callback=my_callback),
)

interface = InterfaceWithIteratorOpts()

# Test with type object and callable via interface.run_conversion
nwbfile_path = tmp_path / "interface_test.nwb"
interface.run_conversion(
nwbfile_path=nwbfile_path,
iterator_opts=iterator_opts,
overwrite=True,
)

# Test with type object and callable via ConverterPipe.run_conversion
data_interfaces = {"InterfaceWithIteratorOpts": interface}
conversion_options = {
"InterfaceWithIteratorOpts": {
"iterator_opts": iterator_opts,
}
}
converter = ConverterPipe(data_interfaces=data_interfaces)

nwbfile_path = tmp_path / "converter_test.nwb"
converter.run_conversion(nwbfile_path=nwbfile_path, overwrite=True, conversion_options=conversion_options)
Loading