osxphotos/examples/concurrent_export.py
2023-04-01 13:59:47 -07:00

53 lines
1.7 KiB
Python

"""Example for concurrent export of photos using osxphotos.PhotoExporter.export()
Note: concurrent export can only be used on Python 3.11 and later due to the way
python's sqlite3 module is implemented. See https://docs.python.org/3/library/sqlite3.html#sqlite3.threadsafety
for more information.
"""
import concurrent.futures
import os
import time
import click
import osxphotos
from osxphotos.cli import echo, query_command, verbose
@query_command()
@click.option(
"--workers",
metavar="WORKERS",
help="Maximum number of worker threads to use for export. "
"If not specified, it will default to the number of processors on the machine, multiplied by 5.",
type=int,
)
@click.argument(
"export_dir",
type=click.Path(exists=True, file_okay=False, dir_okay=True, writable=True),
)
def export(workers, export_dir, photos: list[osxphotos.PhotoInfo], **kwargs):
"""Export photos to EXPORT_DIR using concurrent export.
Use --workers to specify the number of worker threads to use.
This simple example exports only the original photo and does not export
edited versions, live photos, etc.
"""
workers = workers or os.cpu_count() * 5
echo(f"Exporting {len(photos)} photos to {export_dir} using {workers} workers")
start_t = time.perf_counter()
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
futures = [executor.submit(p.export, export_dir) for p in photos]
exported = []
for future in concurrent.futures.as_completed(futures):
exported.extend(future.result())
end_t = time.perf_counter()
echo(
f"Exported {len(exported)} photos to {export_dir} in {end_t-start_t:.4f} seconds"
)
if __name__ == "__main__":
export()