Added retry to export_db for #674

This commit is contained in:
Rhet Turnbull
2022-04-24 15:06:13 -07:00
parent ad13565dfd
commit e4b6c0f1e0
6 changed files with 486 additions and 356 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -396,7 +396,7 @@ If called in context manager, returns True (execution is delayed until exiting c
<dt class="sig sig-object py" id="osxphotos.ExportDB.get_file_record"> <dt class="sig sig-object py" id="osxphotos.ExportDB.get_file_record">
<span class="sig-name descname"><span class="pre">get_file_record</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">pathlib.Path</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon"></span> <span class="sig-return-typehint"><span class="pre">osxphotos.export_db.ExportRecord</span></span></span><a class="reference internal" href="_modules/osxphotos/export_db.html#ExportDB.get_file_record"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.ExportDB.get_file_record" title="Permalink to this definition">#</a></dt> <span class="sig-name descname"><span class="pre">get_file_record</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">filename</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Union</span><span class="p"><span class="pre">[</span></span><span class="pre">pathlib.Path</span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">str</span><span class="p"><span class="pre">]</span></span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon"></span> <span class="sig-return-typehint"><span class="pre">osxphotos.export_db.ExportRecord</span></span></span><a class="reference internal" href="_modules/osxphotos/export_db.html#ExportDB.get_file_record"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.ExportDB.get_file_record" title="Permalink to this definition">#</a></dt>
<dd><p>get info for filename and uuid</p> <dd><p>get info for filename and uuid</p>
<p>Returns: an ExportRecord object</p> <p>Returns: an ExportRecord object or None if filename not found</p>
</dd></dl> </dd></dl>
<dl class="py method"> <dl class="py method">
<dt class="sig sig-object py" id="osxphotos.ExportDB.get_photoinfo_for_uuid"> <dt class="sig sig-object py" id="osxphotos.ExportDB.get_photoinfo_for_uuid">

Binary file not shown.

View File

@@ -1,6 +1,7 @@
""" Helper class for managing database used by PhotoExporter for tracking state of exports and updates """ """ Helper class for managing database used by PhotoExporter for tracking state of exports and updates """
import contextlib
import datetime import datetime
import json import json
import logging import logging
@@ -13,6 +14,8 @@ from sqlite3 import Error
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from typing import Optional, Tuple, Union from typing import Optional, Tuple, Union
from tenacity import retry, stop_after_attempt
from ._constants import OSXPHOTOS_EXPORT_DB from ._constants import OSXPHOTOS_EXPORT_DB
from ._version import __version__ from ._version import __version__
from .fileutil import FileUtil from .fileutil import FileUtil
@@ -27,6 +30,9 @@ __all__ = [
OSXPHOTOS_EXPORTDB_VERSION = "6.0" OSXPHOTOS_EXPORTDB_VERSION = "6.0"
OSXPHOTOS_ABOUT_STRING = f"Created by osxphotos version {__version__} (https://github.com/RhetTbull/osxphotos) on {datetime.datetime.now()}" OSXPHOTOS_ABOUT_STRING = f"Created by osxphotos version {__version__} (https://github.com/RhetTbull/osxphotos) on {datetime.datetime.now()}"
# max retry attempts for methods which use tenacity.retry
MAX_RETRY_ATTEMPTS = 5
class ExportDB: class ExportDB:
"""Interface to sqlite3 database used to store state information for osxphotos export command""" """Interface to sqlite3 database used to store state information for osxphotos export command"""
@@ -63,20 +69,19 @@ class ExportDB:
def get_file_record(self, filename: Union[pathlib.Path, str]) -> "ExportRecord": def get_file_record(self, filename: Union[pathlib.Path, str]) -> "ExportRecord":
"""get info for filename and uuid """get info for filename and uuid
Returns: an ExportRecord object Returns: an ExportRecord object or None if filename not found
""" """
filename = self._relative_filepath(filename) filename = self._relative_filepath(filename)
filename_normalized = self._normalize_filepath(filename) filename_normalized = self._normalize_filepath(filename)
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute(
if _ := c.execute(
"SELECT uuid FROM export_data WHERE filepath_normalized = ?;", "SELECT uuid FROM export_data WHERE filepath_normalized = ?;",
(filename_normalized,), (filename_normalized,),
).fetchone() ).fetchone():
return ExportRecord(conn, filename_normalized)
if not row: return None
return None
return ExportRecord(conn, filename_normalized)
def create_file_record( def create_file_record(
self, filename: Union[pathlib.Path, str], uuid: str self, filename: Union[pathlib.Path, str], uuid: str
@@ -362,13 +367,11 @@ class ExportDB:
def __del__(self): def __del__(self):
"""ensure the database connection is closed""" """ensure the database connection is closed"""
try: with contextlib.suppress(Exception):
self._conn.close() self._conn.close()
except:
pass
def _insert_run_info(self): def _insert_run_info(self):
dt = datetime.datetime.utcnow().isoformat() dt = datetime.datetime.now(datetime.timezone.utc).isoformat()
python_path = sys.executable python_path = sys.executable
cmd = sys.argv[0] cmd = sys.argv[0]
args = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else "" args = " ".join(sys.argv[1:]) if len(sys.argv) > 1 else ""
@@ -593,6 +596,7 @@ class ExportDBInMemory(ExportDB):
self._conn = self._open_export_db(self._dbfile) self._conn = self._open_export_db(self._dbfile)
self._insert_run_info() self._insert_run_info()
@retry(stop=stop_after_attempt(MAX_RETRY_ATTEMPTS))
def write_to_disk(self): def write_to_disk(self):
"""Write changes from in-memory database back to disk""" """Write changes from in-memory database back to disk"""
@@ -677,10 +681,8 @@ class ExportDBInMemory(ExportDB):
def __del__(self): def __del__(self):
"""close the database connection""" """close the database connection"""
try: with contextlib.suppress(Error):
self.close() self.close()
except Error as e:
pass
class ExportDBTemp(ExportDBInMemory): class ExportDBTemp(ExportDBInMemory):
@@ -720,11 +722,10 @@ class ExportRecord:
"""return filepath""" """return filepath"""
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute( if row := c.execute(
"SELECT filepath FROM export_data WHERE filepath_normalized = ?;", "SELECT filepath FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,), (self._filepath_normalized,),
).fetchone() ).fetchone():
if row:
return row[0] return row[0]
raise ValueError( raise ValueError(
@@ -741,11 +742,10 @@ class ExportRecord:
"""return uuid""" """return uuid"""
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute( if row := c.execute(
"SELECT uuid FROM export_data WHERE filepath_normalized = ?;", "SELECT uuid FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,), (self._filepath_normalized,),
).fetchone() ).fetchone():
if row:
return row[0] return row[0]
raise ValueError(f"No uuid found in database for {self._filepath_normalized}") raise ValueError(f"No uuid found in database for {self._filepath_normalized}")
@@ -755,11 +755,10 @@ class ExportRecord:
"""returns the digest value""" """returns the digest value"""
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute( if row := c.execute(
"SELECT digest FROM export_data WHERE filepath_normalized = ?;", "SELECT digest FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,), (self._filepath_normalized,),
).fetchone() ).fetchone():
if row:
return row[0] return row[0]
raise ValueError(f"No digest found in database for {self._filepath_normalized}") raise ValueError(f"No digest found in database for {self._filepath_normalized}")
@@ -781,11 +780,10 @@ class ExportRecord:
"""returns exifdata value for record""" """returns exifdata value for record"""
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute( if row := c.execute(
"SELECT exifdata FROM export_data WHERE filepath_normalized = ?;", "SELECT exifdata FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,), (self._filepath_normalized,),
).fetchone() ).fetchone():
if row:
return row[0] return row[0]
raise ValueError( raise ValueError(
@@ -812,11 +810,10 @@ class ExportRecord:
"""return source file signature value""" """return source file signature value"""
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute( if row := c.execute(
"SELECT src_mode, src_size, src_mtime FROM export_data WHERE filepath_normalized = ?;", "SELECT src_mode, src_size, src_mtime FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,), (self._filepath_normalized,),
).fetchone() ).fetchone():
if row:
mtime = int(row[2]) if row[2] is not None else None mtime = int(row[2]) if row[2] is not None else None
return (row[0], row[1], mtime) return (row[0], row[1], mtime)
@@ -846,11 +843,10 @@ class ExportRecord:
"""return destination file signature""" """return destination file signature"""
conn = self._conn conn = self._conn
c = conn.cursor() c = conn.cursor()
row = c.execute( if row := c.execute(
"SELECT dest_mode, dest_size, dest_mtime FROM export_data WHERE filepath_normalized = ?;", "SELECT dest_mode, dest_size, dest_mtime FROM export_data WHERE filepath_normalized = ?;",
(self._filepath_normalized,), (self._filepath_normalized,),
).fetchone() ).fetchone():
if row:
mtime = int(row[2]) if row[2] is not None else None mtime = int(row[2]) if row[2] is not None else None
return (row[0], row[1], mtime) return (row[0], row[1], mtime)

View File

@@ -23,6 +23,7 @@ PyYAML>=5.4.1,<6.0.0
requests>=2.27.1,<3.0.0 requests>=2.27.1,<3.0.0
rich>=11.2.0,<13.0.0 rich>=11.2.0,<13.0.0
rich_theme_manager>=0.7.0 rich_theme_manager>=0.7.0
tenacity>=8.0.1,<9.0.0
textx>=2.3.0,<2.4.0 textx>=2.3.0,<2.4.0
toml>=0.10.2,<0.11.0 toml>=0.10.2,<0.11.0
wrapt>=1.13.3,<1.14.0 wrapt>=1.13.3,<1.14.0

View File

@@ -98,6 +98,7 @@ setup(
"requests>=2.27.1,<3.0.0", "requests>=2.27.1,<3.0.0",
"rich>=11.2.0,<13.0.0", "rich>=11.2.0,<13.0.0",
"rich_theme_manager>=0.7.0", "rich_theme_manager>=0.7.0",
"tenacity>=8.0.1,<9.0.0",
"textx>=2.3.0,<3.0.0", "textx>=2.3.0,<3.0.0",
"toml>=0.10.2,<0.11.0", "toml>=0.10.2,<0.11.0",
"wrapt>=1.13.3,<1.14.0", "wrapt>=1.13.3,<1.14.0",