Skip to content

Commit

Permalink
Do not respect application overrides when saving the base class. (#7)
Browse files Browse the repository at this point in the history
* Do not respect application overrides when saving the base class.

This is more predictable and avoids multiple calls to overriding methods when
traversing the class hierarchy via saveObject/readObject.
  • Loading branch information
LTLA authored Oct 23, 2024
1 parent 773a21a commit d292157
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 16 deletions.
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ python_requires = >=3.8
# For more information, check out https://semver.org/.
install_requires =
importlib-metadata; python_version<"3.8"
dolomite-base>=0.2.4
dolomite-matrix>=0.2.1
dolomite-base>=0.3.0
dolomite-matrix>=0.3.0
dolomite-ranges>=0.1.3
summarizedexperiment>=0.4.4

Expand Down
10 changes: 8 additions & 2 deletions src/dolomite_se/read_ranged_summarized_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import dolomite_base as dl
from dolomite_base.read_object import read_object_registry
from summarizedexperiment import RangedSummarizedExperiment
from .read_summarized_experiment import read_summarized_experiment

read_object_registry["ranged_summarized_experiment"] = (
"dolomite_se.read_ranged_summarized_experiment"
Expand Down Expand Up @@ -34,8 +35,13 @@ def read_ranged_summarized_experiment(
:py:class:`~summarizedexperiment.RangedSummarizedExperiment.RangedSummarizedExperiment`
with file-backed arrays in the assays.
"""
metadata["type"] = "summarized_experiment"
se = dl.alt_read_object(path, metadata=metadata, **kwargs)

# We don't try to respect application overrides when loading the base
# instance. Application developers should just pretend that we copied the
# code from read_summarized_experiment, rather than trying to inject in
# custom code at this point, which gets too complicated - see the
# associated commentary for save_ranged_summarized_experiment.
se = read_summarized_experiment(path, metadata=metadata, **kwargs)

rse = RangedSummarizedExperiment(
assays=se.get_assays(),
Expand Down
33 changes: 21 additions & 12 deletions src/dolomite_se/save_ranged_summarized_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dolomite_base as dl
from summarizedexperiment import RangedSummarizedExperiment, SummarizedExperiment
from .save_summarized_experiment import save_summarized_experiment


@dl.save_object.register
Expand Down Expand Up @@ -46,25 +47,33 @@ def save_ranged_summarized_experiment(
if assay_args is None:
assay_args = {}

# convert to SE
_se = SummarizedExperiment(
assays=x.get_assays(),
row_data=x.get_row_data(),
column_data=x.get_column_data(),
row_names=x.get_row_names(),
column_names=x.get_column_names(),
metadata=x.get_metadata(),
)
dl.alt_save_object(
_se, path, data_frame_args=data_frame_args, assay_args=assay_args, **kwargs
# We do not respond to application overrides for the SummarizedExperiment
# base class. Developers should just pretend that method copied all of the
# code from the save_SE function; this call is just an implementation
# detail, nothing special is done about the fact that it's the base class.
#
# This simplifies the dispatch and ensures that an override is only called
# once. Consider the alternative - namely, casting to the next subclass and
# then calling alt_save_object to respect the override. This would call
# the override's SE method repeatedly for every step from the subclass to
# SE. If the override's behavior is not idempotent, we have a problem.
#
# So, if an application wants to set an override for all SEs, then it
# should register an SE method for alt_save_object and then call it. If the
# override is slightly different for particular SE subclasses, developers
# should just duplicate the common override logic in the alt_save_object
# methods for affected subclasses, rather than expecting some injection of
# the overriding method into the save_object dispatch hierarchy.
save_summarized_experiment(
x, path, data_frame_args=data_frame_args, assay_args=assay_args, **kwargs
)

# save row_ranges
_ranges = x.get_row_ranges()
if _ranges is not None:
dl.alt_save_object(_ranges, path=os.path.join(path, "row_ranges"), **kwargs)

# Modify OBJECT
# modify OBJECT
_info = dl.read_object_file(path)
_info["ranged_summarized_experiment"] = {"version": "1.0"}
dl.save_object_file(path, "ranged_summarized_experiment", _info)
Expand Down

0 comments on commit d292157

Please sign in to comment.