Best Hacksaw Hacksaw Online We Are A Moving What

4d Result The Start Magnum4d Live Age Games

Date 31 10 2026 sat draw no 443 26, 4d results live for malaysia and singapore live start Latest 4d Results Results Jackpot Free Malaysia Enthusiasts Lucky at 7 00 pm, lotto 4d live 4d results magnum toto da ma cai gd lotto more, live 4d results magnum 4d sportstoto damacai 1 3d.

Check 4d Latest 4d Results Latest Today 4dyes There Are Also Completed Good lotto results today for malaysia singapore magnum sports toto da ma cai gd lotto 9 lotto perdana singapore pools updated after every draw, malaysia latest 4d 5d 6d jackpot results live from magnum sports toto damacai at 4dyes com.

Latest 4d Com Results Malaysia Latest 4d Life Checking Can

Check past 4d result numbers from magnum 4d sports toto da ma cai and other providers review Good4d Live 4d Date Today Latest 4d Results Can Fastest previous 4d draw results for reference, fastest real time live 4d results of malaysia magnum 4d toto 4d damacai sabah 4d88 cashsweep sandakan 4d singapore pools 4d.

Live 4d result magnum 4d damacai 4d sportstoto 4d my sg, malaysia latest 4d 5d 6d jackpot results live from magnum sports toto damacai at 4dyes com, get the latest 4d live result lottery result for magnum 4d perdana 4d toto 4d singapore 4d sabah sarawak all in one place updated live. Latest 4d Results Latest Home List Of 4d Magnum4d Winning Sportstoto

Live 4d Cambodia Singapore Check Today S Has Website

4d results today malaysia magnum toto da ma cai, 4d results malaysia today magnum toto da ma cai, malaysia lotto 4d results today on grand lotto da ma chai toto magnum 4d hari Check 4d Results Toto Numbers Games 4d Rm3 Enthusiasts Grand hari 4d good 4d grand lotto perdana 4d sabah and sarawak 4d.

Check today s malaysia 4d results for magnum sports toto and da ma cai including live draw numbers and 4d Results Past Result Singapore 4d2u Magnum4d Live Draw Data Website prize results, malaysia 4d results today for sports toto magnum 4d da ma cai grand dragon 4d east malaysia and singapore live numbers update automatically and completed results show source status.

Check the 4d special draw date in malaysia, malaysia singapore 4d results statistics, check lotto 4d results live magnum toto damacai gd lotto 9 lotto perdana updated instantly after every draw fast verified keputusan 4d at 4dmy. Latest Magnum Dragon Lotto Check The Numbers Inspirations 4dyes

Check 4d Number Good4d Latest 4d2u Live Grand Dragon Place Com

4d result today live 4d toto lotto magnum damacai 4d, 4d result from magnum damacai and 4d toto updated live data fast accurate and history 4d 4d Result And Toto Get The Latest Has Providing Sure results malaysia, latest magnum 4d results live, 4d88 4d results today magnum 4d sports toto 4d jackpot damacai 1 3d.

Merged
ehennestad merged 41 commits into
fix-nwb-outstanding-review-findingsfrom
reland-nwb-converter-registry
Nov 5, 2026
Merged

ehennestad merged 41 commits into
fix-nwb-outstanding-review-findingsfrom
reland-nwb-converter-registry

Conversation

@ehennestad

@ehennestadehennestad commented Aug 29, 2026•

Copy link
Copy Markdown
Collaborator

Re-lands the roadmap 2.0 converter architecture on top of #18, rather than merging the May vertical slice. A trial merge of that slice produced 18 conflicted files, all in shared pilot files main has since renamed, re-helped and re-whitespaced, while main had independently landed the same foundation work. Re-landing keeps main's versions and applies the conventions it settled.

What this adds

A converter turns one data variable into entries in an NWB file. It is a function plus a descriptor saying what it accepts, produces and requires. Converters come from three places and nothing downstream distinguishes them: the ones shipped here, NeuroConv data interfaces reached through Python, and ones a lab registers from its own folder.

ConverterRegistry answers which converters suit a variable. NWBFileConverter walks a configuration and owns the NWB file. NWBFileConfiguration and NWBDataItemConfig replace the .mat catalog with JSON. NWBSessionConfigBuilder fills in what a NANSEN project already knows, and writeNwbFile becomes the shim it was meant to be.

Three things the runner does that no converter can do for itself

It creates the file and writes the session, subject and general metadata before any converter runs, so exactly one writer owns them and NeuroConv-backed converters append to what it wrote.

It exports as rarely as correctness allows. Every export appends a file_create_date entry and rewrites the file, so a conversion of any number of mutating items reaches disk once. Changes held in memory are written before a converter that works on the file on disk runs, and the file is read back afterwards.

It orders items so a converter producing a type runs before one requiring it. ROI signals index the plane segmentation's rows; relying on the configuration's array order made that silently positional.

Converter matching is ranked, not boolean

A converter naming a variable's source format beats one accepting its MATLAB class, which beats one accepting anything. The slice treated a file path as a pseudo-type, which made every path-taking converter match every file-backed variable — precisely where the configurator most needs to discriminate. Class evidence and format evidence are now separate descriptor fields. A format match counts only when the converter accepts the data's class, and an item's TargetNWBType narrows the matches to the converters that produce it.

Verified against real NeuroConv

A conversion was run end to end from MATLAB: the runner created the file, an ImageInterface conversion appended into it through py.*, every field the runner wrote survived, and the file carries one file_create_date entry. This is the last of the four Phase 1 acceptance criteria and the first time it has been met.

Running it corrected an assumption taken from reading NeuroConv's source. Appending drops the fields required inside the NWBFile metadata section, but the section itself stays required, so it is sent empty rather than removed. Removing it fails validation before any data is written.

Defects found along the way

  • getTypesForModule read only the schema's groups key, so types defined as datasets — GrayscaleImage, RGBImage, RGBAImage — were missing from every listing. The count goes from 59 to 70.
  • convertToNeuroDataType had an empty else branch, so anything that was not a timetable or a duration left its output unassigned.
  • Regularly sampled series were written with one timestamp per sample. NWB describes such a series by its start time and rate, and NWB Inspector reports the difference.
  • The pilot addFovProjectionImage capability was nearly lost when the pilot class was replaced. It returns as a converter, taking a struct of named projections.
  • The pilot addRois created a fresh ImageSegmentation on each call, silently dropping earlier planes.

The hand-maintained type list is gone

NeuroDataType listed 75 types by hand and was wrong in both directions against the loaded schema: six deprecated types offered, seven real ones missing. listNeurodataTypes reads the schema instead.

Review fixes

These came out of a review of the stack and are in this PR because they fix its own code.

  • iso8601ToDatetime reads timestamps with whole seconds, such as 2026-05-10T14:30:15+02:00. It returned empty for them, so a hand-written or NeuroConv-produced session_start_time fell through to datetime(text), which cannot read an offset. iso8601ToDatetimeTest covers it.
  • RoiSignals converts the samples × ROIs matrix NANSEN saves, timed by a new SamplingRate converter argument, as well as a timetable. It read .Variables and Properties.SampleRate on every input, so it failed on every class it accepted.
  • The registry matches the types NANSEN file adapters record: TwoPhotonImageStack accepts ImageStack, and RoiSignals accepts RoiSignalArray as a class and a format.
  • registerFolder does nothing for a folder already registered, and lists a folder only once its converters registered. Registering a folder twice used to make every later refresh fail.
  • A converter producing "*" satisfies requirements for its item's TargetNWBType when items are ordered.
  • With OnItemError="continue", an item no converter resolves is skipped and reported instead of stopping the run. writeNwbFile takes an 'OnItemError' parameter, "stop" by default.
  • A tie between converters at the best rank raises nansen:nwb:ambiguousConverter, and no match still raises nansen:nwb:unresolvedConverter, so a caller can tell the two apart without reading the message.
  • nansen.module.nwb.internal.mergeConverterArgs holds the rule by which a data item's ConverterArgs are laid over a converter's DefaultConverterArgs: an argument the item sets replaces the default of the same name whole. The runner uses it, and so do the later PRs that have to predict what a converter receives.
  • Messages that put a name in ''%s'' inside a double-quoted string showed both apostrophes; they use '%s'.
  • buildConfig keeps a configured SourceInfo field the variable model leaves empty, such as the path of a file the model does not know.
  • convertLegacyConfiguration gives a pilot item that used convertGeneralTwoPhotonSeries the TwoPhotonImageStack converter. Other pilot converter functions keep their name as ConverterName, so the runner reports them as unknown instead of choosing another converter.
  • The TIFF and Suite2p NeuroConv entries follow the 0.9.3 signatures. TiffImagingInterface gets file_paths and requires InterfaceArgs.sampling_frequency. Suite2pSegmentationInterface gets the suite2p folder above the plane folder, through a new grandparentFolder source path mode. resolveSourceArg adds the fields of ConverterArgs.InterfaceArgs to the constructor arguments, and RequiredInterfaceArgs names the ones that must be there. The interfaces were not run, because roiextractors is not installed in the test environment.
  • NWBSessionConfigBuilder writes numeric subject and session IDs as digits in the filename.
  • convert's help says that OnItemError="continue" writes the file without the failed items before raising nansen:nwb:itemsFailed.
  • When RoiGroupPlaneSegmentation creates the file's imaging plane, initGeneralOptophysiology first checks the merged metadata for the properties NWB requires: a description and emission_lambda for the optical channel, and excitation_lambda, indicator and location for the plane. A missing one raises nansen:nwb:missingRequiredMetadata, naming the property and the converter argument to set it in, before anything is added to the file. matnwb checks them only on export, after every other item has converted, with an error that names neither.
  • loadMetadata reads no stored metadata when no NANSEN project is open. It called nansen.getCurrentProject, which raises NANSEN:NoActiveUserSession when NANSEN has not been started, so the ROI mask converter failed in any run outside a NANSEN session.
  • builtinConverterTest runs RoiSignals and RoiGroupPlaneSegmentation through the runner, and convertLegacyConfigurationTest covers the pilot converter mapping.

TwoPhotonImageStack is still untested: it writes through NANSEN's NWBExporter, which builds matnwb.types.core objects, a namespace matnwb 2.11 does not define. That is left for a separate fix in NANSEN.

Notes for review

NwbModule and NWBVariableName take the uppercase acronym form here. #14 deferred that only because renaming needed a migration, and this schema has no predecessor to migrate.

Pilot .mat configurations are converted on the spot with a warning. Roadmap section 9 rules out a migration loader and nothing in the conversion path reads the pilot schema, but the configurator still writes .mat until the GUI moves over, and erroring would break the module end to end in the meantime.

The modern GUI is not ported. That depends on the legacy-GUI question in roadmap section 8a, which is still open.

Based on fix-nwb-outstanding-review-findings (#18); retarget to main once that merges.

🤖 Generated with Claude Code

ehennestadand others added 20 commits August 29, 2026 23:48
NWBFileConfiguration and NWBDataItemConfig replace the .mat catalog schema with classes that round-trip through JSON, so configurations are diff-friendly in version control and can be handed to converters that expect JSON metadata. The clean break is also the moment to settle two field names PR #14 deferred: NwbModule and NWBVariableName disagreed with each other and renaming them needed a migration. This schema has no predecessor to migrate, so both take the uppercase acronym form, and TargetNWBType follows. SourceInfo keeps class evidence and format evidence in separate fields. Treating a file path as a pseudo-type would match every path-taking converter against every file-backed variable, which is exactly where converter matching has to discriminate. fromStruct rejects a configuration stamped with a newer schema version rather than reading it as if it were current and dropping what it does not understand. Co-Authored-By: Claude Fable 5 <[email protected]>
A converter turns one data variable into neurodata. The registry answers which converters can handle a variable and which can produce a neurodata type; the runner walks a configuration, dispatches to them, and owns the NWB file. Three things the runner does that no converter can do for itself: It creates the file and writes the session, subject and general metadata before any converter runs, so exactly one writer owns the file-level metadata. NeuroConv-backed converters then append. That split is what NeuroConv's append mode is built for: it drops the required-field constraints on its own NWBFile metadata section when appending, so the sections the runner already wrote are not needed a second time. It exports as rarely as correctness allows. Every export appends a file_create_date entry and rewrites the file, so a conversion of any number of mutating items reaches disk once. Changes held in memory are written before a converter that works on the file on disk runs, and the file is read back afterwards. It orders items so a converter producing a type runs before one requiring it, whatever order the configuration lists them in. ROI signals need the plane segmentation they index; relying on the configuration's array order made that silently positional. Converter matching is ranked rather than boolean. A converter naming the variable's source format beats one accepting its MATLAB class, which beats one accepting anything. Treating a path as a pseudo-type had made every path-taking converter match every file-backed variable. Co-Authored-By: Claude Fable 5 <[email protected]>
The runner tests concentrate on what no converter can check for itself: that a conversion of any number of mutating items reaches disk once, that changes held in memory survive a converter which works on the file on disk, and that a producer runs before the item requiring it. An external converter is simulated with a local function, so the contract is covered without needing Python. Registry tests pin the match ranking rather than only that a match occurs. A registry returning everything for everything would pass a weaker test while being useless to the configurator. Configuration tests round-trip one item, several items, none, and items whose metadata fields differ, because JSON loses the difference between a scalar and a one-element array and jsondecode reshapes values in places MATLAB did not put them. Co-Authored-By: Claude Fable 5 <[email protected]>
A converter in a registered folder is an ordinary function that also returns its own descriptor when asked for one, so a lab can add converters without changing this module. Files that do not answer that way are left alone, letting helpers live beside the converters. Registered folders survive a registry refresh. Refreshing exists to pick up an edited converter, and silently dropping the lab's own converters while doing so would be a surprise. Co-Authored-By: Claude Fable 5 <[email protected]>
NWBSessionConfigBuilder fills in what the project already knows: where the file goes, the identifier, the zoned session start time, the subject, and for each item the class its file adapter produces, that adapter as a source format, and the file path. That is the module's advantage over a standalone converter, and it is why converter matching has evidence to rank on. It reads the variable model rather than loading data, so a configurator can offer converters for a session whose recordings are far larger than memory. Only the subject identifier is taken from the session. Species, sex and age live on the animal record, and guessing them here would put unverified values into the file. writeNwbFile becomes the shim it was meant to be: find the configuration, build it for this session, hand it to the runner. The per-item conversion loop, the placement switch and the export bookkeeping all move into NWBFileConverter, where the standalone API gets them too. Pilot .mat configurations are converted on the spot, with a warning telling the user to re-save. Roadmap section 9 rules out a migration loader, but the configurator still writes .mat until the GUI moves over, and erroring instead would break the module end to end in the meantime. convertLegacyConfiguration is the one-off tool; nothing in the conversion path reads the pilot schema. Co-Authored-By: Claude Fable 5 <[email protected]>
Replacing the pilot NWBFileConverter dropped one capability that had no equivalent among the converters: addFovProjectionImage, which stores field of view projections in an Images collection and carries the matnwb 2.9 image/baseimage rename with it. It comes back as a converter, now able to take a struct of named projections rather than one image at a time. The pilot addTrials is not restored as it was. It hardcoded four column names and a description naming one lab's trial types, and was marked as needing generalizing. The converter takes any timetable with one row per interval, gets stop times from a named stop-time or duration variable, and carries the remaining variables into columns. Without either, an interval runs until the next one starts and the last row is dropped, because nothing says when it ends. convertToNeuroDataType had an empty else branch, so anything that was not a timetable or a duration left its output unassigned and failed with an error about output arguments. Plain arrays now convert, and data carrying no time of its own is rejected with a message naming the metadata that would fix it. Co-Authored-By: Claude Fable 5 <[email protected]>
The NeuroDataType enumeration listed 75 types by hand and had to be edited whenever the NWB schema moved. Against the schema matnwb currently loads it was wrong in both directions: it offered six types that are now deprecated, and was missing seven real ones including ElectrodesTable and EventsTable. listNeurodataTypes reads the loaded schema instead, and can narrow to one module or to the types a converter names as its output. Converters that decide their type at conversion time are left out of that calculation, since counting them would mark every type producible. getTypesForModule read only the schema's groups key. A module defines types under datasets as well, so GrayscaleImage, RGBImage and RGBAImage were absent from every listing while being perfectly usable types. Reading both keys brings the count from 59 to 70. NWBDataConfiguration holds its neurodata type as text and checks it when the conversion runs. A property validator cannot follow a schema that is loaded at runtime. Co-Authored-By: Claude Fable 5 <[email protected]>
docs/converters.md is the public contract: the context a converter receives, what it may return, every descriptor field, how to register a lab's own folder, and what the runner guarantees about file creation, ordering and export. It replaces a four-line scratch note that was checked in as a template. The standalone example converts three items through three different placements without a NANSEN session, which is the claim the layering makes and the thing most likely to break quietly. Running NWB Inspector over its output found a real defect: a regularly sampled series was written with one timestamp per sample. NWB describes such a series by its start time and rate, which is smaller and what a reader expects. Both timetable paths had their own copy of the timestamp handling, so the decision now lives in one place and they share it. Projection images also get a description, which Inspector asks for and only the converter can supply. The example now passes Inspector with nothing above suggestion level, and the remaining suggestions are metadata the example does not invent: experimenter, keywords, and a subject description. Two Phase 0 leftovers go with it: an empty convertVideo stub whose argument validator does not exist anywhere, and an empty file of the same name in the mixin folder. The real video exporter is unaffected. Co-Authored-By: Claude Fable 5 <[email protected]>
The MATLAB to Python conversion is the part of the bridge most likely to be wrong and least likely to say so: NeuroConv validates metadata against a JSON schema, so a value that crosses as the wrong Python type fails inside Python complaining about the schema rather than about the MATLAB value behind it. It moves out of runConversion into toPythonValue, where it can be tested directly. Verified against a real NeuroConv 0.9.3 install: the import and class lookup work, constructing an interface reaches real NeuroConv code, and a Python traceback survives as the cause of a MATLAB exception rather than being flattened into its message. A conversion of an actual recording is still unverified. The Python environment here has neuroconv but none of the format backends it defers to, so every format interface stops at a missing module. That needs 'pip install neuroconv[ophys]' and a real source file. Co-Authored-By: Claude Fable 5 <[email protected]>
Running a real conversion contradicted what reading the source had suggested. Appending drops the fields NeuroConv requires inside its NWBFile metadata section, but the top-level schema still requires the section to be present, so removing it fails validation with "'NWBFile' is a required property" before any data is written. The section is now sent empty. Subject is dropped, as it is not required and the runner has already written it. Verified end to end against NeuroConv 0.9.3: a file created with session, subject and general metadata, appended to by an ImageInterface conversion, keeps every field the runner wrote, gains the converted data, and carries one file_create_date entry. Co-Authored-By: Claude Fable 5 <[email protected]>
A conversion can finish successfully and still produce a file a repository will reject. Running NWB Inspector over a session export showed the common case: a subject with no age, which Inspector rates critical, and which the session layer cannot supply because age lives on the animal record rather than the session. inspectFile delegates to NWB Inspector rather than reimplementing the practices, since it is the reference implementation and a MATLAB copy would drift from what a repository actually checks on submission. The runner warns rather than errors: the data is written, and what to do about a finding is the user's call. Validation is off by default in the core, which keeps it free of Python, and on for the session method, where a user is present to read the warning. Reading a Python enum member's name needs py.getattr; MATLAB does not expose it as a property, which the first version assumed. Co-Authored-By: Claude Fable 5 <[email protected]>
Three gaps surfaced by studying the roth-2026 conversion, a real published-dataset conversion that used none of this module. Each is something that project needed and had to hand-write. Project-wide metadata defaults: institution, lab, experimenter, keywords and species are per-project facts that were either retyped into every configuration or missing, and missing is what NWB Inspector kept reporting. A nwb_metadata_defaults.json next to the configuration now supplies them; values from the session win. The merge lives in deepMerge, where an empty configuration field means never-filled-in rather than erase-the-default. Subject metadata from the Subject metatable: age, sex, genotype and date of birth live on the subject record, not the session, which is why every session export drew Inspector's critical finding for a subject without an age. The builder now maps a subject record -- AgeDays to an ISO 8601 duration, BiologicalSex to the NWB letters, DateOfBirth to a zoned timestamp -- and writeNwbFile looks the record up in the project's Subject metatable when one exists. The date gets a time zone because pynwb rejects a bare date; the roth code writes yyyy-MM-dd and draws a validation warning for it. Output path as a strategy: roth writes to a Processed data location in per-figure subfolders, which no fixed convention can express. An OutputPathFcn hook derives the path from the session; an explicit OutputPath overrides; the BIDS-style default stands. Nothing is guessed anywhere: a record without an age produces metadata without an age, and the validation step reports the gap. Co-Authored-By: Claude Fable 5 <[email protected]>
# Conflicts: # +nansen/+module/+nwb/+sessionmethod/+data/+nwb/writeNwbFile.m
The ROI mask converter passes DeviceMetadata, OpticalChannelMetadata and ImagingPlaneMetadata to initGeneralOptophysiology, whose arguments block accepted only the plane and channel counts, so the converter failed on every file without optophysiology metadata. The three are now accepted and laid over the project's stored metadata. loadMetadata returns nothing when there is no current project, which is the standalone case rather than an error. Co-Authored-By: Claude Fable 5.1 <[email protected]>
jsonencode writes a datetime in display format without its zone, so a saved configuration reloaded with an unzoned session_start_time, which the runner refuses. Datetime fields are now written as ISO 8601 text with the UTC offset, and session_start_time is read back as a zoned datetime. An unzoned datetime stays unzoned on the way through, so the runner's message is still what reports it. Co-Authored-By: Claude Fable 5.1 <[email protected]>
When overwriting, the file is built under a work name and moved over the previous file only once every item is in it, and converters are resolved and the session metadata checked before the file is touched, so neither a failing item nor a misspelled converter name destroys the previous output. The resolution rule moves to ConverterRegistry.resolveForItem, where the configurator can ask the same question, and honours the rank order the registry computes: only a tie at the best rank is ambiguous. A converter returning something other than the file, nothing or a result struct is rejected instead of being read as "mutated in place" with its data dropped. A MetadataResolver option lets the session layer turn the names of linked instances in an item's metadata into objects in the file before an in-memory converter runs, as the session method did before the runner existed; the objects are discarded with the file copy they were built on after an external converter. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Each element of a multi-object result is placed under its own name; the item's name applied to all of them and only the last survived. Datetime interval times are measured from the session start, as NWB measures every time, rather than from each column's own first value. ROI signals are added to an existing response interface instead of replacing it. The generic path demands a time reference only for time series, so a type without time, such as an image, can be built. Co-Authored-By: Claude Fable 5.1 <[email protected]>
DataLocationModel returns NaT for a time it could not parse and the raw text when no format is configured; isempty catches neither, and the failure surfaced from duration() without naming the session. Both are now reported with what to configure. A missing subject or session identifier is treated as blank. Co-Authored-By: Claude Fable 5.1 <[email protected]>
The schema listing includes NWBFile, Subject, Device and the abstract containers, none of which a data variable converts to. The global dropdown now applies the same exclusions as the per-module refresh. Co-Authored-By: Claude Fable 5.1 <[email protected]>
The folder fixture deletes the folder at teardown while registerFolder had left it on the path. A helper that takes no arguments must not be executed during discovery. Co-Authored-By: Claude Fable 5.1 <[email protected]>
ehennestadand others added 8 commits November 4, 2026 08:23
…nverter-registry # Conflicts: # +nansen/+module/+nwb/+sessionmethod/+data/+nwb/writeNwbFile.m
iso8601ToDatetime counted the fraction digits as the length past 20 characters and returned empty when that count was negative. Text with whole seconds, such as "2026-05-10T14:30:15+02:00", has 19 characters after the offset is removed, so it was always rejected. The session start time in a hand-written configuration or NeuroConv metadata then fell through to datetime(text), which cannot read an offset or "Z". The fraction is now parsed only when there are characters past the seconds, and must be a decimal point followed by at least one digit. datetimeToIso8601 always writes milliseconds, so the round-trip tests never reached this case. iso8601ToDatetimeTest covers whole seconds, offsets, UTC and malformed text. Co-Authored-By: Claude Opus 5.5 <[email protected]>
The RoiSignals descriptor accepted double, single and struct, but convertRoiResponses read signalArray.Variables and Properties.SampleRate, which only a timetable has. Every accepted class therefore failed. NANSEN saves the RoiSignals_* variables as a double matrix of samples by ROIs (SignalExtractor). convertRoiResponses now takes a matrix together with a SamplingRate, and convertRoiSignals passes the SamplingRate converter argument. A matrix without a rate, or with more than two dimensions, raises a named error. The descriptor lists the classes the converter reads: double, single and timetable. struct is dropped because no code path reads one. builtinConverterTest now runs RoiSignals through the runner, appending to a file seeded with a plane segmentation built in matnwb. Co-Authored-By: Claude Opus 5.5 <[email protected]>
defaultOutputPath passed subjectID and sessionID to sprintf("%s") unconverted. NANSEN does not type them, and %s writes a number as the character with that code, so subject 5 gave "sub-\x05_ses-....nwb". They are converted with string() first, as the identifier already is. Co-Authored-By: Claude Opus 5.5 <[email protected]>
convert's help said the work file is moved over the previous file only once every item is in it. With OnItemError "continue" the file without the failed items is moved into place and itemsFailed is raised afterwards, as the error message already says. The class and method help now describe that. Co-Authored-By: Claude Opus 5.5 <[email protected]>
sourceInfoForItem records a variable's DataType and FileAdapter as class and format evidence. NANSEN fills DataType with the file adapter's DataType constant, such as "ImageStack" or "RoiSignalArray", not the MATLAB class the adapter returns. TwoPhotonImageStack and RoiSignals named only MATLAB classes and a "roisignals" format, so a NANSEN image stack or ROI signal variable matched neither of them. TwoPhotonImageStack now also accepts "ImageStack". RoiSignals accepts "RoiSignalArray" as a class and as a format. matchRank also gave a format match the top rank without looking at the classes a converter declares. RoiGroupPlaneSegmentation, which takes only ROI groups, could therefore outrank the timetable converters for a timetable of Suite2p signals. A format match now counts only when the converter accepts the data's class, or declares no classes, or accepts any class. Co-Authored-By: Claude Opus 5.5 <[email protected]>
resolveForItem never compared an item's TargetNWBType with what the candidate converters produce. A timetable with TargetNWBType "TimeIntervals" tied TimetableTimeSeries and TimetableTimeIntervals at the class rank and was handed to GenericNeurodataType, which fails on TimeIntervals. A single class match won even when it produced another type than the one asked for. When TargetNWBType is set, the matches are narrowed to converters that produce it, or produce any type, before the best rank is taken. docs/converters.md says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
ehennestadand others added 8 commits November 4, 2026 09:22
registerFolder added the folder to ConverterFolders before registering its converters, and add raises on a name that is already registered. Registering a folder a second time, as a project's startup code does whenever the project is reopened in one MATLAB session, raised and left the folder listed twice. instance(Refresh=true) then failed on the second entry on every refresh. A folder already registered, compared by absolute path, is now skipped. A folder is added to ConverterFolders only after all its converters registered. Co-Authored-By: Claude Opus 5.5 <[email protected]>
orderDataItems took each converter's ProducesNWBType literally. A converter that produces "*", such as GenericNeurodataType, builds the type its item names in TargetNWBType, but it never satisfied a requirement for that type. A generic item with TargetNWBType "PlaneSegmentation" next to a RoiSignals item failed with unmetRequirement. A "*" producer now counts as producing its item's TargetNWBType. Co-Authored-By: Claude Opus 5.5 <[email protected]>
orderDataItems resolves every item's converter before any item runs, outside the per-item try. An item naming an unregistered converter, or one no converter matches, raised there even with OnItemError "continue", so it could not be skipped like an item whose converter fails. With "continue", such an item is now reported with a warning, added to FailedItems and left out of the run. The itemsFailed message counts every configured item. Co-Authored-By: Claude Opus 5.5 <[email protected]>
buildConfig replaced every item's SourceInfo with what sourceInfoForItem reports from the variable model. For a file the model has no entry for, getDataFilePath throws and SourceInfo comes back empty. A Path and Format set in a hand-written configuration were then discarded, and resolveSourceArg asked the user to set the path they had set. Each SourceInfo field the session leaves empty now keeps the configured value. Fields the session reports still win. Co-Authored-By: Claude Opus 5.5 <[email protected]>
writeNwbFile builds NWBFileConverter with the default OnItemError "stop", so one item that fails stops the export and leaves the previous file as it was. The pilot writeNwbFile wrote the other items and warned about the failed one, and there was no way to ask for that. The new 'OnItemError' parameter is passed to the converter. It defaults to "stop"; "continue" writes the file without the failed items and raises nansen:nwb:itemsFailed at the end. Co-Authored-By: Claude Opus 5.5 <[email protected]>
convertLegacyConfiguration gave a pilot item that named its own converter function an empty ConverterName, so the runner chose a converter from the source evidence. An item that used convertGeneralTwoPhotonSeries resolved to GenericNeurodataType, which fails on an ImageStack and stopped the export. A pilot converter with a registered equivalent now gets it: convertGeneralTwoPhotonSeries becomes TwoPhotonImageStack. Any other pilot converter keeps its namespace-qualified name as the ConverterName, so the runner reports an unknown converter, or skips the item with OnItemError "continue". The warning says these items will not convert. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Two registered NeuroConv interfaces were given arguments their 0.9.3 constructors do not take as intended. TiffImagingInterface needs a sampling frequency, which a file path cannot supply, and its file_path argument is deprecated in favour of file_paths. Suite2pSegmentationInterface takes the suite2p folder that holds the plane folders, and picks a plane by plane_name. The registry passed it the plane folder that holds the variable's file. resolveSourceArg now adds the fields of ConverterArgs.InterfaceArgs to the constructor arguments. ConverterArgs.RequiredInterfaceArgs names the ones that must be there, and a missing one raises missingConverterArg naming it. A new grandparentFolder SourcePathMode gives the folder two levels above the recorded path. The TIFF entry now passes file_paths and requires InterfaceArgs.sampling_frequency. The Suite2p entry passes the suite2p folder; NeuroConv picks the first plane unless InterfaceArgs.plane_name says otherwise. The interfaces were not run: roiextractors, which they need, is not installed in the test environment. Co-Authored-By: Claude Opus 5.5 <[email protected]>
builtinConverterTest had no case for RoiGroupPlaneSegmentation. It now converts a struct with the roiArray and FovImageSize properties convertRoiGroup reads, so the test needs no NANSEN classes. It checks the plane segmentation rows and the imaging plane the converter creates. TwoPhotonImageStack stays untested here. It writes through NANSEN's NWBExporter, which builds matnwb.types.core objects, a namespace matnwb 2.11 does not define. Co-Authored-By: Claude Opus 5.5 <[email protected]>
ehennestadand others added 5 commits November 4, 2026 10:57
loadMetadata treats a missing current project as the standalone case and returns no stored metadata. It checked for that with isempty(nansen.getCurrentProject()), but getCurrentProject raises NANSEN:NoActiveUserSession when NANSEN has not been started, and does not exist without NANSEN. The ROI mask converter, which reads stored optophysiology metadata through loadMetadata, therefore failed in any conversion run outside a NANSEN session. A missing getCurrentProject or that error now count as no project. Any other error from getCurrentProject is raised as before. Found while testing the next commit, which cannot be tested outside a NANSEN session without this one. Co-Authored-By: Claude Opus 5.5 <[email protected]>
When the file has no imaging plane yet, RoiGroupPlaneSegmentation creates one through initGeneralOptophysiology from the converter arguments and the project's stored metadata. Nothing checked that they set what NWB requires. matnwb checks required properties only on export, so a plane without an indicator failed at the end of the run, after every other item had been converted, with an error that named neither the item nor the argument to set. initGeneralOptophysiology now merges the metadata of every channel and plane first, and checks it before adding anything to the file: description and emission_lambda for an optical channel, and excitation_lambda, indicator and location for an imaging plane. A missing one raises nansen:nwb:missingRequiredMetadata, which names the object, the properties and the converter argument to set them in. The runner reports it against the item, and the previous file is left as it was. With OnItemError "continue" the item is skipped. Co-Authored-By: Claude Opus 5.5 <[email protected]>
resolveForItem raised nansen:nwb:unresolvedConverter both when no converter matches and when several match equally well. A caller that must tell the two apart, such as the configurator's status, could do so only by looking for "Several" in the message. A tie now raises nansen:nwb:ambiguousConverter. The runner skips such an item under OnItemError "continue", as it does an unresolved one. Co-Authored-By: Claude Opus 5.5 <[email protected]>
NWBFileConverter laid a data item's ConverterArgs over the converter's DefaultConverterArgs in a private method, so code that has to predict the arguments a converter receives had to copy the rule. nansen.module.nwb.internal.mergeConverterArgs now holds it: an argument the item sets replaces the default of the same name whole. The runner calls it, and the session builder and writeNwbFile's start-time lookup can use the same rule. mergeConverterArgsTest covers it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Four messages were double-quoted strings that put a name in ''%s''. Doubling an apostrophe escapes it only inside a single-quoted char vector, so the user saw both apostrophes, as in "Skipping ''broken''". The runner's skip warnings, its NWB Inspector warning and the descriptor validation error now use '%s'. Co-Authored-By: Claude Opus 5.5 <[email protected]>
@ehennestad
ehennestad merged commit fabd750 into mainNov 5, 2026
@ehennestad
ehennestad deleted the reland-nwb-converter-registry branch November 5, 2026 14:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ehennestad