Added function filter to template system, closes #429
This commit is contained in:
parent
9371db094e
commit
dd6d519135
@ -913,42 +913,44 @@ class PhotoTemplate:
|
||||
if values and type(values) == list:
|
||||
value = [v.lower() for v in values]
|
||||
else:
|
||||
value = [values.lower()]
|
||||
value = [values.lower()] if values else []
|
||||
elif filter_ == "upper":
|
||||
if values and type(values) == list:
|
||||
value = [v.upper() for v in values]
|
||||
else:
|
||||
value = [values.upper()]
|
||||
value = [values.upper()] if values else []
|
||||
elif filter_ == "strip":
|
||||
if values and type(values) == list:
|
||||
value = [v.strip() for v in values]
|
||||
else:
|
||||
value = [values.strip()]
|
||||
value = [values.strip()] if values else []
|
||||
elif filter_ == "capitalize":
|
||||
if values and type(values) == list:
|
||||
value = [v.capitalize() for v in values]
|
||||
else:
|
||||
value = [values.capitalize()]
|
||||
value = [values.capitalize()] if values else []
|
||||
elif filter_ == "titlecase":
|
||||
if values and type(values) == list:
|
||||
value = [v.title() for v in values]
|
||||
else:
|
||||
value = [values.title()]
|
||||
value = [values.title()] if values else []
|
||||
elif filter_ == "braces":
|
||||
if values and type(values) == list:
|
||||
value = ["{" + v + "}" for v in values]
|
||||
else:
|
||||
value = ["{" + values + "}"]
|
||||
value = ["{" + values + "}"] if values else []
|
||||
elif filter_ == "parens":
|
||||
if values and type(values) == list:
|
||||
value = ["(" + v + ")" for v in values]
|
||||
else:
|
||||
value = ["(" + values + ")"]
|
||||
value = ["(" + values + ")"] if values else []
|
||||
elif filter_ == "brackets":
|
||||
if values and type(values) == list:
|
||||
value = ["[" + v + "]" for v in values]
|
||||
else:
|
||||
value = ["[" + values + "]"]
|
||||
value = ["[" + values + "]"] if values else []
|
||||
elif filter_.startswith("function:"):
|
||||
value = self.get_template_value_filter_function(filter_, values)
|
||||
else:
|
||||
value = []
|
||||
return value
|
||||
@ -1097,8 +1099,6 @@ class PhotoTemplate:
|
||||
|
||||
filename, funcname = subfield.split("::")
|
||||
|
||||
print(filename, funcname)
|
||||
|
||||
if not pathlib.Path(filename).is_file():
|
||||
raise ValueError(f"'{filename}' does not appear to be a file")
|
||||
|
||||
@ -1120,6 +1120,35 @@ class PhotoTemplate:
|
||||
|
||||
return values
|
||||
|
||||
def get_template_value_filter_function(self, filter_, values):
|
||||
"""Filter template value from external function """
|
||||
|
||||
filter_ = filter_.replace("function:","")
|
||||
|
||||
if "::" not in filter_:
|
||||
raise ValueError(
|
||||
f"SyntaxError: could not parse function name from '{filter_}'"
|
||||
)
|
||||
|
||||
filename, funcname = filter_.split("::")
|
||||
|
||||
if not pathlib.Path(filename).is_file():
|
||||
raise ValueError(f"'{filename}' does not appear to be a file")
|
||||
|
||||
template_func = load_function(filename, funcname)
|
||||
|
||||
if not isinstance(values, (list, tuple)):
|
||||
values = [values]
|
||||
values = template_func(values)
|
||||
|
||||
if not isinstance(values, list):
|
||||
raise TypeError(
|
||||
f"Invalid return type for function {funcname}: expected list"
|
||||
)
|
||||
|
||||
return values
|
||||
|
||||
|
||||
def get_photo_video_type(self, default):
|
||||
""" return media type, e.g. photo or video """
|
||||
default_dict = parse_default_kv(default, PHOTO_VIDEO_TYPE_DEFAULTS)
|
||||
|
||||
@ -74,7 +74,7 @@ Filter:
|
||||
;
|
||||
|
||||
FILTER_WORD:
|
||||
/[\.\w]+/
|
||||
/[\.\w:\/]+/
|
||||
;
|
||||
|
||||
Conditional:
|
||||
|
||||
17
tests/template_filter.py
Normal file
17
tests/template_filter.py
Normal file
@ -0,0 +1,17 @@
|
||||
""" Example of using a custom python function as an osxphotos template filter
|
||||
|
||||
Use in formath:
|
||||
"{template_field|template_filter.py::myfilter}"
|
||||
|
||||
Your filter function will receive a list of strings even if the template renders to a single value.
|
||||
You should expect a list and return a list and be able to handle multi-value templates like {keyword}
|
||||
as well as single-value templates like {original_name}
|
||||
"""
|
||||
|
||||
from typing import List
|
||||
|
||||
def myfilter(values: List[str]) -> List[str]:
|
||||
""" Custom filter to append "foo-" to template value """
|
||||
values = ["foo-" + val for val in values]
|
||||
return values
|
||||
|
||||
@ -982,3 +982,31 @@ def test_function_bad(photosdb):
|
||||
"{function:tests/template_function.py::foobar}"
|
||||
)
|
||||
|
||||
|
||||
def test_function_filter(photosdb):
|
||||
""" Test {field|function} filter"""
|
||||
photo = photosdb.get_photo(UUID_MULTI_KEYWORDS)
|
||||
|
||||
rendered, _ = photo.render_template(
|
||||
"{photo.original_filename|function:tests/template_filter.py::myfilter}"
|
||||
)
|
||||
assert rendered == [f"foo-{photo.original_filename}"]
|
||||
|
||||
rendered, _ = photo.render_template(
|
||||
"{photo.original_filename|lower|function:tests/template_filter.py::myfilter}"
|
||||
)
|
||||
assert rendered == [f"foo-{photo.original_filename.lower()}"]
|
||||
|
||||
rendered, _ = photo.render_template(
|
||||
"{photo.original_filename|function:tests/template_filter.py::myfilter|lower}"
|
||||
)
|
||||
assert rendered == [f"foo-{photo.original_filename.lower()}"]
|
||||
|
||||
|
||||
def test_function_filter_bad(photosdb):
|
||||
""" Test invalid {field|function} filter"""
|
||||
photo = photosdb.get_photo(UUID_MULTI_KEYWORDS)
|
||||
with pytest.raises(ValueError):
|
||||
rendered, _ = photo.render_template(
|
||||
"{photo.original_filename|function:tests/template_filter.py::foobar}"
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user