mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-17 22:11:36 +00:00
Remove stale autosave file on clean Blender quit
Previously the autosaved copy was only ever overwritten, never removed, so a deliberate quit (whether the user saved or chose "don't save") still nagged with a recovery prompt on next startup. Registers an atexit cleanup that removes the active IFC's autosave file(s) on a graceful interpreter shutdown. atexit never runs on an actual crash, so a genuine crash still leaves the recovery file in place as before. The cleanup reads a cached plain-string path kept up to date by reset_timer(), rather than looking it up live via bpy.context - by the time atexit fires, Blender's C++ side is torn down far enough that even a read-only bpy.context.scene access aborts the process (std::bad_optional_access) instead of raising a catchable exception. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import atexit
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -36,6 +37,9 @@ AUTOSAVING_SUFFIX = "_autosaving.ifc"
|
|||||||
AUTOSAVED_SUFFIX = "_autosaved.ifc"
|
AUTOSAVED_SUFFIX = "_autosaved.ifc"
|
||||||
|
|
||||||
_timer_callback: Union[Callable[[], None], None] = None
|
_timer_callback: Union[Callable[[], None], None] = None
|
||||||
|
# See cleanup_stale_autosave() for why this is a cached plain string rather
|
||||||
|
# than looked up live.
|
||||||
|
_active_ifc_path_cache: Union[str, None] = None
|
||||||
|
|
||||||
|
|
||||||
class Autosave:
|
class Autosave:
|
||||||
@@ -59,6 +63,12 @@ class Autosave:
|
|||||||
return None
|
return None
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _update_active_ifc_path_cache(cls) -> None:
|
||||||
|
global _active_ifc_path_cache
|
||||||
|
ifc_path = cls.get_active_ifc_path()
|
||||||
|
_active_ifc_path_cache = ifc_path.as_posix() if ifc_path is not None else None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_enabled(cls) -> bool:
|
def is_enabled(cls) -> bool:
|
||||||
return bool(tool.Blender.get_addon_preferences().autosave_enabled)
|
return bool(tool.Blender.get_addon_preferences().autosave_enabled)
|
||||||
@@ -82,6 +92,7 @@ class Autosave:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def reset_timer(cls) -> None:
|
def reset_timer(cls) -> None:
|
||||||
cls.cancel_timer()
|
cls.cancel_timer()
|
||||||
|
cls._update_active_ifc_path_cache()
|
||||||
if not cls.is_eligible():
|
if not cls.is_eligible():
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -147,3 +158,31 @@ class Autosave:
|
|||||||
if autosaved_path.stat().st_mtime > path.stat().st_mtime:
|
if autosaved_path.stat().st_mtime > path.stat().st_mtime:
|
||||||
return autosaved_path.as_posix().replace("\\", "/")
|
return autosaved_path.as_posix().replace("\\", "/")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def cleanup_stale_autosave(cls) -> None:
|
||||||
|
"""Remove the active IFC's autosave file(s) on a graceful shutdown.
|
||||||
|
|
||||||
|
Registered via `atexit`, which only runs on a normal interpreter
|
||||||
|
shutdown - never on an actual crash. So a deliberate quit (whether
|
||||||
|
the user saved or chose "don't save") clears the recovery file and
|
||||||
|
won't prompt on next startup, while a genuine crash leaves it in
|
||||||
|
place for recovery, since no atexit callbacks fire then.
|
||||||
|
|
||||||
|
Deliberately reads only `_active_ifc_path_cache` - a plain string
|
||||||
|
kept up to date by `reset_timer()` - rather than touching `bpy` here.
|
||||||
|
By the time `atexit` fires, Blender's own C++ side is torn down far
|
||||||
|
enough that even reading `bpy.context.scene` aborts the process
|
||||||
|
(std::bad_optional_access) instead of raising a catchable exception.
|
||||||
|
"""
|
||||||
|
if _active_ifc_path_cache is None:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
_, autosaving_path, autosaved_path = cls.get_paths(_active_ifc_path_cache)
|
||||||
|
autosaving_path.unlink(missing_ok=True)
|
||||||
|
autosaved_path.unlink(missing_ok=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
atexit.register(Autosave.cleanup_stale_autosave)
|
||||||
|
|||||||
Reference in New Issue
Block a user