fix(dupe): guard dupe-scan startup against crashes; fix packaged-build logging (#111) #119

Merged
ValleyGeek merged 3 commits from 0.1.38/issue-111-dupe-scan-crash into main 2026-06-22 00:45:10 +00:00
Member

Summary

  • #111 — the duplicate scan could crash the app on startup with no visible error (especially on console-disabled Windows builds). _start_dupe_scan() and its progress/finished/error signal handlers had no exception handling of their own; any exception in that path propagated straight out of a Qt slot and the app just closed. Wrapped the synchronous start path and each signal handler in try/except, routing failures through a new _fail_dupe_scan() helper that shows a "Duplicate Scan Error" dialog and resets scan state (each reset step runs independently so one failing widget call can't suppress the rest, including the dialog itself).
  • Follow-on fix: setup_logging() only checked sys.frozen, which Nuitka doesn't reliably set on packaged builds — so packaged builds fell through to the dev logging branch (a useless/silently-swallowed stdout handler on Windows, and no file handler at all), meaning any exception logged via logger.exception() along the #111 path would vanish without a trace. Added _running_packaged() (matching resource_paths.py's __compiled__ check) so packaged builds get a durable log file under the global config dir instead.

Test plan

  • ruff check / ruff format --check
  • pytest
  • PR-prep version bump 0.1.38 → 0.1.39

Refs #111.

First of a chain of 11 sequential PRs (each based on the previous one's tip) bringing the full feature-branch backlog into main in order.

## Summary - **#111** — the duplicate scan could crash the app on startup with no visible error (especially on console-disabled Windows builds). `_start_dupe_scan()` and its progress/finished/error signal handlers had no exception handling of their own; any exception in that path propagated straight out of a Qt slot and the app just closed. Wrapped the synchronous start path and each signal handler in try/except, routing failures through a new `_fail_dupe_scan()` helper that shows a "Duplicate Scan Error" dialog and resets scan state (each reset step runs independently so one failing widget call can't suppress the rest, including the dialog itself). - Follow-on fix: `setup_logging()` only checked `sys.frozen`, which Nuitka doesn't reliably set on packaged builds — so packaged builds fell through to the dev logging branch (a useless/silently-swallowed stdout handler on Windows, and no file handler at all), meaning any exception logged via `logger.exception()` along the #111 path would vanish without a trace. Added `_running_packaged()` (matching `resource_paths.py`'s `__compiled__` check) so packaged builds get a durable log file under the global config dir instead. ## Test plan - [x] `ruff check` / `ruff format --check` - [x] `pytest` - [x] PR-prep version bump 0.1.38 → 0.1.39 Refs #111. First of a chain of 11 sequential PRs (each based on the previous one's tip) bringing the full feature-branch backlog into `main` in order.
_start_dupe_scan() and its progress/finished/error signal handlers had no
exception handling of their own. An exception raised anywhere in that path
(start, progress, or finish) propagated straight out of a Qt slot instead of
being caught — on a console-disabled Windows build there is no visible
traceback at all, so the app appears to simply crash and close (#111).

Wrap the synchronous start path and each signal handler in try/except,
routing failures through a new _fail_dupe_scan() helper that resets scan
state and shows a "Duplicate Scan Error" dialog instead. _fail_dupe_scan()
itself runs each reset step independently so one failing widget call can't
suppress the rest (including the dialog).

Threading notes: DupeWorker (background thread) is unchanged — it already
wraps its run() in try/except and only emits plain-data signals. This change
only hardens the main-thread consumers of those signals, consistent with the
Error Handling rule that a bug in this path must never take down the app.

Fixes #111
setup_logging() only checked getattr(sys, "frozen", False) to decide between
dev and packaged logging config. core/resource_paths.py already documents
that Nuitka does not always set sys.frozen, so on the real packaged build
this fell through to the dev branch: it attached a stdout StreamHandler
(useless and silently swallowed on Windows, where main.py builds with
--windows-console-mode=disable and sys.stdout is None) and skipped the file
handler entirely (the "not frozen" guard on log_file), leaving the packaged
app with no log output anywhere. Any exception logged via logger.exception()
in a path like #111's dupe-scan handlers would vanish without a trace.

Add _running_packaged(), matching resource_paths.py's __compiled__ check, and
route packaged builds to a durable log file under the global config dir
(<config dir>/logs/bulk-image-organizer.log) instead. Also guard the dev-mode
console handler against a None sys.stdout for the same reason.
docs: PR-prep for issue 111 - bump to 0.1.39
All checks were successful
CI / lint (push) Successful in 8s
CI / test (push) Successful in 1m42s
CI / appimage (push) Successful in 8m26s
CI / build-appimage (push) Successful in 0s
CI / windows-exe (push) Successful in 9m41s
CI / build-windows-exe (push) Successful in 0s
69530c435f
ValleyGeek deleted branch 0.1.38/issue-111-dupe-scan-crash 2026-06-22 00:45:11 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ai-collab/bulk-image-organizer!119
No description provided.