legend-dataflow-scripts 0.4.0a1__tar.gz → 0.4.0a2__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.
- {legend_dataflow_scripts-0.4.0a1/src/legend_dataflow_scripts.egg-info → legend_dataflow_scripts-0.4.0a2}/PKG-INFO +1 -1
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2/src/legend_dataflow_scripts.egg-info}/PKG-INFO +1 -1
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/scm_file_list.json +1 -0
- legend_dataflow_scripts-0.4.0a2/src/legend_dataflow_scripts.egg-info/scm_version.json +8 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/_version.py +3 -3
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/alias_table.py +37 -27
- legend_dataflow_scripts-0.4.0a2/src/legenddataflowscripts/workflow/pre_compile_catalog.py +113 -0
- legend_dataflow_scripts-0.4.0a1/src/legend_dataflow_scripts.egg-info/scm_version.json +0 -8
- legend_dataflow_scripts-0.4.0a1/src/legenddataflowscripts/workflow/pre_compile_catalog.py +0 -44
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/LICENSE +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/README.md +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/pyproject.toml +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/setup.cfg +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/SOURCES.txt +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/dependency_links.txt +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/entry_points.txt +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/not-zip-safe +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/requires.txt +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legend_dataflow_scripts.egg-info/top_level.txt +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/dplms.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/eopt.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/evtsel.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/nopt.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/pz.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/svm.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/dsp/svm_build.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/hit/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/hit/aoe.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/hit/ecal.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/hit/lq.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/par/geds/hit/qc.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/tier/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/tier/dsp.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/tier/hit.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/cfgtools.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/convert_np.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/discharge.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/files.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/lgdo_utils.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/log.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/plot_dict.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/utils/pulser_removal.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/workflow/__init__.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/workflow/execenv.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/workflow/filedb.py +0 -0
- {legend_dataflow_scripts-0.4.0a1 → legend_dataflow_scripts-0.4.0a2}/src/legenddataflowscripts/workflow/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: legend-dataflow-scripts
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.0a2
|
|
4
4
|
Summary: Python package for the processing scripts for LEGEND-200 data
|
|
5
5
|
Author-email: George Marshall <ggmarsh@uw.edu>, Luigi Pertoldi <gipert@pm.me>
|
|
6
6
|
Maintainer: The LEGEND Collaboration
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: legend-dataflow-scripts
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.0a2
|
|
4
4
|
Summary: Python package for the processing scripts for LEGEND-200 data
|
|
5
5
|
Author-email: George Marshall <ggmarsh@uw.edu>, Luigi Pertoldi <gipert@pm.me>
|
|
6
6
|
Maintainer: The LEGEND Collaboration
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.4.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 4, 0, '
|
|
21
|
+
__version__ = version = '0.4.0a2'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 4, 0, 'a2')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g4e182698a'
|
|
@@ -7,7 +7,7 @@ import h5py
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def convert_parents_to_structs(h5group):
|
|
10
|
-
"""
|
|
10
|
+
"""Annotate HDF5 parent groups with LGDO ``struct`` datatype attributes.
|
|
11
11
|
|
|
12
12
|
When a new alias (hard link) is created inside an HDF5 file the parent
|
|
13
13
|
groups may not carry the ``datatype`` attribute expected by the LGDO reader.
|
|
@@ -15,38 +15,48 @@ def convert_parents_to_structs(h5group):
|
|
|
15
15
|
every ancestor group carries a ``datatype`` attribute of the form
|
|
16
16
|
``struct{child1,child2,…}``.
|
|
17
17
|
|
|
18
|
+
The root group is only updated if it already carries a ``datatype``; the
|
|
19
|
+
walk always stops there.
|
|
20
|
+
|
|
18
21
|
Parameters
|
|
19
22
|
----------
|
|
20
23
|
h5group : h5py.Group
|
|
21
24
|
Leaf group whose parent hierarchy should be annotated.
|
|
22
25
|
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
# the walk must be iterative: in h5py the root group is its own parent, so
|
|
27
|
+
# recursing on ``h5group.parent`` never terminates once ``/`` is reached
|
|
28
|
+
while h5group.name != "/":
|
|
29
|
+
parent = h5group.parent
|
|
30
|
+
child = h5group.name.rsplit("/", 1)[-1]
|
|
31
|
+
|
|
32
|
+
if "datatype" not in parent.attrs:
|
|
33
|
+
# never invent a datatype on the file root
|
|
34
|
+
if parent.name == "/":
|
|
35
|
+
return
|
|
36
|
+
parent.attrs.update({"datatype": "struct{" + child + "}"})
|
|
37
|
+
else:
|
|
38
|
+
datatype = parent.attrs["datatype"]
|
|
39
|
+
if not (datatype.startswith("struct{") and datatype.endswith("}")):
|
|
40
|
+
msg = (
|
|
41
|
+
f"cannot register alias {child!r}: parent group "
|
|
42
|
+
f"{parent.name!r} has non-struct datatype {datatype!r}"
|
|
43
|
+
)
|
|
44
|
+
raise ValueError(msg)
|
|
45
|
+
# membership must be tested against the parsed field list, not by
|
|
46
|
+
# substring (e.g. 'raw' is a substring of 'raw_blind')
|
|
47
|
+
fields = [
|
|
48
|
+
field.strip()
|
|
49
|
+
for field in datatype[len("struct{") : -1].split(",")
|
|
50
|
+
if field.strip()
|
|
51
|
+
]
|
|
52
|
+
if child in fields:
|
|
53
|
+
# ancestors were annotated when this member was first added
|
|
54
|
+
return
|
|
55
|
+
parent.attrs.update(
|
|
56
|
+
{"datatype": "struct{" + ",".join([*fields, child]) + "}"}
|
|
32
57
|
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# substring (e.g. 'raw' is a substring of 'raw_blind')
|
|
36
|
-
fields = [
|
|
37
|
-
field.strip()
|
|
38
|
-
for field in datatype[len("struct{") : -1].split(",")
|
|
39
|
-
if field.strip()
|
|
40
|
-
]
|
|
41
|
-
if child in fields:
|
|
42
|
-
return
|
|
43
|
-
h5group.parent.attrs.update(
|
|
44
|
-
{"datatype": "struct{" + ",".join([*fields, child]) + "}"}
|
|
45
|
-
)
|
|
46
|
-
else:
|
|
47
|
-
return
|
|
48
|
-
convert_parents_to_structs(h5group.parent)
|
|
49
|
-
return
|
|
58
|
+
|
|
59
|
+
h5group = parent
|
|
50
60
|
|
|
51
61
|
|
|
52
62
|
def alias_table(file: str | Path, mapping: str):
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import os
|
|
5
|
+
import pickle
|
|
6
|
+
import tempfile
|
|
7
|
+
from datetime import UTC, datetime
|
|
8
|
+
from importlib.metadata import version
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from dbetto import TextDB
|
|
12
|
+
from dbetto.catalog import Catalog
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _content_digest(validity_path: Path) -> str:
|
|
16
|
+
"""Digest of the directory contents (relative path, mtime and size of
|
|
17
|
+
every file) plus the dbetto version, identifying one compiled state of
|
|
18
|
+
the catalog."""
|
|
19
|
+
state = [version("dbetto")]
|
|
20
|
+
for f in sorted(validity_path.rglob("*")):
|
|
21
|
+
if f.is_file():
|
|
22
|
+
st = f.stat()
|
|
23
|
+
state.append(
|
|
24
|
+
f"{f.relative_to(validity_path)}:{st.st_mtime_ns}:{st.st_size}"
|
|
25
|
+
)
|
|
26
|
+
return hashlib.sha256("\n".join(state).encode()).hexdigest()[:16]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _cache_dir(validity_path: Path) -> Path:
|
|
30
|
+
"""Per-directory cache namespace, keyed on the resolved directory path, so
|
|
31
|
+
same-named directories in different locations cannot evict each other's
|
|
32
|
+
pickles."""
|
|
33
|
+
base = os.environ.get("XDG_CACHE_HOME") or str(Path.home() / ".cache")
|
|
34
|
+
dir_key = hashlib.sha256(str(validity_path.resolve()).encode()).hexdigest()[:16]
|
|
35
|
+
return (
|
|
36
|
+
Path(base)
|
|
37
|
+
/ "legend-dataflow"
|
|
38
|
+
/ "precompiled-catalogs"
|
|
39
|
+
/ f"{validity_path.name}-{dir_key}"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def pre_compile_catalog(validity_path: str | Path):
|
|
44
|
+
"""Pre-compile a dbetto validity catalog for fast repeated access.
|
|
45
|
+
|
|
46
|
+
Reads the ``validity.yaml`` catalog from *validity_path* and, for each
|
|
47
|
+
system and each entry in the catalog, eagerly loads the corresponding
|
|
48
|
+
:class:`dbetto.TextDB` state (instead of loading it lazily on first
|
|
49
|
+
access). The resulting :class:`dbetto.catalog.Catalog` can be serialised
|
|
50
|
+
and reused across many Snakemake jobs without re-parsing YAML on every
|
|
51
|
+
invocation.
|
|
52
|
+
|
|
53
|
+
The compiled catalog is cached on disk under
|
|
54
|
+
``$XDG_CACHE_HOME/legend-dataflow/precompiled-catalogs``, in a
|
|
55
|
+
subdirectory per (resolved) input directory, keyed on the directory
|
|
56
|
+
contents (file mtimes/sizes) and the dbetto version, so repeated
|
|
57
|
+
workflow parses skip the eager compilation entirely.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
validity_path : str or pathlib.Path
|
|
62
|
+
Directory containing the ``validity.yaml`` file and all referenced
|
|
63
|
+
database files.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
dbetto.catalog.Catalog
|
|
68
|
+
Pre-compiled catalog with all entries eagerly resolved.
|
|
69
|
+
"""
|
|
70
|
+
if isinstance(validity_path, str):
|
|
71
|
+
validity_path = Path(validity_path)
|
|
72
|
+
|
|
73
|
+
cache_dir = _cache_dir(validity_path)
|
|
74
|
+
cache_file = cache_dir / f"{_content_digest(validity_path)}.pkl"
|
|
75
|
+
if cache_file.is_file() and not cache_file.is_symlink():
|
|
76
|
+
try:
|
|
77
|
+
with cache_file.open("rb") as f:
|
|
78
|
+
cached = pickle.load(f)
|
|
79
|
+
# tampered/corrupt caches must never be handed back as a catalog
|
|
80
|
+
if isinstance(cached, Catalog):
|
|
81
|
+
return cached
|
|
82
|
+
except Exception: # unreadable pickle: rebuild below
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
catalog = Catalog.read_from(validity_path / "validity.yaml")
|
|
86
|
+
entries = {}
|
|
87
|
+
textdb = TextDB(validity_path, lazy=False)
|
|
88
|
+
for system in catalog.entries:
|
|
89
|
+
entries[system] = []
|
|
90
|
+
for entry in catalog.entries[system]:
|
|
91
|
+
db = textdb.on(
|
|
92
|
+
datetime.fromtimestamp(entry.valid_from, tz=UTC), category=system
|
|
93
|
+
)
|
|
94
|
+
new_entry = Catalog.Entry(entry.valid_from, db)
|
|
95
|
+
entries[system].append(new_entry)
|
|
96
|
+
compiled = Catalog(entries)
|
|
97
|
+
|
|
98
|
+
try:
|
|
99
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
100
|
+
for stale in cache_dir.glob("*.pkl"):
|
|
101
|
+
stale.unlink(missing_ok=True)
|
|
102
|
+
fd, tmp_name = tempfile.mkstemp(dir=cache_dir, suffix=".tmp")
|
|
103
|
+
try:
|
|
104
|
+
with os.fdopen(fd, "wb") as f:
|
|
105
|
+
pickle.dump(compiled, f, protocol=pickle.HIGHEST_PROTOCOL)
|
|
106
|
+
Path(tmp_name).replace(cache_file)
|
|
107
|
+
except BaseException:
|
|
108
|
+
Path(tmp_name).unlink(missing_ok=True)
|
|
109
|
+
raise
|
|
110
|
+
except Exception:
|
|
111
|
+
pass # caching is best-effort; a failed write must not break parsing
|
|
112
|
+
|
|
113
|
+
return compiled
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from datetime import UTC, datetime
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from dbetto import TextDB
|
|
7
|
-
from dbetto.catalog import Catalog
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def pre_compile_catalog(validity_path: str | Path):
|
|
11
|
-
"""Pre-compile a dbetto validity catalog for fast repeated access.
|
|
12
|
-
|
|
13
|
-
Reads the ``validity.yaml`` catalog from *validity_path* and, for each
|
|
14
|
-
system and each entry in the catalog, eagerly loads the corresponding
|
|
15
|
-
:class:`dbetto.TextDB` state (instead of loading it lazily on first
|
|
16
|
-
access). The resulting :class:`dbetto.catalog.Catalog` can be serialised
|
|
17
|
-
and reused across many Snakemake jobs without re-parsing YAML on every
|
|
18
|
-
invocation.
|
|
19
|
-
|
|
20
|
-
Parameters
|
|
21
|
-
----------
|
|
22
|
-
validity_path : str or pathlib.Path
|
|
23
|
-
Directory containing the ``validity.yaml`` file and all referenced
|
|
24
|
-
database files.
|
|
25
|
-
|
|
26
|
-
Returns
|
|
27
|
-
-------
|
|
28
|
-
dbetto.catalog.Catalog
|
|
29
|
-
Pre-compiled catalog with all entries eagerly resolved.
|
|
30
|
-
"""
|
|
31
|
-
if isinstance(validity_path, str):
|
|
32
|
-
validity_path = Path(validity_path)
|
|
33
|
-
catalog = Catalog.read_from(validity_path / "validity.yaml")
|
|
34
|
-
entries = {}
|
|
35
|
-
textdb = TextDB(validity_path, lazy=False)
|
|
36
|
-
for system in catalog.entries:
|
|
37
|
-
entries[system] = []
|
|
38
|
-
for entry in catalog.entries[system]:
|
|
39
|
-
db = textdb.on(
|
|
40
|
-
datetime.fromtimestamp(entry.valid_from, tz=UTC), system=system
|
|
41
|
-
)
|
|
42
|
-
new_entry = Catalog.Entry(entry.valid_from, db)
|
|
43
|
-
entries[system].append(new_entry)
|
|
44
|
-
return Catalog(entries)
|
|
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
|