From a300139fdc27f1943f99f6665190362eced9898c Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 25 Mar 2026 16:49:47 +0000 Subject: [PATCH 1/2] Fix _get_superclass_str to handle bare dict superclasses MATLAB's jsonencode unwraps single-element cell arrays into scalar values, so documents with a single superclass arrive as a bare dict instead of a list. This caused _get_superclass_str to return an empty string, breaking isa() queries for those documents. Normalize bare dict superclasses to single-element lists before processing, in both the top-level and document_class code paths. Fixes: Waltham-Data-Science/NDI-python#52 https://claude.ai/code/session_01W4C2GYKchUodXEVKnnM66T --- src/did/implementations/doc2sql.py | 9 +++++- tests/test_doc2sql_superclass.py | 49 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/test_doc2sql_superclass.py diff --git a/src/did/implementations/doc2sql.py b/src/did/implementations/doc2sql.py index 72ef97a..68d27a6 100644 --- a/src/did/implementations/doc2sql.py +++ b/src/did/implementations/doc2sql.py @@ -51,8 +51,12 @@ def _get_superclass_str(doc_props): For DID-python style ["base", "demoA"], use directly. """ # DID-python schema format: top-level 'superclasses' list of strings - if "superclasses" in doc_props and isinstance(doc_props["superclasses"], list): + if "superclasses" in doc_props and isinstance(doc_props["superclasses"], (list, dict)): superclasses = doc_props["superclasses"] + # Normalize bare dict to a single-element list (MATLAB's jsonencode + # unwraps single-element cell arrays into scalars). + if isinstance(superclasses, dict): + superclasses = [superclasses] if not superclasses: return "" names = [] @@ -70,6 +74,9 @@ def _get_superclass_str(doc_props): # NDI / MATLAB format: document_class.superclasses superclasses = get_field(doc_props, ["document_class.superclasses"]) + # Normalize bare dict (single superclass from MATLAB's jsonencode) + if isinstance(superclasses, dict): + superclasses = [superclasses] if isinstance(superclasses, list): names = [] for sc in superclasses: diff --git a/tests/test_doc2sql_superclass.py b/tests/test_doc2sql_superclass.py new file mode 100644 index 0000000..3c65227 --- /dev/null +++ b/tests/test_doc2sql_superclass.py @@ -0,0 +1,49 @@ +"""Tests for _get_superclass_str handling of bare dict superclasses. + +Regression tests for https://github.com/Waltham-Data-Science/NDI-python/issues/52 +""" + +from did.implementations.doc2sql import _get_superclass_str + + +class TestGetSuperclassStrBareDict: + """Bare dict superclasses (from MATLAB's jsonencode) should be handled.""" + + def test_top_level_bare_dict(self): + doc_props = { + "superclasses": {"definition": "$NDIDOCUMENTPATH/base.json"} + } + assert _get_superclass_str(doc_props) == "base" + + def test_top_level_list_single(self): + doc_props = { + "superclasses": [{"definition": "$NDIDOCUMENTPATH/base.json"}] + } + assert _get_superclass_str(doc_props) == "base" + + def test_document_class_bare_dict(self): + doc_props = { + "document_class": { + "superclasses": {"definition": "$NDIDOCUMENTPATH/base.json"} + } + } + assert _get_superclass_str(doc_props) == "base" + + def test_document_class_list(self): + doc_props = { + "document_class": { + "superclasses": [ + {"definition": "$NDIDOCUMENTPATH/base.json"}, + {"definition": "$NDIDOCUMENTPATH/demoA.json"}, + ] + } + } + assert _get_superclass_str(doc_props) == "base, demoA" + + def test_empty_superclasses(self): + doc_props = {"superclasses": []} + assert _get_superclass_str(doc_props) == "" + + def test_no_superclasses(self): + doc_props = {} + assert _get_superclass_str(doc_props) == "" From 4d08393ea96b5d686a0e95fd59db5511ccb55aab Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 25 Mar 2026 16:53:37 +0000 Subject: [PATCH 2/2] Apply black formatting to doc2sql.py and test file https://claude.ai/code/session_01W4C2GYKchUodXEVKnnM66T --- src/did/implementations/doc2sql.py | 4 +++- tests/test_doc2sql_superclass.py | 8 ++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/did/implementations/doc2sql.py b/src/did/implementations/doc2sql.py index 68d27a6..9b2dfb7 100644 --- a/src/did/implementations/doc2sql.py +++ b/src/did/implementations/doc2sql.py @@ -51,7 +51,9 @@ def _get_superclass_str(doc_props): For DID-python style ["base", "demoA"], use directly. """ # DID-python schema format: top-level 'superclasses' list of strings - if "superclasses" in doc_props and isinstance(doc_props["superclasses"], (list, dict)): + if "superclasses" in doc_props and isinstance( + doc_props["superclasses"], (list, dict) + ): superclasses = doc_props["superclasses"] # Normalize bare dict to a single-element list (MATLAB's jsonencode # unwraps single-element cell arrays into scalars). diff --git a/tests/test_doc2sql_superclass.py b/tests/test_doc2sql_superclass.py index 3c65227..ec20b01 100644 --- a/tests/test_doc2sql_superclass.py +++ b/tests/test_doc2sql_superclass.py @@ -10,15 +10,11 @@ class TestGetSuperclassStrBareDict: """Bare dict superclasses (from MATLAB's jsonencode) should be handled.""" def test_top_level_bare_dict(self): - doc_props = { - "superclasses": {"definition": "$NDIDOCUMENTPATH/base.json"} - } + doc_props = {"superclasses": {"definition": "$NDIDOCUMENTPATH/base.json"}} assert _get_superclass_str(doc_props) == "base" def test_top_level_list_single(self): - doc_props = { - "superclasses": [{"definition": "$NDIDOCUMENTPATH/base.json"}] - } + doc_props = {"superclasses": [{"definition": "$NDIDOCUMENTPATH/base.json"}]} assert _get_superclass_str(doc_props) == "base" def test_document_class_bare_dict(self):