Allow stiching to be cancelled after a scan complete

Closes #417
This commit is contained in:
Julian Stirling 2025-07-02 18:13:48 +01:00
parent 248f43d0fc
commit e7cf0c3f24

View file

@ -398,7 +398,7 @@ class SmartScanThing(Thing):
should return to the starting x,y,z position should return to the starting x,y,z position
""" """
# Used to check if finally was reached via exeption (except # Used to check if finally was reached via exception (except
# cancel by user) # cancel by user)
scan_successful = True scan_successful = True
@ -416,6 +416,8 @@ class SmartScanThing(Thing):
except InvocationCancelledError: except InvocationCancelledError:
scan_successful = False scan_successful = False
# Reset the cancel event so it can be thrown again
self._cancel.clear()
self._scan_logger.info("Stopping scan because it was cancelled.") self._scan_logger.info("Stopping scan because it was cancelled.")
self._update_scan_data_json(scan_result="cancelled by user") self._update_scan_data_json(scan_result="cancelled by user")
except scan_directories.NotEnoughFreeSpaceError as e: except scan_directories.NotEnoughFreeSpaceError as e:
@ -447,7 +449,7 @@ class SmartScanThing(Thing):
# log the error. # log the error.
if scan_successful: if scan_successful:
self._scan_logger.error( self._scan_logger.error(
"The scan appears to have started successfully, however " "The scan appears to have completed successfully, however "
f"the final capture raised the following error: {e}." f"the final capture raised the following error: {e}."
"Attempting to stitch and archive images.", "Attempting to stitch and archive images.",
exc_info=e, exc_info=e,
@ -557,6 +559,7 @@ class SmartScanThing(Thing):
self._scan_logger.info("Stitching final image (may take some time)...") self._scan_logger.info("Stitching final image (may take some time)...")
self.stitch_scan( self.stitch_scan(
logger=self._scan_logger, logger=self._scan_logger,
cancel=self._cancel,
scan_name=self._ongoing_scan.name, scan_name=self._ongoing_scan.name,
stitch_resize=self._scan_data["stitch_resize"], stitch_resize=self._scan_data["stitch_resize"],
overlap=self._scan_data["overlap"], overlap=self._scan_data["overlap"],
@ -847,6 +850,7 @@ class SmartScanThing(Thing):
def run_subprocess( def run_subprocess(
self, self,
logger: InvocationLogger, logger: InvocationLogger,
cancel: CancelHook,
cmd: list[str], cmd: list[str],
) -> CompletedProcess: ) -> CompletedProcess:
""" """
@ -854,6 +858,7 @@ class SmartScanThing(Thing):
Raises: Raises:
ChildProcessError if exit code is not zero ChildProcessError if exit code is not zero
InvocationCancelledError if the action is cancelled.
""" """
logger.info(f"Running command in subprocess: `{' '.join(cmd)}`") logger.info(f"Running command in subprocess: `{' '.join(cmd)}`")
@ -876,7 +881,15 @@ class SmartScanThing(Thing):
while process.poll() is None: while process.poll() is None:
log_buffer(process.stdout) log_buffer(process.stdout)
# Once buffer is clear sleep for 0.2s before trying again. # Once buffer is clear sleep for 0.2s before trying again.
time.sleep(0.2)
try:
# Note that using cancel.sleep allows the InvocationCancelledError to
# be thrown
cancel.sleep(0.2)
except InvocationCancelledError as e:
logger.info("Stitching cancelled by user")
process.kill()
raise e
# Print everything in the buffer when program finishes # Print everything in the buffer when program finishes
log_buffer(process.stdout) log_buffer(process.stdout)
@ -890,6 +903,7 @@ class SmartScanThing(Thing):
def stitch_scan( def stitch_scan(
self, self,
logger: InvocationLogger, logger: InvocationLogger,
cancel: CancelHook,
scan_name: str, scan_name: str,
stitch_resize: Optional[float] = None, stitch_resize: Optional[float] = None,
overlap: float = 0.0, overlap: float = 0.0,
@ -951,21 +965,27 @@ class SmartScanThing(Thing):
) )
stitch_resize = 0.5 stitch_resize = 0.5
self.run_subprocess( try:
logger, self.run_subprocess(
[ logger=logger,
STITCHING_CMD, cancel=cancel,
"--stitching_mode", cmd=[
"all", STITCHING_CMD,
f"{tiff_arg}", "--stitching_mode",
"--stitch_dzi", "all",
"--minimum_overlap", f"{tiff_arg}",
f"{round(overlap * 0.9, 2)}", "--stitch_dzi",
"--resize", "--minimum_overlap",
f"{stitch_resize}", f"{round(overlap * 0.9, 2)}",
self._scan_dir_manager.img_dir_for(scan_name), "--resize",
], f"{stitch_resize}",
) self._scan_dir_manager.img_dir_for(scan_name),
],
)
except InvocationCancelledError:
# Sleep for 1 second just to allow invocation logs to pass to user.
time.sleep(1)
pass
@thing_action @thing_action
def download_zip( def download_zip(