blissdata 2.1.1__tar.gz → 2.3.0__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.
- {blissdata-2.1.1/src/blissdata.egg-info → blissdata-2.3.0}/PKG-INFO +2 -3
- {blissdata-2.1.1 → blissdata-2.3.0}/pyproject.toml +2 -6
- blissdata-2.3.0/src/blissdata/__init__.py +4 -0
- blissdata-2.3.0/src/blissdata/deprecation.py +12 -0
- blissdata-2.3.0/src/blissdata/h5api/h5_scan_map.py +133 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/redis_hdf5.py +239 -100
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5map/data_items.py +1 -1
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/lima/client.py +2 -5
- blissdata-2.3.0/src/blissdata/redis_engine/encoding/json.py +11 -0
- blissdata-2.3.0/src/blissdata/redis_engine/encoding/numeric.py +11 -0
- blissdata-2.3.0/src/blissdata/redis_engine/event_stream.py +11 -0
- blissdata-2.3.0/src/blissdata/redis_engine/exceptions.py +12 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/redis_engine/memory_tracker.py +2 -4
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/redis_engine/scan.py +48 -32
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/redis_engine/store.py +1 -1
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/scan.py +5 -1
- blissdata-2.1.1/src/blissdata/streams/base.py → blissdata-2.3.0/src/blissdata/streams/__init__.py +22 -123
- blissdata-2.3.0/src/blissdata/streams/base.py +39 -0
- blissdata-2.3.0/src/blissdata/streams/default.py +160 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata/streams}/event_stream.py +1 -1
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/streams/hdf5_fallback/stream.py +3 -2
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/streams/lima/stream.py +16 -6
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/streams/scan_sequence/stream.py +3 -3
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/conftest.py +10 -1
- blissdata-2.3.0/src/blissdata/tests/h5api/test_redis_files.py +485 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5map/test_data_items.py +1 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/redis_engine/test_cursor.py +4 -3
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/redis_engine/test_memory_tracker.py +2 -2
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/redis_engine/test_scan.py +3 -6
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/redis_engine/test_search.py +1 -1
- {blissdata-2.1.1/src/blissdata/tests/redis_engine → blissdata-2.3.0/src/blissdata/tests/streams}/encoding/test_json.py +1 -1
- {blissdata-2.1.1/src/blissdata/tests/redis_engine → blissdata-2.3.0/src/blissdata/tests/streams}/encoding/test_numeric.py +1 -1
- {blissdata-2.1.1/src/blissdata/tests/plugin_streams → blissdata-2.3.0/src/blissdata/tests/streams/plugins}/test_file_backed_stream.py +4 -4
- blissdata-2.3.0/src/blissdata/tests/streams/plugins/test_plugin_base.py +111 -0
- {blissdata-2.1.1/src/blissdata/tests/redis_engine → blissdata-2.3.0/src/blissdata/tests/streams}/test_event_stream.py +3 -3
- {blissdata-2.1.1 → blissdata-2.3.0/src/blissdata.egg-info}/PKG-INFO +2 -3
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata.egg-info/SOURCES.txt +16 -11
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata.egg-info/entry_points.txt +0 -1
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata.egg-info/requires.txt +1 -2
- blissdata-2.1.1/src/blissdata/h5api/scan_mapping.py +0 -295
- blissdata-2.1.1/src/blissdata/streams/lima2/__init__.py +0 -4
- blissdata-2.1.1/src/blissdata/streams/lima2/stream.py +0 -266
- blissdata-2.1.1/src/blissdata/tests/h5api/test_redis_files.py +0 -287
- blissdata-2.1.1/src/blissdata/tests/plugin_streams/test_lima2_stream.py +0 -168
- blissdata-2.1.1/src/blissdata/tests/redis_engine/encoding/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/LICENSE +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/README.md +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/setup.cfg +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/beacon/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/beacon/_base.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/beacon/_utils.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/beacon/config.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/beacon/data.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/beacon/files.py +0 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata}/exceptions.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/abstract.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/dynamic_hdf5.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/file_arguments.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/static_hdf5.py +0 -0
- {blissdata-2.1.1/src/blissdata → blissdata-2.3.0/src/blissdata/h5api/utils}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/utils/bliss.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/utils/hdf5.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/utils/hdf5_retry.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/utils/lima.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5api/utils/types.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5map/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/h5map/hdf5_items.py +0 -0
- {blissdata-2.1.1/src/blissdata/h5api/utils → blissdata-2.3.0/src/blissdata/lima}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/lima/image_utils.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/py.typed +0 -0
- {blissdata-2.1.1/src/blissdata/lima → blissdata-2.3.0/src/blissdata/redis_engine}/__init__.py +0 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata/redis_engine/encoding}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/redis_engine/identities.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/schemas/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/schemas/scan_info.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/schemas/scan_info_display.py +0 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata/streams}/encoding/__init__.py +0 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata/streams}/encoding/json.py +0 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata/streams}/encoding/numeric.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/streams/hdf5_fallback/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/streams/lima/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/streams/scan_sequence/__init__.py +0 -0
- {blissdata-2.1.1/src/blissdata/redis_engine → blissdata-2.3.0/src/blissdata/streams}/sink.py +0 -0
- {blissdata-2.1.1/src/blissdata/streams → blissdata-2.3.0/src/blissdata/tests}/__init__.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests → blissdata-2.3.0/src/blissdata/tests/beacon}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/beacon/test_config.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/beacon/test_data.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/beacon/test_files.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests/beacon → blissdata-2.3.0/src/blissdata/tests/h5api}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5api/scanner.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5api/test_dynamic_files.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5api/test_h5api_lima_utils.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5api/test_hdf5_handlers.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5api/test_static_files.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests/h5api → blissdata-2.3.0/src/blissdata/tests/h5map}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/h5map/test_hdf5_items.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests/h5map → blissdata-2.3.0/src/blissdata/tests/lima}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/lima/test_image_utils.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests/lima → blissdata-2.3.0/src/blissdata/tests/redis_engine}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/redis_engine/conftest.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata/tests/redis_engine/utils.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests/plugin_streams → blissdata-2.3.0/src/blissdata/tests/streams/encoding}/__init__.py +0 -0
- {blissdata-2.1.1/src/blissdata/tests/redis_engine → blissdata-2.3.0/src/blissdata/tests/streams/plugins}/__init__.py +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata.egg-info/dependency_links.txt +0 -0
- {blissdata-2.1.1 → blissdata-2.3.0}/src/blissdata.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blissdata
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: Bliss data streaming client
|
|
5
5
|
Maintainer: BCU (ESRF)
|
|
6
6
|
License-Expression: LGPL-3.0-or-later
|
|
@@ -26,8 +26,7 @@ Requires-Dist: silx>=1.1.0
|
|
|
26
26
|
Provides-Extra: tango
|
|
27
27
|
Requires-Dist: pytango>=9.3.1; extra == "tango"
|
|
28
28
|
Provides-Extra: lima2
|
|
29
|
-
Requires-Dist: blissdata
|
|
30
|
-
Requires-Dist: lima2-client~=4.0; extra == "lima2"
|
|
29
|
+
Requires-Dist: blissdata-lima2>=2.0; extra == "lima2"
|
|
31
30
|
Provides-Extra: test
|
|
32
31
|
Requires-Dist: gevent>=20.9.0; extra == "test"
|
|
33
32
|
Requires-Dist: pytest>=7; extra == "test"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "blissdata"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.3.0"
|
|
4
4
|
description = "Bliss data streaming client"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "LGPL-3.0-or-later"
|
|
@@ -32,10 +32,7 @@ Changes = "https://gitlab.esrf.fr/bliss/blissdata/-/blob/master/CHANGELOG.md"
|
|
|
32
32
|
|
|
33
33
|
[project.optional-dependencies]
|
|
34
34
|
tango = ["pytango>=9.3.1"]
|
|
35
|
-
lima2 = [
|
|
36
|
-
"blissdata[tango]",
|
|
37
|
-
"lima2-client~=4.0"
|
|
38
|
-
]
|
|
35
|
+
lima2 = ["blissdata-lima2>=2.0"]
|
|
39
36
|
test = [
|
|
40
37
|
"gevent>=20.9.0",
|
|
41
38
|
"pytest>=7",
|
|
@@ -62,7 +59,6 @@ memory_tracker = "blissdata.redis_engine.memory_tracker:cli"
|
|
|
62
59
|
hdf5_fallback = "blissdata.streams.hdf5_fallback"
|
|
63
60
|
scan_sequence = "blissdata.streams.scan_sequence"
|
|
64
61
|
lima = "blissdata.streams.lima"
|
|
65
|
-
lima2 = "blissdata.streams.lima2"
|
|
66
62
|
|
|
67
63
|
[build-system]
|
|
68
64
|
requires = ["setuptools"]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from warnings import warn
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def warn_deprecated(old_name, new_name, removal_version=None):
|
|
5
|
+
msg = f"'{old_name}' is deprecated, use '{new_name}' instead."
|
|
6
|
+
if removal_version:
|
|
7
|
+
msg += f" It will be removed in version {removal_version}."
|
|
8
|
+
warn(
|
|
9
|
+
msg,
|
|
10
|
+
FutureWarning,
|
|
11
|
+
stacklevel=3,
|
|
12
|
+
)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from pathlib import PurePosixPath as Path
|
|
5
|
+
from blissdata import ScanState
|
|
6
|
+
from blissdata.h5map import HDF5ItemType, Group
|
|
7
|
+
|
|
8
|
+
_logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class H5ScanMap(Mapping):
|
|
12
|
+
"""H5ScanMap is a wrapper around a blissdata's Scan. It exposes its HDF5
|
|
13
|
+
mapping with conventional dict API, but also handles automatic refresh of
|
|
14
|
+
the underlying model from Redis (see _updated_root method).
|
|
15
|
+
|
|
16
|
+
IMPORTANT: This is not an H5-like object, it helps manipulating the mapping
|
|
17
|
+
within a scan. Then H5-like groups and datasets can be implemented on top of
|
|
18
|
+
it."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, scan):
|
|
21
|
+
self._scan = scan
|
|
22
|
+
self._root = None
|
|
23
|
+
self._last_update = time.perf_counter()
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def scan(self):
|
|
27
|
+
return self._scan
|
|
28
|
+
|
|
29
|
+
def __len__(self):
|
|
30
|
+
return len(self._updated_root().children)
|
|
31
|
+
|
|
32
|
+
def __iter__(self):
|
|
33
|
+
yield from self._updated_root().children.keys()
|
|
34
|
+
|
|
35
|
+
def __getitem__(self, path: str) -> HDF5ItemType:
|
|
36
|
+
"""Return the HDF5Item associated to that path.
|
|
37
|
+
Links are not resolved here, instead a SoftLink or ExternalLink is
|
|
38
|
+
returned and it is caller choice to resolve it or not.
|
|
39
|
+
"""
|
|
40
|
+
assert path.startswith("/")
|
|
41
|
+
h5_item = self._updated_root()
|
|
42
|
+
current_path = Path("/")
|
|
43
|
+
for part in Path(path).parts:
|
|
44
|
+
if part == "/":
|
|
45
|
+
continue
|
|
46
|
+
current_path /= part
|
|
47
|
+
if not isinstance(h5_item, Group):
|
|
48
|
+
raise KeyError(str(current_path))
|
|
49
|
+
try:
|
|
50
|
+
h5_item = h5_item.children[part]
|
|
51
|
+
except KeyError:
|
|
52
|
+
raise KeyError(str(current_path))
|
|
53
|
+
return h5_item
|
|
54
|
+
|
|
55
|
+
def path_partition(self, path: str) -> tuple[str, HDF5ItemType | None, str]:
|
|
56
|
+
"""Similar to __getitem__, but may return partially resolved path.
|
|
57
|
+
Goal is to allow link items to be returned along with the remaining
|
|
58
|
+
part of the path. Links can be resolved before going further.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
tuple:
|
|
62
|
+
- path of the returned item
|
|
63
|
+
- h5map item or None if path doesn't exist
|
|
64
|
+
- remaining path (empty if item is the actual target)
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
/
|
|
68
|
+
├─a
|
|
69
|
+
│ ├─b (link to d)
|
|
70
|
+
│ └─c
|
|
71
|
+
└─d
|
|
72
|
+
└─e
|
|
73
|
+
|
|
74
|
+
path_partition("/a/b/c") -> "/a/b/c", Dataset(...), ""
|
|
75
|
+
path_partition("/a/b/e") -> "/a/b", SoftLink("/d"), "e"
|
|
76
|
+
path_partition("/a/x/y") -> "/a/x", None, "y"
|
|
77
|
+
"""
|
|
78
|
+
assert path.startswith("/")
|
|
79
|
+
h5_item = self._updated_root()
|
|
80
|
+
item_parts = ["/"]
|
|
81
|
+
remaining_parts = list(Path(path).parts[1:])
|
|
82
|
+
while remaining_parts:
|
|
83
|
+
if isinstance(h5_item, Group):
|
|
84
|
+
try:
|
|
85
|
+
item_parts.append(remaining_parts.pop(0))
|
|
86
|
+
h5_item = h5_item.children[item_parts[-1]]
|
|
87
|
+
except KeyError:
|
|
88
|
+
h5_item = None
|
|
89
|
+
break
|
|
90
|
+
else:
|
|
91
|
+
break
|
|
92
|
+
remaining_path = str(Path(*remaining_parts)) if remaining_parts else ""
|
|
93
|
+
return str(Path(*item_parts)), h5_item, remaining_path
|
|
94
|
+
|
|
95
|
+
def _updated_root(self) -> Group:
|
|
96
|
+
"""Return an h5map.Group loaded from scan info. Reuse previous answer if
|
|
97
|
+
not older than 0.2 seconds (polling Redis to 5Hz at most if fine).
|
|
98
|
+
Moreover, scan state doesn't change that much and the scan's json is
|
|
99
|
+
only downloaded on changes.
|
|
100
|
+
|
|
101
|
+
In case the scan provides no mapping, an empty Group is returned.
|
|
102
|
+
"""
|
|
103
|
+
scan_state_changed = False
|
|
104
|
+
|
|
105
|
+
# Mapping is not expected to be published before scan is prepared, wait
|
|
106
|
+
while self._scan.state < ScanState.PREPARED:
|
|
107
|
+
self._scan.update()
|
|
108
|
+
self._last_update = time.perf_counter()
|
|
109
|
+
scan_state_changed = True
|
|
110
|
+
|
|
111
|
+
# Update whenever the scan is not CLOSED and the last_update is not too
|
|
112
|
+
# recent.
|
|
113
|
+
min_update_interval = 0.2
|
|
114
|
+
now = time.perf_counter()
|
|
115
|
+
if (
|
|
116
|
+
self._last_update + min_update_interval < now
|
|
117
|
+
and self._scan.state < ScanState.CLOSED
|
|
118
|
+
):
|
|
119
|
+
scan_state_changed = self._scan.update(block=False)
|
|
120
|
+
self._last_update = time.perf_counter()
|
|
121
|
+
|
|
122
|
+
# (re)generate mapping tree if necessary
|
|
123
|
+
if scan_state_changed or self._root is None:
|
|
124
|
+
try:
|
|
125
|
+
mappings = self._scan.info.get("h5maps", {})
|
|
126
|
+
self._root = Group.model_validate(mappings[self._scan.path])
|
|
127
|
+
except KeyError:
|
|
128
|
+
_logger.warning(
|
|
129
|
+
f"Scan {self._scan.number} has no hdf5 mapping ({self._scan.key})"
|
|
130
|
+
)
|
|
131
|
+
return Group()
|
|
132
|
+
|
|
133
|
+
return self._root
|