Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions src/ibex_bluesky_core/callbacks/file_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import csv
import logging
import os
from datetime import datetime
from pathlib import Path
from platform import node
Expand All @@ -28,7 +29,7 @@
RB = "rb_number"
PRECISION = "precision"
INSTRUMENT = node()
DEFAULT_PATH = Path("//isis/inst$") / INSTRUMENT / "user" / "TEST" / "scans"
DEFAULT_PATH = Path("//isis.cclrc.ac.uk/inst$") / INSTRUMENT / "user" / "TEST" / "scans"


class HumanReadableFileCallback(CallbackBase):
Expand Down Expand Up @@ -59,10 +60,19 @@ def start(self, doc: RunStart) -> None:
title_format_datetime = datetime_obj.astimezone(ZoneInfo("Europe/London")).strftime(
"%Y-%m-%d_%H-%M-%S"
)
axes = "_".join(self.fields)
rb_num = doc.get("rb_number", "Unknown RB")

detectors = doc.get("detectors", [])
# motors is a tuple, we need to convert to a list to join the two below
motors = doc.get("motors", [])
if motors:
motors = list(motors)

detectors_and_motors = "_".join(detectors + motors)
self.filename = (
self.output_dir / f"{rb_num}" / f"{INSTRUMENT}_{axes}_{title_format_datetime}Z.txt"
self.output_dir
/ f"{rb_num}"
/ f"{INSTRUMENT}_{detectors_and_motors}_{title_format_datetime}Z.txt"
)
if rb_num == "Unknown RB":
logger.warning('No RB number found, saving to "Unknown RB"')
Expand All @@ -79,9 +89,11 @@ def start(self, doc: RunStart) -> None:
)
header_data[START_TIME] = formatted_time

with open(self.filename, "a", newline="", encoding="utf-8") as outfile:
for key, value in header_data.items():
outfile.write(f"{key}: {value}\n")
# make sure the parent directory exists, create it if not
os.makedirs(self.filename.parent, exist_ok=True)

with open(self.filename, "a", newline="\n", encoding="utf-8") as outfile:
outfile.writelines([f"{key}: {value}\n" for key, value in header_data.items()])

logger.debug("successfully wrote header in %s", self.filename)

Expand Down
6 changes: 4 additions & 2 deletions src/ibex_bluesky_core/callbacks/fitting/livefit_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,15 @@ def stop(self, doc: RunStop) -> None:

self.stats = self.livefit.result.fit_report().split("\n")

# make sure the parent directory exists, create it if not
os.makedirs(self.filename.parent, exist_ok=True)

# Writing to csv file
with open(self.filename, "w", newline="", encoding="utf-8") as csvfile:
# Writing the data
self.csvwriter = csv.writer(csvfile)

for row in self.stats:
csvfile.write(row + os.linesep)
csvfile.writelines([row + os.linesep for row in self.stats])

csvfile.write(os.linesep) # Space out file
csvfile.write(os.linesep)
Expand Down
26 changes: 20 additions & 6 deletions tests/callbacks/fitting/test_fit_logging_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ def test_after_fitting_callback_writes_to_file_successfully_no_y_uncertainty(

lf = LiveFit(Linear.fit(), y="invariant", x="motor", update_every=50)
lfl = LiveFitLogger(lf, y="invariant", x="motor", postfix=postfix, output_dir=filepath)
with patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m):
with (
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m),
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.os.makedirs"),
):
with patch("time.time", MagicMock(return_value=time)):
RE(scan([invariant], mot, -1, 1, 3), [lf, lfl], rb_number="0")

Expand All @@ -38,11 +41,12 @@ def test_after_fitting_callback_writes_to_file_successfully_no_y_uncertainty(
) # type: ignore

handle = m()
rows_writelines = next(i.args[0] for i in handle.writelines.call_args_list)
rows = [i.args[0] for i in handle.write.call_args_list]

# Check that it starts writing to the file in the expected way

assert f" Model({Linear.__name__} [{Linear.equation}])" + os.linesep in rows
assert f" Model({Linear.__name__} [{Linear.equation}])" + os.linesep in rows_writelines
assert "x,y,modelled y\r\n" in rows


Expand All @@ -58,7 +62,10 @@ def test_fitting_callback_handles_no_rb_number_save(

lf = LiveFit(Linear.fit(), y="invariant", x="motor", update_every=50)
lfl = LiveFitLogger(lf, y="invariant", x="motor", postfix=postfix, output_dir=filepath)
with patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m):
with (
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m),
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.os.makedirs"),
):
with patch("time.time", MagicMock(return_value=time)):
RE(scan([invariant], mot, -1, 1, 3), [lf, lfl])

Expand All @@ -84,7 +91,10 @@ def test_after_fitting_callback_writes_to_file_successfully_with_y_uncertainty(
lf, y="invariant", x="motor", postfix=postfix, output_dir=filepath, yerr="uncertainty"
)

with patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m):
with (
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m),
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.os.makedirs"),
):
with patch("time.time", MagicMock(return_value=time)):
RE(scan([invariant, uncertainty], mot, -1, 1, 3), [lf, lfl], rb_number="0")

Expand All @@ -95,10 +105,11 @@ def test_after_fitting_callback_writes_to_file_successfully_with_y_uncertainty(

handle = m()
rows = [i.args[0] for i in handle.write.call_args_list]
rows_writelines = next(i.args[0] for i in handle.writelines.call_args_list)

# Check that it starts writing to the file in the expected way

assert f" Model({Linear.__name__} [{Linear.equation}])" + os.linesep in rows
assert f" Model({Linear.__name__} [{Linear.equation}])" + os.linesep in rows_writelines
assert "x,y,y uncertainty,modelled y\r\n" in rows


Expand All @@ -117,7 +128,10 @@ def test_file_not_written_if_no_fitting_result(RE: run_engine.RunEngine):
lf = LiveFit(method, y="invariant", x="motor")
lfl = LiveFitLogger(lf, y="invariant", x="motor", postfix=postfix, output_dir=filepath)

with patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m):
with (
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.open", m),
patch("ibex_bluesky_core.callbacks.fitting.livefit_logger.os.makedirs"),
):
RE(scan([invariant], mot, -1, 1, 3), [lf, lfl], rb_number="0")

assert not m.called
Expand Down
57 changes: 45 additions & 12 deletions tests/callbacks/test_write_log_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,67 @@ def test_header_data_all_available_on_start(cb):
time = 1728049423.5860472
uid = "test123"
scan_id = 1234
run_start = RunStart(time=time, uid=uid, scan_id=scan_id, rb_number="0")
with patch("ibex_bluesky_core.callbacks.file_logger.open", mock_open()) as mock_file:
run_start = RunStart(
time=time, uid=uid, scan_id=scan_id, rb_number="0", detectors=["dae"], motors=("block",)
)
with (
patch("ibex_bluesky_core.callbacks.file_logger.open", mock_open()) as mock_file,
patch("ibex_bluesky_core.callbacks.file_logger.os.makedirs"),
):
cb.start(run_start)
result = (
save_path
/ f"{run_start.get('rb_number', None)}"
/ f"{node()}_block_dae_2024-10-04_14-43-43Z.txt"
/ f"{node()}_dae_block_2024-10-04_14-43-43Z.txt"
)

mock_file.assert_called_with(result, "a", newline="", encoding="utf-8")
mock_file.assert_called_with(result, "a", newline="\n", encoding="utf-8")
writelines_call_args = mock_file().writelines.call_args[0][0]
# time should have been renamed to start_time and converted to human readable
mock_file().write.assert_any_call("start_time: 2024-10-04 14:43:43\n")
mock_file().write.assert_any_call(f"uid: {uid}\n")
assert "start_time: 2024-10-04 14:43:43\n" in writelines_call_args
assert f"uid: {uid}\n" in writelines_call_args


def test_no_rb_number_folder(cb):
time = 1728049423.5860472
uid = "test123"
scan_id = 1234
run_start = RunStart(time=time, uid=uid, scan_id=scan_id)
with patch("ibex_bluesky_core.callbacks.file_logger.open", mock_open()) as mock_file:
run_start = RunStart(time=time, uid=uid, scan_id=scan_id, detectors=["dae"], motors=("block",))

with (
patch("ibex_bluesky_core.callbacks.file_logger.open", mock_open()) as mock_file,
patch("ibex_bluesky_core.callbacks.file_logger.os.makedirs") as mock_mkdir,
):
cb.start(run_start)
result = save_path / "Unknown RB" / f"{node()}_dae_block_2024-10-04_14-43-43Z.txt"
assert mock_mkdir.called

mock_file.assert_called_with(result, "a", newline="\n", encoding="utf-8")
# time should have been renamed to start_time and converted to human readable
writelines_call_args = mock_file().writelines.call_args[0][0]
assert "start_time: 2024-10-04 14:43:43\n" in writelines_call_args
assert f"uid: {uid}\n" in writelines_call_args


def test_no_motors_doesnt_append_to_filename(cb):
time = 1728049423.5860472
uid = "test123"
scan_id = 1234
run_start = RunStart(time=time, uid=uid, scan_id=scan_id, detectors=["dae"])

with (
patch("ibex_bluesky_core.callbacks.file_logger.open", mock_open()) as mock_file,
patch("ibex_bluesky_core.callbacks.file_logger.os.makedirs") as mock_mkdir,
):
cb.start(run_start)
result = save_path / "Unknown RB" / f"{node()}_block_dae_2024-10-04_14-43-43Z.txt"
result = save_path / "Unknown RB" / f"{node()}_dae_2024-10-04_14-43-43Z.txt"
assert mock_mkdir.called

mock_file.assert_called_with(result, "a", newline="", encoding="utf-8")
mock_file.assert_called_with(result, "a", newline="\n", encoding="utf-8")
# time should have been renamed to start_time and converted to human readable
mock_file().write.assert_any_call("start_time: 2024-10-04 14:43:43\n")
mock_file().write.assert_any_call(f"uid: {uid}\n")
writelines_call_args = mock_file().writelines.call_args[0][0]
assert "start_time: 2024-10-04 14:43:43\n" in writelines_call_args
assert f"uid: {uid}\n" in writelines_call_args


def test_descriptor_data_does_nothing_if_doc_not_called_primary(cb):
Expand Down
Loading