refactored template code to fix #213

This commit is contained in:
Rhet Turnbull
2020-10-17 23:21:08 -07:00
parent 1332e7b45a
commit ff0fdffa9b
47 changed files with 527 additions and 248 deletions

View File

@@ -7,7 +7,7 @@
<key>hostuuid</key>
<string>9575E48B-8D5F-5654-ABAC-4431B1167324</string>
<key>pid</key>
<integer>2964</integer>
<integer>40469</integer>
<key>processname</key>
<string>photolibraryd</string>
<key>uid</key>

View File

@@ -3,24 +3,24 @@
<plist version="1.0">
<dict>
<key>BackgroundHighlightCollection</key>
<date>2020-06-24T04:02:13Z</date>
<date>2020-10-17T23:45:25Z</date>
<key>BackgroundHighlightEnrichment</key>
<date>2020-06-24T04:02:12Z</date>
<date>2020-10-17T23:45:25Z</date>
<key>BackgroundJobAssetRevGeocode</key>
<date>2020-06-24T04:02:13Z</date>
<date>2020-10-17T23:45:25Z</date>
<key>BackgroundJobSearch</key>
<date>2020-06-24T04:02:13Z</date>
<date>2020-10-17T23:45:25Z</date>
<key>BackgroundPeopleSuggestion</key>
<date>2020-06-24T04:02:12Z</date>
<date>2020-10-17T23:45:25Z</date>
<key>BackgroundUserBehaviorProcessor</key>
<date>2020-06-24T04:02:13Z</date>
<date>2020-10-17T23:45:25Z</date>
<key>PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey</key>
<date>2020-05-30T02:16:06Z</date>
<date>2020-10-17T23:45:33Z</date>
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
<date>2020-05-29T04:31:37Z</date>
<date>2020-10-17T23:45:24Z</date>
<key>PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate</key>
<date>2020-06-24T04:02:13Z</date>
<date>2020-10-17T23:45:26Z</date>
<key>SiriPortraitDonation</key>
<date>2020-06-24T04:02:13Z</date>
<date>2020-10-17T23:45:25Z</date>
</dict>
</plist>

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>NumberOfFacesProcessedOnLastRun</key>
<integer>7</integer>
<integer>11</integer>
<key>ProcessedInQuiescentState</key>
<true/>
<key>SuggestedMeIdentifier</key>

View File

@@ -3,8 +3,8 @@
<plist version="1.0">
<dict>
<key>FaceIDModelLastGenerationKey</key>
<date>2020-05-29T03:44:04Z</date>
<date>2020-10-17T23:45:32Z</date>
<key>LastContactClassificationKey</key>
<date>2020-05-29T04:31:40Z</date>
<date>2020-10-17T23:45:54Z</date>
</dict>
</plist>

View File

@@ -24,6 +24,7 @@ KEYWORDS = [
"St. James's Park",
"UK",
"United Kingdom",
"foo/bar",
]
# Photos 5 includes blank person for detected face
PERSONS = ["Katie", "Suzy", "Maria", _UNKNOWN_PERSON]
@@ -47,6 +48,7 @@ KEYWORDS_DICT = {
"St. James's Park": 1,
"UK": 1,
"United Kingdom": 1,
"foo/bar": 1,
}
PERSONS_DICT = {"Katie": 3, "Suzy": 2, "Maria": 2, _UNKNOWN_PERSON: 1}
ALBUM_DICT = {

View File

@@ -229,8 +229,23 @@ CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES_PATHSEP = [
"2019-10:11 Paris Clermont/IMG_4547.jpg",
]
CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES_KEYWORD_PATHSEP = [
"foo:bar/foo:bar_IMG_3092.heic"
]
CLI_EXPORTED_FILENAME_TEMPLATE_LONG_DESCRIPTION = [
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "
"Aenean commodo ligula eget dolor. Aenean massa. "
"Cum sociis natoque penatibus et magnis dis parturient montes, "
"nascetur ridiculus mus. Donec quam felis, ultricies nec, "
"pellentesque eu, pretium q.tif"
]
CLI_EXPORT_UUID = "D79B8D77-BFFC-460B-9312-034F2877D35B"
CLI_EXPORT_UUID_STATUE = "3DD2C897-F19E-4CA6-8C22-B027D5A71907"
CLI_EXPORT_UUID_KEYWORD_PATHSEP = "7783E8E6-9CAC-40F3-BE22-81FB7051C266"
CLI_EXPORT_UUID_LONG_DESCRIPTION = "8846E3E6-8AC8-4857-8448-E3D025784410"
CLI_EXPORT_UUID_FILENAME = "Pumkins2.jpg"
@@ -568,10 +583,7 @@ def test_query_uuid_from_file_1():
# build list of uuids we got from the output JSON
json_got = json.loads(result.output)
uuid_got = []
for photo in json_got:
uuid_got.append(photo["uuid"])
uuid_got = [photo["uuid"] for photo in json_got]
assert sorted(UUID_EXPECTED_FROM_FILE) == sorted(uuid_got)
@@ -601,10 +613,7 @@ def test_query_uuid_from_file_2():
# build list of uuids we got from the output JSON
json_got = json.loads(result.output)
uuid_got = []
for photo in json_got:
uuid_got.append(photo["uuid"])
uuid_got = [photo["uuid"] for photo in json_got]
uuid_expected = UUID_EXPECTED_FROM_FILE.copy()
uuid_expected.append(UUID_NOT_FROM_FILE)
assert sorted(uuid_expected) == sorted(uuid_got)
@@ -1965,13 +1974,12 @@ def test_export_filename_template_2():
assert sorted(files) == sorted(CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES2)
def test_export_filename_template_pathsep_in_name():
def test_export_filename_template_pathsep_in_name_1():
""" export photos using filename template with folder_album and "/" in album name """
import locale
import os
import os.path
import pathlib
import osxphotos
from osxphotos.__main__ import export
locale.setlocale(locale.LC_ALL, "en_US")
@@ -1998,6 +2006,71 @@ def test_export_filename_template_pathsep_in_name():
assert pathlib.Path(fname).is_file()
def test_export_filename_template_pathsep_in_name_2():
""" export photos using filename template with keyword and "/" in keyword """
import locale
import os
import os.path
import pathlib
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, PHOTOS_DB_15_6),
".",
"-V",
"--directory",
"{keyword}",
"--filename",
"{keyword}_{original_name}",
"--uuid",
CLI_EXPORT_UUID_KEYWORD_PATHSEP,
],
)
assert result.exit_code == 0
for fname in CLI_EXPORTED_FILENAME_TEMPLATE_FILENAMES_KEYWORD_PATHSEP:
assert pathlib.Path(fname).is_file()
def test_export_filename_template_long_description():
""" export photos using filename template with description that exceeds max length """
import locale
import os
import os.path
import pathlib
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, PHOTOS_DB_15_6),
".",
"-V",
"--filename",
"{descr}",
"--uuid",
CLI_EXPORT_UUID_LONG_DESCRIPTION,
],
)
assert result.exit_code == 0
for fname in CLI_EXPORTED_FILENAME_TEMPLATE_LONG_DESCRIPTION:
assert pathlib.Path(fname).is_file()
def test_export_filename_template_3():
""" test --filename with invalid template """
import glob
@@ -2489,9 +2562,8 @@ def test_export_sidecar_keyword_template():
"EXIF:ModifyDate": "2020:04:11 12:34:16"}]"""
)[0]
json_file = open("Pumkins2.jpg.json", "r")
json_got = json.load(json_file)[0]
json_file.close()
with open("Pumkins2.jpg.json", "r") as json_file:
json_got = json.load(json_file)[0]
# some gymnastics to account for different sort order in different pythons
for k, v in json_got.items():

117
tests/test_path_utils.py Normal file
View File

@@ -0,0 +1,117 @@
""" Test path_utils.py """
def test_sanitize_filename():
from osxphotos.path_utils import sanitize_filename
from osxphotos._constants import MAX_FILENAME_LEN
# basic sanitize
filenames = {
"Foobar.txt": "Foobar.txt",
"Foo:bar.txt": "Foo:bar.txt",
"Foo/bar.txt": "Foo:bar.txt",
"Foo//.txt": "Foo::.txt",
}
for filename, sanitized in filenames.items():
filename = sanitize_filename(filename)
assert filename == sanitized
# sanitize with replacement
filenames = {
"Foobar.txt": "Foobar.txt",
"Foo:bar.txt": "Foo:bar.txt",
"Foo/bar.txt": "Foo_bar.txt",
"Foo//.txt": "Foo__.txt",
}
for filename, sanitized in filenames.items():
filename = sanitize_filename(filename, replacement="_")
assert filename == sanitized
# filename too long
filename = "foo" + "x" * 512
new_filename = sanitize_filename(filename)
assert len(new_filename) == MAX_FILENAME_LEN
assert new_filename == "foo" + "x" * 252
# filename too long with extension
filename = "x" * 512 + ".jpeg"
new_filename = sanitize_filename(filename)
assert len(new_filename) == MAX_FILENAME_LEN
assert new_filename == "x" * 250 + ".jpeg"
# more than one extension
filename = "foo.bar" + "x" * 255 + ".foo.bar.jpeg"
new_filename = sanitize_filename(filename)
assert len(new_filename) == MAX_FILENAME_LEN
assert new_filename == "foo.bar" + "x" * 243 + ".jpeg"
# shorter than drop count
filename = "foo." + "x" * 256
new_filename = sanitize_filename(filename)
assert len(new_filename) == MAX_FILENAME_LEN
assert new_filename == "foo." + "x" * 251
def test_sanitize_dirname():
from osxphotos.path_utils import sanitize_dirname
from osxphotos._constants import MAX_DIRNAME_LEN
# basic sanitize
dirnames = {
"Foobar": "Foobar",
"Foo:bar": "Foo:bar",
"Foo/bar": "Foo:bar",
"Foo//": "Foo::",
}
for dirname, sanitized in dirnames.items():
dirname = sanitize_dirname(dirname)
assert dirname == sanitized
# sanitize with replacement
dirnames = {
"Foobar": "Foobar",
"Foo:bar": "Foo:bar",
"Foo/bar": "Foo_bar",
"Foo//": "Foo__",
}
for dirname, sanitized in dirnames.items():
dirname = sanitize_dirname(dirname, replacement="_")
assert dirname == sanitized
# dirname too long
dirname = "foo" + "x" * 512 + "bar"
new_dirname = sanitize_dirname(dirname)
assert len(new_dirname) == MAX_DIRNAME_LEN
assert new_dirname == "foo" + "x" * 252
def test_sanitize_pathpart():
from osxphotos.path_utils import sanitize_pathpart
from osxphotos._constants import MAX_DIRNAME_LEN
# basic sanitize
dirnames = {
"Foobar": "Foobar",
"Foo:bar": "Foo:bar",
"Foo/bar": "Foo:bar",
"Foo//": "Foo::",
}
for dirname, sanitized in dirnames.items():
dirname = sanitize_pathpart(dirname)
assert dirname == sanitized
# sanitize with replacement
dirnames = {
"Foobar": "Foobar",
"Foo:bar": "Foo:bar",
"Foo/bar": "Foo_bar",
"Foo//": "Foo__",
}
for dirname, sanitized in dirnames.items():
dirname = sanitize_pathpart(dirname, replacement="_")
assert dirname == sanitized
# dirname too long
dirname = "foo" + "x" * 512 + "bar"
new_dirname = sanitize_pathpart(dirname)
assert len(new_dirname) == MAX_DIRNAME_LEN
assert new_dirname == "foo" + "x" * 252