Skip to content

Port utility functions, validators, and enforce strict MATLAB naming#15

Merged
stevevanhooser merged 7 commits into
mainfrom
claude/update-ndi-porting-guide-U5HRa
Mar 11, 2026
Merged

Port utility functions, validators, and enforce strict MATLAB naming#15
stevevanhooser merged 7 commits into
mainfrom
claude/update-ndi-porting-guide-U5HRa

Conversation

@stevevanhooser

Copy link
Copy Markdown
Contributor

Summary

This PR ports a comprehensive set of utility functions and validators from the MATLAB NDI codebase to Python, while enforcing strict adherence to MATLAB function naming conventions. The changes include new modules for hex diffing/dumping, timeseries downsampling, JSON rehydration, and a complete validator framework that mirrors MATLAB's arguments block validation.

Key Changes

New Utility Functions (ndi.util)

  • hexDiff / hexDump / hexDiffBytes: Hex comparison and display utilities for binary file inspection
  • getHexDiffFromFileObj: Chunk-by-chunk comparison of file-like objects
  • downsampleTimeseries: Anti-aliasing low-pass filter + downsampling using scipy
  • datestamp2datetime: ISO 8601 datestamp parsing to Python datetime
  • rehydrateJSONNanNull: Sentinel string replacement for NaN/Infinity in JSON
  • unwrapTableCellContent: Recursive unwrapping of nested lists (MATLAB cell arrays)

New Validator Framework (ndi.validators)

Comprehensive validation functions mirroring MATLAB's custom validators:

  • ID validation: mustBeID (33-char format with underscore at position 17)
  • Type validators: mustBeNumericClass, mustBeClassnameOfType, is_ndarray
  • Collection validators: mustBeCellArrayOfClass, mustBeCellArrayOfNonEmptyCharacterArrays, mustBeCellArrayOfNdiSessions
  • Field/column validators: mustHaveFields, mustHaveRequiredColumns
  • Format validators: mustBeEpochInput, mustBeTextLike, mustMatchRegex, is_iso8601

Strict MATLAB Naming Enforcement

Renamed functions to match MATLAB source exactly (no snake_case translation):

  • find_epoch_nodefindepochnode
  • spikes_for_probespikesForProbe
  • clear_cacheresetepochtable
  • save_to_filesavetofile
  • load_from_fileloadfromfile
  • init_probe_type_mapinitProbeTypeMap
  • get_probe_type_mapgetProbeTypeMap

Updated PYTHON_PORTING_GUIDE.md to emphasize that MATLAB function names are the source of truth and must not be translated to PEP 8 conventions.

Implementation Details

  • All utility functions use @pydantic.validate_call for robust input validation
  • Validators use Annotated[type, pydantic.Field(...)] for constraints (e.g., gt=0, ge=0)
  • Hex formatting utilities (_format_chunk, _print_header) are shared between hexDiff and hexDump
  • File I/O functions handle edge cases (empty files, byte offset validation)
  • Timeseries downsampling uses scipy's Chebyshev Type I filter with 4th-order cutoff
  • All docstrings include MATLAB equivalents for cross-reference

Test Updates

Updated test files to use new function names:

  • test_batch_e.py: Updated find_epoch_node references
  • test_batch_a.py: Updated save_to_file/load_from_file references
  • test_probe.py: Updated probe type map function names
  • test_element.py: Updated element function names

Documentation Updates

  • MATLAB_MAPPING.md: Corrected probe function mappings and soft-delete API entries
  • PYTHON_PORTING_GUIDE.md: Added section 4a on reusable validators and clarified naming rules with verification guidance

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp

claude added 7 commits March 11, 2026 13:19
MATLAB function names are the canonical reference. Renames:
- save_to_file → savetofile (epochprobemap_daqsystem)
- load_from_file → loadfromfile (epochprobemap_daqsystem)
- clear_cache → resetepochtable (epochset)
- find_epoch_node → findepochnode (epoch/functions)
- init_probe_type_map → initProbeTypeMap (probe)
- get_probe_type_map → getProbeTypeMap (probe)
- spikes_for_probe → spikesForProbe (element/functions)

Also adds probestring() method to Probe class (exists in MATLAB
probe.m but was missing from Python port), and updates
PYTHON_PORTING_GUIDE.md with the "MATLAB function names are the
source of truth" instruction.

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
- Add Namespace Coverage Status section to PYTHON_PORTING_GUIDE.md with
  verified per-submodule coverage table for ndi.cloud.api (100% across
  datasets, documents, files, users, compute, auth)
- Fix MATLAB_MAPPING.md: undeleteDataset, listDeletedDatasets, and
  listDeletedDocuments exist in MATLAB (not Python-only)
- Fix MATLAB_MAPPING.md: duplicateDocuments is ported (internal.py)

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
…TLAB

ndi.validators: All 11 MATLAB argument-block validators ported 1:1
- mustBeCellArrayOfClass, mustBeCellArrayOfNdiSessions,
  mustBeCellArrayOfNonEmptyCharacterArrays, mustBeClassnameOfType,
  mustBeEpochInput, mustBeID, mustBeNumericClass, mustBeTextLike,
  mustHaveFields, mustHaveRequiredColumns, mustMatchRegex

ndi.util: All 8 portable utility functions ported 1:1
- datestamp2datetime, downsampleTimeseries, hexDiff, hexDiffBytes,
  getHexDiffFromFileObj, hexDump, rehydrateJSONNanNull,
  unwrapTableCellContent
- GUI-only (choosefile, choosefileordir) and MATLAB-specific
  (toolboxdir) intentionally skipped

Also updates MATLAB_MAPPING.md and PYTHON_PORTING_GUIDE.md with
coverage tables for both namespaces.

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
Per PYTHON_PORTING_GUIDE Rule 4, all public-facing API functions must
use @pydantic.validate_call to mirror MATLAB arguments blocks. Replaces
manual isinstance checks with Pydantic validation. Uses Annotated +
pydantic.Field for constraints (ge=0, gt=0) and
arbitrary_types_allowed=True where numpy/IO types are needed.

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
…uide

Create ndi.validators.is_ndarray and ndi.validators.is_iso8601 as
reusable validation functions following the MATLAB +ndi/+validators/
pattern. Update PYTHON_PORTING_GUIDE Section 4 with new subsection 4a
documenting the requirement to centralise custom validators in
ndi/validators/ rather than writing inline checks.

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
Add Section 5 (Code Style & Linting) to PYTHON_PORTING_GUIDE requiring
black --check before every commit. Run black to fix the 12 files that
were out of compliance.

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
Add ruff check requirement alongside black in Section 5 of
PYTHON_PORTING_GUIDE. Fix unused `math` import in
unwrapTableCellContent.py caught by ruff.

https://claude.ai/code/session_016oPH9EoxCLcsUSTpgN9iZp
@stevevanhooser stevevanhooser merged commit 5c9b944 into main Mar 11, 2026
4 checks passed
@stevevanhooser stevevanhooser deleted the claude/update-ndi-porting-guide-U5HRa branch March 14, 2026 16:32
Sign up for free to 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.

2 participants