Summary
src/easyreflectometry/data/data_store.py:59-72, two independent breakages:
def as_dict(self, skip: list = []) -> dict:
this_dict = super(DataStore, self).as_dict(self, skip=skip) # passes self twice
this_dict['items'] = [...]
# no return -> always None
@classmethod
def from_dict(cls, d):
items = d['items']
del d['items']
obj = cls.from_dict(d) # calls itself -> infinite recursion
Also a mutable default argument (skip: list = []).
DataStore/ProjectData appear to be legacy — Project manages its own _experiments dict and bespoke _as_dict_add_experiments — yet the classes remain exported and entirely untested (which is why both bugs survive).
Suggested fix
Either delete the dead classes or fix (super().as_dict(skip=skip) + return; super().from_dict(d)) and add round-trip tests. Related fragility in the live path: _as_dict_add_experiments (project.py:896-905) writes experiments_models/experiments_names only inside if experiment.xe is not None:, while _from_dict_extract_experiments (:950-962) reads them (and [key][3]) unconditionally — masked today only because DataSet1D always materializes xe.
Found during deep code review (DEEP_ANALYSIS.md §5.2, §5.3, §5.8).
Summary
src/easyreflectometry/data/data_store.py:59-72, two independent breakages:Also a mutable default argument (
skip: list = []).DataStore/ProjectDataappear to be legacy —Projectmanages its own_experimentsdict and bespoke_as_dict_add_experiments— yet the classes remain exported and entirely untested (which is why both bugs survive).Suggested fix
Either delete the dead classes or fix (
super().as_dict(skip=skip)+return;super().from_dict(d)) and add round-trip tests. Related fragility in the live path:_as_dict_add_experiments(project.py:896-905) writesexperiments_models/experiments_namesonly insideif experiment.xe is not None:, while_from_dict_extract_experiments(:950-962) reads them (and[key][3]) unconditionally — masked today only becauseDataSet1Dalways materializesxe.Found during deep code review (DEEP_ANALYSIS.md §5.2, §5.3, §5.8).