From 7fa3704840f7800689b4ac5f8edee8210eb3e8db Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sat, 7 Nov 2020 23:06:36 -0800 Subject: [PATCH] Implemented boolean type template fields --- README.md | 8 +++++++- osxphotos/__main__.py | 5 ++++- osxphotos/_version.py | 2 +- osxphotos/phototemplate.py | 23 ++++++++++++++++++----- tests/test_template.py | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b66ca066..220b4d7f 100644 --- a/README.md +++ b/README.md @@ -398,7 +398,9 @@ specify an alternate default value by appending ',DEFAULT' after template_field. e.g. '{title,no_title}' would result in 'no_title' if the photo had no title. You may include other text in the template string outside the {} and use more than one template field, e.g. '{created.year} - -{created.month}' (e.g. '2020 - November'). +{created.month}' (e.g. '2020 - November'). Some template fields such as 'hdr' +are boolean and resolve to True or False. These take the form: +'{TEMPLATE_FIELD?VALUE_IF_TRUE,VALUE_IF_FALSE}', e.g. '{hdr?is_hdr,not_hdr}'. With the --directory and --filename options you may specify a template for the export directory or filename, respectively. The directory will be appended to @@ -458,6 +460,8 @@ Substitution Description the image is. To customize, use default value as in '{photo_or_video,photo=fotos;video=videos}' +{hdr} Photo is HDR?; True/False value, use in + format '{hdr?VALUE_IF_TRUE,VALUE_IF_FALSE}' {created.date} Photo's creation date in ISO format, e.g. '2020-03-22' {created.year} 4-digit year of photo creation time @@ -1862,6 +1866,7 @@ To get the path of every raw photo, whether it's a single raw photo or a raw+JPE ### Template Substitutions The following template field substitutions are availabe for use with `PhotoInfo.render_template()` + | Substitution | Description | |--------------|-------------| |{name}|Current filename of the photo| @@ -1870,6 +1875,7 @@ The following template field substitutions are availabe for use with `PhotoInfo. |{descr}|Description of the photo| |{media_type}|Special media type resolved in this precedence: selfie, time_lapse, panorama, slow_mo, screenshot, portrait, live_photo, burst, photo, video. Defaults to 'photo' or 'video' if no special type. Customize one or more media types using format: '{media_type,video=vidéo;time_lapse=vidéo_accélérée}'| |{photo_or_video}|'photo' or 'video' depending on what type the image is. To customize, use default value as in '{photo_or_video,photo=fotos;video=videos}'| +|{hdr}|Photo is HDR?; True/False value, use in format '{hdr?VALUE_IF_TRUE,VALUE_IF_FALSE}'| |{created.date}|Photo's creation date in ISO format, e.g. '2020-03-22'| |{created.year}|4-digit year of photo creation time| |{created.yy}|2-digit year of photo creation time| diff --git a/osxphotos/__main__.py b/osxphotos/__main__.py index 69948bca..0592facc 100644 --- a/osxphotos/__main__.py +++ b/osxphotos/__main__.py @@ -168,7 +168,10 @@ class ExportCommand(click.Command): + "You may specify an alternate default value by appending ',DEFAULT' after template_field. " + "e.g. '{title,no_title}' would result in 'no_title' if the photo had no title. " + "You may include other text in the template string outside the {} and use more than " - + "one template field, e.g. '{created.year} - {created.month}' (e.g. '2020 - November')." + + "one template field, e.g. '{created.year} - {created.month}' (e.g. '2020 - November'). " + + "Some template fields such as 'hdr' are boolean and resolve to True or False. " + + "These take the form: '{TEMPLATE_FIELD?VALUE_IF_TRUE,VALUE_IF_FALSE}', e.g. " + + "'{hdr?is_hdr,not_hdr}'." ) formatter.write("\n") formatter.write_text( diff --git a/osxphotos/_version.py b/osxphotos/_version.py index aefaa7fc..c729d4f8 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,4 +1,4 @@ """ version info """ -__version__ = "0.36.10" +__version__ = "0.36.11" diff --git a/osxphotos/phototemplate.py b/osxphotos/phototemplate.py index b1391a38..d6885710 100644 --- a/osxphotos/phototemplate.py +++ b/osxphotos/phototemplate.py @@ -50,6 +50,7 @@ TEMPLATE_SUBSTITUTIONS = { "Customize one or more media types using format: '{media_type,video=vidéo;time_lapse=vidéo_accélérée}'" ), "{photo_or_video}": "'photo' or 'video' depending on what type the image is. To customize, use default value as in '{photo_or_video,photo=fotos;video=videos}'", + "{hdr}": "Photo is HDR?; True/False value, use in format '{hdr?VALUE_IF_TRUE,VALUE_IF_FALSE}'", "{created.date}": "Photo's creation date in ISO format, e.g. '2020-03-22'", "{created.year}": "4-digit year of photo creation time", "{created.yy}": "2-digit year of photo creation time", @@ -221,11 +222,15 @@ class PhotoTemplate: if groups == 5: delim = matchobj.group(1) field = matchobj.group(2) - boolval = matchobj.group(3) + bool_val = matchobj.group(3) default = matchobj.group(4) default_val = matchobj.group(5) + if bool_val is not None: + # drop the ? + bool_val = bool_val[1:] + try: - val = get_func(field, default_val) + val = get_func(field, default_val, bool_val) except ValueError: return matchobj.group(0) @@ -302,7 +307,7 @@ class PhotoTemplate: else None ) - def lookup_template_value_multi(lookup_value, _): + def lookup_template_value_multi(lookup_value, *_): """ Closure passed to make_subst_function get_func Capture val and field in the closure Allows make_subst_function to be re-used w/o modification @@ -323,7 +328,7 @@ class PhotoTemplate: # create a new template string for each value for val in values: - def lookup_template_value_multi(lookup_value, _): + def lookup_template_value_multi(lookup_value, *_): """ Closure passed to make_subst_function get_func Capture val and field in the closure Allows make_subst_function to be re-used w/o modification @@ -369,7 +374,7 @@ class PhotoTemplate: return rendered_strings, unmatched def get_template_value( - self, field, default, filename=False, dirname=False, replacement=":" + self, field, default, bool_val=None, filename=False, dirname=False, replacement=":" ): """lookup value for template field (single-value template substitutions) @@ -406,6 +411,8 @@ class PhotoTemplate: value = self.get_media_type(default) elif field == "photo_or_video": value = self.get_photo_video_type(default) + elif field == "hdr": + value = self.get_photo_hdr(default, bool_val) elif field == "created.date": value = DateTimeFormatter(self.photo.date).date elif field == "created.year": @@ -735,6 +742,12 @@ class PhotoTemplate: return default_dict["photo"] + def get_photo_hdr(self, default, bool_val): + if self.photo.hdr: + return bool_val + else: + return default + def parse_default_kv(default, default_dict): """ parse a string in form key1=value1;key2=value2,... as used for some template fields diff --git a/tests/test_template.py b/tests/test_template.py index d75381a5..c1d90c8f 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -35,6 +35,12 @@ UUID_MEDIA_TYPE = { "burst": None, } +# Boolean type values that render to True +UUID_BOOL_VALUES = {"hdr": "D11D25FF-5F31-47D2-ABA9-58418878DC15"} + +# Boolean type values that render to False +UUID_BOOL_VALUES_NOT = {"hdr": "51F2BEF7-431A-4D31-8AC1-3284A57826AE"} + TEMPLATE_VALUES = { "{name}": "128FB4C6-0B16-4E7D-9108-FB2E90DA1546", "{original_name}": "IMG_1064", @@ -598,3 +604,29 @@ def test_media_type_default(): photo = photosdb.get_photo(uuid) rendered, _ = photo.render_template("{media_type," + f"{field}" + "=foo}") assert rendered[0] == "foo" + + +def test_bool_values(): + """ test {bool?TRUE,FALSE} template values """ + import osxphotos + + photosdb = osxphotos.PhotosDB(PHOTOS_DB_CLOUD) + + for field, uuid in UUID_BOOL_VALUES.items(): + if uuid is not None: + photo = photosdb.get_photo(uuid) + rendered, _ = photo.render_template("{" + f"{field}" + "?True,False}") + assert rendered[0] == "True" + + +def test_bool_values_not(): + """ test {bool?TRUE,FALSE} template values for FALSE values """ + import osxphotos + + photosdb = osxphotos.PhotosDB(PHOTOS_DB_CLOUD) + + for field, uuid in UUID_BOOL_VALUES_NOT.items(): + if uuid is not None: + photo = photosdb.get_photo(uuid) + rendered, _ = photo.render_template("{" + f"{field}" + "?True,False}") + assert rendered[0] == "False"