Initial implementation of exiftool command, #691 (#696)

* Initial implementation of exiftool command, #691

* updated comment [skip ci]
This commit is contained in:
Rhet Turnbull
2022-05-20 22:12:48 -07:00
committed by GitHub
parent 6d5af5c5e8
commit 79e4b333e9
15 changed files with 763 additions and 41 deletions

View File

@@ -80,19 +80,19 @@ def generate_sidecars(dbname, uuid_dict):
# generate JSON files
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json")
json_ = exporter._exiftool_json_sidecar()
json_ = exporter.exiftool_json_sidecar()
with open(sidecar, "w") as file:
file.write(json_)
# no tag groups
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_no_tag_groups.json")
json_ = exporter._exiftool_json_sidecar(tag_groups=False)
json_ = exporter.exiftool_json_sidecar(tag_groups=False)
with open(sidecar, "w") as file:
file.write(json_)
# ignore_date_modified
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_ignore_date_modified.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(ignore_date_modified=True)
)
with open(sidecar, "w") as file:
@@ -100,7 +100,7 @@ def generate_sidecars(dbname, uuid_dict):
# keyword_template
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_keyword_template.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(keyword_template=["{folder_album}"])
)
with open(sidecar, "w") as file:
@@ -108,7 +108,7 @@ def generate_sidecars(dbname, uuid_dict):
# persons_as_keywords
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_persons_as_keywords.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(use_persons_as_keywords=True)
)
with open(sidecar, "w") as file:
@@ -116,7 +116,7 @@ def generate_sidecars(dbname, uuid_dict):
# albums_as_keywords
sidecar = str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_albums_as_keywords.json")
json_ = exporter._exiftool_json_sidecar(
json_ = exporter.exiftool_json_sidecar(
ExportOptions(use_albums_as_keywords=True)
)
with open(sidecar, "w") as file:

258
tests/test_cli_exiftool.py Normal file
View File

@@ -0,0 +1,258 @@
"""Tests for `osxphotos exiftool` command."""
import glob
import json
import os
import pytest
from click.testing import CliRunner
from osxphotos.cli.exiftool_cli import exiftool
from osxphotos.cli.export import export
from osxphotos.exiftool import ExifTool, get_exiftool_path
from .test_cli import CLI_EXIFTOOL, PHOTOS_DB_15_7
# determine if exiftool installed so exiftool tests can be skipped
try:
exiftool_path = get_exiftool_path()
except FileNotFoundError:
exiftool_path = None
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool():
"""Test osxphotos exiftool"""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
uuid_option = []
for uuid in CLI_EXIFTOOL:
uuid_option.extend(("--uuid", uuid))
# first, export without --exiftool
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
*uuid_option,
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert sorted(files) == sorted(
[CLI_EXIFTOOL[uuid]["File:FileName"] for uuid in CLI_EXIFTOOL]
)
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
["--db", os.path.join(cwd, PHOTOS_DB_15_7), "-V", "--db-config", temp_dir],
)
assert result.exit_code == 0
exif = ExifTool(CLI_EXIFTOOL[uuid]["File:FileName"]).asdict()
for key in CLI_EXIFTOOL[uuid]:
if type(exif[key]) == list:
assert sorted(exif[key]) == sorted(CLI_EXIFTOOL[uuid][key])
else:
assert exif[key] == CLI_EXIFTOOL[uuid][key]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
"--exiftool",
"--update",
*uuid_option,
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: {len(CLI_EXIFTOOL)}" in result.output
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool_album_keyword():
"""Test osxphotos exiftool with --album-template."""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
# first, export without --exiftool
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
"--album",
"Pumpkin Farm",
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert len(files) == 3
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
"-V",
"--db-config",
"--report",
"exiftool.json",
"--album-keyword",
temp_dir,
],
)
assert result.exit_code == 0
report = json.load(open("exiftool.json", "r"))
assert len(report) == 3
# verify exiftool metadata was updated
for file in report:
exif = ExifTool(file["filename"]).asdict()
assert "Pumpkin Farm" in exif["IPTC:Keywords"]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
"--exiftool",
"--update",
"--album",
"Pumpkin Farm",
"--album-keyword",
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: 3" in result.output
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool_keyword_template():
"""Test osxphotos exiftool with --keyword-template."""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
uuid_option = []
for uuid in CLI_EXIFTOOL:
uuid_option.extend(("--uuid", uuid))
# first, export without --exiftool
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
*uuid_option,
],
)
assert result.exit_code == 0
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
[
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
"-V",
"--db-config",
"--keyword-template",
"FOO",
temp_dir,
"--report",
"exiftool.json",
],
)
assert result.exit_code == 0
report = json.load(open("exiftool.json", "r"))
for file in report:
exif = ExifTool(file["filename"]).asdict()
assert "FOO" in exif["IPTC:Keywords"]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
"--exiftool",
"--keyword-template",
"FOO",
"--update",
*uuid_option,
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: {len(CLI_EXIFTOOL)}" in result.output
@pytest.mark.skipif(exiftool_path is None, reason="exiftool not installed")
def test_export_exiftool_load_config():
"""Test osxphotos exiftool with --load-config"""
runner = CliRunner()
cwd = os.getcwd()
with runner.isolated_filesystem() as temp_dir:
uuid_option = []
for uuid in CLI_EXIFTOOL:
uuid_option.extend(("--uuid", uuid))
# first, export without --exiftool
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
"--save-config",
"config.toml",
*uuid_option,
],
)
assert result.exit_code == 0
# now, run exiftool command to update exiftool metadata
result = runner.invoke(
exiftool,
["-V", "--load-config", "config.toml", temp_dir],
)
assert result.exit_code == 0
exif = ExifTool(CLI_EXIFTOOL[uuid]["File:FileName"]).asdict()
for key in CLI_EXIFTOOL[uuid]:
if type(exif[key]) == list:
assert sorted(exif[key]) == sorted(CLI_EXIFTOOL[uuid][key])
else:
assert exif[key] == CLI_EXIFTOOL[uuid][key]
# now, export with --exiftool --update, no files should be updated
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_15_7),
".",
"-V",
"--exiftool",
"--update",
*uuid_option,
],
)
assert result.exit_code == 0
assert f"exported: 0, updated: 0, skipped: {len(CLI_EXIFTOOL)}" in result.output

View File

@@ -1,6 +1,8 @@
""" test ConfigOptions class """
import pathlib
from io import StringIO
import pytest
import toml
@@ -43,6 +45,15 @@ def test_write_to_file_load_from_file(tmpdir):
assert cfg2.bar
def test_load_from_str(tmpdir):
cfg = ConfigOptions("test", VARS)
cfg.bar = True
cfg_str = cfg.write_to_str()
cfg2 = ConfigOptions("test", VARS).load_from_str(cfg_str)
assert cfg2.foo == "bar"
assert cfg2.bar
def test_load_from_file_error(tmpdir):
cfg_file = pathlib.Path(str(tmpdir)) / "test.toml"
cfg = ConfigOptions("test", VARS)

View File

@@ -404,7 +404,7 @@ def test_exiftool_json_sidecar(photosdb):
with open(str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json"), "r") as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar()
json_got = PhotoExporter(photo).exiftool_json_sidecar()
json_got = json.loads(json_got)[0]
assert json_got == json_expected
@@ -420,7 +420,7 @@ def test_exiftool_json_sidecar_ignore_date_modified(photosdb):
) as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(ignore_date_modified=True)
)
json_got = json.loads(json_got)[0]
@@ -453,7 +453,7 @@ def test_exiftool_json_sidecar_keyword_template_long(capsys, photosdb):
long_str = "x" * (_MAX_IPTC_KEYWORD_LEN + 1)
photos[0]._verbose = print
json_got = PhotoExporter(photos[0])._exiftool_json_sidecar(
json_got = PhotoExporter(photos[0]).exiftool_json_sidecar(
ExportOptions(keyword_template=[long_str])
)
json_got = json.loads(json_got)[0]
@@ -479,7 +479,7 @@ def test_exiftool_json_sidecar_keyword_template(photosdb):
str(pathlib.Path(SIDECAR_DIR) / f"{uuid}_keyword_template.json"), "r"
) as fp:
json_expected = json.load(fp)
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(keyword_template=["{folder_album}"])
)
json_got = json.loads(json_got)
@@ -497,7 +497,7 @@ def test_exiftool_json_sidecar_use_persons_keyword(photosdb):
) as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(use_persons_as_keywords=True)
)
json_got = json.loads(json_got)[0]
@@ -515,7 +515,7 @@ def test_exiftool_json_sidecar_use_albums_keywords(photosdb):
) as fp:
json_expected = json.load(fp)
json_got = PhotoExporter(photo)._exiftool_json_sidecar(
json_got = PhotoExporter(photo).exiftool_json_sidecar(
ExportOptions(use_albums_as_keywords=True)
)
json_got = json.loads(json_got)
@@ -530,7 +530,7 @@ def test_exiftool_sidecar(photosdb):
with open(pathlib.Path(SIDECAR_DIR) / f"{uuid}_no_tag_groups.json", "r") as fp:
json_expected = fp.read()
json_got = PhotoExporter(photo)._exiftool_json_sidecar(tag_groups=False)
json_got = PhotoExporter(photo).exiftool_json_sidecar(tag_groups=False)
assert json_got == json_expected

View File

@@ -337,7 +337,7 @@ def test_exiftool_json_sidecar(photosdb):
with open(str(pathlib.Path(SIDECAR_DIR) / f"{uuid}.json"), "r") as fp:
json_expected = json.load(fp)[0]
json_got = PhotoExporter(photo)._exiftool_json_sidecar()
json_got = PhotoExporter(photo).exiftool_json_sidecar()
json_got = json.loads(json_got)[0]
assert json_got == json_expected