dcnum 0.25.10__tar.gz → 0.25.11__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dcnum might be problematic. Click here for more details.
- {dcnum-0.25.10 → dcnum-0.25.11}/CHANGELOG +5 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/PKG-INFO +3 -3
- {dcnum-0.25.10 → dcnum-0.25.11}/README.rst +2 -2
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/_version.py +2 -2
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/logic/ctrl.py +3 -11
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/__init__.py +4 -1
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/hdf5_data.py +37 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/write/writer.py +16 -1
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum.egg-info/PKG-INFO +3 -3
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_logic_pipeline.py +21 -5
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_hdf5_basins.py +61 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/.github/workflows/check.yml +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/.github/workflows/deploy_pypi.yml +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/.gitignore +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/.readthedocs.yml +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/LICENSE +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/benchmark/.gitignore +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/benchmark/Readme.md +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/benchmark/benchmark.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/benchmark/bm_write_deque_writer_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/benchmark/bm_write_queue_collector_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/docs/.gitignore +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/docs/conf.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/docs/extensions/github_changelog.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/docs/index.rst +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/docs/requirements.txt +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/docs/sec_design.rst +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/pyproject.toml +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/setup.cfg +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/event_extractor_manager_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_background/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_background/base.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_background/bg_copy.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_background/bg_roll_median.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_background/bg_sparse_median.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_brightness/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_brightness/bright_all.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_brightness/common.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_contour/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_contour/contour.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_contour/moments.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_contour/volume.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_texture/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_texture/common.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/feat_texture/tex_all.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/gate.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/feat/queue_event_extractor.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/logic/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/logic/job.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/logic/json_encoder.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/meta/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/meta/paths.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/meta/ppid.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/os_env_st.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/cache.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/const.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/detect_flicker.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/hdf5_concat.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/read/mapped.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_thresh.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/segm_torch_base.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/segm_torch_mpo.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/segm_torch_sto.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/torch_model.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/torch_postproc.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segm_torch/torch_preproc.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segmenter.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segmenter_manager_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segmenter_mpo.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/segm/segmenter_sto.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/write/__init__.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/write/deque_writer_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum/write/queue_collector_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum.egg-info/SOURCES.txt +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum.egg-info/dependency_links.txt +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum.egg-info/requires.txt +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/src/dcnum.egg-info/top_level.txt +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/conftest.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_cytoshot_extended-moments-features.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_cytoshot_full-features_2023.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_cytoshot_full-features_2024.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_cytoshot_full-features_legacy_allev_2023.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_shapein_empty.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_shapein_raw-with-variable-length-logs.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/segm-torch-model_unet-dcnum-test_g1_910c2.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/segm-torch-model_unet-dcnum-test_g2_17ec6.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/data/segm-torch-test-data_unet-dcnum-test_g1_910c2.zip +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/helper_methods.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/requirements.txt +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_background_base.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_background_bg_copy.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_background_bg_roll_median.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_background_bg_sparsemed.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_brightness.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_event_extractor_manager.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_gate.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_haralick.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_moments_based.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_moments_based_extended.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_feat_volume.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_init.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_logic_job.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_logic_join.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_logic_json.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_paths.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_ppid_base.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_ppid_bg.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_ppid_data.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_ppid_feat.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_ppid_gate.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_meta_ppid_segm.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_basin.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_concat_hdf5.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_detect_flicker.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_hdf5.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_hdf5_concat.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_read_hdf5_index_mapping.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_base.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_mpo.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_no_mask_proc.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_sto.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_thresh.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_torch.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_segm_torch_preproc.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_write_deque_writer_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_write_queue_collector_thread.py +0 -0
- {dcnum-0.25.10 → dcnum-0.25.11}/tests/test_write_writer.py +0 -0
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
0.25.11
|
|
2
|
+
- enh: align measurement identifier computation with that of dclab
|
|
3
|
+
- enh: new `get_measurement_identifier` method
|
|
4
|
+
- enh: allow to optionally store measurement identifier in basin metadata
|
|
5
|
+
- enh: measurement identifier check for basin data
|
|
1
6
|
0.25.10
|
|
2
7
|
- fix: search for validation strings in logs did not use re.MULTILINE
|
|
3
8
|
- enh: allow to validate torch model applicability based on meta values
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dcnum
|
|
3
|
-
Version: 0.25.
|
|
3
|
+
Version: 0.25.11
|
|
4
4
|
Summary: numerics toolbox for imaging deformability cytometry
|
|
5
5
|
Author: Maximilian Schlögel, Paul Müller, Raghava Alajangi
|
|
6
6
|
Maintainer-email: Paul Müller <dev@craban.de>
|
|
@@ -55,12 +55,12 @@ For more options, please check out the `documentation
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
.. |dcnum| image:: https://raw.github.com/DC-analysis/dcnum/
|
|
58
|
+
.. |dcnum| image:: https://raw.github.com/DC-analysis/dcnum/main/docs/logo/dcnum.png
|
|
59
59
|
.. |PyPI Version| image:: https://img.shields.io/pypi/v/dcnum.svg
|
|
60
60
|
:target: https://pypi.python.org/pypi/dcnum
|
|
61
61
|
.. |Build Status| image:: https://img.shields.io/github/actions/workflow/status/DC-analysis/dcnum/check.yml
|
|
62
62
|
:target: https://github.com/DC-analysis/dcnum/actions?query=workflow%3AChecks
|
|
63
|
-
.. |Coverage Status| image:: https://img.shields.io/codecov/c/github/DC-analysis/dcnum
|
|
63
|
+
.. |Coverage Status| image:: https://img.shields.io/codecov/c/github/DC-analysis/dcnum
|
|
64
64
|
:target: https://codecov.io/gh/DC-analysis/dcnum
|
|
65
65
|
.. |Docs Status| image:: https://readthedocs.org/projects/dcnum/badge/?version=latest
|
|
66
66
|
:target: https://readthedocs.org/projects/dcnum/builds/
|
|
@@ -24,12 +24,12 @@ For more options, please check out the `documentation
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
.. |dcnum| image:: https://raw.github.com/DC-analysis/dcnum/
|
|
27
|
+
.. |dcnum| image:: https://raw.github.com/DC-analysis/dcnum/main/docs/logo/dcnum.png
|
|
28
28
|
.. |PyPI Version| image:: https://img.shields.io/pypi/v/dcnum.svg
|
|
29
29
|
:target: https://pypi.python.org/pypi/dcnum
|
|
30
30
|
.. |Build Status| image:: https://img.shields.io/github/actions/workflow/status/DC-analysis/dcnum/check.yml
|
|
31
31
|
:target: https://github.com/DC-analysis/dcnum/actions?query=workflow%3AChecks
|
|
32
|
-
.. |Coverage Status| image:: https://img.shields.io/codecov/c/github/DC-analysis/dcnum
|
|
32
|
+
.. |Coverage Status| image:: https://img.shields.io/codecov/c/github/DC-analysis/dcnum
|
|
33
33
|
:target: https://codecov.io/gh/DC-analysis/dcnum
|
|
34
34
|
.. |Docs Status| image:: https://readthedocs.org/projects/dcnum/badge/?version=latest
|
|
35
35
|
:target: https://readthedocs.org/projects/dcnum/builds/
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import collections
|
|
2
2
|
import datetime
|
|
3
|
-
import hashlib
|
|
4
3
|
import importlib
|
|
5
4
|
import json
|
|
6
5
|
import logging
|
|
@@ -24,7 +23,7 @@ from ..feat import gate
|
|
|
24
23
|
from ..feat import EventExtractorManagerThread
|
|
25
24
|
from ..segm import SegmenterManagerThread, get_available_segmenters
|
|
26
25
|
from ..meta import ppid
|
|
27
|
-
from ..read import HDF5Data, get_mapping_indices
|
|
26
|
+
from ..read import HDF5Data, get_measurement_identifier, get_mapping_indices
|
|
28
27
|
from .._version import version, version_tuple
|
|
29
28
|
from ..write import (
|
|
30
29
|
DequeWriterThread, HDF5Writer, QueueCollectorThread, copy_features,
|
|
@@ -453,15 +452,7 @@ class DCNumJobRunner(threading.Thread):
|
|
|
453
452
|
# segmentation did actually take place.
|
|
454
453
|
mid_ap = f"dcn-{self.pphash[:7]}"
|
|
455
454
|
# This is the current measurement identifier
|
|
456
|
-
mid_cur = hw.h5
|
|
457
|
-
if not mid_cur:
|
|
458
|
-
# Compute a measurement identifier from the metadata
|
|
459
|
-
m_time = hw.h5.attrs.get("experiment:time", "none")
|
|
460
|
-
m_date = hw.h5.attrs.get("experiment:date", "none")
|
|
461
|
-
m_sid = hw.h5.attrs.get("setup:identifier", "none")
|
|
462
|
-
hasher = hashlib.md5(
|
|
463
|
-
f"{m_time}_{m_date}_{m_sid}".encode("utf-8"))
|
|
464
|
-
mid_cur = str(uuid.UUID(hex=hasher.hexdigest()))
|
|
455
|
+
mid_cur = get_measurement_identifier(hw.h5)
|
|
465
456
|
# The new measurement identifier is a combination of both.
|
|
466
457
|
mid_new = f"{mid_cur}_{mid_ap}" if mid_cur else mid_ap
|
|
467
458
|
hw.h5.attrs["experiment:run identifier"] = mid_new
|
|
@@ -666,6 +657,7 @@ class DCNumJobRunner(threading.Thread):
|
|
|
666
657
|
mapping=basinmap0,
|
|
667
658
|
paths=paths,
|
|
668
659
|
description=f"Created with dcnum {version}",
|
|
660
|
+
identifier=get_measurement_identifier(hin),
|
|
669
661
|
)
|
|
670
662
|
self._progress_bn += 1 / len(feats_raw)
|
|
671
663
|
t_tot = time.perf_counter() - t0
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
from .cache import md5sum
|
|
3
3
|
from .const import PROTECTED_FEATURES
|
|
4
4
|
from .detect_flicker import detect_flickering
|
|
5
|
-
from .hdf5_data import
|
|
5
|
+
from .hdf5_data import (
|
|
6
|
+
HDF5Data, HDF5ImageCache, get_measurement_identifier,
|
|
7
|
+
BasinIdentifierMismatchError
|
|
8
|
+
)
|
|
6
9
|
from .hdf5_concat import concatenated_hdf5_data
|
|
7
10
|
from .mapped import get_mapping_indices, get_mapped_object
|
|
@@ -16,6 +16,10 @@ from .const import PROTECTED_FEATURES
|
|
|
16
16
|
from .mapped import get_mapped_object, get_mapping_indices
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
class BasinIdentifierMismatchError(BaseException):
|
|
20
|
+
"""Used when basin identifiers do not match"""
|
|
21
|
+
|
|
22
|
+
|
|
19
23
|
class HDF5Data:
|
|
20
24
|
"""HDF5 (.rtdc) input file data instance"""
|
|
21
25
|
def __init__(self,
|
|
@@ -473,6 +477,12 @@ class HDF5Data:
|
|
|
473
477
|
features = []
|
|
474
478
|
else:
|
|
475
479
|
h5 = h5py.File(path, "r")
|
|
480
|
+
# verify that the basin was identified correctly
|
|
481
|
+
if ((id_exp := bn_dict.get("identifier")) is not None
|
|
482
|
+
and (id_act := get_measurement_identifier(h5)) != id_exp):
|
|
483
|
+
raise BasinIdentifierMismatchError(
|
|
484
|
+
f"The basin '{path}' with identifier '{id_act}' "
|
|
485
|
+
f"does not match the expected identifier '{id_exp}'")
|
|
476
486
|
h5group = h5["events"]
|
|
477
487
|
# features defined in the basin
|
|
478
488
|
features = bn_dict.get("features")
|
|
@@ -560,3 +570,30 @@ def concatenated_hdf5_data(*args, **kwargs):
|
|
|
560
570
|
DeprecationWarning)
|
|
561
571
|
from . import hdf5_concat
|
|
562
572
|
return hdf5_concat.concatenated_hdf5_data(*args, **kwargs)
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def get_measurement_identifier(h5: h5py.Group) -> str | None:
|
|
576
|
+
"""Return the measurement identifier for the given H5File object
|
|
577
|
+
|
|
578
|
+
The basin identifier is taken from the HDF5 attributes. If the
|
|
579
|
+
"experiment:run identifier" attribute is not set, it is
|
|
580
|
+
computed from the HDF5 attributes "experiment:time",
|
|
581
|
+
"experiment:date", and "setup:identifier".
|
|
582
|
+
|
|
583
|
+
If the measurement identifier cannot be found or computed,
|
|
584
|
+
return None.
|
|
585
|
+
"""
|
|
586
|
+
# This is the current measurement identifier
|
|
587
|
+
mid = h5.attrs.get("experiment:run identifier")
|
|
588
|
+
if not mid:
|
|
589
|
+
# Compute a measurement identifier from the metadata
|
|
590
|
+
m_time = h5.attrs.get("experiment:time", None) or None
|
|
591
|
+
m_date = h5.attrs.get("experiment:date", None) or None
|
|
592
|
+
m_sid = h5.attrs.get("setup:identifier", None) or None
|
|
593
|
+
if None not in [m_time, m_date, m_sid]:
|
|
594
|
+
# Only compute an identifier if all of the above
|
|
595
|
+
# are defined.
|
|
596
|
+
hasher = hashlib.md5(
|
|
597
|
+
f"{m_time}_{m_date}_{m_sid}".encode("utf-8"))
|
|
598
|
+
mid = str(uuid.UUID(hex=hasher.hexdigest()))
|
|
599
|
+
return mid
|
|
@@ -8,7 +8,7 @@ import h5py
|
|
|
8
8
|
import hdf5plugin
|
|
9
9
|
import numpy as np
|
|
10
10
|
|
|
11
|
-
from ..read import HDF5Data
|
|
11
|
+
from ..read import HDF5Data, get_measurement_identifier
|
|
12
12
|
from .._version import version
|
|
13
13
|
|
|
14
14
|
|
|
@@ -157,6 +157,7 @@ class HDF5Writer:
|
|
|
157
157
|
description: str | None = None,
|
|
158
158
|
mapping: np.ndarray = None,
|
|
159
159
|
internal_data: Dict | None = None,
|
|
160
|
+
identifier: str | None = None,
|
|
160
161
|
):
|
|
161
162
|
"""Write an HDF5-based file basin
|
|
162
163
|
|
|
@@ -177,6 +178,10 @@ class HDF5Writer:
|
|
|
177
178
|
internal_data: dict of ndarrays
|
|
178
179
|
internal basin data to store; If this is set, then `features`
|
|
179
180
|
and `paths` must be set to `None`.
|
|
181
|
+
identifier: str
|
|
182
|
+
the measurement identifier of the basin as computed by
|
|
183
|
+
the :func:`~dcnum.read.hdf5_data.get_measurement_identifier`
|
|
184
|
+
function.
|
|
180
185
|
"""
|
|
181
186
|
bdat = {
|
|
182
187
|
"description": description,
|
|
@@ -190,6 +195,9 @@ class HDF5Writer:
|
|
|
190
195
|
if paths is not None:
|
|
191
196
|
raise ValueError("`paths` must be set to None when storing "
|
|
192
197
|
"internal basin features")
|
|
198
|
+
if identifier is not None:
|
|
199
|
+
warnings.warn(f"Not storing identifier for internal "
|
|
200
|
+
f"basin '{name}' (got '{identifier}')")
|
|
193
201
|
# store the internal basin information
|
|
194
202
|
for feat in internal_data:
|
|
195
203
|
if feat in self.h5.require_group("basin_events"):
|
|
@@ -206,6 +214,8 @@ class HDF5Writer:
|
|
|
206
214
|
bdat["format"] = "hdf5"
|
|
207
215
|
bdat["paths"] = [str(pp) for pp in paths]
|
|
208
216
|
bdat["type"] = "file"
|
|
217
|
+
# identifier only makes sense here (not for internal basins)
|
|
218
|
+
bdat["identifier"] = identifier
|
|
209
219
|
|
|
210
220
|
# Explicit features stored in basin file
|
|
211
221
|
if features is not None and len(features):
|
|
@@ -322,6 +332,7 @@ def create_with_basins(
|
|
|
322
332
|
warnings.warn(f"Creating basin-based file '{path_out}' without any "
|
|
323
333
|
f"basins, since the list `basin_paths' is empty!",
|
|
324
334
|
CreatingFileWithoutBasinWarning)
|
|
335
|
+
basin_paths = []
|
|
325
336
|
with HDF5Writer(path_out, mode="w") as hw:
|
|
326
337
|
# Get the metadata from the first available basin path
|
|
327
338
|
|
|
@@ -359,16 +370,19 @@ def create_with_basins(
|
|
|
359
370
|
features = sorted(h5["events"].keys())
|
|
360
371
|
features = [f for f in features if
|
|
361
372
|
not f.startswith("basinmap")]
|
|
373
|
+
basin_identifier = get_measurement_identifier(h5)
|
|
362
374
|
name = prep.name
|
|
363
375
|
else:
|
|
364
376
|
features = None
|
|
365
377
|
name = bps[0]
|
|
378
|
+
basin_identifier = None
|
|
366
379
|
|
|
367
380
|
# Write the basin data
|
|
368
381
|
hw.store_basin(name=name,
|
|
369
382
|
paths=bps,
|
|
370
383
|
features=features,
|
|
371
384
|
description=f"Created by dcnum {version}",
|
|
385
|
+
identifier=basin_identifier,
|
|
372
386
|
)
|
|
373
387
|
|
|
374
388
|
|
|
@@ -404,6 +418,7 @@ def copy_basins(h5_src: h5py.File,
|
|
|
404
418
|
paths=bn_dict["paths"],
|
|
405
419
|
features=bn_dict["features"],
|
|
406
420
|
mapping=mapping,
|
|
421
|
+
identifier=bn_dict.get("identifier"),
|
|
407
422
|
)
|
|
408
423
|
else:
|
|
409
424
|
warnings.warn(f"Ignored basin of type '{bn_dict['type']}'",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dcnum
|
|
3
|
-
Version: 0.25.
|
|
3
|
+
Version: 0.25.11
|
|
4
4
|
Summary: numerics toolbox for imaging deformability cytometry
|
|
5
5
|
Author: Maximilian Schlögel, Paul Müller, Raghava Alajangi
|
|
6
6
|
Maintainer-email: Paul Müller <dev@craban.de>
|
|
@@ -55,12 +55,12 @@ For more options, please check out the `documentation
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
.. |dcnum| image:: https://raw.github.com/DC-analysis/dcnum/
|
|
58
|
+
.. |dcnum| image:: https://raw.github.com/DC-analysis/dcnum/main/docs/logo/dcnum.png
|
|
59
59
|
.. |PyPI Version| image:: https://img.shields.io/pypi/v/dcnum.svg
|
|
60
60
|
:target: https://pypi.python.org/pypi/dcnum
|
|
61
61
|
.. |Build Status| image:: https://img.shields.io/github/actions/workflow/status/DC-analysis/dcnum/check.yml
|
|
62
62
|
:target: https://github.com/DC-analysis/dcnum/actions?query=workflow%3AChecks
|
|
63
|
-
.. |Coverage Status| image:: https://img.shields.io/codecov/c/github/DC-analysis/dcnum
|
|
63
|
+
.. |Coverage Status| image:: https://img.shields.io/codecov/c/github/DC-analysis/dcnum
|
|
64
64
|
:target: https://codecov.io/gh/DC-analysis/dcnum
|
|
65
65
|
.. |Docs Status| image:: https://readthedocs.org/projects/dcnum/badge/?version=latest
|
|
66
66
|
:target: https://readthedocs.org/projects/dcnum/builds/
|
|
@@ -41,11 +41,10 @@ def get_log(hd: read.hdf5_data.HDF5Data,
|
|
|
41
41
|
},
|
|
42
42
|
["experiment:run identifier"],
|
|
43
43
|
"f0cfdc6f-93c7-c093-d135-a20f3e5bdbfa"],
|
|
44
|
-
# delete everything, this
|
|
44
|
+
# delete everything, this should yield only the pipeline ID
|
|
45
45
|
[{},
|
|
46
|
-
["setup:identifier", "experiment:time", "experiment:run identifier",
|
|
47
|
-
|
|
48
|
-
"07d18822-3045-4e6b-da0b-f1a16c80132a"],
|
|
46
|
+
["setup:identifier", "experiment:time", "experiment:run identifier"],
|
|
47
|
+
None],
|
|
49
48
|
])
|
|
50
49
|
def test_basin_experiment_identifier_correct(
|
|
51
50
|
override_attrs, delete_keys, meas_id):
|
|
@@ -77,7 +76,10 @@ def test_basin_experiment_identifier_correct(
|
|
|
77
76
|
|
|
78
77
|
with h5py.File(path_out) as hout:
|
|
79
78
|
appid = hout.attrs["pipeline:dcnum hash"]
|
|
80
|
-
|
|
79
|
+
if meas_id is not None:
|
|
80
|
+
eri_exp = f"{meas_id}_dcn-{appid[:7]}"
|
|
81
|
+
else:
|
|
82
|
+
eri_exp = f"dcn-{appid[:7]}"
|
|
81
83
|
# this is the actual test
|
|
82
84
|
assert hout.attrs["experiment:run identifier"] == eri_exp
|
|
83
85
|
|
|
@@ -185,9 +187,23 @@ def test_basin_strategy_tap():
|
|
|
185
187
|
assert "image" not in h5["events"]
|
|
186
188
|
for feat in h5["events"]:
|
|
187
189
|
assert len(h5["events"][feat]) == 275
|
|
190
|
+
# Make sure the correct basin identifier is stored
|
|
191
|
+
# (must be the original identifier plus a dcn pipeline hash tag)
|
|
192
|
+
assert h5.attrs["experiment:run identifier"] \
|
|
193
|
+
== "d5a40aed-0b6c-0412-e87c-59789fdd28d0_dcn-17decbe"
|
|
194
|
+
|
|
188
195
|
# The other features are accessed via basins
|
|
189
196
|
hd = read.HDF5Data(h5)
|
|
190
197
|
assert "image" in hd
|
|
198
|
+
# Check whether the basin identifier is set correctly.
|
|
199
|
+
for bn in hd.basins:
|
|
200
|
+
print(bn)
|
|
201
|
+
if bn["type"] == "file":
|
|
202
|
+
assert bn["identifier"] \
|
|
203
|
+
== "d5a40aed-0b6c-0412-e87c-59789fdd28d0"
|
|
204
|
+
break
|
|
205
|
+
else:
|
|
206
|
+
assert False, "Something went wrong, the basin is missing"
|
|
191
207
|
|
|
192
208
|
|
|
193
209
|
def test_basin_strategy_tap_rollmed():
|
|
@@ -76,6 +76,67 @@ def test_basin_features_path_absolute_mapped():
|
|
|
76
76
|
assert np.allclose(hd["image"][:], hd_src["image"][4:10])
|
|
77
77
|
|
|
78
78
|
|
|
79
|
+
def test_basin_identifier_mismatch(tmp_path):
|
|
80
|
+
path = retrieve_data(
|
|
81
|
+
"fmt-hdf5_cytoshot_full-features_legacy_allev_2023.zip")
|
|
82
|
+
path_test = path.parent / "test.h5"
|
|
83
|
+
|
|
84
|
+
with h5py.File(path, "a") as h5:
|
|
85
|
+
rid = read.get_measurement_identifier(h5)
|
|
86
|
+
area_um = h5["events/area_um"][:]
|
|
87
|
+
del h5["events/area_um"]
|
|
88
|
+
assert rid == "d5a40aed-0b6c-0412-e87c-59789fdd28d0"
|
|
89
|
+
|
|
90
|
+
# We basically create a file that consists only of the metadata.
|
|
91
|
+
with write.HDF5Writer(path_test) as hw:
|
|
92
|
+
hw.store_basin(name="pidemon",
|
|
93
|
+
paths=[path],
|
|
94
|
+
features=["deform"],
|
|
95
|
+
description="Wrong basin identifier specified",
|
|
96
|
+
identifier=rid + "-wrong",
|
|
97
|
+
)
|
|
98
|
+
hw.store_feature_chunk("area_um", area_um)
|
|
99
|
+
|
|
100
|
+
with h5py.File(path_test) as hb:
|
|
101
|
+
basins = read.HDF5Data.extract_basin_dicts(hb)
|
|
102
|
+
assert len(basins) == 1
|
|
103
|
+
|
|
104
|
+
with read.HDF5Data(path_test) as hd:
|
|
105
|
+
# Accessing data in the new file works
|
|
106
|
+
assert hd["area_um"][0]
|
|
107
|
+
with pytest.raises(read.BasinIdentifierMismatchError,
|
|
108
|
+
match="does not match"):
|
|
109
|
+
hd["deform"][0]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_basin_identifier_normal_use_case(tmp_path):
|
|
113
|
+
path = retrieve_data(
|
|
114
|
+
"fmt-hdf5_cytoshot_full-features_legacy_allev_2023.zip")
|
|
115
|
+
path_test = path.parent / "test.h5"
|
|
116
|
+
|
|
117
|
+
with h5py.File(path) as h5:
|
|
118
|
+
rid = read.get_measurement_identifier(h5)
|
|
119
|
+
assert rid == "d5a40aed-0b6c-0412-e87c-59789fdd28d0"
|
|
120
|
+
|
|
121
|
+
# We basically create a file that consists only of the metadata.
|
|
122
|
+
with write.HDF5Writer(path_test) as hw:
|
|
123
|
+
hw.store_basin(name="pidemon",
|
|
124
|
+
paths=[path],
|
|
125
|
+
description="Basin identifier specified",
|
|
126
|
+
identifier=rid,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
with h5py.File(path_test) as hb:
|
|
130
|
+
basins = read.HDF5Data.extract_basin_dicts(hb)
|
|
131
|
+
assert len(basins) == 1
|
|
132
|
+
bn = basins[0]
|
|
133
|
+
assert bn["identifier"] == rid
|
|
134
|
+
|
|
135
|
+
with read.HDF5Data(path_test) as hd:
|
|
136
|
+
# Accessing data in the new file works
|
|
137
|
+
assert hd["deform"][0]
|
|
138
|
+
|
|
139
|
+
|
|
79
140
|
def test_basin_mapped_with_mapped_dataset():
|
|
80
141
|
"""You can have a mapped dataset opening a mapped basin"""
|
|
81
142
|
path_src = retrieve_data(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_cytoshot_full-features_legacy_allev_2023.zip
RENAMED
|
File without changes
|
|
File without changes
|
{dcnum-0.25.10 → dcnum-0.25.11}/tests/data/fmt-hdf5_shapein_raw-with-variable-length-logs.zip
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dcnum-0.25.10 → dcnum-0.25.11}/tests/data/segm-torch-test-data_unet-dcnum-test_g1_910c2.zip
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|