osxphotos/tests/test_cli_export_sidecar_template.py
Rhet Turnbull 3999e54f6c
Feature custom sidecar 1123 cache (#1131)
* Added caching to Template, fixed typos

* Added additional sidecar tests
2023-07-25 06:44:39 -07:00

479 lines
15 KiB
Python

"""Test export with --sidecar-template (#1123)"""
import csv
import json
import os
import pathlib
import sqlite3
import pytest
from click.testing import CliRunner
from osxphotos.cli import export
PHOTOS_DB = "./tests/Test-10.15.7.photoslibrary"
PHOTO_UUID = "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51" # wedding.jpg
SIDECAR_FILENAME = "wedding.jpg.txt"
SIDECAR_FILENAME_2 = "wedding.jpg.sidecar"
SIDECAR_DATA = """
Sidecar: wedding.jpg.txt
Photo: wedding.jpg
UUID: E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51
Rating: ★★★★★
"""
SIDECAR_DATA_2 = """
Sidecar: wedding.jpg.sidecar
Photo: wedding.jpg
UUID: E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51
Rating: ★★★★★
"""
def test_export_sidecar_template_1():
"""test basic export with --sidecar-template"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
assert sidecar_data == SIDECAR_DATA
def test_export_sidecar_template_strip_whitespace():
"""test basic export with --sidecar-template and STRIP_WHITESPACE = True"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"yes",
"no",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
sidecar_expected = (
"\n".join(line.strip() for line in SIDECAR_DATA.splitlines()) + "\n"
)
assert sidecar_data == sidecar_expected
def test_export_sidecar_template_strip_lines():
"""test basic export with --sidecar-template and STRIP_LINES = True"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"yes",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
sidecar_expected = "\n".join(
line for line in SIDECAR_DATA.splitlines() if line.strip()
)
assert sidecar_data == sidecar_expected
def test_export_sidecar_template_strip_lines_strip_whitespace():
"""test basic export with --sidecar-template and STRIP_LINES = True and STRIP_WHITESPACE = True"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"yes",
"yes",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
sidecar_expected = "\n".join(
line.strip() for line in SIDECAR_DATA.splitlines() if line.strip()
)
assert sidecar_data == sidecar_expected
def test_export_sidecar_template_update_no():
"""test basic export with --sidecar-template and WRITE_SKIPPED = False, also test --cleanup"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
],
)
# run export again, should not update sidecar
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
"--update",
"--cleanup",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
sidecar_expected = "\n".join(
line.strip() for line in SIDECAR_DATA.splitlines() if line.strip()
)
assert sidecar_data == SIDECAR_DATA
assert "Skipping existing sidecar file" in result.output
assert "Deleted: 0 files, 0 directories" in result.output
def test_export_sidecar_template_update_ues():
"""test basic export with --sidecar-template and WRITE_SKIPPED = True, also test --cleanup"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
],
)
# run export again, should not update sidecar
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"yes",
"no",
"no",
"--update",
"--cleanup",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
sidecar_expected = "\n".join(
line.strip() for line in SIDECAR_DATA.splitlines() if line.strip()
)
assert sidecar_data == SIDECAR_DATA
assert "Skipping existing sidecar file" not in result.output
assert "Writing sidecar file" in result.output
assert "Deleted: 0 files, 0 directories" in result.output
def test_export_sidecar_template_report_csv():
"""test basic export with --sidecar-template --report to csv"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
"--report",
"report.csv",
],
)
assert result.exit_code == 0
# verify report output
report_file = pathlib.Path("report.csv")
assert report_file.exists()
csvreader = csv.DictReader(report_file.open())
assert "sidecar_user" in csvreader.fieldnames
found_sidecar = 0
for row in csvreader: # sourcery skip: no-loop-in-tests
# sidecar ends with .txt so verify report has sidecar_user = 1
if row["filename"].endswith(
".txt"
): # sourcery skip: no-conditionals-in-tests
assert str(row["sidecar_user"]) == "1"
found_sidecar += 1
else:
assert str(row["sidecar_user"]) == "0"
assert found_sidecar
def test_export_sidecar_template_report_json():
"""test basic export with --sidecar-template --report to json"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
"--report",
"report.json",
],
)
assert result.exit_code == 0
# read the json report output and verify it is correct
report_file = pathlib.Path("report.json")
assert report_file.exists()
report_data = json.loads(report_file.read_text())
assert "sidecar_user" in report_data[0]
found_sidecar = 0
for row in report_data: # sourcery skip: no-loop-in-tests
# sidecar ends with .txt so verify report has sidecar_user = 1
if row["filename"].endswith(
".txt"
): # sourcery skip: no-conditionals-in-tests
assert row["sidecar_user"]
found_sidecar += 1
else:
assert not row["sidecar_user"]
assert found_sidecar
def test_export_sidecar_template_report_db():
"""test basic export with --sidecar-template --report to sqlite db"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
"--report",
"report.db",
],
)
assert result.exit_code == 0
# read the report sqlite db and verify it is correct
report_file = pathlib.Path("report.db")
assert report_file.exists()
conn = sqlite3.connect(report_file)
c = conn.cursor()
c.execute("SELECT filename, sidecar_user FROM report")
rows = c.fetchall()
found_sidecar = 0
for row in rows: # sourcery skip: no-loop-in-tests
# sidecar ends with .txt so verify report has sidecar_user = 1
if row[0].endswith(".txt"): # sourcery skip: no-conditionals-in-tests
assert row[1] == 1
found_sidecar += 1
else:
assert row[1] == 0
assert found_sidecar
def test_export_sidecar_template_multiple():
"""test export with multiple --sidecar-template options"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--uuid",
PHOTO_UUID,
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.sidecar",
"no",
"no",
"no",
],
)
assert result.exit_code == 0
sidecar_file = pathlib.Path(SIDECAR_FILENAME)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
assert sidecar_data == SIDECAR_DATA
sidecar_file = pathlib.Path(SIDECAR_FILENAME_2)
assert sidecar_file.exists()
sidecar_data = sidecar_file.read_text()
assert sidecar_data == SIDECAR_DATA_2
def test_export_sidecar_template_full_library():
"""test export with --sidecar-template option against full library (repeated calls to generate sidecar files))"""
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
"--library",
os.path.join(cwd, PHOTOS_DB),
".",
"-V",
"--sidecar-template",
os.path.join(cwd, "tests", "custom_sidecar.mako"),
"{filepath}.txt",
"no",
"no",
"no",
],
)
assert result.exit_code == 0