Added --description-template to CLI, closes #166

This commit is contained in:
Rhet Turnbull
2020-06-28 20:10:38 -07:00
parent 59507077ba
commit bb4bc8fd96
5 changed files with 107 additions and 6 deletions

View File

@@ -1146,6 +1146,18 @@ def query(
'--keyword-template "{created.year}" '
"See Templating System below.",
)
@click.option(
"--description-template",
metavar="TEMPLATE",
multiple=False,
default=None,
help="For use with --exiftool, --sidecar; specify a template string to use as "
"description in the form '{name,DEFAULT}' "
"This is the same format as --directory. For example, if you wanted to append "
"'exported with osxphotos on [today's date]' to the description, you could specify "
'--description-template "{descr} exported with osxphotos on {today.date}" '
"See Templating System below.",
)
@click.option(
"--current-name",
is_flag=True,
@@ -1260,6 +1272,7 @@ def export(
person_keyword,
album_keyword,
keyword_template,
description_template,
current_name,
sidecar,
only_photos,
@@ -1505,6 +1518,7 @@ def export(
album_keyword=album_keyword,
person_keyword=person_keyword,
keyword_template=keyword_template,
description_template=description_template,
export_db=export_db,
fileutil=fileutil,
dry_run=dry_run,
@@ -1541,6 +1555,7 @@ def export(
album_keyword=album_keyword,
person_keyword=person_keyword,
keyword_template=keyword_template,
description_template=description_template,
export_db=export_db,
fileutil=fileutil,
dry_run=dry_run,
@@ -2012,6 +2027,7 @@ def export_photo(
album_keyword=None,
person_keyword=None,
keyword_template=None,
description_template=None,
export_db=None,
fileutil=FileUtil,
dry_run=None,
@@ -2039,6 +2055,7 @@ def export_photo(
album_keyword: boolean; if True, exports album names as keywords in metadata
person_keyword: boolean; if True, exports person names as keywords in metadata
keyword_template: list of strings; if provided use rendered template strings as keywords
description_template: string; optional template string that will be rendered for use as photo description
export_db: export database instance compatible with ExportDB_ABC
fileutil: file util class compatible with FileUtilABC
dry_run: boolean; if True, doesn't actually export or update any files
@@ -2113,6 +2130,7 @@ def export_photo(
use_albums_as_keywords=album_keyword,
use_persons_as_keywords=person_keyword,
keyword_template=keyword_template,
description_template=description_template,
update=update,
export_db=export_db,
fileutil=fileutil,
@@ -2168,6 +2186,7 @@ def export_photo(
use_albums_as_keywords=album_keyword,
use_persons_as_keywords=person_keyword,
keyword_template=keyword_template,
description_template=description_template,
update=update,
export_db=export_db,
fileutil=fileutil,

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.30.2"
__version__ = "0.30.3"

View File

@@ -215,6 +215,7 @@ def export(
use_albums_as_keywords=False,
use_persons_as_keywords=False,
keyword_template=None,
description_template=None,
):
""" export photo
dest: must be valid destination path (or exception raised)
@@ -250,6 +251,7 @@ def export(
use_persons_as_keywords: (boolean, default = False); if True, will include person names in keywords
when exporting metadata with exiftool or sidecar
keyword_template: (list of strings); list of template strings that will be rendered as used as keywords
description_template: string; optional template string that will be rendered for use as photo description
returns: list of photos exported
"""
@@ -273,6 +275,7 @@ def export(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
return results.exported
@@ -297,6 +300,7 @@ def export2(
use_albums_as_keywords=False,
use_persons_as_keywords=False,
keyword_template=None,
description_template=None,
update=False,
export_db=None,
fileutil=FileUtil,
@@ -336,6 +340,7 @@ def export2(
use_persons_as_keywords: (boolean, default = False); if True, will include person names in keywords
when exporting metadata with exiftool or sidecar
keyword_template: (list of strings); list of template strings that will be rendered as used as keywords
description_template: string; optional template string that will be rendered for use as photo description
update: (boolean, default=False); if True export will run in update mode, that is, it will
not export the photo if the current version already exists in the destination
export_db: (ExportDB_ABC); instance of a class that conforms to ExportDB_ABC with methods
@@ -670,6 +675,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
if not dry_run:
try:
@@ -685,6 +691,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
if not dry_run:
try:
@@ -712,6 +719,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
)[0]
if old_data != current_data:
@@ -727,6 +735,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
export_db.set_exifdata_for_file(
exported_file,
@@ -734,6 +743,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
),
)
export_db.set_stat_exif_for_file(
@@ -749,6 +759,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
export_db.set_exifdata_for_file(
exported_file,
@@ -756,6 +767,7 @@ def export2(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
),
)
export_db.set_stat_exif_for_file(
@@ -955,6 +967,7 @@ def _write_exif_data(
use_albums_as_keywords=False,
use_persons_as_keywords=False,
keyword_template=None,
description_template=None,
):
""" write exif data to image file at filepath
filepath: full path to the image file """
@@ -966,6 +979,7 @@ def _write_exif_data(
use_albums_as_keywords=use_albums_as_keywords,
use_persons_as_keywords=use_persons_as_keywords,
keyword_template=keyword_template,
description_template=description_template,
)
)[0]
for exiftag, val in exif_info.items():
@@ -984,6 +998,7 @@ def _exiftool_json_sidecar(
use_albums_as_keywords=False,
use_persons_as_keywords=False,
keyword_template=None,
description_template=None,
):
""" return json string of EXIF details in exiftool sidecar format
Does not include all the EXIF fields as those are likely already in the image
@@ -1009,7 +1024,13 @@ def _exiftool_json_sidecar(
exif = {}
exif["_CreatedBy"] = "osxphotos, https://github.com/RhetTbull/osxphotos"
if self.description:
if description_template is not None:
description = self.render_template(
description_template, expand_inplace=True, inplace_sep=", "
)[0]
exif["EXIF:ImageDescription"] = description
exif["XMP:Description"] = description
elif self.description:
exif["EXIF:ImageDescription"] = self.description
exif["XMP:Description"] = self.description
@@ -1112,16 +1133,25 @@ def _xmp_sidecar(
use_albums_as_keywords=False,
use_persons_as_keywords=False,
keyword_template=None,
description_template=None,
):
""" returns string for XMP sidecar
use_albums_as_keywords: treat album names as keywords
use_persons_as_keywords: treat person names as keywords
keyword_template: (list of strings); list of template strings to render as keywords """
keyword_template: (list of strings); list of template strings to render as keywords
description_template: string; optional template string that will be rendered for use as photo description """
# TODO: add additional fields to XMP file?
xmp_template = Template(filename=os.path.join(_TEMPLATE_DIR, _XMP_TEMPLATE_NAME))
if description_template is not None:
description = self.render_template(
description_template, expand_inplace=True, inplace_sep=", "
)[0]
else:
description = self.description if self.description is not None else ""
keyword_list = []
if self.keywords:
keyword_list.extend(self.keywords)
@@ -1178,7 +1208,11 @@ def _xmp_sidecar(
subject_list = list(self.keywords) + person_list
xmp_str = xmp_template.render(
photo=self, keywords=keyword_list, persons=person_list, subjects=subject_list
photo=self,
description=description,
keywords=keyword_list,
persons=person_list,
subjects=subject_list,
)
# remove extra lines that mako inserts from template

View File

@@ -77,7 +77,7 @@
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
${dc_description(photo.description)}
${dc_description(description)}
${dc_title(photo.title)}
${dc_subject(subjects)}
${dc_datecreated(photo.date)}

View File

@@ -197,7 +197,13 @@ CLI_EXPORT_RAW_EDITED = [
]
CLI_EXPORT_RAW_EDITED_ORIGINAL = ["IMG_0476_2.CR2", "IMG_0476_2_edited.jpeg"]
CLI_UUID_DICT_15_5 = {"intrash": "71E3E212-00EB-430D-8A63-5E294B268554"}
CLI_UUID_DICT_15_5 = {
"intrash": "71E3E212-00EB-430D-8A63-5E294B268554",
"template": "F12384F6-CD17-4151-ACBA-AE0E3688539E",
}
CLI_TEMPLATE_SIDECAR_FILENAME = "Pumkins1.json"
CLI_UUID_DICT_14_6 = {"intrash": "3tljdX43R8+k6peNHVrJNQ"}
PHOTOS_NOT_IN_TRASH_LEN_14_6 = 7
@@ -1095,6 +1101,48 @@ def test_export_sidecar():
assert sorted(files) == sorted(CLI_EXPORT_SIDECAR_FILENAMES)
def test_export_sidecar_templates():
import json
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, PHOTOS_DB_15_5),
".",
"--sidecar=json",
f"--uuid={CLI_UUID_DICT_15_5['template']}",
"-V",
"--keyword-template",
"{person}",
"--description-template",
"{descr} {person} {keyword} {album}",
],
)
assert result.exit_code == 0
assert os.path.isfile(CLI_TEMPLATE_SIDECAR_FILENAME)
with open(CLI_TEMPLATE_SIDECAR_FILENAME, "r") as jsonfile:
exifdata = json.load(jsonfile)
assert (
exifdata[0]["XMP:Description"][0]
== "Girls with pumpkins Katie, Suzy Kids Pumpkin Farm, Test Album"
)
assert (
exifdata[0]["EXIF:ImageDescription"][0]
== "Girls with pumpkins Katie, Suzy Kids Pumpkin Farm, Test Album"
)
def test_export_live():
import glob
import os