Add module-level _graph_request() that wraps requests.request() with:
- Up to 3 retries on HTTP 429 (rate limited) and 503 (unavailable)
- Exponential backoff capped at 60 s, honouring Retry-After header
- Default timeout=30 s injected via setdefault (caller can override)
Wire all 13 retry-eligible API calls through _graph_request(). The 3
file-upload requests.put(data=f) calls are kept direct since an open
stream cannot be re-read after the first attempt.
Add 9 unit tests covering: success path, 429/503 retry, Retry-After
header, max-retry exhaustion, timeout injection and override.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add timeout= to every requests.get/post/put/patch/delete call so that
background threads cannot hang indefinitely when the network is stalled:
- timeout=30 on all API calls (delete, post, patch, get — 13 locations)
- timeout=120 on file upload calls (requests.put with data= — 3 locations)
to allow sufficient time for large file transfers
Add 1 new unit test that scans the source file and fails if any
requests.* call is missing a timeout= parameter.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace 4 bare `except:` with `except Exception:` (load_settings,
get_txt, get_icon_idx_for_file, process_file cleanup block) so
SystemExit and KeyboardInterrupt are no longer swallowed
- Replace 2 print() calls with logger.error() (__init__ MSAL init,
ensure_valid_token) so errors appear in the configurable log output
- Sanitize item['name'] with os.path.basename() in on_download_clicked
and _download_folder_recursive_sync to prevent path traversal from
server-controlled filenames
- Add 8 new unit tests covering all Task 7 changes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
19 tests covering:
- I2/I3: STRINGS dict entries (System tab label, status_loading_items)
- I1/C-1/S-2: nav_gen guard logic in _finalize_list_loading
(matching gen applies, stale gen discards, None bypasses guard,
old zero default now correctly treated as stale)
- C1: url=None initialization order in _fetch_tree_children_bg
- S2: dead SITE branch absent from _append_list_items
- S-1: is_breadcrumb parameter removed from _navigate_to_item_data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The S3 fix removed the only conditional that read is_breadcrumb. Remove
the parameter from the signature and its kwarg from the one call site in
the breadcrumb button handler.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Change nav_gen default from 0 to None in _fetch_list_contents_bg and
_finalize_list_loading. The guard is updated to only apply when a gen
is explicitly provided (`nav_gen is not None`).
Refresh call sites (lines 1515, 1529, 1538) pass no gen, so they receive
None and bypass the guard — their results are always applied. Navigation
calls still pass an explicit integer gen, so stale-navigation protection
remains fully intact.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- S1: drop pulse_gauge(True) from inside pagination while-loops in
_fetch_sites_bg, _fetch_tree_children_bg, and _fetch_list_contents_bg;
the gauge is already running from the call before the loop
- S3: remove the is_breadcrumb bypass on the early-return guard so
clicking the already-active breadcrumb segment no longer fires a
redundant network request
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces self._nav_gen, incremented on every _navigate_to_item_data
call. The counter is threaded through _fetch_list_contents_bg and
checked in _finalize_list_loading: if the user navigated away while a
fetch was in flight, the stale results are silently discarded instead of
overwriting the active folder view and re-sorting its items.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- C2: remove duplicate EVT_SIZE binding (on_status_bar_resize); merge
gauge repositioning into the single on_resize handler
- I4: position gauge correctly on first show by updating rect inside
pulse_gauge._do() when start=True, so no resize event is required
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- C1: initialize url=None before conditional in _fetch_tree_children_bg
to prevent UnboundLocalError on unexpected data types
- I2: translate System tab label via get_txt instead of hardcoded string
- I3: add status_loading_items to STRINGS (da+en) and use it in
_fetch_list_contents_bg instead of hardcoded Danish f-string
- S2: remove unreachable SITE branch from _append_list_items
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>