Added --report option to CLI, implements #253
This commit is contained in:
@@ -373,6 +373,8 @@ Options:
|
|||||||
work with iTerm2 (use with Terminal.app).
|
work with iTerm2 (use with Terminal.app).
|
||||||
This is faster and more reliable than the
|
This is faster and more reliable than the
|
||||||
default AppleScript interface.
|
default AppleScript interface.
|
||||||
|
--report REPORTNAME.CSV Write a CSV formatted report of all files
|
||||||
|
that were exported.
|
||||||
-h, --help Show this message and exit.
|
-h, --help Show this message and exit.
|
||||||
|
|
||||||
** Export **
|
** Export **
|
||||||
|
|||||||
@@ -1413,6 +1413,12 @@ def query(
|
|||||||
"Highly experimental alpha feature; does not work with iTerm2 (use with Terminal.app). "
|
"Highly experimental alpha feature; does not work with iTerm2 (use with Terminal.app). "
|
||||||
"This is faster and more reliable than the default AppleScript interface.",
|
"This is faster and more reliable than the default AppleScript interface.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--report",
|
||||||
|
metavar="REPORTNAME.CSV",
|
||||||
|
help="Write a CSV formatted report of all files that were exported.",
|
||||||
|
type=click.Path(),
|
||||||
|
)
|
||||||
@DB_ARGUMENT
|
@DB_ARGUMENT
|
||||||
@click.argument("dest", nargs=1, type=click.Path(exists=True))
|
@click.argument("dest", nargs=1, type=click.Path(exists=True))
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
@@ -1505,6 +1511,7 @@ def export(
|
|||||||
deleted_only,
|
deleted_only,
|
||||||
use_photos_export,
|
use_photos_export,
|
||||||
use_photokit,
|
use_photokit,
|
||||||
|
report,
|
||||||
):
|
):
|
||||||
""" Export photos from the Photos database.
|
""" Export photos from the Photos database.
|
||||||
Export path DEST is required.
|
Export path DEST is required.
|
||||||
@@ -1522,7 +1529,12 @@ def export(
|
|||||||
VERBOSE = bool(verbose_)
|
VERBOSE = bool(verbose_)
|
||||||
|
|
||||||
if not os.path.isdir(dest):
|
if not os.path.isdir(dest):
|
||||||
sys.exit(f"DEST {dest} must be valid path")
|
click.echo(f"DEST {dest} must be valid path", err=True)
|
||||||
|
raise click.Abort()
|
||||||
|
|
||||||
|
if report and os.path.isdir(report):
|
||||||
|
click.echo(f"report is a directory, must be file name", err=True)
|
||||||
|
raise click.Abort()
|
||||||
|
|
||||||
# sanity check input args
|
# sanity check input args
|
||||||
exclusive = [
|
exclusive = [
|
||||||
@@ -1729,8 +1741,11 @@ def export(
|
|||||||
results_skipped = []
|
results_skipped = []
|
||||||
results_exif_updated = []
|
results_exif_updated = []
|
||||||
results_touched = []
|
results_touched = []
|
||||||
results_sidecar_json = []
|
results_converted = []
|
||||||
results_sidecar_xmp = []
|
results_sidecar_json_written = []
|
||||||
|
results_sidecar_json_skipped = []
|
||||||
|
results_sidecar_xmp_written = []
|
||||||
|
results_sidecar_xmp_skipped = []
|
||||||
if verbose_:
|
if verbose_:
|
||||||
for p in photos:
|
for p in photos:
|
||||||
results = export_photo(
|
results = export_photo(
|
||||||
@@ -1774,8 +1789,11 @@ def export(
|
|||||||
results_skipped.extend(results.skipped)
|
results_skipped.extend(results.skipped)
|
||||||
results_exif_updated.extend(results.exif_updated)
|
results_exif_updated.extend(results.exif_updated)
|
||||||
results_touched.extend(results.touched)
|
results_touched.extend(results.touched)
|
||||||
results_sidecar_json.extend(results.sidecar_json)
|
results_converted.extend(results.converted_to_jpeg)
|
||||||
results_sidecar_xmp.extend(results.sidecar_xmp)
|
results_sidecar_json_written.extend(results.sidecar_json_written)
|
||||||
|
results_sidecar_json_skipped.extend(results.sidecar_json_skipped)
|
||||||
|
results_sidecar_xmp_written.extend(results.sidecar_xmp_written)
|
||||||
|
results_sidecar_xmp_skipped.extend(results.sidecar_xmp_skipped)
|
||||||
|
|
||||||
# if convert_to_jpeg and p.isphoto and p.uti != "public.jpeg":
|
# if convert_to_jpeg and p.isphoto and p.uti != "public.jpeg":
|
||||||
# for photo_file in set(
|
# for photo_file in set(
|
||||||
@@ -1828,8 +1846,11 @@ def export(
|
|||||||
results_skipped.extend(results.skipped)
|
results_skipped.extend(results.skipped)
|
||||||
results_exif_updated.extend(results.exif_updated)
|
results_exif_updated.extend(results.exif_updated)
|
||||||
results_touched.extend(results.touched)
|
results_touched.extend(results.touched)
|
||||||
results_sidecar_json.extend(results.sidecar_json)
|
results_converted.extend(results.converted_to_jpeg)
|
||||||
results_sidecar_xmp.extend(results.sidecar_xmp)
|
results_sidecar_json_written.extend(results.sidecar_json_written)
|
||||||
|
results_sidecar_json_skipped.extend(results.sidecar_json_skipped)
|
||||||
|
results_sidecar_xmp_written.extend(results.sidecar_xmp_written)
|
||||||
|
results_sidecar_xmp_skipped.extend(results.sidecar_xmp_skipped)
|
||||||
|
|
||||||
stop_time = time.perf_counter()
|
stop_time = time.perf_counter()
|
||||||
# print summary results
|
# print summary results
|
||||||
@@ -1839,9 +1860,27 @@ def export(
|
|||||||
# print(f"results_skipped: {results_skipped}")
|
# print(f"results_skipped: {results_skipped}")
|
||||||
# print(f"results_exif_updated: {results_exif_updated}")
|
# print(f"results_exif_updated: {results_exif_updated}")
|
||||||
# print(f"results_touched: {results_touched}")
|
# print(f"results_touched: {results_touched}")
|
||||||
|
# print(f"results_converted: {results_converted}")
|
||||||
# print(f"results_sidecar_json: {results_sidecar_json}")
|
# print(f"results_sidecar_json: {results_sidecar_json}")
|
||||||
# print(f"results_sidecar_xmp: {results_sidecar_xmp}")
|
# print(f"results_sidecar_xmp: {results_sidecar_xmp}")
|
||||||
|
|
||||||
|
if report:
|
||||||
|
verbose(f"Writing export report to {report}")
|
||||||
|
write_export_report(
|
||||||
|
report,
|
||||||
|
results_exported=results_exported,
|
||||||
|
results_new=results_new,
|
||||||
|
results_updated=results_updated,
|
||||||
|
results_skipped=results_skipped,
|
||||||
|
results_exif_updated=results_exif_updated,
|
||||||
|
results_touched=results_touched,
|
||||||
|
results_converted=results_converted,
|
||||||
|
results_sidecar_json_written=results_sidecar_json_written,
|
||||||
|
results_sidecar_json_skipped=results_sidecar_json_skipped,
|
||||||
|
results_sidecar_xmp_written=results_sidecar_xmp_written,
|
||||||
|
results_sidecar_xmp_skipped=results_sidecar_xmp_skipped,
|
||||||
|
)
|
||||||
|
|
||||||
if update:
|
if update:
|
||||||
photo_str_new = "photos" if len(results_new) != 1 else "photo"
|
photo_str_new = "photos" if len(results_new) != 1 else "photo"
|
||||||
photo_str_updated = "photos" if len(results_updated) != 1 else "photo"
|
photo_str_updated = "photos" if len(results_updated) != 1 else "photo"
|
||||||
@@ -2391,19 +2430,19 @@ def export_photo(
|
|||||||
if photo.ismissing:
|
if photo.ismissing:
|
||||||
space = " " if not verbose_ else ""
|
space = " " if not verbose_ else ""
|
||||||
verbose(f"{space}Skipping missing photo {photo.original_filename}")
|
verbose(f"{space}Skipping missing photo {photo.original_filename}")
|
||||||
return ExportResults([], [], [], [], [], [], [], [])
|
return ExportResults([], [], [], [], [], [], [], [], [], [], [])
|
||||||
elif photo.path is None:
|
elif photo.path is None:
|
||||||
space = " " if not verbose_ else ""
|
space = " " if not verbose_ else ""
|
||||||
verbose(
|
verbose(
|
||||||
f"{space}WARNING: photo {photo.original_filename} ({photo.uuid}) is missing but ismissing=False, "
|
f"{space}WARNING: photo {photo.original_filename} ({photo.uuid}) is missing but ismissing=False, "
|
||||||
f"skipping {photo.original_filename}"
|
f"skipping {photo.original_filename}"
|
||||||
)
|
)
|
||||||
return ExportResults([], [], [], [], [], [], [], [])
|
return ExportResults([], [], [], [], [], [], [], [], [], [], [])
|
||||||
elif photo.ismissing and not photo.iscloudasset and not photo.incloud:
|
elif photo.ismissing and not photo.iscloudasset and not photo.incloud:
|
||||||
verbose(
|
verbose(
|
||||||
f"Skipping missing {photo.original_filename}: not iCloud asset or missing from cloud"
|
f"Skipping missing {photo.original_filename}: not iCloud asset or missing from cloud"
|
||||||
)
|
)
|
||||||
return ExportResults([], [], [], [], [], [], [], [])
|
return ExportResults([], [], [], [], [], [], [], [], [], [], [])
|
||||||
|
|
||||||
results_exported = []
|
results_exported = []
|
||||||
results_new = []
|
results_new = []
|
||||||
@@ -2411,8 +2450,11 @@ def export_photo(
|
|||||||
results_skipped = []
|
results_skipped = []
|
||||||
results_exif_updated = []
|
results_exif_updated = []
|
||||||
results_touched = []
|
results_touched = []
|
||||||
results_sidecar_json = []
|
results_converted = []
|
||||||
results_sidecar_xmp = []
|
results_sidecar_json_written = []
|
||||||
|
results_sidecar_json_skipped = []
|
||||||
|
results_sidecar_xmp_written = []
|
||||||
|
results_sidecar_xmp_skipped = []
|
||||||
|
|
||||||
export_original = not (skip_original_if_edited and photo.hasadjustments)
|
export_original = not (skip_original_if_edited and photo.hasadjustments)
|
||||||
|
|
||||||
@@ -2507,8 +2549,11 @@ def export_photo(
|
|||||||
results_skipped.extend(export_results.skipped)
|
results_skipped.extend(export_results.skipped)
|
||||||
results_exif_updated.extend(export_results.exif_updated)
|
results_exif_updated.extend(export_results.exif_updated)
|
||||||
results_touched.extend(export_results.touched)
|
results_touched.extend(export_results.touched)
|
||||||
results_sidecar_json.extend(export_results.sidecar_json)
|
results_converted.extend(export_results.converted_to_jpeg)
|
||||||
results_sidecar_xmp.extend(export_results.sidecar_xmp)
|
results_sidecar_json_written.extend(export_results.sidecar_json_written)
|
||||||
|
results_sidecar_json_skipped.extend(export_results.sidecar_json_skipped)
|
||||||
|
results_sidecar_xmp_written.extend(export_results.sidecar_xmp_written)
|
||||||
|
results_sidecar_xmp_skipped.extend(export_results.sidecar_xmp_skipped)
|
||||||
|
|
||||||
if verbose_:
|
if verbose_:
|
||||||
for exported in export_results.exported:
|
for exported in export_results.exported:
|
||||||
@@ -2580,8 +2625,19 @@ def export_photo(
|
|||||||
results_skipped.extend(export_results_edited.skipped)
|
results_skipped.extend(export_results_edited.skipped)
|
||||||
results_exif_updated.extend(export_results_edited.exif_updated)
|
results_exif_updated.extend(export_results_edited.exif_updated)
|
||||||
results_touched.extend(export_results_edited.touched)
|
results_touched.extend(export_results_edited.touched)
|
||||||
results_sidecar_json.extend(export_results_edited.sidecar_json)
|
results_converted.extend(export_results_edited.converted_to_jpeg)
|
||||||
results_sidecar_xmp.extend(export_results_edited.sidecar_xmp)
|
results_sidecar_json_written.extend(
|
||||||
|
export_results_edited.sidecar_json_written
|
||||||
|
)
|
||||||
|
results_sidecar_json_skipped.extend(
|
||||||
|
export_results_edited.sidecar_json_skipped
|
||||||
|
)
|
||||||
|
results_sidecar_xmp_written.extend(
|
||||||
|
export_results_edited.sidecar_xmp_written
|
||||||
|
)
|
||||||
|
results_sidecar_xmp_skipped.extend(
|
||||||
|
export_results_edited.sidecar_xmp_skipped
|
||||||
|
)
|
||||||
|
|
||||||
if verbose_:
|
if verbose_:
|
||||||
for exported in export_results_edited.exported:
|
for exported in export_results_edited.exported:
|
||||||
@@ -2602,8 +2658,11 @@ def export_photo(
|
|||||||
results_skipped,
|
results_skipped,
|
||||||
results_exif_updated,
|
results_exif_updated,
|
||||||
results_touched,
|
results_touched,
|
||||||
results_sidecar_json,
|
results_converted,
|
||||||
results_sidecar_xmp,
|
results_sidecar_json_written,
|
||||||
|
results_sidecar_json_skipped,
|
||||||
|
results_sidecar_xmp_written,
|
||||||
|
results_sidecar_xmp_skipped,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -2755,5 +2814,111 @@ def load_uuid_from_file(filename):
|
|||||||
return uuid
|
return uuid
|
||||||
|
|
||||||
|
|
||||||
|
def write_export_report(
|
||||||
|
report_file,
|
||||||
|
results_exported,
|
||||||
|
results_new,
|
||||||
|
results_updated,
|
||||||
|
results_skipped,
|
||||||
|
results_exif_updated,
|
||||||
|
results_touched,
|
||||||
|
results_converted,
|
||||||
|
results_sidecar_json_written,
|
||||||
|
results_sidecar_json_skipped,
|
||||||
|
results_sidecar_xmp_written,
|
||||||
|
results_sidecar_xmp_skipped,
|
||||||
|
):
|
||||||
|
|
||||||
|
""" write CSV report with results from export """
|
||||||
|
|
||||||
|
# Collect results for reporting
|
||||||
|
# TODO: pull this in a separate write_report function
|
||||||
|
all_results = {
|
||||||
|
result: {
|
||||||
|
"filename": result,
|
||||||
|
"exported": 0,
|
||||||
|
"new": 0,
|
||||||
|
"updated": 0,
|
||||||
|
"skipped": 0,
|
||||||
|
"exif_updated": 0,
|
||||||
|
"touched": 0,
|
||||||
|
"converted_to_jpeg": 0,
|
||||||
|
"sidecar_xmp": 0,
|
||||||
|
"sidecar_json": 0,
|
||||||
|
}
|
||||||
|
for result in results_exported
|
||||||
|
+ results_new
|
||||||
|
+ results_updated
|
||||||
|
+ results_skipped
|
||||||
|
+ results_exif_updated
|
||||||
|
+ results_touched
|
||||||
|
+ results_converted
|
||||||
|
+ results_sidecar_json_written
|
||||||
|
+ results_sidecar_json_skipped
|
||||||
|
+ results_sidecar_xmp_written
|
||||||
|
+ results_sidecar_xmp_skipped
|
||||||
|
}
|
||||||
|
|
||||||
|
for result in results_exported:
|
||||||
|
all_results[result]["exported"] = 1
|
||||||
|
|
||||||
|
for result in results_new:
|
||||||
|
all_results[result]["new"] = 1
|
||||||
|
|
||||||
|
for result in results_updated:
|
||||||
|
all_results[result]["updated"] = 1
|
||||||
|
|
||||||
|
for result in results_skipped:
|
||||||
|
all_results[result]["skipped"] = 1
|
||||||
|
|
||||||
|
for result in results_exif_updated:
|
||||||
|
all_results[result]["exif_updated"] = 1
|
||||||
|
|
||||||
|
for result in results_touched:
|
||||||
|
all_results[result]["touched"] = 1
|
||||||
|
|
||||||
|
for result in results_converted:
|
||||||
|
all_results[result]["converted_to_jpeg"] = 1
|
||||||
|
|
||||||
|
for result in results_sidecar_xmp_written:
|
||||||
|
all_results[result]["sidecar_xmp"] = 1
|
||||||
|
all_results[result]["exported"] = 1
|
||||||
|
|
||||||
|
for result in results_sidecar_xmp_skipped:
|
||||||
|
all_results[result]["sidecar_xmp"] = 1
|
||||||
|
all_results[result]["skipped"] = 1
|
||||||
|
|
||||||
|
for result in results_sidecar_json_written:
|
||||||
|
all_results[result]["sidecar_json"] = 1
|
||||||
|
all_results[result]["exported"] = 1
|
||||||
|
|
||||||
|
for result in results_sidecar_json_skipped:
|
||||||
|
all_results[result]["sidecar_json"] = 1
|
||||||
|
all_results[result]["skipped"] = 1
|
||||||
|
|
||||||
|
report_columns = [
|
||||||
|
"filename",
|
||||||
|
"exported",
|
||||||
|
"new",
|
||||||
|
"updated",
|
||||||
|
"skipped",
|
||||||
|
"exif_updated",
|
||||||
|
"touched",
|
||||||
|
"converted_to_jpeg",
|
||||||
|
"sidecar_xmp",
|
||||||
|
"sidecar_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(report_file, "w") as csvfile:
|
||||||
|
writer = csv.DictWriter(csvfile, fieldnames=report_columns)
|
||||||
|
writer.writeheader()
|
||||||
|
for data in [result for result in all_results.values()]:
|
||||||
|
writer.writerow(data)
|
||||||
|
except IOError:
|
||||||
|
click.echo("Could not open output file for writing", err=True)
|
||||||
|
raise click.Abort()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
cli() # pylint: disable=no-value-for-parameter
|
cli() # pylint: disable=no-value-for-parameter
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.37.0"
|
__version__ = "0.37.1"
|
||||||
|
|
||||||
|
|||||||
@@ -53,8 +53,11 @@ ExportResults = namedtuple(
|
|||||||
"skipped",
|
"skipped",
|
||||||
"exif_updated",
|
"exif_updated",
|
||||||
"touched",
|
"touched",
|
||||||
"sidecar_json",
|
"converted_to_jpeg",
|
||||||
"sidecar_xmp",
|
"sidecar_json_written",
|
||||||
|
"sidecar_json_skipped",
|
||||||
|
"sidecar_xmp_written",
|
||||||
|
"sidecar_xmp_skipped",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -425,6 +428,9 @@ def export2(
|
|||||||
# list of all files with utime touched (touch_file = True)
|
# list of all files with utime touched (touch_file = True)
|
||||||
touched_files = []
|
touched_files = []
|
||||||
|
|
||||||
|
# list of all files convereted to jpeg
|
||||||
|
converted_to_jpeg_files = []
|
||||||
|
|
||||||
# check edited and raise exception trying to export edited version of
|
# check edited and raise exception trying to export edited version of
|
||||||
# photo that hasn't been edited
|
# photo that hasn't been edited
|
||||||
if edited and not self.hasadjustments:
|
if edited and not self.hasadjustments:
|
||||||
@@ -597,6 +603,7 @@ def export2(
|
|||||||
update_updated_files = results.updated
|
update_updated_files = results.updated
|
||||||
update_skipped_files = results.skipped
|
update_skipped_files = results.skipped
|
||||||
touched_files = results.touched
|
touched_files = results.touched
|
||||||
|
converted_to_jpeg_files = results.converted_to_jpeg
|
||||||
|
|
||||||
# copy live photo associated .mov if requested
|
# copy live photo associated .mov if requested
|
||||||
if live_photo and self.live_photo:
|
if live_photo and self.live_photo:
|
||||||
@@ -622,6 +629,7 @@ def export2(
|
|||||||
update_updated_files.extend(results.updated)
|
update_updated_files.extend(results.updated)
|
||||||
update_skipped_files.extend(results.skipped)
|
update_skipped_files.extend(results.skipped)
|
||||||
touched_files.extend(results.touched)
|
touched_files.extend(results.touched)
|
||||||
|
converted_to_jpeg_files.extend(results.converted_to_jpeg)
|
||||||
|
|
||||||
# copy associated RAW image if requested
|
# copy associated RAW image if requested
|
||||||
if raw_photo and self.has_raw:
|
if raw_photo and self.has_raw:
|
||||||
@@ -648,6 +656,7 @@ def export2(
|
|||||||
update_updated_files.extend(results.updated)
|
update_updated_files.extend(results.updated)
|
||||||
update_skipped_files.extend(results.skipped)
|
update_skipped_files.extend(results.skipped)
|
||||||
touched_files.extend(results.touched)
|
touched_files.extend(results.touched)
|
||||||
|
converted_to_jpeg_files.extend(results.converted_to_jpeg)
|
||||||
else:
|
else:
|
||||||
# use_photo_export
|
# use_photo_export
|
||||||
exported = []
|
exported = []
|
||||||
@@ -748,10 +757,10 @@ def export2(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# export metadata
|
# export metadata
|
||||||
sidecar_json_files = []
|
sidecar_json_files_skipped = []
|
||||||
|
sidecar_json_files_written = []
|
||||||
if sidecar_json:
|
if sidecar_json:
|
||||||
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.json")
|
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.json")
|
||||||
sidecar_json_files.append(str(sidecar_filename))
|
|
||||||
sidecar_str = self._exiftool_json_sidecar(
|
sidecar_str = self._exiftool_json_sidecar(
|
||||||
use_albums_as_keywords=use_albums_as_keywords,
|
use_albums_as_keywords=use_albums_as_keywords,
|
||||||
use_persons_as_keywords=use_persons_as_keywords,
|
use_persons_as_keywords=use_persons_as_keywords,
|
||||||
@@ -774,6 +783,7 @@ def export2(
|
|||||||
)
|
)
|
||||||
if write_sidecar:
|
if write_sidecar:
|
||||||
verbose(f"Writing exiftool JSON sidecar {sidecar_filename}")
|
verbose(f"Writing exiftool JSON sidecar {sidecar_filename}")
|
||||||
|
sidecar_json_files_written.append(str(sidecar_filename))
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
self._write_sidecar(sidecar_filename, sidecar_str)
|
self._write_sidecar(sidecar_filename, sidecar_str)
|
||||||
export_db.set_sidecar_for_file(
|
export_db.set_sidecar_for_file(
|
||||||
@@ -783,11 +793,12 @@ def export2(
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
verbose(f"Skipped up to date exiftool JSON sidecar {sidecar_filename}")
|
verbose(f"Skipped up to date exiftool JSON sidecar {sidecar_filename}")
|
||||||
|
sidecar_json_files_skipped.append(str(sidecar_filename))
|
||||||
|
|
||||||
sidecar_xmp_files = []
|
sidecar_xmp_files_skipped = []
|
||||||
|
sidecar_xmp_files_written = []
|
||||||
if sidecar_xmp:
|
if sidecar_xmp:
|
||||||
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.xmp")
|
sidecar_filename = dest.parent / pathlib.Path(f"{dest.stem}{dest.suffix}.xmp")
|
||||||
sidecar_xmp_files.append(str(sidecar_filename))
|
|
||||||
sidecar_str = self._xmp_sidecar(
|
sidecar_str = self._xmp_sidecar(
|
||||||
use_albums_as_keywords=use_albums_as_keywords,
|
use_albums_as_keywords=use_albums_as_keywords,
|
||||||
use_persons_as_keywords=use_persons_as_keywords,
|
use_persons_as_keywords=use_persons_as_keywords,
|
||||||
@@ -810,6 +821,7 @@ def export2(
|
|||||||
)
|
)
|
||||||
if write_sidecar:
|
if write_sidecar:
|
||||||
verbose(f"Writing XMP sidecar {sidecar_filename}")
|
verbose(f"Writing XMP sidecar {sidecar_filename}")
|
||||||
|
sidecar_xmp_files_written.append(str(sidecar_filename))
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
self._write_sidecar(sidecar_filename, sidecar_str)
|
self._write_sidecar(sidecar_filename, sidecar_str)
|
||||||
export_db.set_sidecar_for_file(
|
export_db.set_sidecar_for_file(
|
||||||
@@ -819,6 +831,7 @@ def export2(
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
verbose(f"Skipped up to date XMP sidecar {sidecar_filename}")
|
verbose(f"Skipped up to date XMP sidecar {sidecar_filename}")
|
||||||
|
sidecar_xmp_files_skipped.append(str(sidecar_filename))
|
||||||
|
|
||||||
# if exiftool, write the metadata
|
# if exiftool, write the metadata
|
||||||
if update:
|
if update:
|
||||||
@@ -918,8 +931,11 @@ def export2(
|
|||||||
update_skipped_files,
|
update_skipped_files,
|
||||||
exif_files_updated,
|
exif_files_updated,
|
||||||
touched_files,
|
touched_files,
|
||||||
sidecar_json_files,
|
converted_to_jpeg_files,
|
||||||
sidecar_xmp_files,
|
sidecar_json_files_written,
|
||||||
|
sidecar_json_files_skipped,
|
||||||
|
sidecar_xmp_files_written,
|
||||||
|
sidecar_xmp_files_skipped,
|
||||||
)
|
)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@@ -976,6 +992,7 @@ def _export_photo(
|
|||||||
update_new_files = []
|
update_new_files = []
|
||||||
update_skipped_files = []
|
update_skipped_files = []
|
||||||
touched_files = []
|
touched_files = []
|
||||||
|
converted_to_jpeg_files = []
|
||||||
|
|
||||||
dest_str = str(dest)
|
dest_str = str(dest)
|
||||||
dest_exists = dest.exists()
|
dest_exists = dest.exists()
|
||||||
@@ -1065,6 +1082,7 @@ def _export_photo(
|
|||||||
# use convert_to_jpeg to export the file
|
# use convert_to_jpeg to export the file
|
||||||
fileutil.convert_to_jpeg(src, dest_str, compression_quality=jpeg_quality)
|
fileutil.convert_to_jpeg(src, dest_str, compression_quality=jpeg_quality)
|
||||||
converted_stat = fileutil.file_sig(dest_str)
|
converted_stat = fileutil.file_sig(dest_str)
|
||||||
|
converted_to_jpeg_files.append(dest_str)
|
||||||
else:
|
else:
|
||||||
fileutil.copy(src, dest_str, norsrc=no_xattr)
|
fileutil.copy(src, dest_str, norsrc=no_xattr)
|
||||||
|
|
||||||
@@ -1090,6 +1108,9 @@ def _export_photo(
|
|||||||
update_skipped_files,
|
update_skipped_files,
|
||||||
[],
|
[],
|
||||||
touched_files,
|
touched_files,
|
||||||
|
converted_to_jpeg_files,
|
||||||
|
[],
|
||||||
|
[],
|
||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3763,3 +3763,44 @@ def test_persons():
|
|||||||
|
|
||||||
json_got = json.loads(result.output)
|
json_got = json.loads(result.output)
|
||||||
assert json_got == PERSONS_JSON
|
assert json_got == PERSONS_JSON
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_report():
|
||||||
|
""" test export with --report option """
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import osxphotos
|
||||||
|
from osxphotos.__main__ import export
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[os.path.join(cwd, CLI_PHOTOS_DB), ".", "-V", "--report", "report.csv"],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert "Writing export report" in result.output
|
||||||
|
assert os.path.exists("report.csv")
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_report_not_a_file():
|
||||||
|
""" test export with --report option and bad report value """
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import osxphotos
|
||||||
|
from osxphotos.__main__ import export
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export, [os.path.join(cwd, CLI_PHOTOS_DB), ".", "-V", "--report", "."]
|
||||||
|
)
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert "Aborted!" in result.output
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user