Updated CHANGELOG.md
This commit is contained in:
27
README.md
27
README.md
@@ -446,6 +446,13 @@ Options:
|
|||||||
do not include an extension in the FILENAME
|
do not include an extension in the FILENAME
|
||||||
template. See below for additional details
|
template. See below for additional details
|
||||||
on templating system.
|
on templating system.
|
||||||
|
--strip Optionally strip leading and trailing
|
||||||
|
whitespace from any rendered templates. For
|
||||||
|
example, if --filename template is "{title,}
|
||||||
|
{original_name}" and image has no title,
|
||||||
|
resulting file would have a leading space
|
||||||
|
but if used with --strip, this will be
|
||||||
|
removed.
|
||||||
--edited-suffix SUFFIX Optional suffix template for naming edited
|
--edited-suffix SUFFIX Optional suffix template for naming edited
|
||||||
photos. Default name for edited photos is
|
photos. Default name for edited photos is
|
||||||
in form 'photoname_edited.ext'. For example,
|
in form 'photoname_edited.ext'. For example,
|
||||||
@@ -885,6 +892,19 @@ Substitution Description
|
|||||||
e.g. 'Summer'; (Photos 5+ only, applied
|
e.g. 'Summer'; (Photos 5+ only, applied
|
||||||
automatically by Photos' image
|
automatically by Photos' image
|
||||||
categorization algorithms).
|
categorization algorithms).
|
||||||
|
{exif.camera_make} Camera make from original photo's EXIF
|
||||||
|
inormation as imported by Photos, e.g.
|
||||||
|
'Apple'
|
||||||
|
{exif.camera_model} Camera model from original photo's EXIF
|
||||||
|
inormation as imported by Photos, e.g.
|
||||||
|
'iPhone 6s'
|
||||||
|
{exif.lens_model} Lens model from original photo's EXIF
|
||||||
|
inormation 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'
|
||||||
|
|
||||||
The following substitutions may result in multiple values. Thus if specified
|
The following substitutions may result in multiple values. Thus if specified
|
||||||
for --directory these could result in multiple copies of a photo being being
|
for --directory these could result in multiple copies of a photo being being
|
||||||
@@ -1778,7 +1798,7 @@ If overwrite=False and increment=False, export will fail if destination file alr
|
|||||||
|
|
||||||
#### <a name="rendertemplate">`render_template()`</a>
|
#### <a name="rendertemplate">`render_template()`</a>
|
||||||
|
|
||||||
`render_template(template_str, none_str = "_", path_sep = None, expand_inplace = False, inplace_sep = None, filename=False, dirname=False)`
|
`render_template(template_str, none_str = "_", path_sep = None, expand_inplace = False, inplace_sep = None, filename=False, dirname=False, strip=False)`
|
||||||
|
|
||||||
Render template string for photo. none_str is used if template substitution results in None value and no default specified.
|
Render template string for photo. none_str is used if template substitution results in None value and no default specified.
|
||||||
|
|
||||||
@@ -1789,6 +1809,7 @@ 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 ','
|
- `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
|
- `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
|
- `dirname`: if True, template output will be sanitized to produce valid directory name
|
||||||
|
- `strip`: if True, leading/trailign whitespace will be stripped from rendered template strings
|
||||||
|
|
||||||
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"].
|
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"].
|
||||||
|
|
||||||
@@ -2401,6 +2422,10 @@ The following template field substitutions are availabe for use with `PhotoInfo.
|
|||||||
|{place.address.country}|Country name of the postal address, e.g. 'United States'|
|
|{place.address.country}|Country name of the postal address, e.g. 'United States'|
|
||||||
|{place.address.country_code}|ISO country code of the postal address, e.g. 'US'|
|
|{place.address.country_code}|ISO country code of the postal address, e.g. 'US'|
|
||||||
|{searchinfo.season}|Season of the year associated with a photo, e.g. 'Summer'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).|
|
|{searchinfo.season}|Season of the year associated with a photo, e.g. 'Summer'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).|
|
||||||
|
|{exif.camera_make}|Camera make from original photo's EXIF inormation as imported by Photos, e.g. 'Apple'|
|
||||||
|
|{exif.camera_model}|Camera model from original photo's EXIF inormation as imported by Photos, e.g. 'iPhone 6s'|
|
||||||
|
|{exif.lens_model}|Lens model from original photo's EXIF inormation 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'|
|
||||||
|{album}|Album(s) photo is contained in|
|
|{album}|Album(s) photo is contained in|
|
||||||
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
|{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder|
|
||||||
|{keyword}|Keyword(s) assigned to photo|
|
|{keyword}|Keyword(s) assigned to photo|
|
||||||
|
|||||||
@@ -1586,6 +1586,14 @@ def query(
|
|||||||
"File extension will be added automatically--do not include an extension in the FILENAME template. "
|
"File extension will be added automatically--do not include an extension in the FILENAME template. "
|
||||||
"See below for additional details on templating system.",
|
"See below for additional details on templating system.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--strip",
|
||||||
|
is_flag=True,
|
||||||
|
help="Optionally strip leading and trailing whitespace from any rendered templates. "
|
||||||
|
'For example, if --filename template is "{title,} {original_name}" and image has no '
|
||||||
|
"title, resulting file would have a leading space but if used with --strip, this will "
|
||||||
|
"be removed.",
|
||||||
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--edited-suffix",
|
"--edited-suffix",
|
||||||
metavar="SUFFIX",
|
metavar="SUFFIX",
|
||||||
@@ -1749,6 +1757,7 @@ def export(
|
|||||||
has_raw,
|
has_raw,
|
||||||
directory,
|
directory,
|
||||||
filename_template,
|
filename_template,
|
||||||
|
strip,
|
||||||
edited_suffix,
|
edited_suffix,
|
||||||
original_suffix,
|
original_suffix,
|
||||||
place,
|
place,
|
||||||
@@ -1887,6 +1896,7 @@ def export(
|
|||||||
has_raw = cfg.has_raw
|
has_raw = cfg.has_raw
|
||||||
directory = cfg.directory
|
directory = cfg.directory
|
||||||
filename_template = cfg.filename_template
|
filename_template = cfg.filename_template
|
||||||
|
strip = cfg.strip
|
||||||
edited_suffix = cfg.edited_suffix
|
edited_suffix = cfg.edited_suffix
|
||||||
original_suffix = cfg.original_suffix
|
original_suffix = cfg.original_suffix
|
||||||
place = cfg.place
|
place = cfg.place
|
||||||
@@ -2252,6 +2262,7 @@ def export(
|
|||||||
ignore_date_modified=ignore_date_modified,
|
ignore_date_modified=ignore_date_modified,
|
||||||
use_photokit=use_photokit,
|
use_photokit=use_photokit,
|
||||||
exiftool_option=exiftool_option,
|
exiftool_option=exiftool_option,
|
||||||
|
strip=strip,
|
||||||
)
|
)
|
||||||
results += export_results
|
results += export_results
|
||||||
|
|
||||||
@@ -2276,13 +2287,14 @@ def export(
|
|||||||
person_keyword=person_keyword,
|
person_keyword=person_keyword,
|
||||||
exiftool_merge_keywords=exiftool_merge_keywords,
|
exiftool_merge_keywords=exiftool_merge_keywords,
|
||||||
finder_tag_template=finder_tag_template,
|
finder_tag_template=finder_tag_template,
|
||||||
|
strip=strip,
|
||||||
)
|
)
|
||||||
results.xattr_written.extend(tags_written)
|
results.xattr_written.extend(tags_written)
|
||||||
results.xattr_skipped.extend(tags_skipped)
|
results.xattr_skipped.extend(tags_skipped)
|
||||||
|
|
||||||
if xattr_template:
|
if xattr_template:
|
||||||
xattr_written, xattr_skipped = write_extended_attributes(
|
xattr_written, xattr_skipped = write_extended_attributes(
|
||||||
p, photo_files, xattr_template
|
p, photo_files, xattr_template, strip=strip
|
||||||
)
|
)
|
||||||
results.xattr_written.extend(xattr_written)
|
results.xattr_written.extend(xattr_written)
|
||||||
results.xattr_skipped.extend(xattr_skipped)
|
results.xattr_skipped.extend(xattr_skipped)
|
||||||
@@ -2822,6 +2834,7 @@ def export_photo(
|
|||||||
ignore_date_modified=False,
|
ignore_date_modified=False,
|
||||||
use_photokit=False,
|
use_photokit=False,
|
||||||
exiftool_option=None,
|
exiftool_option=None,
|
||||||
|
strip=False,
|
||||||
):
|
):
|
||||||
"""Helper function for export that does the actual export
|
"""Helper function for export that does the actual export
|
||||||
|
|
||||||
@@ -2912,12 +2925,14 @@ def export_photo(
|
|||||||
if photo.hasadjustments and photo.path_edited is None:
|
if photo.hasadjustments and photo.path_edited is None:
|
||||||
missing_edited = True
|
missing_edited = True
|
||||||
|
|
||||||
filenames = get_filenames_from_template(photo, filename_template, original_name)
|
filenames = get_filenames_from_template(
|
||||||
|
photo, filename_template, original_name, strip=strip
|
||||||
|
)
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if original_suffix:
|
if original_suffix:
|
||||||
try:
|
try:
|
||||||
rendered_suffix, unmatched = photo.render_template(
|
rendered_suffix, unmatched = photo.render_template(
|
||||||
original_suffix, filename=True
|
original_suffix, filename=True, strip=strip
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadOptionUsage(
|
raise click.BadOptionUsage(
|
||||||
@@ -2950,7 +2965,7 @@ def export_photo(
|
|||||||
)
|
)
|
||||||
|
|
||||||
dest_paths = get_dirnames_from_template(
|
dest_paths = get_dirnames_from_template(
|
||||||
photo, directory, export_by_date, dest, dry_run
|
photo, directory, export_by_date, dest, dry_run, strip=strip
|
||||||
)
|
)
|
||||||
|
|
||||||
sidecar = [s.lower() for s in sidecar]
|
sidecar = [s.lower() for s in sidecar]
|
||||||
@@ -3062,7 +3077,7 @@ def export_photo(
|
|||||||
if edited_suffix:
|
if edited_suffix:
|
||||||
try:
|
try:
|
||||||
rendered_suffix, unmatched = photo.render_template(
|
rendered_suffix, unmatched = photo.render_template(
|
||||||
edited_suffix, filename=True
|
edited_suffix, filename=True, strip=strip
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadOptionUsage(
|
raise click.BadOptionUsage(
|
||||||
@@ -3167,7 +3182,7 @@ def export_photo(
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def get_filenames_from_template(photo, filename_template, original_name):
|
def get_filenames_from_template(photo, filename_template, original_name, strip=False):
|
||||||
"""get list of export filenames for a photo
|
"""get list of export filenames for a photo
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -3185,7 +3200,7 @@ def get_filenames_from_template(photo, filename_template, original_name):
|
|||||||
photo_ext = pathlib.Path(photo.original_filename).suffix
|
photo_ext = pathlib.Path(photo.original_filename).suffix
|
||||||
try:
|
try:
|
||||||
filenames, unmatched = photo.render_template(
|
filenames, unmatched = photo.render_template(
|
||||||
filename_template, path_sep="_", filename=True
|
filename_template, path_sep="_", filename=True, strip=strip
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadOptionUsage(
|
raise click.BadOptionUsage(
|
||||||
@@ -3208,7 +3223,9 @@ def get_filenames_from_template(photo, filename_template, original_name):
|
|||||||
return filenames
|
return filenames
|
||||||
|
|
||||||
|
|
||||||
def get_dirnames_from_template(photo, directory, export_by_date, dest, dry_run):
|
def get_dirnames_from_template(
|
||||||
|
photo, directory, export_by_date, dest, dry_run, strip=False
|
||||||
|
):
|
||||||
"""get list of directories to export a photo into, creates directories if they don't exist
|
"""get list of directories to export a photo into, creates directories if they don't exist
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -3236,7 +3253,9 @@ def get_dirnames_from_template(photo, directory, export_by_date, dest, dry_run):
|
|||||||
elif directory:
|
elif directory:
|
||||||
# got a directory template, render it and check results are valid
|
# got a directory template, render it and check results are valid
|
||||||
try:
|
try:
|
||||||
dirnames, unmatched = photo.render_template(directory, dirname=True)
|
dirnames, unmatched = photo.render_template(
|
||||||
|
directory, dirname=True, strip=strip
|
||||||
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadOptionUsage("directory", f"Invalid template '{directory}'")
|
raise click.BadOptionUsage("directory", f"Invalid template '{directory}'")
|
||||||
if not dirnames or unmatched:
|
if not dirnames or unmatched:
|
||||||
@@ -3498,6 +3517,7 @@ def write_finder_tags(
|
|||||||
person_keyword=None,
|
person_keyword=None,
|
||||||
exiftool_merge_keywords=None,
|
exiftool_merge_keywords=None,
|
||||||
finder_tag_template=None,
|
finder_tag_template=None,
|
||||||
|
strip=False,
|
||||||
):
|
):
|
||||||
"""Write Finder tags (extended attributes) to files; only writes attributes if attributes on file differ from what would be written
|
"""Write Finder tags (extended attributes) to files; only writes attributes if attributes on file differ from what would be written
|
||||||
|
|
||||||
@@ -3537,7 +3557,10 @@ def write_finder_tags(
|
|||||||
for template_str in finder_tag_template:
|
for template_str in finder_tag_template:
|
||||||
try:
|
try:
|
||||||
rendered, unmatched = photo.render_template(
|
rendered, unmatched = photo.render_template(
|
||||||
template_str, none_str=_OSXPHOTOS_NONE_SENTINEL, path_sep="/"
|
template_str,
|
||||||
|
none_str=_OSXPHOTOS_NONE_SENTINEL,
|
||||||
|
path_sep="/",
|
||||||
|
strip=strip,
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadOptionUsage(
|
raise click.BadOptionUsage(
|
||||||
@@ -3575,7 +3598,7 @@ def write_finder_tags(
|
|||||||
return (written, skipped)
|
return (written, skipped)
|
||||||
|
|
||||||
|
|
||||||
def write_extended_attributes(photo, files, xattr_template):
|
def write_extended_attributes(photo, files, xattr_template, strip=False):
|
||||||
""" Writes extended attributes to exported files
|
""" Writes extended attributes to exported files
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -3590,7 +3613,10 @@ def write_extended_attributes(photo, files, xattr_template):
|
|||||||
for xattr, template_str in xattr_template:
|
for xattr, template_str in xattr_template:
|
||||||
try:
|
try:
|
||||||
rendered, unmatched = photo.render_template(
|
rendered, unmatched = photo.render_template(
|
||||||
template_str, none_str=_OSXPHOTOS_NONE_SENTINEL, path_sep="/"
|
template_str,
|
||||||
|
none_str=_OSXPHOTOS_NONE_SENTINEL,
|
||||||
|
path_sep="/",
|
||||||
|
strip=strip,
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise click.BadOptionUsage(
|
raise click.BadOptionUsage(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.39.4"
|
__version__ = "0.39.5"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -832,6 +832,7 @@ class PhotoInfo:
|
|||||||
inplace_sep=None,
|
inplace_sep=None,
|
||||||
filename=False,
|
filename=False,
|
||||||
dirname=False,
|
dirname=False,
|
||||||
|
strip=False,
|
||||||
):
|
):
|
||||||
"""Renders a template string for PhotoInfo instance using PhotoTemplate
|
"""Renders a template string for PhotoInfo instance using PhotoTemplate
|
||||||
|
|
||||||
@@ -846,6 +847,7 @@ class PhotoInfo:
|
|||||||
with expand_inplace; default is ','
|
with expand_inplace; default is ','
|
||||||
filename: if True, template output will be sanitized to produce valid file name
|
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
|
dirname: if True, template output will be sanitized to produce valid directory name
|
||||||
|
strip: if True, strips leading/trailing white space from resulting template
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values
|
([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values
|
||||||
@@ -859,6 +861,7 @@ class PhotoInfo:
|
|||||||
inplace_sep=inplace_sep,
|
inplace_sep=inplace_sep,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
dirname=dirname,
|
dirname=dirname,
|
||||||
|
strip=strip,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -118,6 +118,10 @@ TEMPLATE_SUBSTITUTIONS = {
|
|||||||
"{place.address.country}": "Country name of the postal address, e.g. 'United States'",
|
"{place.address.country}": "Country name of the postal address, e.g. 'United States'",
|
||||||
"{place.address.country_code}": "ISO country code of the postal address, e.g. 'US'",
|
"{place.address.country_code}": "ISO country code of the postal address, e.g. 'US'",
|
||||||
"{searchinfo.season}": "Season of the year associated with a photo, e.g. 'Summer'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).",
|
"{searchinfo.season}": "Season of the year associated with a photo, e.g. 'Summer'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).",
|
||||||
|
"{exif.camera_make}": "Camera make from original photo's EXIF inormation as imported by Photos, e.g. 'Apple'",
|
||||||
|
"{exif.camera_model}": "Camera model from original photo's EXIF inormation as imported by Photos, e.g. 'iPhone 6s'",
|
||||||
|
"{exif.lens_model}": "Lens model from original photo's EXIF inormation 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'",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Permitted multi-value substitutions (each of these returns None or 1 or more values)
|
# Permitted multi-value substitutions (each of these returns None or 1 or more values)
|
||||||
@@ -251,6 +255,7 @@ class PhotoTemplate:
|
|||||||
inplace_sep=None,
|
inplace_sep=None,
|
||||||
filename=False,
|
filename=False,
|
||||||
dirname=False,
|
dirname=False,
|
||||||
|
strip=False,
|
||||||
):
|
):
|
||||||
""" Render a filename or directory template
|
""" Render a filename or directory template
|
||||||
|
|
||||||
@@ -264,6 +269,7 @@ class PhotoTemplate:
|
|||||||
with expand_inplace; default is ','
|
with expand_inplace; default is ','
|
||||||
filename: if True, template output will be sanitized to produce valid file name
|
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
|
dirname: if True, template output will be sanitized to produce valid directory name
|
||||||
|
strip: if True, strips leading/trailing whitespace from rendered templates
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values
|
([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values
|
||||||
@@ -364,6 +370,11 @@ class PhotoTemplate:
|
|||||||
sanitize_filename(rendered_str) for rendered_str in rendered_strings
|
sanitize_filename(rendered_str) for rendered_str in rendered_strings
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if strip:
|
||||||
|
rendered_strings = [
|
||||||
|
rendered_str.strip() for rendered_str in rendered_strings
|
||||||
|
]
|
||||||
|
|
||||||
return rendered_strings, unmatched
|
return rendered_strings, unmatched
|
||||||
|
|
||||||
def _render_multi_valued_templates(
|
def _render_multi_valued_templates(
|
||||||
@@ -890,6 +901,14 @@ class PhotoTemplate:
|
|||||||
)
|
)
|
||||||
elif field == "searchinfo.season":
|
elif field == "searchinfo.season":
|
||||||
value = self.photo.search_info.season if self.photo.search_info else None
|
value = self.photo.search_info.season if self.photo.search_info else None
|
||||||
|
elif field == "exif.camera_make":
|
||||||
|
value = self.photo.exif_info.camera_make if self.photo.exif_info else None
|
||||||
|
elif field == "exif.camera_model":
|
||||||
|
value = self.photo.exif_info.camera_model if self.photo.exif_info else None
|
||||||
|
elif field == "exif.lens_model":
|
||||||
|
value = self.photo.exif_info.lens_model if self.photo.exif_info else None
|
||||||
|
elif field == "uuid":
|
||||||
|
value = self.photo.uuid
|
||||||
else:
|
else:
|
||||||
# if here, didn't get a match
|
# if here, didn't get a match
|
||||||
raise ValueError(f"Unhandled template value: {field}")
|
raise ValueError(f"Unhandled template value: {field}")
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -2880,7 +2880,6 @@ def test_export_filename_template_1():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
workdir = os.getcwd()
|
|
||||||
files = glob.glob("*.*")
|
files = glob.glob("*.*")
|
||||||
assert sorted(files) == sorted(CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES1)
|
assert sorted(files) == sorted(CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES1)
|
||||||
|
|
||||||
@@ -2915,6 +2914,37 @@ def test_export_filename_template_2():
|
|||||||
assert sorted(files) == sorted(CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES2)
|
assert sorted(files) == sorted(CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_filename_template_strip():
|
||||||
|
""" export photos using filename template with --strip """
|
||||||
|
import glob
|
||||||
|
import locale
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import osxphotos
|
||||||
|
from osxphotos.__main__ import export
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_ALL, "en_US")
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
os.path.join(cwd, CLI_PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--filename",
|
||||||
|
"{searchinfo.venue,} {created.year}-{original_name}",
|
||||||
|
"--strip",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
files = glob.glob("*.*")
|
||||||
|
assert sorted(files) == sorted(CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES1)
|
||||||
|
|
||||||
|
|
||||||
def test_export_filename_template_pathsep_in_name_1():
|
def test_export_filename_template_pathsep_in_name_1():
|
||||||
""" export photos using filename template with folder_album and "/" in album name """
|
""" export photos using filename template with folder_album and "/" in album name """
|
||||||
import locale
|
import locale
|
||||||
|
|||||||
@@ -136,6 +136,10 @@ TEMPLATE_VALUES = {
|
|||||||
"{place.address.postal_code}": "20009",
|
"{place.address.postal_code}": "20009",
|
||||||
"{place.address.country}": "United States",
|
"{place.address.country}": "United States",
|
||||||
"{place.address.country_code}": "US",
|
"{place.address.country_code}": "US",
|
||||||
|
"{uuid}": "128FB4C6-0B16-4E7D-9108-FB2E90DA1546",
|
||||||
|
"{exif.camera_make}": "Apple",
|
||||||
|
"{exif.camera_model}": "iPhone 6s",
|
||||||
|
"{exif.lens_model}": "iPhone 6s back camera 4.15mm f/2.2",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user