From 478715a363f5009e4a38148e832bf0ad3c4cc4f8 Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sun, 3 Jan 2021 07:38:07 -0800 Subject: [PATCH] Implemented text replacement for templates, issue #316 --- README.md | 133 +++++++++++----- osxphotos/__main__.py | 232 +++++++++++++++++++--------- osxphotos/_version.py | 2 +- osxphotos/photoinfo/photoinfo.py | 3 - osxphotos/phototemplate.py | 255 ++++++++++++++++++++----------- tests/test_template.py | 14 ++ 6 files changed, 428 insertions(+), 211 deletions(-) diff --git a/README.md b/README.md index 9d9ee8af..af52be64 100644 --- a/README.md +++ b/README.md @@ -588,50 +588,24 @@ _keys ** Templating System ** Several options, such as --directory, allow you to specify a template which -will be rendered to substitute template fields with values from the photo. -For example, '{created.month}' would be replaced with the month name of the -photo creation date. e.g. 'November'. +will be rendered to substitute template fields with values from the photo. For +example, '{created.month}' would be replaced with the month name of the photo +creation date. e.g. 'November'. Some options supporting templates may be repeated e.g., --keyword-template '{label}' --keyword-template '{media_type}' to add both labels and media types to the keywords. -The general format for a template is '{TEMPLATE_FIELD[,[DEFAULT]]}'. Some -templates have optional modifiers in form -'{[[DELIM]+]TEMPLATE_FIELD[(PATH_SEP)][?VALUE_IF_TRUE][,[DEFAULT]]}' +The general format for a template is '{TEMPLATE_FIELD,DEFAULT}'. The full +template format is: +'{DELIM+TEMPLATE_FIELD(PATH_SEP)[OLD,NEW]?VALUE_IF_TRUE,DEFAULT}' -The ',' and DEFAULT value are optional. If TEMPLATE_FIELD results in a null -(empty) value, the default is '_'. 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'). +With a few exceptions (like '{created.strftime}') everything but the +TEMPLATE_FIELD is optional. -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} which would result in 'is_hdr' if photo is an HDR image -and 'not_hdr' otherwise. - -Some template fields such as 'folder_template' are "path-like" in that they -join multiple elements into a single path-like string. For example, if photo -is in album Album1 in folder Folder1, '{folder_album}` results in -'Folder1/Album1'. This is so these template fields may be used as paths in ---directory. If you intend to use such a field as a string, e.g. in the -filename, you may specify a different path separator using the form: -'{TEMPLATE_FIELD(PATH_SEP)}'. For example, using the example above, -'{folder_album(-)}' would result in 'Folder1-Album1' and '{folder_album()}' -would result in 'Folder1Album1'. - -Some templates may resolve to more than one value. For example, a photo can -have multiple keywords so '{keyword}' can result in multiple values. If used -in a filename or directory, these templates may result in more than one copy -of the photo being exported. For example, if photo has keywords "foo" and -"bar", --directory '{keyword}' will result in copies of the photo being -exported to 'foo/image_name.jpeg' and 'bar/image_name.jpeg'. - -Multi-value template fields such as '{keyword}' may be expanded 'in place' -with an optional delimiter using the template form '{DELIM+TEMPLATE_FIELD}'. -For example, a photo with keywords 'foo' and 'bar': +- 'DELIM+' Multi-value template fields such as '{keyword}' may be expanded 'in +place' with an optional delimiter using the template form +'{DELIM+TEMPLATE_FIELD}'. For example, a photo with keywords 'foo' and 'bar': '{keyword}' renders to 'foo' and 'bar' @@ -641,6 +615,62 @@ For example, a photo with keywords 'foo' and 'bar': '{+keyword}' renders to 'foobar' +- 'TEMPLATE_FIELD' The name of the template field, for example 'keyword' + +- '(PATH_SEP)' Some template fields such as '{folder_album}' are "path-like" +in that they join multiple elements into a single path-like string. For +example, if photo is in album Album1 in folder Folder1, '{folder_album}' +results in 'Folder1/Album1'. This is so these template fields may be used as +paths in --directory. If you intend to use such a field as a string, e.g. in +the filename, you may specify a different path separator using the form: +'{TEMPLATE_FIELD(PATH_SEP)}'. For example, using the example above, +'{folder_album(-)}' would result in 'Folder1-Album1' and '{folder_album()}' +would result in 'Folder1Album1'. + +- '[OLD,NEW]' Use the [OLD,NEW] option to replace text "OLD" in the template +value with text "NEW". For example, if you have album names with '/' in the +album name you could replace '/' with "-" using the template '{album[/,-]}'. +This would replace any occurence of "/" in the album name with "-"; album +"Vacation/2019" would thus become "Vacation-2019". You may specify more than +one pair of OLD,NEW values by listing them delimited by '|'. For example: +'{album[/,-|:,-]}' to replace both '/' and ':' by '-'. You can also use the +[OLD,NEW] syntax to delete a character by omitting the NEW value as in +'{album[/,]}'. + +- '?' 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} which would result in 'is_hdr' if photo is an HDR +image and 'not_hdr' otherwise. + +- ',DEFAULT' The ',' and DEFAULT value are optional. If TEMPLATE_FIELD +results in a null (empty) value, the template will result in default value of +'_'. You may specify an alternate default value by appending ',DEFAULT' after +template_field. Example: '{title,no_title}' would result in 'no_title' if the +photo had no title. Example: '{created.year}/{place.address,NO_ADDRESS}' but +there was no address associated with the photo, the resulting output would +be: '2020/NO_ADDRESS/photoname.jpg'. If specified, the default value may not +contain a brace symbol ('{' or '}'). + +Again, if you do not specify a default value and the template substitution has +no value, '_' (underscore) will be used as the default value. For example, in +the above example, this would result in '2020/_/photoname.jpg' if address was +null. + +You may specify a null default (e.g. "" or empty string) by omitting the value +after the comma, e.g. {title,} which would render to "" if title had no value +thus effectively deleting the template from the resulting string. + +You may include other text in the template string outside the {} and use more +than one template field in a single string, e.g. '{created.year} - +{created.month}' (e.g. '2020 - November'). + +Some templates may resolve to more than one value. For example, a photo can +have multiple keywords so '{keyword}' can result in multiple values. If used +in a filename or directory, these templates may result in more than one copy +of the photo being exported. For example, if photo has keywords "foo" and +"bar", --directory '{keyword}' will result in copies of the photo being +exported to 'foo/image_name.jpeg' and 'bar/image_name.jpeg'. + Some template fields such as '{media_type}' use the 'DEFAULT' value to allow customization of the output. For example, '{media_type}' resolves to the special media type of the photo such as 'panorama' or 'selfie'. You may use @@ -650,6 +680,28 @@ photo is a time_lapse photo, 'media_type' would resolve to 'vidéo_accélérée instead of 'time_lapse' and video would resolve to 'vidéo' if photo is an ordinary video. +With the --directory and --filename options you may specify a template for the +export directory or filename, respectively. The directory will be appended to +the export path specified in the export DEST argument to export. For example, +if template is '{created.year}/{created.month}', and export destination DEST +is '/Users/maria/Pictures/export', the actual export directory for a photo +would be '/Users/maria/Pictures/export/2020/March' if the photo was created in +March 2020. + +The templating system may also be used with the --keyword-template option to +set keywords on export (with --exiftool or --sidecar), for example, to set a +new keyword in format 'folder/subfolder/album' to preserve the folder/album +structure, you can use --keyword-template "{folder_album}" + +In the template, valid template substitutions will be replaced by the +corresponding value from the table below. Invalid substitutions will result +in an error. + +If you want the actual text of the template substition to appear in the +rendered name, use double braces, e.g. '{{' or '}}', thus using +'{created.year}/{{name}}' for --directory would result in output of +2020/{name}/photoname.jpg + With the --directory and --filename options you may specify a template for the export directory or filename, respectively. The directory will be appended to the export path specified in the export DEST argument to export. For example, @@ -1726,7 +1778,7 @@ If overwrite=False and increment=False, export will fail if destination file alr #### `render_template()` -`render_template(template_str, none_str = "_", path_sep = None, expand_inplace = False, inplace_sep = None, filename=False, dirname=False, replacement=":",)` +`render_template(template_str, none_str = "_", path_sep = None, expand_inplace = False, inplace_sep = None, filename=False, dirname=False)` Render template string for photo. none_str is used if template substitution results in None value and no default specified. @@ -1737,7 +1789,6 @@ Render template string for photo. none_str is used if template substitution res - `inplace_sep`: optional string to use as separator between multi-valued keywords with expand_inplace; default is ',' - `filename`: if True, template output will be sanitized to produce valid file name - `dirname`: if True, template output will be sanitized to produce valid directory name -- `replacement`: str, value to replace any illegal file path characters with; default = ":" Returns a tuple of (rendered, unmatched) where rendered is a list of rendered strings with all substitutions made and unmatched is a list of any strings that resembled a template substitution but did not match a known substitution. E.g. if template contained "{foo}", unmatched would be ["foo"]. @@ -1751,7 +1802,7 @@ Some substitutions, notably `album`, `keyword`, and `person` could return multip The template field format contains optional modifiers: -`"{[[DELIM]+]name[(PATH_SEP)][?TRUE_VALUE][,[DEFAULT]]}"` +`"{DELIM+name(PATH_SEP)[OLD,NEW]?TRUE_VALUE,DEFAULT}"` `DELIM`: optional delimiter string to use when expanding multi-valued template values in-place @@ -1772,6 +1823,8 @@ e.g. If Photo is in `Album1` in `Folder1`: - `"{folder_album(:)}"` renders to `["Folder1:Album1"]` - `"{folder_album()}"` renders to `["Folder1Album1"]` +`[OLD,NEW]`: optional text replacement to perform on rendered template value. For example, to replace "/" in an album name, you could use the template `"{album[/,-]}"`. + `?TRUE_VALUE`: optional value to use if name is boolean-type field which evaluates to true. For example `"{hdr}"` evaluates to True if photo is an high dynamic range (HDR) image and False otherwise. In these types of fields, use `?TRUE_VALUE` to provide the value if True and `,DEFAULT` to provide the value of False. e.g. if photo is an HDR image, diff --git a/osxphotos/__main__.py b/osxphotos/__main__.py index f049ebd6..37ff47d3 100644 --- a/osxphotos/__main__.py +++ b/osxphotos/__main__.py @@ -222,66 +222,118 @@ The following attributes may be used with '--xattr-template': formatter.write("\n") formatter.write_text( """ -Several options, such as --directory, allow you to specify a template -which will be rendered to substitute template fields with values from the photo. -For example, '{created.month}' would be replaced with the month name of the photo creation date. -e.g. 'November'. -\n -Some options supporting templates may be repeated e.g., --keyword-template '{label}' ---keyword-template '{media_type}' to add both labels and media types to the -keywords. -\n -The general format for a template is '{TEMPLATE_FIELD[,[DEFAULT]]}'. -Some templates have optional modifiers in form -'{[[DELIM]+]TEMPLATE_FIELD[(PATH_SEP)][?VALUE_IF_TRUE][,[DEFAULT]]}' -\n -The ',' and DEFAULT value are optional. -If TEMPLATE_FIELD results in a null (empty) value, the default is '_'. -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'). -\n -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} which would result in 'is_hdr' if photo is an HDR -image and 'not_hdr' otherwise. -\n -Some template fields such as 'folder_template' are "path-like" in that they join -multiple elements into a single path-like string. For example, if photo is in -album Album1 in folder Folder1, '{folder_album}` results in 'Folder1/Album1'. -This is so these template fields may be used as paths in --directory. -If you intend to use such a field as a string, e.g. in the filename, you may specify -a different path separator using the form: '{TEMPLATE_FIELD(PATH_SEP)}'. -For example, using the example above, '{folder_album(-)}' would result in -'Folder1-Album1' and '{folder_album()}' would result in -'Folder1Album1'. -\n -Some templates may resolve to more than one value. For example, a photo can have -multiple keywords so '{keyword}' can result in multiple values. If used in a filename -or directory, these templates may result in more than one copy of the photo being exported. -For example, if photo has keywords "foo" and "bar", --directory '{keyword}' will result in -copies of the photo being exported to 'foo/image_name.jpeg' and 'bar/image_name.jpeg'. -\n -Multi-value template fields such as '{keyword}' may be expanded 'in place' with an optional -delimiter using the template form '{DELIM+TEMPLATE_FIELD}'. For example, a photo with -keywords 'foo' and 'bar': -\n +Several options, such as --directory, allow you to specify a template which +will be rendered to substitute template fields with values from the photo. +For example, '{created.month}' would be replaced with the month name of the +photo creation date. e.g. 'November'. + +Some options supporting templates may be repeated e.g., --keyword-template +'{label}' --keyword-template '{media_type}' to add both labels and media +types to the keywords. + +The general format for a template is '{TEMPLATE_FIELD,DEFAULT}'. The full template format is: +'{DELIM+TEMPLATE_FIELD(PATH_SEP)[OLD,NEW]?VALUE_IF_TRUE,DEFAULT}' + +With a few exceptions (like '{created.strftime}') everything but the TEMPLATE_FIELD +is optional. + +- 'DELIM+' Multi-value template fields such as '{keyword}' may be expanded 'in place' +with an optional delimiter using the template form '{DELIM+TEMPLATE_FIELD}'. +For example, a photo with keywords 'foo' and 'bar': + '{keyword}' renders to 'foo' and 'bar' -\n + '{,+keyword}' renders to: 'foo,bar' -\n + '{; +keyword}' renders to: 'foo; bar' -\n + '{+keyword}' renders to 'foobar' -\n -Some template fields such as '{media_type}' use the 'DEFAULT' value to allow customization -of the output. For example, '{media_type}' resolves to the special media type of the -photo such as 'panorama' or 'selfie'. You may use the 'DEFAULT' value to override -these in form: '{media_type,video=vidéo;time_lapse=vidéo_accélérée}'. -In this example, if photo is a time_lapse photo, 'media_type' would resolve to -'vidéo_accélérée' instead of 'time_lapse' and video would resolve to 'vidéo' if photo -is an ordinary video. + +- 'TEMPLATE_FIELD' The name of the template field, for example 'keyword' + +- '(PATH_SEP)' Some template fields such as '{folder_album}' are "path-like" in +that they join multiple elements into a single path-like string. For example, +if photo is in album Album1 in folder Folder1, '{folder_album}' results in +'Folder1/Album1'. This is so these template fields may be used as paths in +--directory. If you intend to use such a field as a string, e.g. in the +filename, you may specify a different path separator using the form: +'{TEMPLATE_FIELD(PATH_SEP)}'. For example, using the example above, +'{folder_album(-)}' would result in 'Folder1-Album1' and '{folder_album()}' +would result in 'Folder1Album1'. + +- '[OLD,NEW]' Use the [OLD,NEW] option to replace text "OLD" in the template value +with text "NEW". For example, if you have album names with '/' in the album name you +could replace '/' with "-" using the template '{album[/,-]}'. This would replace +any occurence of "/" in the album name with "-"; album "Vacation/2019" would thus +become "Vacation-2019". You may specify more than one pair of OLD,NEW values by +listing them delimited by '|'. For example: '{album[/,-|:,-]}' to replace both +'/' and ':' by '-'. You can also use the [OLD,NEW] syntax to delete a character by +omitting the NEW value as in '{album[/,]}'. + +- '?' 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} which would result in 'is_hdr' if photo is an HDR image +and 'not_hdr' otherwise. + +- ',DEFAULT' The ',' and DEFAULT value are optional. If TEMPLATE_FIELD results +in a null (empty) value, the template will result in default value of '_'. +You may specify an alternate default value by appending ',DEFAULT' after +template_field. Example: '{title,no_title}' would result in 'no_title' if the photo +had no title. Example: '{created.year}/{place.address,NO_ADDRESS}' but there was +no address associated with the photo, the resulting output would be: +'2020/NO_ADDRESS/photoname.jpg'. If specified, the default value may not +contain a brace symbol ('{' or '}'). + +Again, if you do not specify a default value and the template substitution has no +value, '_' (underscore) will be used as the default value. For example, in the +above example, this would result in '2020/_/photoname.jpg' if address was +null. + +You may specify a null default (e.g. "" or empty string) by omitting the value +after the comma, e.g. {title,} which would render to "" if title had no value thus +effectively deleting the template from the resulting string. + +You may include other text in the template string outside the {} +and use more than one template field in a single string, +e.g. '{created.year} - {created.month}' (e.g. '2020 - November'). + +Some templates may resolve to more than one value. For example, a photo can +have multiple keywords so '{keyword}' can result in multiple values. If used +in a filename or directory, these templates may result in more than one copy +of the photo being exported. For example, if photo has keywords "foo" and +"bar", --directory '{keyword}' will result in copies of the photo being +exported to 'foo/image_name.jpeg' and 'bar/image_name.jpeg'. + +Some template fields such as '{media_type}' use the 'DEFAULT' value to allow +customization of the output. For example, '{media_type}' resolves to the +special media type of the photo such as 'panorama' or 'selfie'. You may use +the 'DEFAULT' value to override these in form: +'{media_type,video=vidéo;time_lapse=vidéo_accélérée}'. In this example, if +photo is a time_lapse photo, 'media_type' would resolve to 'vidéo_accélérée' +instead of 'time_lapse' and video would resolve to 'vidéo' if photo is an +ordinary video. + +With the --directory and --filename options you may specify a template for the +export directory or filename, respectively. The directory will be appended to +the export path specified in the export DEST argument to export. For example, +if template is '{created.year}/{created.month}', and export destination DEST +is '/Users/maria/Pictures/export', the actual export directory for a photo +would be '/Users/maria/Pictures/export/2020/March' if the photo was created in +March 2020. + +The templating system may also be used with the --keyword-template option to +set keywords on export (with --exiftool or --sidecar), for example, to set a +new keyword in format 'folder/subfolder/album' to preserve the folder/album +structure, you can use --keyword-template "{folder_album}" + +In the template, valid template substitutions will be replaced by the +corresponding value from the table below. Invalid substitutions will result +in an error. + +If you want the actual text of the template substition to appear in the +rendered name, use double braces, e.g. '{{' or '}}', thus using +'{created.year}/{{name}}' for --directory would result in output of +2020/{name}/photoname.jpg """ ) formatter.write("\n") @@ -1515,7 +1567,7 @@ def query( help="Set extended attribute ATTRIBUTE to TEMPLATE value. Valid attributes are: " f"{', '.join(EXTENDED_ATTRIBUTE_NAMES_QUOTED)}. " "For example, to set Finder comment to the photo's title and description: " - "'--xattr-template findercomment \"{title}; {descr}\" " + '\'--xattr-template findercomment "{title}; {descr}" ' "See Extended Attributes below for additional details on this option.", ) @click.option( @@ -2863,9 +2915,15 @@ def export_photo( filenames = get_filenames_from_template(photo, filename_template, original_name) for filename in filenames: if original_suffix: - rendered_suffix, unmatched = photo.render_template( - original_suffix, filename=True - ) + try: + rendered_suffix, unmatched = photo.render_template( + original_suffix, filename=True + ) + except ValueError: + raise click.BadOptionUsage( + "original_suffix", + f"Invalid template for --original-suffix '{original_suffix}'", + ) if not rendered_suffix or unmatched: raise click.BadOptionUsage( "original_suffix", @@ -3002,10 +3060,15 @@ def export_photo( edited_ext = pathlib.Path(photo.filename).suffix if edited_suffix: - rendered_suffix, unmatched = photo.render_template( - edited_suffix, filename=True - ) - + try: + rendered_suffix, unmatched = photo.render_template( + edited_suffix, filename=True + ) + except ValueError: + raise click.BadOptionUsage( + "edited_suffix", + f"Invalid template for --edited-suffix '{edited_suffix}'", + ) if not rendered_suffix or unmatched: raise click.BadOptionUsage( "edited_suffix", @@ -3120,9 +3183,14 @@ def get_filenames_from_template(photo, filename_template, original_name): """ if filename_template: photo_ext = pathlib.Path(photo.original_filename).suffix - filenames, unmatched = photo.render_template( - filename_template, path_sep="_", filename=True - ) + try: + filenames, unmatched = photo.render_template( + filename_template, path_sep="_", filename=True + ) + except ValueError: + raise click.BadOptionUsage( + "filename_template", f"Invalid template '{filename_template}'" + ) if not filenames or unmatched: raise click.BadOptionUsage( "filename_template", @@ -3167,7 +3235,10 @@ def get_dirnames_from_template(photo, directory, export_by_date, dest, dry_run): dest_paths = [dest_path] elif directory: # got a directory template, render it and check results are valid - dirnames, unmatched = photo.render_template(directory, dirname=True) + try: + dirnames, unmatched = photo.render_template(directory, dirname=True) + except ValueError: + raise click.BadOptionUsage("directory", f"Invalid template '{directory}'") if not dirnames or unmatched: raise click.BadOptionUsage( "directory", @@ -3464,9 +3535,16 @@ def write_finder_tags( if finder_tag_template: rendered_tags = [] for template_str in finder_tag_template: - rendered, unmatched = photo.render_template( - template_str, none_str=_OSXPHOTOS_NONE_SENTINEL, path_sep="/" - ) + try: + rendered, unmatched = photo.render_template( + template_str, none_str=_OSXPHOTOS_NONE_SENTINEL, path_sep="/" + ) + except ValueError: + raise click.BadOptionUsage( + "finder_tag_template", + f"Invalid template for --finder-tag-template': {template_str}", + ) + if unmatched: click.echo( click.style( @@ -3510,9 +3588,15 @@ def write_extended_attributes(photo, files, xattr_template): attributes = {} for xattr, template_str in xattr_template: - rendered, unmatched = photo.render_template( - template_str, none_str=_OSXPHOTOS_NONE_SENTINEL, path_sep="/" - ) + try: + rendered, unmatched = photo.render_template( + template_str, none_str=_OSXPHOTOS_NONE_SENTINEL, path_sep="/" + ) + except ValueError: + raise click.BadOptionUsage( + "xattr_template", + f"Invalid template for --xattr-template': {template_str}", + ) if unmatched: click.echo( click.style( diff --git a/osxphotos/_version.py b/osxphotos/_version.py index af0a971e..0a48d76f 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,5 +1,5 @@ """ version info """ -__version__ = "0.39.3" +__version__ = "0.39.4" diff --git a/osxphotos/photoinfo/photoinfo.py b/osxphotos/photoinfo/photoinfo.py index 083eb07b..952fae90 100644 --- a/osxphotos/photoinfo/photoinfo.py +++ b/osxphotos/photoinfo/photoinfo.py @@ -832,7 +832,6 @@ class PhotoInfo: inplace_sep=None, filename=False, dirname=False, - replacement=":", ): """Renders a template string for PhotoInfo instance using PhotoTemplate @@ -847,7 +846,6 @@ class PhotoInfo: with expand_inplace; default is ',' filename: if True, template output will be sanitized to produce valid file name dirname: if True, template output will be sanitized to produce valid directory name - replacement: str, value to replace any illegal file path characters with; default = ":" Returns: ([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values @@ -861,7 +859,6 @@ class PhotoInfo: inplace_sep=inplace_sep, filename=filename, dirname=dirname, - replacement=replacement, ) @property diff --git a/osxphotos/phototemplate.py b/osxphotos/phototemplate.py index 92669dc0..6edd98bd 100644 --- a/osxphotos/phototemplate.py +++ b/osxphotos/phototemplate.py @@ -6,9 +6,9 @@ # 2. Needed to handle default values if template not found # 3. Didn't want user to need to know python (e.g. by using Mako which is # already used elsewhere in this project) -# 4. Couldn't figure out how to do #1 and #2 with str.format() # -# This code isn't elegant but it seems to work well. PRs gladly accepted. +# This code isn't elegant and is prime for refactoring but it seems to work well. PRs gladly accepted. + import datetime import locale import os @@ -145,6 +145,29 @@ MULTI_VALUE_SUBSTITUTIONS = [ for field in TEMPLATE_SUBSTITUTIONS_MULTI_VALUED ] +# regular expressions for matching template syntax +RE_OPENING_BRACE = r"(?