added --keyword-template

This commit is contained in:
Rhet Turnbull
2020-05-01 22:05:46 -07:00
parent 7af1ccd4ed
commit 65674f57bc
36 changed files with 984 additions and 505 deletions

View File

@@ -7,7 +7,7 @@
<key>hostuuid</key>
<string>9575E48B-8D5F-5654-ABAC-4431B1167324</string>
<key>pid</key>
<integer>2322</integer>
<integer>725</integer>
<key>processname</key>
<string>photolibraryd</string>
<key>uid</key>

View File

@@ -3,24 +3,24 @@
<plist version="1.0">
<dict>
<key>BackgroundHighlightCollection</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-01T23:03:12Z</date>
<key>BackgroundHighlightEnrichment</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-01T23:03:11Z</date>
<key>BackgroundJobAssetRevGeocode</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-02T01:35:19Z</date>
<key>BackgroundJobSearch</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-01T23:03:12Z</date>
<key>BackgroundPeopleSuggestion</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-01T23:03:11Z</date>
<key>BackgroundUserBehaviorProcessor</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-01T23:03:13Z</date>
<key>PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey</key>
<date>2020-04-29T06:08:13Z</date>
<date>2020-05-02T01:35:36Z</date>
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
<date>2020-04-29T06:08:10Z</date>
<date>2020-05-01T23:03:11Z</date>
<key>PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate</key>
<date>2020-04-29T06:08:12Z</date>
<date>2020-05-02T01:35:19Z</date>
<key>SiriPortraitDonation</key>
<date>2020-04-29T06:08:11Z</date>
<date>2020-05-01T23:03:13Z</date>
</dict>
</plist>

View File

@@ -3,8 +3,8 @@
<plist version="1.0">
<dict>
<key>FaceIDModelLastGenerationKey</key>
<date>2020-04-29T06:08:12Z</date>
<date>2020-05-01T23:03:14Z</date>
<key>LastContactClassificationKey</key>
<date>2020-04-29T06:08:14Z</date>
<date>2020-05-01T23:03:18Z</date>
</dict>
</plist>

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>IncrementalPersonProcessingStage</key>
<integer>6</integer>
<integer>0</integer>
<key>PersonBuilderLastMinimumFaceGroupSizeForCreatingMergeCandidates</key>
<integer>15</integer>
<key>PersonBuilderMergeCandidatesEnabled</key>

View File

@@ -332,6 +332,7 @@ def test_export_sidecar():
"-V",
],
)
assert result.exit_code == 0
files = glob.glob("*.*")
assert sorted(files) == sorted(CLI_EXPORT_SIDECAR_FILENAMES)
@@ -855,3 +856,70 @@ def test_no_folder_1_14():
json_got = json.loads(result.output)
assert len(json_got) == 1 # single element
assert json_got[0]["uuid"] == "15uNd7%8RguTEgNPKHfTWw"
def test_export_sidecar_keyword_template():
import json
import glob
import os
import os.path
import osxphotos
from osxphotos.__main__ import cli
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
cli,
[
"export",
"--db",
os.path.join(cwd, CLI_PHOTOS_DB),
".",
"--sidecar=json",
"--sidecar=xmp",
"--keyword-template",
"{folder_album}",
f"--uuid={CLI_EXPORT_UUID}",
"-V",
],
)
assert result.exit_code == 0
files = glob.glob("*.*")
assert sorted(files) == sorted(CLI_EXPORT_SIDECAR_FILENAMES)
json_expected = json.loads(
"""
[{"_CreatedBy": "osxphotos, https://github.com/RhetTbull/osxphotos",
"EXIF:ImageDescription": "Girl holding pumpkin",
"XMP:Description": "Girl holding pumpkin",
"XMP:Title": "I found one!",
"XMP:TagsList": ["Kids", "Multi Keyword", "Test Album", "Pumpkin Farm"],
"IPTC:Keywords": ["Kids", "Multi Keyword", "Test Album", "Pumpkin Farm"],
"XMP:PersonInImage": ["Katie"],
"XMP:Subject": ["Kids", "Katie"],
"EXIF:DateTimeOriginal": "2018:09:28 16:07:07",
"EXIF:OffsetTimeOriginal": "-04:00",
"EXIF:ModifyDate": "2020:04:11 12:34:16"}]"""
)[0]
import logging
json_file = open("Pumkins2.json", "r")
json_got = json.load(json_file)[0]
json_file.close()
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
assert sorted(json_expected[k]) == sorted(v)
else:
assert json_expected[k] == v
for k, v in json_expected.items():
if type(v) in (list, tuple):
assert sorted(json_got[k]) == sorted(v)
else:
assert json_got[k] == v

View File

@@ -467,7 +467,6 @@ def test_exiftool_json_sidecar():
json_got = photos[0]._exiftool_json_sidecar()
json_got = json.loads(json_got)[0]
# some gymnastics to account for different sort order in different pythons
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
@@ -508,7 +507,6 @@ def test_exiftool_json_sidecar_use_persons_keyword():
json_got = photos[0]._exiftool_json_sidecar(use_persons_as_keywords=True)
json_got = json.loads(json_got)[0]
# some gymnastics to account for different sort order in different pythons
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
@@ -549,7 +547,6 @@ def test_exiftool_json_sidecar_use_albums_keyword():
json_got = photos[0]._exiftool_json_sidecar(use_albums_as_keywords=True)
json_got = json.loads(json_got)[0]
# some gymnastics to account for different sort order in different pythons
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
@@ -612,14 +609,16 @@ def test_xmp_sidecar():
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar()
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(xmp_expected_lines, xmp_got_lines):
for line_expected, line_got in zip(
sorted(xmp_expected_lines), sorted(xmp_got_lines)
):
assert line_expected == line_got
@@ -673,14 +672,16 @@ def test_xmp_sidecar_use_persons_keyword():
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(use_persons_as_keywords=True)
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(xmp_expected_lines, xmp_got_lines):
for line_expected, line_got in zip(
sorted(xmp_expected_lines), sorted(xmp_got_lines)
):
assert line_expected == line_got
@@ -734,12 +735,14 @@ def test_xmp_sidecar_use_albums_keyword():
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(use_albums_as_keywords=True)
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(xmp_expected_lines, xmp_got_lines):
for line_expected, line_got in zip(
sorted(xmp_expected_lines), sorted(xmp_got_lines)
):
assert line_expected == line_got

View File

@@ -155,4 +155,3 @@ def test_export_edited_no_edit(photosdb):
with pytest.raises(Exception) as e:
assert photos[0].export(dest, use_photos_export=True, edited=True)
assert e.type == ValueError

View File

@@ -0,0 +1,219 @@
import pytest
from osxphotos._constants import _UNKNOWN_PERSON
PHOTOS_DB = "./tests/Test-10.15.4.photoslibrary/database/photos.db"
TOP_LEVEL_FOLDERS = ["Folder1"]
TOP_LEVEL_CHILDREN = ["SubFolder1", "SubFolder2"]
FOLDER_ALBUM_DICT = {"Folder1": [], "SubFolder1": [], "SubFolder2": ["AlbumInFolder"]}
ALBUM_NAMES = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album"]
ALBUM_PARENT_DICT = {
"Pumpkin Farm": None,
"AlbumInFolder": "SubFolder2",
"Test Album": None,
}
ALBUM_FOLDER_NAMES_DICT = {
"Pumpkin Farm": [],
"AlbumInFolder": ["Folder1", "SubFolder2"],
"Test Album": [],
}
ALBUM_LEN_DICT = {"Pumpkin Farm": 3, "AlbumInFolder": 2, "Test Album": 1}
ALBUM_PHOTO_UUID_DICT = {
"Pumpkin Farm": [
"F12384F6-CD17-4151-ACBA-AE0E3688539E",
"D79B8D77-BFFC-460B-9312-034F2877D35B",
"1EB2B765-0765-43BA-A90C-0D0580E6172C",
],
"Test Album": [
"F12384F6-CD17-4151-ACBA-AE0E3688539E",
"D79B8D77-BFFC-460B-9312-034F2877D35B",
],
"AlbumInFolder": [
"3DD2C897-F19E-4CA6-8C22-B027D5A71907",
"E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
],
}
UUID_DICT = {
"two_albums": "F12384F6-CD17-4151-ACBA-AE0E3688539E",
"in_album": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
"xmp": "F12384F6-CD17-4151-ACBA-AE0E3688539E",
}
def test_exiftool_json_sidecar_keyword_template_long(caplog):
import osxphotos
from osxphotos._constants import _MAX_IPTC_KEYWORD_LEN
import json
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["in_album"]])
json_expected = json.loads(
"""
[{"_CreatedBy": "osxphotos, https://github.com/RhetTbull/osxphotos",
"EXIF:ImageDescription": "Bride Wedding day",
"XMP:Description": "Bride Wedding day",
"XMP:TagsList": ["wedding", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
"IPTC:Keywords": ["wedding", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
"XMP:PersonInImage": ["Maria"],
"XMP:Subject": ["wedding", "Maria"],
"EXIF:DateTimeOriginal": "2019:04:15 14:40:24",
"EXIF:OffsetTimeOriginal": "-04:00", "EXIF:ModifyDate": "2019:11:24 13:09:17"}]
"""
)[0]
long_str = "x" * (_MAX_IPTC_KEYWORD_LEN + 1)
json_got = photos[0]._exiftool_json_sidecar(keyword_template=[long_str])
json_got = json.loads(json_got)[0]
assert "Some keywords exceed max IPTC Keyword length" in caplog.text
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
assert sorted(json_expected[k]) == sorted(v)
else:
assert json_expected[k] == v
for k, v in json_expected.items():
if type(v) in (list, tuple):
assert sorted(json_got[k]) == sorted(v)
else:
assert json_got[k] == v
for k, v in json_expected.items():
if type(v) in (list, tuple):
assert sorted(json_got[k]) == sorted(v)
else:
assert json_got[k] == v
def test_exiftool_json_sidecar_keyword_template():
import osxphotos
import json
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["in_album"]])
json_expected = json.loads(
"""
[{"_CreatedBy": "osxphotos, https://github.com/RhetTbull/osxphotos",
"EXIF:ImageDescription": "Bride Wedding day",
"XMP:Description": "Bride Wedding day",
"XMP:TagsList": ["wedding", "Folder1/SubFolder2/AlbumInFolder"],
"IPTC:Keywords": ["wedding", "Folder1/SubFolder2/AlbumInFolder"],
"XMP:PersonInImage": ["Maria"],
"XMP:Subject": ["wedding", "Maria"],
"EXIF:DateTimeOriginal": "2019:04:15 14:40:24",
"EXIF:OffsetTimeOriginal": "-04:00", "EXIF:ModifyDate": "2019:11:24 13:09:17"}]
"""
)[0]
json_got = photos[0]._exiftool_json_sidecar(keyword_template=["{folder_album}"])
json_got = json.loads(json_got)[0]
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
assert sorted(json_expected[k]) == sorted(v)
else:
assert json_expected[k] == v
for k, v in json_expected.items():
if type(v) in (list, tuple):
assert sorted(json_got[k]) == sorted(v)
else:
assert json_got[k] == v
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():
if type(v) in (list, tuple):
assert sorted(json_expected[k]) == sorted(v)
else:
assert json_expected[k] == v
for k, v in json_expected.items():
if type(v) in (list, tuple):
assert sorted(json_got[k]) == sorted(v)
else:
assert json_got[k] == v
for k, v in json_expected.items():
if type(v) in (list, tuple):
assert sorted(json_got[k]) == sorted(v)
else:
assert json_got[k] == v
def test_xmp_sidecar_keyword_template():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["xmp"]])
xmp_expected = """<!-- Created with osxphotos https://github.com/RhetTbull/osxphotos -->
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0">
<!-- mirrors Photos 5 "Export IPTC as XMP" option -->
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does -->
<dc:subject>
<rdf:Seq>
<rdf:li>Kids</rdf:li>
<rdf:li>Suzy</rdf:li>
<rdf:li>Katie</rdf:li>
</rdf:Seq>
</dc:subject>
<photoshop:DateCreated>2018-09-28T15:35:49.063000-04:00</photoshop:DateCreated>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:Iptc4xmpExt='http://iptc.org/std/Iptc4xmpExt/2008-02-29/'>
<Iptc4xmpExt:PersonInImage>
<rdf:Bag>
<rdf:li>Suzy</rdf:li>
<rdf:li>Katie</rdf:li>
</rdf:Bag>
</Iptc4xmpExt:PersonInImage>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:digiKam='http://www.digikam.org/ns/1.0/'>
<digiKam:TagsList>
<rdf:Seq>
<rdf:li>Kids</rdf:li>
<rdf:li>Pumpkin Farm</rdf:li>
<rdf:li>Test Album</rdf:li>
<rdf:li>2018</rdf:li>
</rdf:Seq>
</digiKam:TagsList>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
<xmp:CreateDate>2018-09-28T15:35:49</xmp:CreateDate>
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(
keyword_template=["{created.year}", "{folder_album}"]
)
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(
sorted(xmp_expected_lines), sorted(xmp_got_lines)
):
assert line_expected == line_got

View File

@@ -454,7 +454,7 @@ def test_xmp_sidecar():
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
@@ -464,3 +464,68 @@ def test_xmp_sidecar():
for line_expected, line_got in zip(xmp_expected_lines, xmp_got_lines):
assert line_expected == line_got
def test_xmp_sidecar_keyword_template():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["xmp"]])
xmp_expected = """<!-- Created with osxphotos https://github.com/RhetTbull/osxphotos -->
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0">
<!-- mirrors Photos 5 "Export IPTC as XMP" option -->
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<dc:description>Girls with pumpkins</dc:description>
<dc:title>Can we carry this?</dc:title>
<!-- keywords and persons listed in <dc:subject> as Photos does -->
<dc:subject>
<rdf:Seq>
<rdf:li>Kids</rdf:li>
<rdf:li>Suzy</rdf:li>
<rdf:li>Katie</rdf:li>
</rdf:Seq>
</dc:subject>
<photoshop:DateCreated>2018-09-28T15:35:49.063000-04:00</photoshop:DateCreated>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:Iptc4xmpExt='http://iptc.org/std/Iptc4xmpExt/2008-02-29/'>
<Iptc4xmpExt:PersonInImage>
<rdf:Bag>
<rdf:li>Suzy</rdf:li>
<rdf:li>Katie</rdf:li>
</rdf:Bag>
</Iptc4xmpExt:PersonInImage>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:digiKam='http://www.digikam.org/ns/1.0/'>
<digiKam:TagsList>
<rdf:Seq>
<rdf:li>Kids</rdf:li>
<rdf:li>Test Album</rdf:li>
<rdf:li>Pumpkin Farm</rdf:li>
<rdf:li>2018</rdf:li>
</rdf:Seq>
</digiKam:TagsList>
</rdf:Description>
<rdf:Description rdf:about=''
xmlns:xmp='http://ns.adobe.com/xap/1.0/'>
<xmp:CreateDate>2018-09-28T15:35:49</xmp:CreateDate>
<xmp:ModifyDate>2018-09-28T15:35:49</xmp:ModifyDate>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>"""
xmp_expected_lines = [line.strip() for line in xmp_expected.split("\n")]
xmp_got = photos[0]._xmp_sidecar(
keyword_template=["{folder_album}", "{created.year}"]
)
xmp_got_lines = [line.strip() for line in xmp_got.split("\n")]
for line_expected, line_got in zip(
sorted(xmp_expected_lines), sorted(xmp_got_lines)
):
assert line_expected == line_got

View File

@@ -92,18 +92,14 @@ def test_lookup():
""" Test that a lookup is returned for every possible value """
import re
import osxphotos
from osxphotos.template import (
get_template_value,
render_filepath_template,
TEMPLATE_SUBSTITUTIONS,
)
from osxphotos.template import TEMPLATE_SUBSTITUTIONS
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
for subst in TEMPLATE_SUBSTITUTIONS:
lookup_str = re.match(r"\{([^\\,}]+)\}", subst).group(1)
lookup = get_template_value(lookup_str, photo)
lookup = photo.get_template_value(lookup_str)
assert lookup or lookup is None
@@ -111,14 +107,13 @@ def test_subst():
""" Test that substitutions are correct """
import locale
import osxphotos
from osxphotos.template import render_filepath_template
locale.setlocale(locale.LC_ALL, "en_US")
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
for template in TEMPLATE_VALUES:
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert rendered[0] == TEMPLATE_VALUES[template]
@@ -130,13 +125,12 @@ def test_subst_locale_1():
# osxphotos.template sets local on load so set the environment first
# set locale to DE
locale.setlocale(locale.LC_ALL, "de_DE.UTF-8")
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
for template in TEMPLATE_VALUES_DEU:
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert rendered[0] == TEMPLATE_VALUES_DEU[template]
@@ -155,13 +149,11 @@ def test_subst_locale_2():
os.environ["LC_NUMERIC"] = "de_DE.UTF-8"
os.environ["LC_TIME"] = "de_DE.UTF-8"
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
for template in TEMPLATE_VALUES_DEU:
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert rendered[0] == TEMPLATE_VALUES_DEU[template]
@@ -169,14 +161,13 @@ def test_subst_default_val():
""" Test substitution with default value specified """
import locale
import osxphotos
from osxphotos.template import render_filepath_template
locale.setlocale(locale.LC_ALL, "en_US")
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
template = "{place.name.area_of_interest,UNKNOWN}"
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert rendered[0] == "UNKNOWN"
@@ -184,14 +175,13 @@ def test_subst_default_val_2():
""" Test substitution with ',' but no default value """
import locale
import osxphotos
from osxphotos.template import render_filepath_template
locale.setlocale(locale.LC_ALL, "en_US")
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
template = "{place.name.area_of_interest,}"
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert rendered[0] == "_"
@@ -199,32 +189,30 @@ def test_subst_unknown_val():
""" Test substitution with unknown value specified """
import locale
import osxphotos
from osxphotos.template import render_filepath_template
locale.setlocale(locale.LC_ALL, "en_US")
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
template = "{created.year}/{foo}"
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert rendered[0] == "2020/{foo}"
assert unknown == ["foo"]
template = "{place.name.area_of_interest,}"
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert rendered[0] == "_"
def test_subst_double_brace():
""" Test substitution with double brace {{ which should be ignored """
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
template = "{created.year}/{{foo}}"
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert rendered[0] == "2020/{foo}"
assert not unknown
@@ -233,14 +221,13 @@ def test_subst_unknown_val_with_default():
""" Test substitution with unknown value specified """
import locale
import osxphotos
from osxphotos.template import render_filepath_template
locale.setlocale(locale.LC_ALL, "en_US")
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
template = "{created.year}/{foo,bar}"
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert rendered[0] == "2020/{foo,bar}"
assert unknown == ["foo"]
@@ -249,14 +236,13 @@ def test_subst_multi_1_1_2():
""" Test that substitutions are correct """
# one album, one keyword, two persons
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
photo = photosdb.photos(uuid=[UUID_DICT["1_1_2"]])[0]
template = "{created.year}/{album}/{keyword}/{person}"
expected = ["2018/Pumpkin Farm/Kids/Katie", "2018/Pumpkin Farm/Kids/Suzy"]
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
@@ -264,7 +250,6 @@ def test_subst_multi_2_1_1():
""" Test that substitutions are correct """
# 2 albums, 1 keyword, 1 person
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -276,7 +261,7 @@ def test_subst_multi_2_1_1():
"2018/Test Album/Kids/Katie",
"2018/Multi Keyword/Kids/Katie",
]
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
@@ -284,7 +269,6 @@ def test_subst_multi_2_1_1_single():
""" Test that substitutions are correct """
# 2 albums, 1 keyword, 1 person but only do keywords
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -292,7 +276,7 @@ def test_subst_multi_2_1_1_single():
template = "{keyword}"
expected = ["Kids"]
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
@@ -300,7 +284,6 @@ def test_subst_multi_0_2_0():
""" Test that substitutions are correct """
# 0 albums, 2 keywords, 0 persons
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -308,7 +291,7 @@ def test_subst_multi_0_2_0():
template = "{created.year}/{album}/{keyword}/{person}"
expected = ["2019/_/wedding/_", "2019/_/flowers/_"]
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
@@ -316,7 +299,6 @@ def test_subst_multi_0_2_0_single():
""" Test that substitutions are correct """
# 0 albums, 2 keywords, 0 persons, but only do albums
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -324,7 +306,7 @@ def test_subst_multi_0_2_0_single():
template = "{created.year}/{album}"
expected = ["2019/_"]
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
@@ -332,7 +314,6 @@ def test_subst_multi_0_2_0_default_val():
""" Test that substitutions are correct """
# 0 albums, 2 keywords, 0 persons, default vals provided
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -340,7 +321,7 @@ def test_subst_multi_0_2_0_default_val():
template = "{created.year}/{album,NOALBUM}/{keyword,NOKEYWORD}/{person,NOPERSON}"
expected = ["2019/NOALBUM/wedding/NOPERSON", "2019/NOALBUM/flowers/NOPERSON"]
rendered, _ = render_filepath_template(template, photo)
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
@@ -348,7 +329,6 @@ def test_subst_multi_0_2_0_default_val_unknown_val():
""" Test that substitutions are correct """
# 0 albums, 2 keywords, 0 persons, default vals provided, unknown val in template
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -361,7 +341,7 @@ def test_subst_multi_0_2_0_default_val_unknown_val():
"2019/NOALBUM/wedding/_/{foo}/{baz}",
"2019/NOALBUM/flowers/_/{foo}/{baz}",
]
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
assert unknown == ["foo"]
@@ -370,7 +350,6 @@ def test_subst_multi_0_2_0_default_val_unknown_val_2():
""" Test that substitutions are correct """
# 0 albums, 2 keywords, 0 persons, default vals provided, unknown val in template
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_1)
# one album, one keyword, two persons
@@ -381,7 +360,7 @@ def test_subst_multi_0_2_0_default_val_unknown_val_2():
"2019/NOALBUM/wedding/_/{foo,bar}/{baz,bar}",
"2019/NOALBUM/flowers/_/{foo,bar}/{baz,bar}",
]
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
assert unknown == ["foo"]
@@ -389,7 +368,6 @@ def test_subst_multi_0_2_0_default_val_unknown_val_2():
def test_subst_multi_folder_albums_1():
""" Test substitutions for folder_album are correct """
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_4)
@@ -397,7 +375,7 @@ def test_subst_multi_folder_albums_1():
photo = photosdb.photos(uuid=[UUID_DICT["folder_album_1"]])[0]
template = "{folder_album}"
expected = ["Folder1/SubFolder2/AlbumInFolder"]
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
assert unknown == []
@@ -405,7 +383,6 @@ def test_subst_multi_folder_albums_1():
def test_subst_multi_folder_albums_2():
""" Test substitutions for folder_album are correct """
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_15_4)
@@ -413,15 +390,14 @@ def test_subst_multi_folder_albums_2():
photo = photosdb.photos(uuid=[UUID_DICT["folder_album_no_folder"]])[0]
template = "{folder_album}"
expected = ["Pumpkin Farm", "Test Album"]
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
assert unknown == []
def test_subst_multi_folder_albums_3(caplog):
def test_subst_multi_folder_albums_3():
""" Test substitutions for folder_album on < Photos 5 """
import osxphotos
from osxphotos.template import render_filepath_template
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_14_6)
@@ -429,6 +405,6 @@ def test_subst_multi_folder_albums_3(caplog):
photo = photosdb.photos(uuid=[UUID_DICT["mojave_album_1"]])[0]
template = "{folder_album}"
expected = ["Folder1/SubFolder2/AlbumInFolder", "Pumpkin Farm", "Test Album (1)"]
rendered, unknown = render_filepath_template(template, photo)
rendered, unknown = photo.render_template(template)
assert sorted(rendered) == sorted(expected)
assert unknown == []