dcnum 0.25.10__py3-none-any.whl → 0.25.11__py3-none-any.whl

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/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.25.10'
21
- __version_tuple__ = version_tuple = (0, 25, 10)
20
+ __version__ = version = '0.25.11'
21
+ __version_tuple__ = version_tuple = (0, 25, 11)
dcnum/logic/ctrl.py CHANGED
@@ -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.attrs.get("experiment:run identifier")
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
dcnum/read/__init__.py CHANGED
@@ -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 HDF5Data, HDF5ImageCache
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
dcnum/read/hdf5_data.py CHANGED
@@ -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
dcnum/write/writer.py CHANGED
@@ -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.10
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/master/docs/logo/dcnum.png
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/master.svg
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/
@@ -1,5 +1,5 @@
1
1
  dcnum/__init__.py,sha256=p0mYg01FQ6nsERYmx_FfVxqqHvYcSMEyIAMBIivAmO8,1206
2
- dcnum/_version.py,sha256=2u4bWaMdcZXyf4_yxgykEAXNXcEaVQumowHKcuxLJUI,515
2
+ dcnum/_version.py,sha256=G2RU878iZqAjfDOQZYI6kgCV8us1Ipc26TtDUjv56s0,515
3
3
  dcnum/os_env_st.py,sha256=4psq-gPuWTTQ118kCiTx0Mhoyads4Irn6JSUzZk8gyc,3052
4
4
  dcnum/feat/__init__.py,sha256=jUJYWTD3VIoDNKrmryXbjHb1rGwYtK4b7VPWihYgUoo,325
5
5
  dcnum/feat/event_extractor_manager_thread.py,sha256=6D3RVYBuH7gOoGZ4Kz74n6fhq7MtlTY26kpSwZRqg3M,7972
@@ -21,18 +21,18 @@ dcnum/feat/feat_texture/__init__.py,sha256=6StM9S540UVtdFFR3bHa7nfCTomeVdoo7Uy9C
21
21
  dcnum/feat/feat_texture/common.py,sha256=COXHpXS-7DMouGu3WF83I76L02Sr7P9re4lxajh6g0E,439
22
22
  dcnum/feat/feat_texture/tex_all.py,sha256=_5H3sXYRN0Uq2eUHn3XUyEHkU_tncEqbqJTC-HZcnGY,5198
23
23
  dcnum/logic/__init__.py,sha256=7J3GrwJInNQbrLk61HRIV7X7p69TAIbMYpR34hh6u14,177
24
- dcnum/logic/ctrl.py,sha256=c06ZOUD0T4_FdQDHbigkLAPQTyoeFxhETg-K3W1UyeM,37520
24
+ dcnum/logic/ctrl.py,sha256=4r5N4WlqJW1f61zpaWFBJofEgMsD7H2APeiqOu9Li08,37099
25
25
  dcnum/logic/job.py,sha256=MprDL6DwXWmvtGgy7W9A7s2rVRx68ObdJB8mvGFwVcw,7718
26
26
  dcnum/logic/json_encoder.py,sha256=wb6uk6EeTkXyrvwtLm9uWe0cfmiBannzcsKLsDLHuQo,843
27
27
  dcnum/meta/__init__.py,sha256=AVqRgyKXO1orKnE305h88IBvoZ1oz6X11HN1WP5nGvg,60
28
28
  dcnum/meta/paths.py,sha256=aIG39JYbZpOlCbPQIlp0SqGumjbGINYhL2AAoznJt5o,1113
29
29
  dcnum/meta/ppid.py,sha256=JInGtwSCsO9nr1E1aishm0k9iQIFB-essBKvv5aBE98,8510
30
- dcnum/read/__init__.py,sha256=vhriJFlJ3DlqkAnRPQsOfUQWKYSzLNNp_NZeZ5eBvmo,286
30
+ dcnum/read/__init__.py,sha256=EzH-a_RHnUdG32ws-UgU5tc_je972G3pYgn48ai8PFc,356
31
31
  dcnum/read/cache.py,sha256=ChxokVuMaTfi6N6ZbOTWpNYkPgAAYi1lR8nD7JbzjPQ,6497
32
32
  dcnum/read/const.py,sha256=x6LfRwWvIxm6nDWlSADVWqDuzMX6bLzy5kQprwLPzA4,496
33
33
  dcnum/read/detect_flicker.py,sha256=XVf7nqaHx6weRTtS7KPa5_WRU2flDQIZTbKspeguqdU,1829
34
34
  dcnum/read/hdf5_concat.py,sha256=A4Ah_NLxa1ESapEWJcUhdglzi7_E3qKNd81ES7A-_2o,5589
35
- dcnum/read/hdf5_data.py,sha256=KGMQJYtirBSjnen7FWwfMJB4sr_eOuT8qPGkLZwuMN0,21293
35
+ dcnum/read/hdf5_data.py,sha256=Hp1nzEe4EYaIFw22-VLFYbzvwFzctMYrtjoHAwdhDI8,22924
36
36
  dcnum/read/mapped.py,sha256=zU2fYdZfLNHn0rKHxDzBhNFMu4--WWa8nSeE2likyZA,3637
37
37
  dcnum/segm/__init__.py,sha256=9cLEAd3JWE8IGqDHV-eSDIYOGBfOepd8OcebtNs8Omk,309
38
38
  dcnum/segm/segm_thresh.py,sha256=iVhvIhzO0Gw0t3rXOgH71rOI0CNjJJQq4Gg6BulUhK8,948
@@ -50,9 +50,9 @@ dcnum/segm/segm_torch/torch_preproc.py,sha256=m4Dd2URdvS7ifA1MkbEkc9d9T30lA_1qbE
50
50
  dcnum/write/__init__.py,sha256=sK79IlvCFIqf2oFABVeyYedMnHOsEIQpxAauEeNO-Tw,273
51
51
  dcnum/write/deque_writer_thread.py,sha256=ao7F1yrVKyufgC4rC0Y2_Vt7snuT6KpI7W2qVxcjdhk,1994
52
52
  dcnum/write/queue_collector_thread.py,sha256=-p5vrk9cDhtaIMFIu_cCmvlZJafrFkW68uONonMURYo,11617
53
- dcnum/write/writer.py,sha256=JkVb4KDBV3oo9r3p2yy9wECO1REx7FG0PRBmVWTxJdk,20577
54
- dcnum-0.25.10.dist-info/licenses/LICENSE,sha256=rX7tNSxP-EhLz-yYUyoBGwjJheA2fiZpT1Iw0LXnJ2M,1069
55
- dcnum-0.25.10.dist-info/METADATA,sha256=twT_YXAb4Xxt24EKrjxEg8-4UgkHDHYOfzS-prFCXTM,2355
56
- dcnum-0.25.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- dcnum-0.25.10.dist-info/top_level.txt,sha256=Hmh38rgG_MFTVDpUDGuO2HWTSq80P585Het4COQzFTg,6
58
- dcnum-0.25.10.dist-info/RECORD,,
53
+ dcnum/write/writer.py,sha256=WZLuetH7ZIvK-lhXjmyskHczAWFa9EfHXZWBUf9w1UE,21394
54
+ dcnum-0.25.11.dist-info/licenses/LICENSE,sha256=rX7tNSxP-EhLz-yYUyoBGwjJheA2fiZpT1Iw0LXnJ2M,1069
55
+ dcnum-0.25.11.dist-info/METADATA,sha256=N1T08nz_vUPVx7WzJ6aT45yfVfLu4VdM5EcUm7CfROY,2342
56
+ dcnum-0.25.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
+ dcnum-0.25.11.dist-info/top_level.txt,sha256=Hmh38rgG_MFTVDpUDGuO2HWTSq80P585Het4COQzFTg,6
58
+ dcnum-0.25.11.dist-info/RECORD,,