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
32 changes: 28 additions & 4 deletions src/did/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,22 @@ def _reset_file_info(self):
datastructures.empty_struct("name", "locations")
)

@staticmethod
def _normalize_file_info(file_info):
"""Normalize file_info to a list.

MATLAB's jsonencode converts single-element cell arrays to scalars,
so file_info may arrive as a bare dict instead of a list.
"""
if isinstance(file_info, dict):
return [file_info] if file_info else []
if not isinstance(file_info, list):
return []
return file_info

def is_in_file_list(self, filename):
file_info = self.document_properties.get("files", {}).get("file_info", [])
if isinstance(file_info, dict) and not file_info:
file_info = []
file_info = self._normalize_file_info(file_info)

for i, info in enumerate(file_info):
if info.get("name") == filename:
Expand All @@ -71,8 +83,7 @@ def add_file(self, filename, location):
if "file_info" not in files_prop:
files_prop["file_info"] = []

if isinstance(files_prop["file_info"], dict) and not files_prop["file_info"]:
files_prop["file_info"] = []
files_prop["file_info"] = self._normalize_file_info(files_prop["file_info"])

file_info_list = files_prop["file_info"]

Expand All @@ -82,6 +93,11 @@ def add_file(self, filename, location):
file_info_list.append(new_info)

def remove_file(self, filename):
files_prop = self.document_properties.get("files")
if files_prop is not None:
files_prop["file_info"] = self._normalize_file_info(
files_prop.get("file_info", [])
)
is_in, _, index = self.is_in_file_list(filename)
if is_in:
del self.document_properties["files"]["file_info"][index]
Expand Down Expand Up @@ -138,7 +154,14 @@ def _normalize_to_document_class(data):
}
return data

def _ensure_depends_on_list(self):
"""Normalize depends_on to a list if it is a bare dict."""
dep = self.document_properties.get("depends_on")
if isinstance(dep, dict):
self.document_properties["depends_on"] = [dep]

def dependency_value(self, dependency_name, error_if_not_found=True):
self._ensure_depends_on_list()
if "depends_on" in self.document_properties:
for dep in self.document_properties["depends_on"]:
if dep.get("name") == dependency_name:
Expand All @@ -149,6 +172,7 @@ def dependency_value(self, dependency_name, error_if_not_found=True):
return None

def set_dependency_value(self, dependency_name, value, error_if_not_found=True):
self._ensure_depends_on_list()
if "depends_on" in self.document_properties:
for dep in self.document_properties["depends_on"]:
if dep.get("name") == dependency_name:
Expand Down
7 changes: 7 additions & 0 deletions src/did/implementations/doc2sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ def _get_superclass_str(doc_props):
def _serialize_depends_on(doc_props):
"""Serialize depends_on matching MATLAB's format: 'name,value;name,value;'"""
depends_on = doc_props.get("depends_on", [])
if isinstance(depends_on, dict):
depends_on = [depends_on]
if not depends_on or not isinstance(depends_on, list):
return ""

Expand Down Expand Up @@ -153,6 +155,11 @@ def doc_to_sql(doc):
"""
doc_props = doc.document_properties

# Normalize bare dict depends_on to a list (MATLAB's jsonencode converts
# single-element cell arrays to scalars).
if isinstance(doc_props.get("depends_on"), dict):
doc_props["depends_on"] = [doc_props["depends_on"]]

# Build the 'meta' table
meta = {"name": "meta", "columns": []}

Expand Down
18 changes: 17 additions & 1 deletion src/did/implementations/sqlitedb.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,19 @@ def _matlab_compatible_props(props):
if isinstance(dep, list) and len(dep) == 1:
props["depends_on"] = dep[0]

# Unwrap files.file_info
files = props.get("files")
if isinstance(files, dict):
fi = files.get("file_info")
if isinstance(fi, list):
if len(fi) == 1:
files["file_info"] = fi[0]

return props

@staticmethod
def _normalize_loaded_props(props):
"""Ensure superclasses and depends_on are always lists.
"""Ensure superclasses, depends_on, file_info, and locations are always lists.

Inverse of _matlab_compatible_props. Mutates and returns props.
"""
Expand All @@ -268,6 +276,14 @@ def _normalize_loaded_props(props):
if dep is not None and not isinstance(dep, list):
props["depends_on"] = [dep]

# Re-wrap files.file_info (but not locations, which may be a bare dict
# from add_file in the Python API)
files = props.get("files")
if isinstance(files, dict):
fi = files.get("file_info")
if isinstance(fi, dict):
files["file_info"] = [fi]

return props

def _do_add_doc(self, document_obj, branch_id, **kwargs):
Expand Down
Loading