dapkel.core¶
The shared substrate every analysis is built on. Anything copied into two
analysis modules belongs here instead — tests/test_api_surface.py fails if a
function name is defined twice.
See Adding an analysis for the contract.
core.io — finding and sizing raw files¶
io ¶
Stage 0: locating and sizing the raw Kelpie '.bin' files.
Every analysis starts by picking the '.bin' files that belong to a measurement and working out how many frames each holds. Both were previously copied into four modules; they live here now so the '.bin' format is described in exactly one place.
frames_in_file ¶
Return how many frames a '.bin' file has room for, from its size.
Do not use this as the acquisition's frame count.
The relation between the frame count an acquisition was asked for and
the size of the '.bin' it produces is not established. Every sample
file measured is a whole power-of-two number of frames - 32 MiB
(16 384 frames) and 16 MiB (8 192) - which is what the exe's DDR3
transfer size would give for a power-of-two nframes, but not what a
10 000-frame acquisition should produce. Either those files were taken
at 16 384 and 8 192, or something rounds; a controlled sweep on the rig
is what settles it.
Both this package's 'unpack' and the reference kelpie_data_ddr3.m
read only the first nframes frames, so the acquisition setting is
what every analysis takes as a required argument, and it is the number
a rate must be normalised by. Use this only when the file size really
is the only record left, and treat it as an upper bound.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fp
|
str
|
Path to the '.bin' file. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Frame capacity of the file, |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised when the file size is not a whole number of frames. |
Source code in src/dapkel/core/io.py
find_bin_files ¶
Find and naturally sort the '.bin' files for a readout tag.
"Naturally" means ordered by the digits in the file name, so ..._2.bin
sorts before ..._10.bin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
folder
|
str
|
Path to the folder with the '.bin' data files. |
required |
tag
|
str
|
Filename fragment selecting the files (e.g. |
required |
require_separator
|
bool
|
When True the tag must be preceded by an underscore (pattern
|
False
|
Returns:
| Type | Description |
|---|---|
list[str]
|
Naturally sorted list of paths to the matching '.bin' files. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
Raised when no '.bin' files match the tag in the folder. |
Source code in src/dapkel/core/io.py
core.timing — frame period and live time¶
timing ¶
Stage 1: resolving how much wall-clock time an acquisition represents.
Counts become rates only once you know how long the sensor was actually collecting, and that depends on the firmware. These helpers previously lived in 'dcr_analysis' as private functions that 'hitmap_analysis' imported across the module boundary; they are shared API, so they live here.
Also the single home for the ORT timing scale. Every time parameter in this
package is in seconds and named with an _s suffix; picoseconds appear only
as internal working units, because that is the scale the TDC lives on. Convert
at the boundary with 'to_ps' / 'to_s'.
Two timescales are easy to conflate and must not be:
open_shutter_time_s- the photon-sensitive window per frame. Sets the rate normalisation, and bounds how far apart two detections in one frame can be.- the TDC full scale - the ORT measurement range, i.e. one period of the reference clock. The timestamp is a code on this range, so it is what the accidental (triangle) background's half-base follows.
They coincide only when the shutter is one clock period. When the shutter is longer, the free-running oscillator has no cycle counter, so timestamps fold into the full scale: a 500 ns shutter read by a 10 MHz (100 ns) TDC gives a 100 ns triangle, not a 500 ns one. Never assume one from the other - 'resolve_tdc_full_scale_s' takes the full scale from the calibration LUT, which is self-describing, and only falls back to the shutter when there is no LUT.
to_ps ¶
Convert seconds to picoseconds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seconds
|
float
|
A time in seconds (the package-wide parameter convention). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The same time in picoseconds (the internal working unit). |
Source code in src/dapkel/core/timing.py
to_s ¶
Convert picoseconds to seconds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
picoseconds
|
float
|
A time in picoseconds (the internal working unit). |
required |
Returns:
| Type | Description |
|---|---|
float
|
The same time in seconds (the package-wide parameter convention). |
Source code in src/dapkel/core/timing.py
codes_for_full_scale ¶
Size the TDC code axis for a given full scale.
The ring sweeps full_scale_s / code_s codes per measurement range; the
headroom covers per-pixel spread in the ring frequency, and the code axis is
trimmed to what is actually populated afterwards anyway.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
full_scale_s
|
float
|
TDC full scale (one reference-clock period), in seconds. |
required |
code_s
|
float
|
Nominal width of one code, in seconds. The default is 'CODE_S'. |
CODE_S
|
headroom
|
float
|
Multiplier applied to the nominal code count. The default is 1.1. |
1.1
|
Returns:
| Type | Description |
|---|---|
int
|
Number of code bins, capped at |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised when |
Warns:
| Type | Description |
|---|---|
UserWarning
|
Raised when the requested full scale exceeds what the coarse counter can express, i.e. the reference clock is too slow and codes will wrap. |
Source code in src/dapkel/core/timing.py
resolve_tdc_full_scale_s ¶
resolve_tdc_full_scale_s(*, time_lut=None, full_scale_s: float | None = None, open_shutter_time_s: float | None = None) -> tuple[float, str]
Return the TDC full scale to model the accidental background on.
The timestamp is a code on the TDC's measurement range, so a difference of two timestamps is bounded by that range and - phases being uniform within it - distributed as a triangle of that half-base. Resolution order, most to least trustworthy:
time_lut- a calibration LUT is self-describing: its largest entry is the full scale it was built for.full_scale_s- stated outright by the caller.open_shutter_time_s- a fallback that is only correct when the shutter is exactly one clock period. Warns, because a shutter longer than the clock period folds (see the module docstring).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time_lut
|
ndarray | None
|
A |
None
|
full_scale_s
|
float | None
|
TDC full scale in seconds, stated explicitly. The default is None. |
None
|
open_shutter_time_s
|
float | None
|
Photon-sensitive window per frame, in seconds, used only as a last resort. The default is None. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[float, str]
|
The full scale in seconds and a human-readable source string. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised when none of the three inputs is given. |
Warns:
| Type | Description |
|---|---|
UserWarning
|
Raised when the full scale had to be guessed from the shutter, or when
a LUT and an explicit |
Source code in src/dapkel/core/timing.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | |
resolve_cycle_time ¶
Return the length of one acquisition cycle and where it came from.
This is the wall-clock repetition period of a frame, which is what a
photon rate divides by: nframes * n_files * cycle is the elapsed
time of a run.
Computed from the firmware setting, and never from the
frame_rate_cnt.txt the acquisition exe writes beside the data: that exe
is not ours, so no analysis here is allowed to depend on its output. The
cycle length is a property of the firmware and the requested exposure, and
Kelpie_run.m states it directly: exp_time_s = 0 -> 9 us,
1e-6 -> 10 us, 2e-6 -> 11 us.
For the record, the counter is self-consistent where it exists - it is a
200 MHz tick count over the whole run, latched by the firmware, and across
every sample folder it fits ticks = nframes * N + 138 + window/5ns
exactly. What it says is that the real cycle is 9.685-9.770 µs, i.e.
685-770 ns per frame longer than the nominal 9 µs used here, and that the
50-500 ns exposure window sits inside the cycle rather than extending it.
So a rate normalised by the nominal 9 µs runs ~7.8% high. Whether to prefer
the nominal or a measured cycle is a decision for the experiment, not for
this function to make silently off a file it happens to find on disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
firmware_version
|
str
|
|
required |
exp_time_s
|
float | None
|
The exposure X requested of long-exposure firmware, in seconds. The
firmware adds 9 µs to it. Required for |
None
|
Returns:
| Type | Description |
|---|---|
tuple[float, str]
|
The cycle length in seconds and a human-readable source string. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised on an unknown |
Source code in src/dapkel/core/timing.py
resolve_frame_time ¶
Return the per-frame period and a description of where it came from.
- explicit
exp_time_ssupplied ->exp_time_s+ 9 µs overhead - fallback -> 9 µs free-running base
The acquisition exe also writes a frame_rate_cnt.txt beside the data -
a 200 MHz tick count for the whole run, latched by the firmware. It is
deliberately not read here. It is written by an exe we do not control, so
nothing in the analysis path is allowed to depend on it; the period comes
from the settings the run was started with. See 'resolve_cycle_time' for
what the counter does contain, and for the measured-vs-nominal gap.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
explicit_s
|
float | None
|
Explicit exposure time in seconds, or None for the free-running base. |
required |
nframes
|
int | None
|
Unused. Kept so existing callers do not break; it was only ever needed to turn the counter's tick count into a period. The default is None. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[float, str]
|
The frame period in seconds and a human-readable source string. |
Source code in src/dapkel/core/timing.py
resolve_live_time ¶
resolve_live_time(firmware_version: str, nframes: int, *, open_shutter_time_s: float | None = None, exp_time_s: float | None = None) -> tuple[float | None, str]
Return the live seconds per frame for the rate normalisation.
The photon rate is counts / (nframes * n_files * live_per_frame). How
much of each frame is photon-sensitive depends on the firmware:
-
'short_window'- the current firmware: each ~9 µs frame is mostly readout and only the open shutter window (open_shutter_time_s, e.g.200e-9s,< 9 µs) is live. Returns(None, ...)whenopen_shutter_time_sis not supplied, so the caller can decide whether that is an error (DCR) or just "no rate available" (hitmap). -
'full_window'- the legacy firmware: the whole frame is live, so the per-frame time comes from 'resolve_frame_time'.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
firmware_version
|
str
|
|
required |
nframes
|
int
|
Frames per file (used by the |
required |
open_shutter_time_s
|
float | None
|
Photon-sensitive window per frame, in seconds ( |
None
|
exp_time_s
|
float | None
|
Legacy exposure time, in seconds ( |
None
|
Returns:
| Type | Description |
|---|---|
tuple[float | None, str]
|
The live seconds per frame (None if unresolved) and a human-readable source string. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised when |
Source code in src/dapkel/core/timing.py
core.pairs — which pixel pairs, and what they are called¶
pairs ¶
Which pixel pairs an analysis is about, and what they are called.
Every coincidence analysis starts by turning two detector groups into an ordered list of pairs and a label per pair. That enumeration decides the row order of every stage-1 artifact, so two analyses are only comparable if they build it the same way - which is why it lives here rather than in each of them. 'delta_t' had it twice: once inline in the feather path, once as a private helper for the counts path.
The label format "ra,ca-rb,cb" is a stored contract: it is the key
'calc_diff.calculate_differences' returns, the column name in the delta-t
feather, and the labels entry in every counts sidecar. Do not reformat it.
pair_label ¶
pair_list ¶
Enumerate the ordered (pixel_a, pixel_b) pairs of two groups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pixels
|
Sequence[Sequence[tuple[int, int]]]
|
Two groups |
required |
mode
|
str
|
|
'all_pairs'
|
Returns:
| Type | Description |
|---|---|
list[tuple[tuple[int, int], tuple[int, int]]]
|
The pairs, in the order every artifact stores them in. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised on an unknown |
Source code in src/dapkel/core/pairs.py
pair_labels ¶
pair_labels(pixels: Sequence[Sequence[Pixel]], mode: str = 'all_pairs') -> tuple[list[str], list[Pixel]]
Pair labels and the de-duplicated pixels they mention.
The two things a stage-1 loop needs: what to call each output row, and which pixels to decode out of the frames.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pixels
|
Sequence[Sequence[tuple[int, int]]]
|
Two groups |
required |
mode
|
str
|
|
'all_pairs'
|
Returns:
| Name | Type | Description |
|---|---|---|
labels |
list[str]
|
|
all_pixels |
list[tuple[int, int]]
|
Every pixel mentioned, de-duplicated, first-seen order. |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised on an unknown |
Source code in src/dapkel/core/pairs.py
core.reduce — folding frames into a map¶
reduce ¶
Stage 1: folding a set of '.bin' files down to one sensor map.
Every count-like analysis in dapkel is the same loop - unpack each file, pull one (32, 32) slab out of the frames, add it up - differing only in which slab it pulls. That loop lives here once; the analyses supply the extraction.
accumulate_frames ¶
accumulate_frames(files: list[str], extract: Extract, *, nframes: int, need_time_series: bool = True, label: str = '', shape: tuple[int, int] = (32, 32)) -> ndarray
Unpack every file and sum an extracted slab over all of them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
files
|
list[str]
|
Paths to the '.bin' files to unpack and accumulate. |
required |
extract
|
callable
|
|
required |
nframes
|
int
|
Frames per file - the acquisition setting, required rather than inferred. 'io.frames_in_file' is there when a file's size is the only record left, but which frame count a run used is the caller's to state, not this loop's to guess. |
required |
need_time_series
|
bool
|
Whether |
True
|
label
|
str
|
Label used in the progress bar. The default is "". |
''
|
shape
|
tuple[int, int]
|
Shape of the accumulator. The default is |
(32, 32)
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The summed map, float64. |
Source code in src/dapkel/core/reduce.py
assemble_64 ¶
Interleave four (32, 32) quadrant maps into the (64, 64) sensor map.
Each SPAD tag reads one micropixel per 2x2 macropixel, so the four
quadrant maps interleave rather than tile: quadrant with offset
(drow, dcol) occupies full[drow::2, dcol::2].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
quadrants
|
dict[str, ndarray]
|
Mapping of SPAD tag to its (32, 32) map. Tags absent from the mapping are left as zero, so a partial acquisition still assembles. |
required |
layout
|
dict[str, tuple[int, int]]
|
Mapping of SPAD tag to its |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The (64, 64) assembled map, float64. |
Source code in src/dapkel/core/reduce.py
core.plots — the two figure shapes¶
plots ¶
Stage 2: the two figure shapes every analysis draws.
A sensor map (a 2D image of the array) and a sorted-percentile distribution cover every plot in the package bar the TDC QA panel. Both used to be copied per analysis, which is how three heatmaps ended up with three different figure sizes and two different NaN policies.
Figure sizing follows the package rule: square sensor maps set 16x16 in
code, everything else takes figure.figsize from the active style (the
dapkel style ships 16x10). So 'sensor_map' is explicit and
'sorted_distribution' is not.
All statistics here are NaN-aware. Plain np.median/np.percentile
propagate NaN, so a single masked pixel would turn vmax into NaN and
flatten the whole image to one colour with no error - see
'docs/adding_an_analysis.md'.
map_stats ¶
Return the NaN-aware (median, max, total) of a sensor map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
The map. |
required |
scale
|
float
|
Multiplied into the data first, for unit conversion (e.g. 100.0 to turn a ratio into a percentage). The default is 1.0. |
1.0
|
Returns:
| Type | Description |
|---|---|
tuple[float, float, float]
|
Median, maximum and sum, all ignoring NaN. An all-NaN map gives
|
Source code in src/dapkel/core/plots.py
sensor_map ¶
sensor_map(data: ndarray, *, title: str, clabel: str | None = None, cmap: str | None = None, scale: float = 1.0, xlabel: str = 'Column', ylabel: str = 'Row') -> Figure
Render a sensor map as a square 2D image with a colour bar.
The colour scale is clipped at the 99th percentile so a handful of hot pixels cannot wash out the rest of the array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
The (rows, cols) map to draw. |
required |
title
|
str
|
Full figure title. Callers build this themselves - the wording is measurement-specific - typically from 'map_stats'. |
required |
clabel
|
str | None
|
Colour-bar label. The default is None (no label). |
None
|
cmap
|
str | None
|
Matplotlib colormap name. The default is None - use the active
style's |
None
|
scale
|
float
|
Multiplied into the data before drawing. The default is 1.0. |
1.0
|
xlabel
|
str
|
Axis labels. The defaults are |
'Column'
|
ylabel
|
str
|
Axis labels. The defaults are |
'Column'
|
Returns:
| Type | Description |
|---|---|
Figure
|
The figure. Nothing is written to disk. |
Source code in src/dapkel/core/plots.py
sorted_distribution ¶
sorted_distribution(data: ndarray, *, ylabel: str, title: str, xlabel: str = 'Pixel percentile (%)', logy: bool = False, scale: float = 1.0, fmt: str = '.3g', unit: str = '') -> Figure
Plot per-pixel values sorted low-to-high against their percentile.
Non-finite values are dropped before sorting, so masked or undefined pixels neither plot nor skew the median and mean lines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
The map whose values are ranked. |
required |
ylabel
|
str
|
Y-axis label, including the unit (e.g. |
required |
title
|
str
|
Figure title. |
required |
xlabel
|
str
|
X-axis label. The default is |
'Pixel percentile (%)'
|
logy
|
bool
|
Use a logarithmic y-axis, appropriate when the values span decades (DCR does). The default is False. |
False
|
scale
|
float
|
Multiplied into the data first. The default is 1.0. |
1.0
|
fmt
|
str
|
Format spec for the median/mean values in the legend. The default is
|
'.3g'
|
unit
|
str
|
Unit appended to the legend entries (e.g. |
''
|
Returns:
| Type | Description |
|---|---|
Figure
|
The figure. Nothing is written to disk. |
Source code in src/dapkel/core/plots.py
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | |
core.store — the stage 1 / stage 2 boundary¶
store ¶
Persistence: the boundary between stage 1 (data) and stage 2 (figures).
The layout under a data folder is::
<data folder>/
*.bin stage 0 - raw, read-only, dapkel never writes here
processed/ stage 1 - arrays ('.npy') + metadata ('.meta.json')
results/<kind>/ stage 2 - figures only
One rule follows from it: stage 2 gets its data by loading a stage-1 artifact, never by re-unpacking '.bin' files. Retrying a colormap costs a 'load_map', not a full re-read of the raw data.
Every array is saved with a .meta.json sidecar recording how it was
acquired (frame counts, live time, tag), so a saved map can still be turned
into a rate months later without the original call arguments.
See 'docs/adding_an_analysis.md' for the contract.
processed_dir ¶
Return (and by default create) the processed/ folder of a dataset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
folder
|
str
|
The data folder holding the '.bin' files. |
required |
create
|
bool
|
Create the folder if missing. The default is True. |
True
|
Returns:
| Type | Description |
|---|---|
str
|
Path to |
Source code in src/dapkel/core/store.py
results_dir ¶
Return (and by default create) the figure folder for one analysis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
folder
|
str
|
The data folder holding the '.bin' files. |
required |
kind
|
str
|
Analysis name, used as the sub-folder (e.g. |
required |
create
|
bool
|
Create the folder if missing. The default is True. |
True
|
Returns:
| Type | Description |
|---|---|
str
|
Path to |
Source code in src/dapkel/core/store.py
map_file_name ¶
Build the '.npy' file name for a stage-1 array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset
|
str
|
Name of the dataset, normally the data folder's base name. |
required |
kind
|
str
|
Analysis name (e.g. |
required |
tag
|
str
|
Readout/quadrant tag distinguishing artifacts of the same kind. The default is "". |
''
|
Returns:
| Type | Description |
|---|---|
str
|
|
Source code in src/dapkel/core/store.py
meta_path ¶
read_meta ¶
Read a saved array's '.meta.json' sidecar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
npy_path
|
str
|
Path to the saved '.npy'. |
required |
Returns:
| Type | Description |
|---|---|
dict
|
The metadata, or an empty dict when the sidecar is missing or unreadable - callers treat metadata as best-effort. |
Source code in src/dapkel/core/store.py
save_map ¶
save_map(data: ndarray, folder: str, *, kind: str, tag: str = '', meta: dict | None = None, file_name: str | None = None, quiet: bool = False) -> str
Save a stage-1 array into processed/ with a metadata sidecar.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ndarray
|
The array to save. |
required |
folder
|
str
|
The data folder; the array lands in its |
required |
kind
|
str
|
Analysis name (e.g. |
required |
tag
|
str
|
Readout/quadrant tag. The default is "". |
''
|
meta
|
dict | None
|
Acquisition metadata written alongside as '.meta.json'. The default is None (an empty sidecar is still written, recording kind and tag). |
None
|
file_name
|
str | None
|
Explicit '.npy' file name, overriding the derived one. Used where a naming scheme is already established (the TDC LUTs). The default is None. |
None
|
quiet
|
bool
|
Suppress the "saved to" printout. The default is False. |
False
|
Returns:
| Type | Description |
|---|---|
str
|
Path the array was saved to. |
Source code in src/dapkel/core/store.py
load_map ¶
load_map(folder: str | None = None, *, kind: str = '', tag: str = '', npy_path: str | None = None, file_name: str | None = None) -> tuple[ndarray, dict]
Load a stage-1 array and its metadata back from processed/.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
folder
|
str | None
|
The data folder to look under. May be None when |
None
|
kind
|
str
|
Analysis name, used to derive the file name. The default is "". |
''
|
tag
|
str
|
Readout/quadrant tag. The default is "". |
''
|
npy_path
|
str | None
|
Explicit path to a saved '.npy', bypassing the derivation entirely. The default is None. |
None
|
file_name
|
str | None
|
Explicit file name within |
None
|
Returns:
| Type | Description |
|---|---|
tuple[ndarray, dict]
|
The array and its metadata (an empty dict when no sidecar exists). |
Raises:
| Type | Description |
|---|---|
ValueError
|
Raised when neither |
FileNotFoundError
|
Raised when the '.npy' does not exist, with the path that was tried. |
Source code in src/dapkel/core/store.py
save_figure ¶
Save a figure into the results folder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fig
|
Figure
|
Figure to save. |
required |
results_dir
|
str
|
Folder the figure should be saved into. Created if missing. |
required |
file_name
|
str
|
Name of the '.png' file to save the figure as. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Path the figure was saved to. |
Source code in src/dapkel/core/store.py
confirm_rewrite ¶
Warn, then pause, before existing artifacts are overwritten.
Call this from any analysis whose rewrite=True is about to destroy
stage-1 data. Nothing is printed and nothing is waited for on a fresh run
(no target exists), so the pause only ever costs something when there is
genuinely something to lose - typically a rewrite=True left in the
script from the previous acquisition.
The countdown is a plain time.sleep, so Ctrl-C during it raises
'KeyboardInterrupt' out of the analysis and the data on disk is untouched.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paths
|
str | Sequence[str]
|
Artifact(s) about to be overwritten. Files and directories are both accepted; entries that do not exist are ignored. Pass every target, including part-file folders, so the warning names them all. |
required |
delay
|
float | None
|
Seconds to count down. The default is None, meaning 'REWRITE_DELAY_S' (5 s). Pass 0 to warn without pausing. |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if something existed and is about to be overwritten, False on a fresh run. |