Fix hang when saving an open bee file that has been removed

This commit is contained in:
Rebecca Breu 2024-05-19 22:38:42 +02:00
parent bdc3653cd6
commit a89027f0ba
4 changed files with 38 additions and 8 deletions

View file

@ -12,6 +12,15 @@ Added
* Added option to export all images from scene (File -> Export Images)
Fixed
-----
* Fixed a case where adding/importing an image would hang while
reading unsupported exif data (#111)
* Fixed a hang when saving an open bee file that has been removed
since being opened
0.3.3 - 2024-05-05
==================

View file

@ -49,7 +49,7 @@ def save_bee(filename, scene, create_new=False, worker=None):
logger.debug(f'Create new: {create_new}')
io = SQLiteIO(filename, scene, create_new, worker=worker)
io.write()
logger.info('Saved!')
logger.info('End save')
def load_images(filenames, pos, scene, worker):

View file

@ -52,7 +52,7 @@ def handle_sqlite_errors(func):
def wrapper(self, *args, **kwargs):
try:
func(self, *args, **kwargs)
except (sqlite3.Error, BeeFileIOError) as e:
except Exception as e:
logger.exception(f'Error while reading/writing {self.filename}')
try:
# Try to roll back transaction if there is any
@ -80,6 +80,7 @@ class SQLiteIO:
self.filename = filename
self.readonly = readonly
self.worker = worker
self.retry = False
def __del__(self):
self._close_connection()
@ -109,7 +110,13 @@ class SQLiteIO:
self._connection = sqlite3.connect(uri, uri=True)
self._cursor = self.connection.cursor()
if not self.create_new:
self._migrate()
try:
self._migrate()
except Exception:
# Updating a file failed; try creating it from scratch instead
logger.exception('Error migrating bee file')
self.create_new = True
self._establish_connection()
def _migrate(self):
"""Migrate database if necessary."""
@ -236,16 +243,19 @@ class SQLiteIO:
def write(self):
if self.readonly:
raise sqlite3.OperationalError(
'attempt to write a readonly database')
'Attempt to write to a readonly database')
try:
self.create_schema_on_new()
self.write_data()
except sqlite3.Error:
if self.create_new:
# If writing to a new file fails, we can't recover
except Exception:
if self.retry:
# Trying to recover failed
raise
else:
# Updating a file failed; try creating it from scratch instead
self.retry = True
# Try creating file from scratch and save again
logger.exception(
f'Updating to existing file {self.filename} failed')
self.create_new = True
self._close_connection()
self.write()

View file

@ -472,6 +472,7 @@ def test_sqliteio_write_removes_nonexisting_pixmap_item(tmpfile, view):
def test_sqliteio_write_update_recovers_from_borked_file(view, tmpfile):
item = BeePixmapItem(QtGui.QImage(), filename='bee.png')
item.save_id = 1
view.scene.addItem(item)
with open(tmpfile, 'w') as f:
@ -483,6 +484,16 @@ def test_sqliteio_write_update_recovers_from_borked_file(view, tmpfile):
assert result[0] == 1
def test_sqliteio_write_update_recovers_from_nonexisting_file(view, tmpfile):
item = BeePixmapItem(QtGui.QImage(), filename='bee.png')
item.save_id = 1
view.scene.addItem(item)
io = SQLiteIO(tmpfile, view.scene, create_new=False)
io.write()
result = io.fetchone('SELECT COUNT(*) FROM items')
assert result[0] == 1
def test_sqliteio_write_updates_progress(tmpfile, view):
worker = MagicMock(canceled=False)
io = SQLiteIO(tmpfile, view.scene, create_new=True, worker=worker)