Refactored --sidecar-template options (#1137)
This commit is contained in:
parent
8c49916253
commit
ed1486fd4b
@ -88,7 +88,7 @@ from .common import (
|
|||||||
)
|
)
|
||||||
from .help import ExportCommand, get_help_msg
|
from .help import ExportCommand, get_help_msg
|
||||||
from .list import _list_libraries
|
from .list import _list_libraries
|
||||||
from .param_types import BooleanString, ExportDBType, FunctionCall, TemplateString
|
from .param_types import CSVOptions, ExportDBType, FunctionCall, TemplateString
|
||||||
from .report_writer import ReportWriterNoOp, export_report_writer_factory
|
from .report_writer import ReportWriterNoOp, export_report_writer_factory
|
||||||
from .rich_progress import rich_progress
|
from .rich_progress import rich_progress
|
||||||
from .sidecar import generate_user_sidecar
|
from .sidecar import generate_user_sidecar
|
||||||
@ -342,15 +342,13 @@ from .verbose import get_verbose_console, verbose_print
|
|||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
metavar="MAKO_TEMPLATE_FILE SIDECAR_FILENAME_TEMPLATE WRITE_SKIPPED STRIP_WHITESPACE STRIP_LINES",
|
metavar="MAKO_TEMPLATE_FILE SIDECAR_FILENAME_TEMPLATE OPTIONS",
|
||||||
multiple=True,
|
multiple=True,
|
||||||
type=click.Tuple(
|
type=click.Tuple(
|
||||||
[
|
[
|
||||||
click.Path(dir_okay=False, file_okay=True, exists=True),
|
click.Path(dir_okay=False, file_okay=True, exists=True),
|
||||||
TemplateString(),
|
TemplateString(),
|
||||||
BooleanString(),
|
CSVOptions(["write_skipped", "strip_whitespace", "strip_lines", "none"])
|
||||||
BooleanString(),
|
|
||||||
BooleanString(),
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
help="Create a custom sidecar file for each photo exported with user provided Mako template (MAKO_TEMPLATE_FILE). "
|
help="Create a custom sidecar file for each photo exported with user provided Mako template (MAKO_TEMPLATE_FILE). "
|
||||||
@ -362,17 +360,19 @@ from .verbose import get_verbose_console, verbose_print
|
|||||||
"which will be rendered to generate the filename of the sidecar file. "
|
"which will be rendered to generate the filename of the sidecar file. "
|
||||||
"The `{filepath}` template variable may be used in the SIDECAR_FILENAME_TEMPLATE to refer to the filename of the "
|
"The `{filepath}` template variable may be used in the SIDECAR_FILENAME_TEMPLATE to refer to the filename of the "
|
||||||
"photo being exported. "
|
"photo being exported. "
|
||||||
"WRITE_SKIPPED is a boolean value (true/false, yes/no, 1/0 are all valid values) and indicates whether or not "
|
"OPTIONS is a comma-separated list of strings providing additional options to the template. "
|
||||||
"write the sidecar file even if the photo is skipped during export. "
|
"Valid options are: write_skipped, strip_whitespace, strip_lines, none. "
|
||||||
"If WRITE_SKIPPED is false, the sidecar file will not be written if the photo is skipped during export. "
|
"write_skipped will cause the sidecar file to be written even if the photo is skipped during export. "
|
||||||
"If WRITE_SKIPPED is true, the sidecar file will be written even if the photo is skipped during export. "
|
"If write_skipped is not passed as an option, the sidecar file will not be written if the photo is skipped during export. "
|
||||||
"STRIP_WHITESPACE and STRIP_LINES are boolean values (true/false, yes/no, 1/0 are all valid values) "
|
"strip_whitespace and strip_lines indicate whether or not to strip whitespace and blank lines, respectively, "
|
||||||
"and indicate whether or not to strip whitespace and blank lines from the resulting sidecar file. "
|
"from the resulting sidecar file. "
|
||||||
"For example, to create a sidecar file with extension .xmp using a template file named 'sidecar.mako' "
|
"For example, to create a sidecar file with extension .xmp using a template file named 'sidecar.mako' "
|
||||||
"and write a sidecar for skipped photos and strip blank lines but not whitespace: "
|
"and write a sidecar for skipped photos and strip blank lines but not whitespace: "
|
||||||
"`--sidecar-template sidecar.mako '{filepath}.xmp' yes no yes`. "
|
"`--sidecar-template sidecar.mako '{filepath}.xmp' write_skipped,strip_lines`. "
|
||||||
"To do the same but to drop the photo extension from the sidecar filename: "
|
"To do the same but to drop the photo extension from the sidecar filename: "
|
||||||
"`--sidecar-template sidecar.mako '{filepath.parent}/{filepath.stem}.xmp' yes no yes --sidecar-drop-ext`. "
|
"`--sidecar-template sidecar.mako '{filepath.parent}/{filepath.stem}.xmp' write_skipped,strip_lines`. "
|
||||||
|
"If you are not passing any options, you must pass 'none' as the last argument to --sidecar-template: "
|
||||||
|
"`--sidecar-template sidecar.mako '{filepath}.xmp' none`. "
|
||||||
"For an example Mako file see https://raw.githubusercontent.com/RhetTbull/osxphotos/main/examples/custom_sidecar.mako",
|
"For an example Mako file see https://raw.githubusercontent.com/RhetTbull/osxphotos/main/examples/custom_sidecar.mako",
|
||||||
)
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
"""Click parameter types for osxphotos CLI"""
|
"""Click parameter types for osxphotos CLI"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
@ -19,6 +22,7 @@ from osxphotos.utils import expand_and_validate_filepath, load_function
|
|||||||
__all__ = [
|
__all__ = [
|
||||||
"BitMathSize",
|
"BitMathSize",
|
||||||
"BooleanString",
|
"BooleanString",
|
||||||
|
"CSVOptions",
|
||||||
"DateOffset",
|
"DateOffset",
|
||||||
"DateTimeISO8601",
|
"DateTimeISO8601",
|
||||||
"DeprecatedPath",
|
"DeprecatedPath",
|
||||||
@ -319,3 +323,30 @@ class BooleanString(click.ParamType):
|
|||||||
self.fail(
|
self.fail(
|
||||||
f"Invalid boolean string {value}. Must be one of True/False, Yes/No, T/F, Y/N, 1/0 (case insensitive)."
|
f"Invalid boolean string {value}. Must be one of True/False, Yes/No, T/F, Y/N, 1/0 (case insensitive)."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CSVOptions(click.ParamType):
|
||||||
|
"""A comma-separated list of option values, not case sensitive"""
|
||||||
|
|
||||||
|
name = "CSVOptions"
|
||||||
|
|
||||||
|
def __init__(self, options: list[str]):
|
||||||
|
"""Initialize CSVOptions
|
||||||
|
|
||||||
|
Args:
|
||||||
|
options: list of valid options as str
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The convert method returns a tuple[str, ...] of the options selected
|
||||||
|
"""
|
||||||
|
self._csv_options = options
|
||||||
|
|
||||||
|
def convert(self, value, param, ctx) -> tuple[str, ...]:
|
||||||
|
values = value.split(",")
|
||||||
|
values = [v.lower().strip() for v in values]
|
||||||
|
for v in values:
|
||||||
|
if v not in self._csv_options:
|
||||||
|
self.fail(
|
||||||
|
f"Invalid option {v}. Must be one of {','.join(self._csv_options)}"
|
||||||
|
)
|
||||||
|
return tuple(values)
|
||||||
|
|||||||
@ -23,7 +23,7 @@ def get_template(template: str) -> Template:
|
|||||||
def generate_user_sidecar(
|
def generate_user_sidecar(
|
||||||
photo: PhotoInfo,
|
photo: PhotoInfo,
|
||||||
export_results: ExportResults,
|
export_results: ExportResults,
|
||||||
sidecar_template: tuple[tuple[str, str, bool, bool]],
|
sidecar_template: tuple[tuple[str, str, tuple[str, ...]], ...],
|
||||||
exiftool_path: str,
|
exiftool_path: str,
|
||||||
export_dir: str,
|
export_dir: str,
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
@ -48,10 +48,12 @@ def generate_user_sidecar(
|
|||||||
for (
|
for (
|
||||||
template_file,
|
template_file,
|
||||||
filename_template,
|
filename_template,
|
||||||
write_skipped,
|
options,
|
||||||
strip_whitespace,
|
|
||||||
strip_lines,
|
|
||||||
) in sidecar_template:
|
) in sidecar_template:
|
||||||
|
strip_whitespace = "strip_whitespace" in options
|
||||||
|
strip_lines = "strip_lines" in options
|
||||||
|
write_skipped = "write_skipped" in options
|
||||||
|
|
||||||
if not write_skipped:
|
if not write_skipped:
|
||||||
# skip writing sidecar if photo not exported
|
# skip writing sidecar if photo not exported
|
||||||
# but if run with --update and --cleanup, a sidecar file may have been written
|
# but if run with --update and --cleanup, a sidecar file may have been written
|
||||||
|
|||||||
@ -52,9 +52,7 @@ def test_export_sidecar_template_1():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -63,6 +61,34 @@ def test_export_sidecar_template_1():
|
|||||||
sidecar_data = sidecar_file.read_text()
|
sidecar_data = sidecar_file.read_text()
|
||||||
assert sidecar_data == SIDECAR_DATA
|
assert sidecar_data == SIDECAR_DATA
|
||||||
|
|
||||||
|
def test_export_sidecar_template_option_case():
|
||||||
|
"""test basic export with --sidecar-template and option case insensitivity"""
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
"--library",
|
||||||
|
os.path.join(cwd, PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--uuid",
|
||||||
|
PHOTO_UUID,
|
||||||
|
"--sidecar-template",
|
||||||
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
|
"{filepath}.txt",
|
||||||
|
"None",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
|
||||||
|
assert sidecar_file.exists()
|
||||||
|
sidecar_data = sidecar_file.read_text()
|
||||||
|
assert sidecar_data == SIDECAR_DATA
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_export_sidecar_template_strip_whitespace():
|
def test_export_sidecar_template_strip_whitespace():
|
||||||
"""test basic export with --sidecar-template and STRIP_WHITESPACE = True"""
|
"""test basic export with --sidecar-template and STRIP_WHITESPACE = True"""
|
||||||
@ -82,9 +108,7 @@ def test_export_sidecar_template_strip_whitespace():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"strip_whitespace",
|
||||||
"yes",
|
|
||||||
"no",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -115,9 +139,7 @@ def test_export_sidecar_template_strip_lines():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"strip_lines",
|
||||||
"no",
|
|
||||||
"yes",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -148,9 +170,7 @@ def test_export_sidecar_template_strip_lines_strip_whitespace():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"strip_whitespace,strip_lines",
|
||||||
"yes",
|
|
||||||
"yes",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -162,6 +182,35 @@ def test_export_sidecar_template_strip_lines_strip_whitespace():
|
|||||||
)
|
)
|
||||||
assert sidecar_data == sidecar_expected
|
assert sidecar_data == sidecar_expected
|
||||||
|
|
||||||
|
def test_export_sidecar_template_strip_lines_strip_whitespace_option_space():
|
||||||
|
"""test basic export with --sidecar-template and STRIP_LINES = True and STRIP_WHITESPACE = True with space in option"""
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
"--library",
|
||||||
|
os.path.join(cwd, PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--uuid",
|
||||||
|
PHOTO_UUID,
|
||||||
|
"--sidecar-template",
|
||||||
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
|
"{filepath}.txt",
|
||||||
|
"strip_whitespace, strip_lines",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
|
||||||
|
assert sidecar_file.exists()
|
||||||
|
sidecar_data = sidecar_file.read_text()
|
||||||
|
sidecar_expected = "\n".join(
|
||||||
|
line.strip() for line in SIDECAR_DATA.splitlines() if line.strip()
|
||||||
|
)
|
||||||
|
assert sidecar_data == sidecar_expected
|
||||||
|
|
||||||
def test_export_sidecar_template_update_no():
|
def test_export_sidecar_template_update_no():
|
||||||
"""test basic export with --sidecar-template and WRITE_SKIPPED = False, also test --cleanup"""
|
"""test basic export with --sidecar-template and WRITE_SKIPPED = False, also test --cleanup"""
|
||||||
@ -181,9 +230,7 @@ def test_export_sidecar_template_update_no():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -200,9 +247,7 @@ def test_export_sidecar_template_update_no():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
"--update",
|
"--update",
|
||||||
"--cleanup",
|
"--cleanup",
|
||||||
],
|
],
|
||||||
@ -237,9 +282,7 @@ def test_export_sidecar_template_update_ues():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -256,9 +299,7 @@ def test_export_sidecar_template_update_ues():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"yes",
|
"write_skipped",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
"--update",
|
"--update",
|
||||||
"--cleanup",
|
"--cleanup",
|
||||||
],
|
],
|
||||||
@ -294,9 +335,7 @@ def test_export_sidecar_template_report_csv():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
"--report",
|
"--report",
|
||||||
"report.csv",
|
"report.csv",
|
||||||
],
|
],
|
||||||
@ -340,9 +379,7 @@ def test_export_sidecar_template_report_json():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
"--report",
|
"--report",
|
||||||
"report.json",
|
"report.json",
|
||||||
],
|
],
|
||||||
@ -385,9 +422,7 @@ def test_export_sidecar_template_report_db():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
"--report",
|
"--report",
|
||||||
"report.db",
|
"report.db",
|
||||||
],
|
],
|
||||||
@ -430,15 +465,11 @@ def test_export_sidecar_template_multiple():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.sidecar",
|
"{filepath}.sidecar",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
@ -470,9 +501,7 @@ def test_export_sidecar_template_full_library():
|
|||||||
"--sidecar-template",
|
"--sidecar-template",
|
||||||
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
os.path.join(cwd, "tests", "custom_sidecar.mako"),
|
||||||
"{filepath}.txt",
|
"{filepath}.txt",
|
||||||
"no",
|
"none",
|
||||||
"no",
|
|
||||||
"no",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user