* Working on custom sidecar, #1123 * Working on custom sidecar, #1123 * Added custom sidecar example * Added WRITE_SKIPPED argument for --sidecar-template * Updated report writer for user sidecars * Added noqa to long lines in report writer * Initial tests for --sidecar-template * Initial tests for --sidecar-template * Initial tests for --sidecar-template * Completed tests for --sidecar-template * Added json example for --sidecar-template * Added json example for --sidecar-template
404 lines
13 KiB
Python
404 lines
13 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_DATA = """
|
|
|
|
|
|
Sidecar: wedding.jpg.txt
|
|
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
|