Added {id} sequence number template, #154

This commit is contained in:
Rhet Turnbull 2021-07-23 05:57:07 -07:00
parent 745161fbd1
commit e95c096784
5 changed files with 43 additions and 2 deletions

View File

@ -1801,6 +1801,14 @@ Substitution Description
unique to the photo, e.g.
'128FB4C6-0B16-4E7D-9108-FB2E90DA1546'
{id} A unique number for the photo based on its
primary key in the Photos database. A
sequential integer, e.g. 1, 2, 3...etc. May be
formatted using a python string format code.
For example, to format as a 5-digit integer
and pad with zeros, use '{id:05d}' which
results in 00001, 00002, 00003...etc.
{comma} A comma: ','
{semicolon} A semicolon: ';'
{questionmark} A question mark: '?'
@ -3649,6 +3657,7 @@ The following template field substitutions are availabe for use the templating s
|{exif.camera_model}|Camera model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s'|
|{exif.lens_model}|Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'|
|{uuid}|Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'|
|{id}|A unique number for the photo based on its primary key in the Photos database. A sequential integer, e.g. 1, 2, 3...etc. May be formatted using a python string format code. For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in 00001, 00002, 00003...etc. |
|{comma}|A comma: ','|
|{semicolon}|A semicolon: ';'|
|{questionmark}|A question mark: '?'|

View File

@ -1,3 +1,3 @@
""" version info """
__version__ = "0.42.65"
__version__ = "0.42.66"

View File

@ -1104,6 +1104,7 @@ class PhotosDB:
# get info on special types
self._dbphotos[uuid]["specialType"] = row[25]
self._dbphotos[uuid]["masterModelID"] = row[26]
self._dbphotos[uuid]["pk"] = row[26] # same as masterModelID, to match Photos 5
self._dbphotos[uuid]["panorama"] = True if row[25] == 1 else False
self._dbphotos[uuid]["slow_mo"] = True if row[25] == 2 else False
self._dbphotos[uuid]["time_lapse"] = True if row[25] == 3 else False
@ -1921,7 +1922,8 @@ class PhotosDB:
{asset_table}.ZVISIBILITYSTATE,
{asset_table}.ZTRASHEDDATE,
{asset_table}.ZSAVEDASSETTYPE,
{asset_table}.ZADDEDDATE
{asset_table}.ZADDEDDATE,
{asset_table}.Z_PK
FROM {asset_table}
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
ORDER BY {asset_table}.ZUUID """
@ -1970,6 +1972,7 @@ class PhotosDB:
# 39 ZGENERICASSET.ZTRASHEDDATE -- date item placed in the trash or null if not in trash
# 40 ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported
# 41 ZGENERICASSET.ZADDEDDATE -- date item added to the library
# 42 ZGENERICASSET.Z_PK -- primary key
for row in c:
uuid = row[0]
@ -2154,6 +2157,8 @@ class PhotosDB:
except (ValueError, TypeError):
info["added_date"] = datetime(1970, 1, 1)
info["pk"] = row[42]
# initialize import session info which will be filled in later
# not every photo has an import session so initialize all records now
info["import_session"] = None

View File

@ -127,6 +127,10 @@ TEMPLATE_SUBSTITUTIONS = {
"{exif.camera_model}": "Camera model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s'",
"{exif.lens_model}": "Lens model from original photo's EXIF information as imported by Photos, e.g. 'iPhone 6s back camera 4.15mm f/2.2'",
"{uuid}": "Photo's internal universally unique identifier (UUID) for the photo, a 36-character string unique to the photo, e.g. '128FB4C6-0B16-4E7D-9108-FB2E90DA1546'",
"{id}": "A unique number for the photo based on its primary key in the Photos database. "
+ "A sequential integer, e.g. 1, 2, 3...etc. May be formatted using a python string format code. "
+ "For example, to format as a 5-digit integer and pad with zeros, use '{id:05d}' which results in "
+ "00001, 00002, 00003...etc. ",
"{comma}": "A comma: ','",
"{semicolon}": "A semicolon: ';'",
"{questionmark}": "A question mark: '?'",
@ -294,6 +298,14 @@ class PhotoTemplateParser:
return self.metamodel.model_from_str(template_statement)
def format_id_str(value, format_str):
"""Format value based on format code in field in format id:02d"""
if not format_str:
return str(value)
format_str = "{0:" + f"{format_str}" + "}"
return format_str.format(value)
class PhotoTemplate:
"""PhotoTemplate class to render a template string from a PhotoInfo object"""
@ -491,6 +503,7 @@ class PhotoTemplate:
vals = self.get_template_value(
field,
default=default,
subfield=subfield,
# delim=delim or self.inplace_sep,
# path_sep=path_sep,
)
@ -645,6 +658,7 @@ class PhotoTemplate:
self,
field,
default,
subfield=None,
# bool_val=None,
# delim=None,
# path_sep=None,
@ -657,6 +671,7 @@ class PhotoTemplate:
bool_val: True value if expression is boolean
delim: delimiter for expand in place
path_sep: path separator for fields that are path-like
subfield: subfield (value after : in field)
Returns:
The matching template value (which may be None).
@ -923,6 +938,8 @@ class PhotoTemplate:
value = self.photo.exif_info.lens_model if self.photo.exif_info else None
elif field == "uuid":
value = self.photo.uuid
elif field.startswith("id"):
value = format_id_str(self.photo._info["pk"], subfield)
elif field in PUNCTUATION:
value = PUNCTUATION[field]
elif field == "osxphotos_version":

View File

@ -1095,3 +1095,13 @@ def test_filepath():
with pytest.raises(ValueError):
rendered, _ = template.render("{filepath.foo}", options)
def test_id(photosdb):
"""Test {id} template"""
photo = photosdb.get_photo(UUID_MULTI_KEYWORDS)
rendered, _ = photo.render_template("{id}")
assert rendered[0] == "7"
rendered, _ = photo.render_template("{id:03d}")
assert rendered[0] == "007"