More refactoring in PhotoTemplate

This commit is contained in:
Rhet Turnbull
2020-05-30 14:42:08 -07:00
parent 16f802bf71
commit f35ea70b72
3 changed files with 86 additions and 58 deletions

View File

@@ -638,7 +638,7 @@ class PhotoInfo:
fields like folder_album; if not provided, defaults to os.path.sep fields like folder_album; if not provided, defaults to os.path.sep
""" """
template = PhotoTemplate(self) template = PhotoTemplate(self)
return template.render_template(template_str, none_str, path_sep) return template.render(template_str, none_str, path_sep)
@property @property
def _longitude(self): def _longitude(self):

View File

@@ -78,24 +78,15 @@ MULTI_VALUE_SUBSTITUTIONS = [
class PhotoTemplate: class PhotoTemplate:
""" PhotoTemplate class to render a template string from a PhotoInfo object """ """ PhotoTemplate class to render a template string from a PhotoInfo object """
def __init__(self, photo, none_str="_", path_sep=None): def __init__(self, photo):
""" Inits PhotoTemplate class with photo, non_str, and path_sep """ Inits PhotoTemplate class with photo, non_str, and path_sep
Args: Args:
photo: a PhotoInfo instance. photo: a PhotoInfo instance.
none_str: a str to use if template field renders to None, default is "_".
path_sep: a single character str to use as path separator when joining
fields like folder_album; if not provided, defaults to os.path.sep
""" """
self.photo = photo self.photo = photo
self.none_str = none_str
self.path_sep = path_sep
if path_sep is None:
self.path_sep = os.path.sep
elif path_sep is not None and len(path_sep) != 1:
raise ValueError(f"path_sep must be single character: {path_sep}")
def render_template(self, template, none_str="_", path_sep=None): def render(self, template, none_str="_", path_sep=None):
""" render a filename or directory template """ render a filename or directory template
template: str template template: str template
none_str: str to use default for None values, default is '_' none_str: str to use default for None values, default is '_'
@@ -132,7 +123,7 @@ class PhotoTemplate:
if groups == 4: if groups == 4:
try: try:
val = get_func(matchobj.group(1)) val = get_func(matchobj.group(1))
except KeyError: except ValueError:
return matchobj.group(0) return matchobj.group(0)
if val is None: if val is None:
@@ -189,20 +180,20 @@ class PhotoTemplate:
for str_template in rendered_strings: for str_template in rendered_strings:
if regex_multi.search(str_template): if regex_multi.search(str_template):
values = self._template_value_multi(field, path_sep) values = self.get_template_value_multi(field, path_sep)
for val in values: for val in values:
def get_template_value_multi(lookup_value): def lookup_template_value_multi(lookup_value):
""" Closure passed to make_subst_function get_func """ Closure passed to make_subst_function get_func
Capture val and field in the closure Capture val and field in the closure
Allows make_subst_function to be re-used w/o modification """ Allows make_subst_function to be re-used w/o modification """
if lookup_value == field: if lookup_value == field:
return val return val
else: else:
raise KeyError(f"Unexpected value: {lookup_value}") raise ValueError(f"Unexpected value: {lookup_value}")
subst = make_subst_function( subst = make_subst_function(
self, none_str, get_func=get_template_value_multi self, none_str, get_func=lookup_template_value_multi
) )
new_string = regex_multi.sub(subst, str_template) new_string = regex_multi.sub(subst, str_template)
new_strings.add(new_string) new_strings.add(new_string)
@@ -229,179 +220,186 @@ class PhotoTemplate:
return rendered_strings, unmatched return rendered_strings, unmatched
def get_template_value(self, lookup): def get_template_value(self, field):
""" lookup template value (single-value template substitutions) for use in make_subst_function """lookup value for template field (single-value template substitutions)
lookup: value to find a match for
returns: either the matching template value (which may be None) Args:
raises: KeyError if no rule exists for lookup """ field: template field to find value for.
Returns:
The matching template value (which may be None).
Raises:
ValueError if no rule exists for field.
"""
# must be a valid keyword # must be a valid keyword
if lookup == "name": if field =="name":
return pathlib.Path(self.photo.filename).stem return pathlib.Path(self.photo.filename).stem
if lookup == "original_name": if field =="original_name":
return pathlib.Path(self.photo.original_filename).stem return pathlib.Path(self.photo.original_filename).stem
if lookup == "title": if field =="title":
return self.photo.title return self.photo.title
if lookup == "descr": if field =="descr":
return self.photo.description return self.photo.description
if lookup == "created.date": if field =="created.date":
return DateTimeFormatter(self.photo.date).date return DateTimeFormatter(self.photo.date).date
if lookup == "created.year": if field =="created.year":
return DateTimeFormatter(self.photo.date).year return DateTimeFormatter(self.photo.date).year
if lookup == "created.yy": if field =="created.yy":
return DateTimeFormatter(self.photo.date).yy return DateTimeFormatter(self.photo.date).yy
if lookup == "created.mm": if field =="created.mm":
return DateTimeFormatter(self.photo.date).mm return DateTimeFormatter(self.photo.date).mm
if lookup == "created.month": if field =="created.month":
return DateTimeFormatter(self.photo.date).month return DateTimeFormatter(self.photo.date).month
if lookup == "created.mon": if field =="created.mon":
return DateTimeFormatter(self.photo.date).mon return DateTimeFormatter(self.photo.date).mon
if lookup == "created.dd": if field =="created.dd":
return DateTimeFormatter(self.photo.date).dd return DateTimeFormatter(self.photo.date).dd
if lookup == "created.dow": if field =="created.dow":
return DateTimeFormatter(self.photo.date).dow return DateTimeFormatter(self.photo.date).dow
if lookup == "created.doy": if field =="created.doy":
return DateTimeFormatter(self.photo.date).doy return DateTimeFormatter(self.photo.date).doy
if lookup == "modified.date": if field =="modified.date":
return ( return (
DateTimeFormatter(self.photo.date_modified).date DateTimeFormatter(self.photo.date_modified).date
if self.photo.date_modified if self.photo.date_modified
else None else None
) )
if lookup == "modified.year": if field =="modified.year":
return ( return (
DateTimeFormatter(self.photo.date_modified).year DateTimeFormatter(self.photo.date_modified).year
if self.photo.date_modified if self.photo.date_modified
else None else None
) )
if lookup == "modified.yy": if field =="modified.yy":
return ( return (
DateTimeFormatter(self.photo.date_modified).yy if self.photo.date_modified else None DateTimeFormatter(self.photo.date_modified).yy if self.photo.date_modified else None
) )
if lookup == "modified.mm": if field =="modified.mm":
return ( return (
DateTimeFormatter(self.photo.date_modified).mm if self.photo.date_modified else None DateTimeFormatter(self.photo.date_modified).mm if self.photo.date_modified else None
) )
if lookup == "modified.month": if field =="modified.month":
return ( return (
DateTimeFormatter(self.photo.date_modified).month DateTimeFormatter(self.photo.date_modified).month
if self.photo.date_modified if self.photo.date_modified
else None else None
) )
if lookup == "modified.mon": if field =="modified.mon":
return ( return (
DateTimeFormatter(self.photo.date_modified).mon DateTimeFormatter(self.photo.date_modified).mon
if self.photo.date_modified if self.photo.date_modified
else None else None
) )
if lookup == "modified.dd": if field =="modified.dd":
return ( return (
DateTimeFormatter(self.photo.date_modified).dd if self.photo.date_modified else None DateTimeFormatter(self.photo.date_modified).dd if self.photo.date_modified else None
) )
if lookup == "modified.doy": if field =="modified.doy":
return ( return (
DateTimeFormatter(self.photo.date_modified).doy DateTimeFormatter(self.photo.date_modified).doy
if self.photo.date_modified if self.photo.date_modified
else None else None
) )
if lookup == "place.name": if field =="place.name":
return self.photo.place.name if self.photo.place else None return self.photo.place.name if self.photo.place else None
if lookup == "place.country_code": if field =="place.country_code":
return self.photo.place.country_code if self.photo.place else None return self.photo.place.country_code if self.photo.place else None
if lookup == "place.name.country": if field =="place.name.country":
return ( return (
self.photo.place.names.country[0] self.photo.place.names.country[0]
if self.photo.place and self.photo.place.names.country if self.photo.place and self.photo.place.names.country
else None else None
) )
if lookup == "place.name.state_province": if field =="place.name.state_province":
return ( return (
self.photo.place.names.state_province[0] self.photo.place.names.state_province[0]
if self.photo.place and self.photo.place.names.state_province if self.photo.place and self.photo.place.names.state_province
else None else None
) )
if lookup == "place.name.city": if field =="place.name.city":
return ( return (
self.photo.place.names.city[0] self.photo.place.names.city[0]
if self.photo.place and self.photo.place.names.city if self.photo.place and self.photo.place.names.city
else None else None
) )
if lookup == "place.name.area_of_interest": if field =="place.name.area_of_interest":
return ( return (
self.photo.place.names.area_of_interest[0] self.photo.place.names.area_of_interest[0]
if self.photo.place and self.photo.place.names.area_of_interest if self.photo.place and self.photo.place.names.area_of_interest
else None else None
) )
if lookup == "place.address": if field =="place.address":
return ( return (
self.photo.place.address_str self.photo.place.address_str
if self.photo.place and self.photo.place.address_str if self.photo.place and self.photo.place.address_str
else None else None
) )
if lookup == "place.address.street": if field =="place.address.street":
return ( return (
self.photo.place.address.street self.photo.place.address.street
if self.photo.place and self.photo.place.address.street if self.photo.place and self.photo.place.address.street
else None else None
) )
if lookup == "place.address.city": if field =="place.address.city":
return ( return (
self.photo.place.address.city self.photo.place.address.city
if self.photo.place and self.photo.place.address.city if self.photo.place and self.photo.place.address.city
else None else None
) )
if lookup == "place.address.state_province": if field =="place.address.state_province":
return ( return (
self.photo.place.address.state_province self.photo.place.address.state_province
if self.photo.place and self.photo.place.address.state_province if self.photo.place and self.photo.place.address.state_province
else None else None
) )
if lookup == "place.address.postal_code": if field =="place.address.postal_code":
return ( return (
self.photo.place.address.postal_code self.photo.place.address.postal_code
if self.photo.place and self.photo.place.address.postal_code if self.photo.place and self.photo.place.address.postal_code
else None else None
) )
if lookup == "place.address.country": if field =="place.address.country":
return ( return (
self.photo.place.address.country self.photo.place.address.country
if self.photo.place and self.photo.place.address.country if self.photo.place and self.photo.place.address.country
else None else None
) )
if lookup == "place.address.country_code": if field =="place.address.country_code":
return ( return (
self.photo.place.address.iso_country_code self.photo.place.address.iso_country_code
if self.photo.place and self.photo.place.address.iso_country_code if self.photo.place and self.photo.place.address.iso_country_code
@@ -409,9 +407,22 @@ class PhotoTemplate:
) )
# if here, didn't get a match # if here, didn't get a match
raise KeyError(f"No rule for processing {lookup}") raise ValueError(f"Unhandled template value: {field}")
def get_template_value_multi(self, field, path_sep):
"""lookup value for template field (multi-value template substitutions)
Args:
field: template field to find value for.
path_sep: path separator to use for folder_album field
Returns:
List of the matching template values or [None].
Raises:
ValueError if no rule exists for field.
"""
def _template_value_multi(self, field, path_sep):
""" return list of values for a multi-valued template field """ """ return list of values for a multi-valued template field """
if field == "album": if field == "album":
values = self.photo.albums values = self.photo.albums

View File

@@ -110,6 +110,23 @@ def test_lookup():
assert lookup or lookup is None assert lookup or lookup is None
def test_lookup_multi():
""" Test that a lookup is returned for every possible value """
import os
import re
import osxphotos
from osxphotos.phototemplate import TEMPLATE_SUBSTITUTIONS_MULTI_VALUED, PhotoTemplate
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
template = PhotoTemplate(photo)
for subst in TEMPLATE_SUBSTITUTIONS_MULTI_VALUED:
lookup_str = re.match(r"\{([^\\,}]+)\}", subst).group(1)
lookup = template.get_template_value_multi(lookup_str,path_sep=os.path.sep)
assert isinstance(lookup, list)
assert len(lookup) >= 1
def test_subst(): def test_subst():
""" Test that substitutions are correct """ """ Test that substitutions are correct """
import locale import locale