Source code for hed.tools.bids.bids_sidecar_file
"""Container for a BIDS sidecar file."""
import os
import io
import json
from hed.models.sidecar import Sidecar
from hed.tools.bids.bids_file import BidsFile
[docs]
class BidsSidecarFile(BidsFile):
"""A BIDS sidecar file."""
[docs]
def __init__(self, file_path):
"""Constructs a bids sidecar from a file.
Parameters:
file_path (str): The real path of the sidecar.
"""
super().__init__(file_path)
[docs]
def is_sidecar_for(self, obj):
"""Return True if this is a sidecar for obj.
Parameters:
obj (BidsFile): A BidsFile object to check.
Returns:
bool: True if this is a BIDS parent of obj and False otherwise.
Notes:
- A sidecar is a sidecar for itself.
"""
if obj.suffix != self.suffix:
return False
elif os.path.dirname(self.file_path) != os.path.commonpath([obj.file_path, self.file_path]):
return False
for key, item in self.entity_dict.items():
if key not in obj.entity_dict or obj.entity_dict[key] != item:
return False
return True
[docs]
def set_contents(self, content_info=None, name="unknown", overwrite=False):
"""Set the contents of the sidecar.
Parameters:
content_info (dict, or None): If None, create a Sidecar from the object's file-path.
name (str): The name of the sidecar.
overwrite (bool): If True, overwrite contents if already set.
Notes:
- The handling of content_info is as follows:
- None: This object's file_path is used.
- dict: This is interpreted as a JSON dictionary.
"""
if not overwrite and self.contents:
return
try:
if not content_info:
self._contents = Sidecar(self.file_path, name=os.path.basename(self.file_path))
else:
self._contents = Sidecar(io.StringIO(json.dumps(content_info)), name=name)
self.has_hed = self.is_hed(self.contents.loaded_dict)
except Exception:
self._contents = None
self.has_hed = False
[docs]
@staticmethod
def is_hed(json_dict):
"""Return True if the json has HED.
Parameters:
json_dict (dict): A dictionary representing a JSON file or merged file.
Returns:
bool: True if the dictionary has HED or HED_assembled as a first or second-level key.
"""
if not json_dict or not isinstance(json_dict, dict):
return False
json_keys = json_dict.keys()
if "HED" in json_keys or "HED_assembled" in json_keys:
return True
for _key, value in json_dict.items():
if not isinstance(value, dict):
continue
val_keys = value.keys()
if "HED" in val_keys or "HED_assembled" in val_keys:
return True
return False
[docs]
@staticmethod
def merge_sidecar_list(sidecar_list, name="merged_sidecar.json"):
"""Merge a list of sidecars into a single sidecar.
Parameters:
sidecar_list (list): A list of Sidecar objects.
name (str): The name of the merged sidecar.
Returns:
Union[Sidecar, None]: A sidecar constructed from the merged list.
"""
merged_dict = {}
for sidecar in sidecar_list:
if not sidecar:
continue
merged_dict.update(sidecar.contents.loaded_dict)
if merged_dict:
return Sidecar(files=io.StringIO(json.dumps(merged_dict)), name=name)
return None