Added today to template system, closes #167
This commit is contained in:
42
README.md
42
README.md
@@ -428,6 +428,34 @@ Substitution Description
|
||||
{modified.hour} 2-digit hour of the file modification time
|
||||
{modified.min} 2-digit minute of the file modification time
|
||||
{modified.sec} 2-digit second of the file modification time
|
||||
{today.date} Current date in iso format, e.g.
|
||||
'2020-03-22'
|
||||
{today.year} 4-digit year of current date
|
||||
{today.yy} 2-digit year of current date
|
||||
{today.mm} 2-digit month of the current date (zero
|
||||
padded)
|
||||
{today.month} Month name in user's locale of the current
|
||||
date
|
||||
{today.mon} Month abbreviation in the user's locale of
|
||||
the current date
|
||||
{today.dd} 2-digit day of the month (zero padded) of
|
||||
current date
|
||||
{today.dow} Day of week in user's locale of the current
|
||||
date
|
||||
{today.doy} 3-digit day of year (e.g Julian day) of
|
||||
current date, starting from 1 (zero padded)
|
||||
{today.hour} 2-digit hour of the current date
|
||||
{today.min} 2-digit minute of the current date
|
||||
{today.sec} 2-digit second of the current date
|
||||
{today.strftime} Apply strftime template to current
|
||||
date/time. Should be used in form
|
||||
{today.strftime,TEMPLATE} where TEMPLATE is
|
||||
a valid strftime template, e.g.
|
||||
{today.strftime,%Y-%U} would result in year-
|
||||
week number of year: '2020-23'. If used with
|
||||
no template will return null value. See
|
||||
https://strftime.org/ for help on strftime
|
||||
templates.
|
||||
{place.name} Place name from the photo's reverse
|
||||
geolocation data, as displayed in Photos
|
||||
{place.country_code} The ISO country code from the photo's
|
||||
@@ -1461,7 +1489,6 @@ Example: find your "best" photo of food
|
||||
### Template Substitutions
|
||||
|
||||
The following substitutions are availabe for use with `PhotoInfo.render_template()`
|
||||
|
||||
| Substitution | Description |
|
||||
|--------------|-------------|
|
||||
|{name}|Current filename of the photo|
|
||||
@@ -1492,6 +1519,19 @@ The following substitutions are availabe for use with `PhotoInfo.render_template
|
||||
|{modified.hour}|2-digit hour of the file modification time|
|
||||
|{modified.min}|2-digit minute of the file modification time|
|
||||
|{modified.sec}|2-digit second of the file modification time|
|
||||
|{today.date}|Current date in iso format, e.g. '2020-03-22'|
|
||||
|{today.year}|4-digit year of current date|
|
||||
|{today.yy}|2-digit year of current date|
|
||||
|{today.mm}|2-digit month of the current date (zero padded)|
|
||||
|{today.month}|Month name in user's locale of the current date|
|
||||
|{today.mon}|Month abbreviation in the user's locale of the current date|
|
||||
|{today.dd}|2-digit day of the month (zero padded) of current date|
|
||||
|{today.dow}|Day of week in user's locale of the current date|
|
||||
|{today.doy}|3-digit day of year (e.g Julian day) of current date, starting from 1 (zero padded)|
|
||||
|{today.hour}|2-digit hour of the current date|
|
||||
|{today.min}|2-digit minute of the current date|
|
||||
|{today.sec}|2-digit second of the current date|
|
||||
|{today.strftime}|Apply strftime template to current date/time. Should be used in form {today.strftime,TEMPLATE} where TEMPLATE is a valid strftime template, e.g. {today.strftime,%Y-%U} would result in year-week number of year: '2020-23'. If used with no template will return null value. See https://strftime.org/ for help on strftime templates.|
|
||||
|{place.name}|Place name from the photo's reverse geolocation data, as displayed in Photos|
|
||||
|{place.country_code}|The ISO country code from the photo's reverse geolocation data|
|
||||
|{place.name.country}|Country name from the photo's reverse geolocation data|
|
||||
|
||||
@@ -3,14 +3,9 @@ import logging
|
||||
from ._version import __version__
|
||||
from .photoinfo import PhotoInfo
|
||||
from .photosdb import PhotosDB
|
||||
from .utils import _set_debug, _debug, _get_logger
|
||||
from .phototemplate import PhotoTemplate
|
||||
from .utils import _debug, _get_logger, _set_debug
|
||||
|
||||
# TODO: find edited photos: see https://github.com/orangeturtle739/photos-export/blob/master/extract_photos.py
|
||||
# TODO: Add test for imageTimeZoneOffsetSeconds = None
|
||||
# TODO: Fix command line so multiple --keyword, etc. are AND (instead of OR as they are in .photos())
|
||||
# Or fix the help text to match behavior
|
||||
# TODO: Add test for __str__ and to_json
|
||||
# TODO: fix docstrings
|
||||
# TODO: Add special albums and magic albums
|
||||
# TODO: cleanup os.path and pathlib code (import pathlib and also from pathlib import Path)
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.29.27"
|
||||
__version__ = "0.29.28"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
# 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.
|
||||
import datetime
|
||||
import locale
|
||||
import os
|
||||
import re
|
||||
@@ -59,6 +60,23 @@ TEMPLATE_SUBSTITUTIONS = {
|
||||
# + "{modified.strftime,%Y-%U} would result in year-week number of year: '2020-23'. "
|
||||
# + "If used with no template will return null value. "
|
||||
# + "See https://strftime.org/ for help on strftime templates.",
|
||||
"{today.date}": "Current date in iso format, e.g. '2020-03-22'",
|
||||
"{today.year}": "4-digit year of current date",
|
||||
"{today.yy}": "2-digit year of current date",
|
||||
"{today.mm}": "2-digit month of the current date (zero padded)",
|
||||
"{today.month}": "Month name in user's locale of the current date",
|
||||
"{today.mon}": "Month abbreviation in the user's locale of the current date",
|
||||
"{today.dd}": "2-digit day of the month (zero padded) of current date",
|
||||
"{today.dow}": "Day of week in user's locale of the current date",
|
||||
"{today.doy}": "3-digit day of year (e.g Julian day) of current date, starting from 1 (zero padded)",
|
||||
"{today.hour}": "2-digit hour of the current date",
|
||||
"{today.min}": "2-digit minute of the current date",
|
||||
"{today.sec}": "2-digit second of the current date",
|
||||
"{today.strftime}": "Apply strftime template to current date/time. Should be used in form "
|
||||
+ "{today.strftime,TEMPLATE} where TEMPLATE is a valid strftime template, e.g. "
|
||||
+ "{today.strftime,%Y-%U} would result in year-week number of year: '2020-23'. "
|
||||
+ "If used with no template will return null value. "
|
||||
+ "See https://strftime.org/ for help on strftime templates.",
|
||||
"{place.name}": "Place name from the photo's reverse geolocation data, as displayed in Photos",
|
||||
"{place.country_code}": "The ISO country code from the photo's reverse geolocation data",
|
||||
"{place.name.country}": "Country name from the photo's reverse geolocation data",
|
||||
@@ -102,6 +120,10 @@ class PhotoTemplate:
|
||||
"""
|
||||
self.photo = photo
|
||||
|
||||
# holds value of current date/time for {today.x} fields
|
||||
# gets initialized in get_template_value
|
||||
self.today = None
|
||||
|
||||
def render(self, template, none_str="_", path_sep=None):
|
||||
""" Render a filename or directory template
|
||||
|
||||
@@ -258,6 +280,10 @@ class PhotoTemplate:
|
||||
ValueError if no rule exists for field.
|
||||
"""
|
||||
|
||||
# initialize today with current date/time if needed
|
||||
if self.today is None:
|
||||
self.today = datetime.datetime.now()
|
||||
|
||||
# must be a valid keyword
|
||||
if field == "name":
|
||||
return pathlib.Path(self.photo.filename).stem
|
||||
@@ -404,6 +430,51 @@ class PhotoTemplate:
|
||||
# else:
|
||||
# return None
|
||||
|
||||
if field == "today.date":
|
||||
return DateTimeFormatter(self.today).date
|
||||
|
||||
if field == "today.year":
|
||||
return DateTimeFormatter(self.today).year
|
||||
|
||||
if field == "today.yy":
|
||||
return DateTimeFormatter(self.today).yy
|
||||
|
||||
if field == "today.mm":
|
||||
return DateTimeFormatter(self.today).mm
|
||||
|
||||
if field == "today.month":
|
||||
return DateTimeFormatter(self.today).month
|
||||
|
||||
if field == "today.mon":
|
||||
return DateTimeFormatter(self.today).mon
|
||||
|
||||
if field == "today.dd":
|
||||
return DateTimeFormatter(self.today).dd
|
||||
|
||||
if field == "today.dow":
|
||||
return DateTimeFormatter(self.today).dow
|
||||
|
||||
if field == "today.doy":
|
||||
return DateTimeFormatter(self.today).doy
|
||||
|
||||
if field == "today.hour":
|
||||
return DateTimeFormatter(self.today).hour
|
||||
|
||||
if field == "today.min":
|
||||
return DateTimeFormatter(self.today).min
|
||||
|
||||
if field == "today.sec":
|
||||
return DateTimeFormatter(self.today).sec
|
||||
|
||||
if field == "today.strftime":
|
||||
if default:
|
||||
try:
|
||||
return self.today.strftime(default)
|
||||
except:
|
||||
raise ValueError(f"Invalid strftime template: '{default}'")
|
||||
else:
|
||||
return None
|
||||
|
||||
if field == "place.name":
|
||||
return self.photo.place.name if self.photo.place else None
|
||||
|
||||
|
||||
70
tests/test_template_today.py
Normal file
70
tests/test_template_today.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
PHOTOS_DB_PLACES = (
|
||||
"./tests/Test-Places-Catalina-10_15_1.photoslibrary/database/photos.db"
|
||||
)
|
||||
|
||||
DATETIME_TODAY = datetime.datetime(2020, 6, 21, 13, 0, 0)
|
||||
""" Used to patch osxphotos.phototemplate.TODAY for testing """
|
||||
|
||||
UUID_DICT = {
|
||||
"place_dc": "128FB4C6-0B16-4E7D-9108-FB2E90DA1546",
|
||||
"1_1_2": "1EB2B765-0765-43BA-A90C-0D0580E6172C",
|
||||
"2_1_1": "D79B8D77-BFFC-460B-9312-034F2877D35B",
|
||||
"0_2_0": "6191423D-8DB8-4D4C-92BE-9BBBA308AAC4",
|
||||
"folder_album_1": "3DD2C897-F19E-4CA6-8C22-B027D5A71907",
|
||||
"folder_album_no_folder": "D79B8D77-BFFC-460B-9312-034F2877D35B",
|
||||
"mojave_album_1": "15uNd7%8RguTEgNPKHfTWw",
|
||||
}
|
||||
|
||||
TODAY_VALUES = {
|
||||
"{today.date}": "2020-06-21",
|
||||
"{today.year}": "2020",
|
||||
"{today.yy}": "20",
|
||||
"{today.mm}": "06",
|
||||
"{today.month}": "June",
|
||||
"{today.mon}": "Jun",
|
||||
"{today.dd}": "21",
|
||||
"{today.dow}": "Sunday",
|
||||
"{today.doy}": "173",
|
||||
"{today.hour}": "13",
|
||||
"{today.min}": "00",
|
||||
"{today.sec}": "00",
|
||||
}
|
||||
|
||||
|
||||
def test_subst_today():
|
||||
""" Test that substitutions are correct for {today.x}"""
|
||||
import locale
|
||||
import osxphotos
|
||||
|
||||
locale.setlocale(locale.LC_ALL, "en_US")
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
|
||||
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
|
||||
|
||||
photo_template = osxphotos.PhotoTemplate(photo)
|
||||
photo_template.today = DATETIME_TODAY
|
||||
|
||||
for template in TODAY_VALUES:
|
||||
rendered, _ = photo_template.render(template)
|
||||
assert rendered[0] == TODAY_VALUES[template]
|
||||
|
||||
|
||||
def test_subst_strftime_today():
|
||||
""" Test that strftime substitutions are correct for {today.strftime}"""
|
||||
import locale
|
||||
import osxphotos
|
||||
|
||||
locale.setlocale(locale.LC_ALL, "en_US")
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_PLACES)
|
||||
photo = photosdb.photos(uuid=[UUID_DICT["place_dc"]])[0]
|
||||
|
||||
photo_template = osxphotos.PhotoTemplate(photo)
|
||||
photo_template.today = DATETIME_TODAY
|
||||
rendered, unmatched = photo_template.render("{today.strftime,%Y-%m-%d-%H%M%S}")
|
||||
assert rendered[0] == "2020-06-21-130000"
|
||||
|
||||
rendered, unmatched = photo.render_template("{today.strftime}")
|
||||
assert rendered[0] == "_"
|
||||
Reference in New Issue
Block a user