From 0940f039d3e628dc4f25c69bf27ce413807d3f71 Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sun, 15 Mar 2020 10:08:56 -0700 Subject: [PATCH] Lots of work on export code --- README.md | 2 +- osxphotos/__main__.py | 2 +- osxphotos/_version.py | 2 +- osxphotos/photoinfo.py | 81 +++++---- osxphotos/utils.py | 7 +- tests/test_catalina_10_15_1.py | 100 +++++------ tests/test_export_catalina_10_15_1.py | 104 +++++------- ...port_catalina_10_15_1_use_photos_export.py | 158 ++++++++++++++++++ tests/test_export_mojave_10_14_6.py | 109 +++++------- tests/test_export_raw_catalina_10_15_1.py | 10 +- tests/test_live_catalina_10_15_1.py | 33 +++- 11 files changed, 370 insertions(+), 238 deletions(-) create mode 100644 tests/test_export_catalina_10_15_1_use_photos_export.py diff --git a/README.md b/README.md index 349fe8eb..9000ab2b 100644 --- a/README.md +++ b/README.md @@ -725,6 +725,7 @@ Export photo from the Photos library to another destination on disk. - use_photos_export: boolean; (default=False), if True will attempt to export photo via applescript interaction with Photos; useful for forcing download of missing photos. This only works if the Photos library being used is the default library (last opened by Photos) as applescript will directly interact with whichever library Photos is currently using. - timeout: (int, default=120) timeout in seconds used with use_photos_export - exiftool: (boolean, default = False) if True, will use [exiftool](https://exiftool.org/) to write metadata directly to the exported photo; exiftool must be installed and in the system path +Returns: list of paths to exported files. More than one file could be exported, for example if live_photo=True, both the original imaage and the associated .mov file will be exported The json sidecar file can be used by exiftool to apply the metadata from the json file to the image. For example: @@ -742,7 +743,6 @@ Then If overwrite=False and increment=False, export will fail if destination file already exists -Returns the full path to the exported file **Implementation Note**: Because the usual python file copy methods don't preserve all the metadata available on MacOS, export uses /usr/bin/ditto to do the copy for export. ditto preserves most metadata such as extended attributes, permissions, ACLs, etc. diff --git a/osxphotos/__main__.py b/osxphotos/__main__.py index 8acada55..7786cbe5 100644 --- a/osxphotos/__main__.py +++ b/osxphotos/__main__.py @@ -1344,7 +1344,7 @@ def export_photo( overwrite=overwrite, use_photos_export=use_photos_export, exiftool=exiftool, - ) + )[0] # if export-edited, also export the edited version # verify the photo has adjustments and valid path to avoid raising an exception diff --git a/osxphotos/_version.py b/osxphotos/_version.py index 928f6c72..504acf6b 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.22.21" +__version__ = "0.22.23" diff --git a/osxphotos/photoinfo.py b/osxphotos/photoinfo.py index 84065c84..a73a2106 100644 --- a/osxphotos/photoinfo.py +++ b/osxphotos/photoinfo.py @@ -505,7 +505,7 @@ class PhotoInfo: ): """ export photo dest: must be valid destination path (or exception raised) - filename: (optional): name of picture; if not provided, will use current filename + filename: (optional): name of exported picture; if not provided, will use current filename **NOTE**: if provided, user must ensure file extension (suffix) is correct. For example, if photo is .CR2 file, edited image may be .jpeg. If you provide an extension different than what the actual file is, @@ -525,12 +525,17 @@ class PhotoInfo: use_photos_export: (boolean, default=False); if True will attempt to export photo via applescript interaction with Photos timeout: (int, default=120) timeout in seconds used with use_photos_export exiftool: (boolean, default = False); if True, will use exiftool to write metadata to export file - returns the full path to the exported file """ + returns list of full paths to the exported files """ # list of all files exported during this call to export exported_files = [] - logging.debug(f"dest ={dest}.filename={filename}") + # check edited and raise exception trying to export edited version of + # photo that hasn't been edited + if edited and not self.hasadjustments: + raise ValueError( + "Photo does not have adjustments, cannot export edited version" + ) # check arguments and get destination path and filename (if provided) if filename and len(filename) > 2: @@ -545,8 +550,8 @@ class PhotoInfo: raise FileNotFoundError("Invalid path passed to export") if filename and len(filename) == 1: - # if filename passed, use it, but verify extension - filename = filename[0] + # if filename passed, use it + fname = filename[0] else: # no filename provided so use the default # if edited file requested, use filename but add _edited @@ -560,25 +565,26 @@ class PhotoInfo: ) edited_name = pathlib.Path(self.path_edited).name edited_suffix = pathlib.Path(edited_name).suffix - filename = ( - pathlib.Path(self.filename).stem + "_edited" + edited_suffix - ) + fname = pathlib.Path(self.filename).stem + "_edited" + edited_suffix else: - filename = self.filename + fname = self.filename # check destination path dest = pathlib.Path(dest) - filename = pathlib.Path(filename) - logging.debug(f"dest ={dest}.filename={filename}") - dest = dest / filename + fname = pathlib.Path(fname) + dest = dest / fname # check extension of destination if edited and self.path_edited is not None: + # use suffix from edited file actual_suffix = pathlib.Path(self.path_edited).suffix elif edited: - logging.warning("Invalid suffix check for missing edited file") - actual_suffix = "" + # use .jpeg as that's probably correct + # if edited and path_edited is None, will raise FileNotFoundError below + # unless use_photos_export is True + actual_suffix = ".jpeg" else: + # use suffix from the non-edited file actual_suffix = pathlib.Path(self.filename).suffix if dest.suffix != actual_suffix: @@ -613,16 +619,11 @@ class PhotoInfo: # get path to source file and verify it's not None and is valid file # TODO: how to handle ismissing or not hasadjustments and edited=True cases? if edited: - if not self.hasadjustments: - logging.warning( - "Attempting to export edited photo but hasadjustments=False" - ) - if self.path_edited is not None: src = self.path_edited else: raise FileNotFoundError( - f"edited=True but path_edited is none; hasadjustments: {self.hasadjustments}" + f"Cannot export edited photo if path_edited is None" ) else: if self.ismissing: @@ -630,13 +631,10 @@ class PhotoInfo: f"Attempting to export photo with ismissing=True: path = {self.path}" ) - if self.path is None: - logging.warning( - f"Attempting to export photo but path is None: ismissing = {self.ismissing}" - ) - raise FileNotFoundError("Cannot export photo if path is None") - else: + if self.path is not None: src = self.path + else: + raise FileNotFoundError("Cannot export photo if path is None") if not os.path.isfile(src): raise FileNotFoundError(f"{src} does not appear to exist") @@ -675,16 +673,18 @@ class PhotoInfo: else: # didn't get passed a filename, add _edited filestem = f"{dest.stem}_edited" - exported = _export_photo_uuid_applescript( - self.uuid, - dest.parent, - filestem=filestem, - original=False, - edited=True, - live_photo=live_photo, - timeout=timeout, - burst=self.burst, - ) + dest = dest.parent / f"{filestem}.jpeg" + + exported = _export_photo_uuid_applescript( + self.uuid, + dest.parent, + filestem=filestem, + original=False, + edited=True, + live_photo=live_photo, + timeout=timeout, + burst=self.burst, + ) else: # export original version and not edited filestem = dest.stem @@ -702,7 +702,9 @@ class PhotoInfo: if exported is not None: exported_files.extend(exported) else: - logging.warning(f"Error exporting photo {self.uuid} to {dest}") + logging.warning( + f"Error exporting photo {self.uuid} to {dest} with use_photos_export" + ) if sidecar_json: logging.debug("writing exiftool_json_sidecar") @@ -724,14 +726,12 @@ class PhotoInfo: logging.warning(f"Error writing xmp sidecar to {sidecar_filename}") raise e - logging.debug(f"export exported_files: {exported_files}") - # if exiftool, write the metadata if exiftool and exported_files: for exported_file in exported_files: self._write_exif_data(exported_file) - return str(dest) + return exported_files def _write_exif_data(self, filepath): """ write exif data to image file at filepath @@ -771,7 +771,6 @@ class PhotoInfo: exif = {} exif["_CreatedBy"] = "osxphotos, https://github.com/RhetTbull/osxphotos" - exif["File:FileName"] = self.filename if self.description: exif["EXIF:ImageDescription"] = self.description diff --git a/osxphotos/utils.py b/osxphotos/utils.py index e74eaf91..3ed943cb 100644 --- a/osxphotos/utils.py +++ b/osxphotos/utils.py @@ -255,7 +255,7 @@ def list_photo_libraries(): # On older MacOS versions, mdfind appears to ignore some libraries # glob to find libraries in ~/Pictures then mdfind to find all the others # TODO: make this more robust - lib_list = glob.glob(f"{str(Path.home())}/Pictures/*.photoslibrary") + lib_list = glob.glob(f"{str(pathlib.Path.home())}/Pictures/*.photoslibrary") # On older OS, may not get all libraries so make sure we get the last one last_lib = get_last_library_path() @@ -327,7 +327,8 @@ def _export_photo_uuid_applescript( If filestem.ext exists, it wil be overwritten original: (boolean) if True, export original image; default = True edited: (boolean) if True, export edited photo; default = False - will produce an error if image does not have edits/adjustments + If photo not edited and edited=True, will still export the original image + caller must verify image has been edited *Note*: must be called with either edited or original but not both, will raise error if called with both edited and original = True live_photo: (boolean) if True, export associated .mov live photo; default = False @@ -448,7 +449,7 @@ def _db_is_locked(dbname): conn.close() logging.debug(f"{dbname} is not locked") locked = False - except Exception as e: + except: logging.debug(f"{dbname} is locked") locked = True diff --git a/tests/test_catalina_10_15_1.py b/tests/test_catalina_10_15_1.py index 85d9771b..e0b5582d 100644 --- a/tests/test_catalina_10_15_1.py +++ b/tests/test_catalina_10_15_1.py @@ -415,20 +415,18 @@ def test_export_1(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) - # remove the temporary file - os.remove(got_dest) - def test_export_2(): # test export with user provided filename @@ -439,21 +437,19 @@ def test_export_2(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) timestamp = time.time() filename = f"osxphotos-export-2-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) - # remove the temporary file - os.remove(got_dest) - def test_export_3(): # test file already exists and test increment=True (default) @@ -464,7 +460,8 @@ def test_export_3(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -473,16 +470,12 @@ def test_export_3(): filename2 = f"{filename2.stem} (1){filename2.suffix}" expected_dest_2 = os.path.join(dest, filename2) - got_dest = photos[0].export(dest) - got_dest_2 = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] + got_dest_2 = photos[0].export(dest)[0] assert got_dest_2 == expected_dest_2 assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - os.remove(got_dest_2) - def test_export_4(): # test user supplied file already exists and test increment=True (default) @@ -494,7 +487,8 @@ def test_export_4(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -503,16 +497,12 @@ def test_export_4(): filename2 = f"osxphotos-export-2-test-{timestamp} (1).jpg" expected_dest_2 = os.path.join(dest, filename2) - got_dest = photos[0].export(dest, filename) - got_dest_2 = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] + got_dest_2 = photos[0].export(dest, filename)[0] assert got_dest_2 == expected_dest_2 assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - os.remove(got_dest_2) - def test_export_5(): # test file already exists and test increment=True (default) @@ -523,23 +513,21 @@ def test_export_5(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) - got_dest_2 = photos[0].export(dest, overwrite=True) + got_dest = photos[0].export(dest)[0] + got_dest_2 = photos[0].export(dest, overwrite=True)[0] assert got_dest_2 == got_dest assert got_dest_2 == expected_dest assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - def test_export_6(): # test user supplied file already exists and test increment=True (default) @@ -552,7 +540,8 @@ def test_export_6(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -560,16 +549,13 @@ def test_export_6(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) - got_dest_2 = photos[0].export(dest, filename, overwrite=True) + got_dest = photos[0].export(dest, filename)[0] + got_dest_2 = photos[0].export(dest, filename, overwrite=True)[0] assert got_dest_2 == got_dest assert got_dest_2 == expected_dest assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - def test_export_7(): # test file already exists and test increment=False (not default), overwrite=False (default) @@ -580,21 +566,19 @@ def test_export_7(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] with pytest.raises(Exception) as e: # try to export again with increment = False assert photos[0].export(dest, increment=False) assert e.type == type(FileExistsError()) - # remove the temporary file - os.remove(got_dest) - def test_export_8(): # try to export missing file @@ -605,14 +589,15 @@ def test_export_8(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["missing"]]) filename = photos[0].filename with pytest.raises(Exception) as e: - assert photos[0].export(dest) + assert photos[0].export(dest)[0] assert e.type == type(FileNotFoundError()) @@ -625,15 +610,16 @@ def test_export_9(): import osxphotos - dest = tempfile.gettempdir() photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) filename = photos[0].filename with pytest.raises(Exception) as e: assert photos[0].export(dest, edited=True) - assert e.type == type(FileNotFoundError()) + assert e.type == ValueError def test_export_10(): @@ -646,8 +632,9 @@ def test_export_10(): import osxphotos - dest = tempfile.gettempdir() photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) timestamp = time.time() @@ -655,7 +642,7 @@ def test_export_10(): with pytest.raises(Exception) as e: assert photos[0].export(dest, filename, edited=True) - assert e.type == type(FileNotFoundError()) + assert e.type == ValueError def test_export_11(): @@ -667,7 +654,8 @@ def test_export_11(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) @@ -675,12 +663,9 @@ def test_export_11(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename, edited=True) + got_dest = photos[0].export(dest, filename, edited=True)[0] assert got_dest == expected_dest - # remove the temporary file - os.remove(got_dest) - def test_export_12(): # export edited file with default name @@ -691,7 +676,8 @@ def test_export_12(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) @@ -700,12 +686,9 @@ def test_export_12(): filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, edited=True) + got_dest = photos[0].export(dest, edited=True)[0] assert got_dest == expected_dest - # remove the temporary file - os.remove(got_dest) - def test_export_13(): # export to invalid destination @@ -716,7 +699,8 @@ def test_export_13(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name # create a folder that doesn't exist i = 0 diff --git a/tests/test_export_catalina_10_15_1.py b/tests/test_export_catalina_10_15_1.py index bc229229..f55db19b 100644 --- a/tests/test_export_catalina_10_15_1.py +++ b/tests/test_export_catalina_10_15_1.py @@ -67,20 +67,18 @@ def test_export_1(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) - # remove the temporary file - os.remove(got_dest) - def test_export_2(): # test export with user provided filename @@ -91,21 +89,19 @@ def test_export_2(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) timestamp = time.time() filename = f"osxphotos-export-2-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) - # remove the temporary file - os.remove(got_dest) - def test_export_3(): # test file already exists and test increment=True (default) @@ -116,7 +112,8 @@ def test_export_3(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -126,16 +123,12 @@ def test_export_3(): expected_dest = os.path.join(dest, filename) expected_dest_2 = os.path.join(dest, filename2) - got_dest = photos[0].export(dest) - got_dest_2 = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] + got_dest_2 = photos[0].export(dest)[0] assert got_dest_2 == expected_dest_2 assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - os.remove(got_dest_2) - def test_export_4(): # test user supplied file already exists and test increment=True (default) @@ -147,7 +140,8 @@ def test_export_4(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -157,16 +151,12 @@ def test_export_4(): expected_dest = os.path.join(dest, filename) expected_dest_2 = os.path.join(dest, filename2) - got_dest = photos[0].export(dest, filename) - got_dest_2 = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] + got_dest_2 = photos[0].export(dest, filename)[0] assert got_dest_2 == expected_dest_2 assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - os.remove(got_dest_2) - def test_export_5(): # test file already exists and test increment=True (default) @@ -177,23 +167,21 @@ def test_export_5(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) - got_dest_2 = photos[0].export(dest, overwrite=True) + got_dest = photos[0].export(dest)[0] + got_dest_2 = photos[0].export(dest, overwrite=True)[0] assert got_dest_2 == got_dest assert got_dest_2 == expected_dest assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - def test_export_6(): # test user supplied file already exists and test increment=True (default) @@ -206,7 +194,8 @@ def test_export_6(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -214,16 +203,13 @@ def test_export_6(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) - got_dest_2 = photos[0].export(dest, filename, overwrite=True) + got_dest = photos[0].export(dest, filename)[0] + got_dest_2 = photos[0].export(dest, filename, overwrite=True)[0] assert got_dest_2 == got_dest assert got_dest_2 == expected_dest assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - def test_export_7(): # test file already exists and test increment=False (not default), overwrite=False (default) @@ -234,22 +220,20 @@ def test_export_7(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] with pytest.raises(Exception) as e: # try to export again with increment = False assert photos[0].export(dest, increment=False) assert e.type == type(FileExistsError()) - # remove the temporary file - os.remove(got_dest) - def test_export_8(): # try to export missing file @@ -260,7 +244,8 @@ def test_export_8(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["missing"]]) @@ -281,16 +266,14 @@ def test_export_9(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) - filename = photos[0].filename - expected_dest = os.path.join(dest, filename) - with pytest.raises(Exception) as e: assert photos[0].export(dest, edited=True) - assert e.type == type(FileNotFoundError()) + assert e.type == ValueError def test_export_10(): @@ -303,7 +286,8 @@ def test_export_10(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) @@ -313,7 +297,7 @@ def test_export_10(): with pytest.raises(Exception) as e: assert photos[0].export(dest, filename, edited=True) - assert e.type == type(FileNotFoundError()) + assert e.type == ValueError def test_export_11(): @@ -325,7 +309,8 @@ def test_export_11(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) @@ -333,12 +318,9 @@ def test_export_11(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename, edited=True) + got_dest = photos[0].export(dest, filename, edited=True)[0] assert got_dest == expected_dest - # remove the temporary file - os.remove(got_dest) - def test_export_12(): # export edited file with default name @@ -349,7 +331,8 @@ def test_export_12(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) @@ -358,12 +341,9 @@ def test_export_12(): filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, edited=True) + got_dest = photos[0].export(dest, edited=True)[0] assert got_dest == expected_dest - # remove the temporary file - os.remove(got_dest) - def test_export_13(): # export to invalid destination @@ -374,7 +354,8 @@ def test_export_13(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name # create a folder that doesn't exist i = 0 @@ -446,8 +427,7 @@ def test_exiftool_json_sidecar(): json_expected = json.loads( """ - [{"File:FileName": "DC99FBDD-7A52-4100-A5BB-344131646C30.jpeg", - "XMP:Title": "St. James\'s Park", + [{"XMP:Title": "St. James\'s Park", "XMP:TagsList": ["London 2018", "St. James\'s Park", "England", "United Kingdom", "UK", "London"], "IPTC:Keywords": ["London 2018", "St. James\'s Park", "England", "United Kingdom", "UK", "London"], "XMP:Subject": ["London 2018", "St. James\'s Park", "England", "United Kingdom", "UK", "London"], diff --git a/tests/test_export_catalina_10_15_1_use_photos_export.py b/tests/test_export_catalina_10_15_1_use_photos_export.py new file mode 100644 index 00000000..1750a2f2 --- /dev/null +++ b/tests/test_export_catalina_10_15_1_use_photos_export.py @@ -0,0 +1,158 @@ +import os +import pytest + +from osxphotos._constants import _UNKNOWN_PERSON + +skip_test = False if "OSXPHOTOS_TEST_EXPORT" in os.environ else True +pytestmark = pytest.mark.skipif( + skip_test, reason="These tests only run against system photos library" +) + +PHOTOS_DB = "/Users/rhet/Pictures/Photos Library.photoslibrary" + +UUID_DICT = { + "has_adjustments": "A8111956-E900-4DEC-9191-A04A87C07BC5", + "no_adjustments": "EA7BB55F-92F1-4818-94E3-E8DEDC6B2E31", + "live": "9032C168-9319-40C0-8210-5ADC42F4C603", +} + + +@pytest.fixture(scope="module") +def photosdb(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + return photosdb + + +def test_export_default_name(photosdb): + # test basic export + # get an unedited image and export it using default filename + import os + import os.path + import tempfile + + import osxphotos + + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name + photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) + + filename = photos[0].filename + expected_dest = os.path.join(dest, filename) + got_dest = photos[0].export(dest, use_photos_export=True)[0] + + assert got_dest == expected_dest + assert os.path.isfile(got_dest) + + +def test_export_supplied_name(photosdb): + # test export with user provided filename + import os + import os.path + import tempfile + import time + + import osxphotos + + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name + photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) + + timestamp = time.time() + filename = f"osxphotos-export-2-test-{timestamp}.jpeg" + expected_dest = os.path.join(dest, filename) + got_dest = photos[0].export(dest, filename, use_photos_export=True)[0] + + assert got_dest == expected_dest + assert os.path.isfile(got_dest) + + +def test_export_edited(photosdb): + # test export edited file + import os + import os.path + import pathlib + import tempfile + + import osxphotos + + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name + photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) + + suffix = pathlib.Path(photos[0].path_edited).suffix + filename = f"{pathlib.Path(photos[0].filename).stem}_edited{suffix}" + expected_dest = os.path.join(dest, filename) + got_dest = photos[0].export(dest, use_photos_export=True, edited=True)[0] + + assert got_dest == expected_dest + assert os.path.isfile(expected_dest) + + +def test_export_edited_exiftool(photosdb): + # test export edited file + import os + import os.path + import pathlib + import tempfile + + import osxphotos + import osxphotos.exiftool + + import logging + + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name + photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) + + got_dest = photos[0].export( + dest, use_photos_export=True, edited=True, exiftool=True + ) + logging.warning(got_dest) + got_dest = got_dest[0] + + assert os.path.isfile(got_dest) + exif = osxphotos.exiftool.ExifTool(got_dest) + assert exif.data["IPTC:Keywords"] == "osxphotos" + + +def test_export_edited_supplied_name(photosdb): + # test export with user provided filename + import os + import os.path + import tempfile + import time + + import osxphotos + + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name + photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) + + timestamp = time.time() + filename = f"osxphotos-export-2-test-{timestamp}.jpeg" + expected_dest = os.path.join(dest, filename) + got_dest = photos[0].export(dest, filename, use_photos_export=True, edited=True)[0] + + assert got_dest == expected_dest + assert os.path.isfile(got_dest) + + +def test_export_edited_no_edit(photosdb): + # test export edited file if not actually edited + import os + import os.path + import pathlib + import tempfile + + import osxphotos + + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name + photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) + + with pytest.raises(Exception) as e: + assert photos[0].export(dest, use_photos_export=True, edited=True) + assert e.type == ValueError + diff --git a/tests/test_export_mojave_10_14_6.py b/tests/test_export_mojave_10_14_6.py index 3013f9c7..97e383e2 100644 --- a/tests/test_export_mojave_10_14_6.py +++ b/tests/test_export_mojave_10_14_6.py @@ -55,20 +55,18 @@ def test_export_1(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) - # remove the temporary file - os.remove(got_dest) - def test_export_2(): # test export with user provided filename @@ -79,21 +77,19 @@ def test_export_2(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) timestamp = time.time() filename = f"osxphotos-export-2-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) - # remove the temporary file - os.remove(got_dest) - def test_export_3(): # test file already exists and test increment=True (default) @@ -104,7 +100,8 @@ def test_export_3(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -114,16 +111,12 @@ def test_export_3(): expected_dest = os.path.join(dest, filename) expected_dest_2 = os.path.join(dest, filename2) - got_dest = photos[0].export(dest) - got_dest_2 = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] + got_dest_2 = photos[0].export(dest)[0] assert got_dest_2 == expected_dest_2 assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - os.remove(got_dest_2) - def test_export_4(): # test user supplied file already exists and test increment=True (default) @@ -135,7 +128,8 @@ def test_export_4(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -145,16 +139,12 @@ def test_export_4(): expected_dest = os.path.join(dest, filename) expected_dest_2 = os.path.join(dest, filename2) - got_dest = photos[0].export(dest, filename) - got_dest_2 = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] + got_dest_2 = photos[0].export(dest, filename)[0] assert got_dest_2 == expected_dest_2 assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - os.remove(got_dest_2) - def test_export_5(): # test file already exists and test increment=True (default) @@ -165,23 +155,21 @@ def test_export_5(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) - got_dest_2 = photos[0].export(dest, overwrite=True) + got_dest = photos[0].export(dest)[0] + got_dest_2 = photos[0].export(dest, overwrite=True)[0] assert got_dest_2 == got_dest assert got_dest_2 == expected_dest assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - def test_export_6(): # test user supplied file already exists and test increment=True (default) @@ -194,7 +182,8 @@ def test_export_6(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) @@ -202,16 +191,13 @@ def test_export_6(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) - got_dest_2 = photos[0].export(dest, filename, overwrite=True) + got_dest = photos[0].export(dest, filename)[0] + got_dest_2 = photos[0].export(dest, filename, overwrite=True)[0] assert got_dest_2 == got_dest assert got_dest_2 == expected_dest assert os.path.isfile(got_dest_2) - # remove the temporary file - os.remove(got_dest) - def test_export_7(): # test file already exists and test increment=False (not default), overwrite=False (default) @@ -222,22 +208,20 @@ def test_export_7(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["export"]]) filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] with pytest.raises(Exception) as e: # try to export again with increment = False - assert photos[0].export(dest, increment=False) + assert photos[0].export(dest, increment=False)[0] assert e.type == type(FileExistsError()) - # remove the temporary file - os.remove(got_dest) - def test_export_8(): # try to export missing file @@ -248,7 +232,8 @@ def test_export_8(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["missing"]]) @@ -256,7 +241,7 @@ def test_export_8(): expected_dest = os.path.join(dest, filename) with pytest.raises(Exception) as e: - assert photos[0].export(dest) + assert photos[0].export(dest)[0] assert e.type == type(FileNotFoundError()) @@ -269,7 +254,8 @@ def test_export_9(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) @@ -278,7 +264,7 @@ def test_export_9(): with pytest.raises(Exception) as e: assert photos[0].export(dest, edited=True) - assert e.type == type(FileNotFoundError()) + assert e.type == ValueError def test_export_10(): @@ -291,7 +277,8 @@ def test_export_10(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) @@ -300,8 +287,8 @@ def test_export_10(): expected_dest = os.path.join(dest, filename) with pytest.raises(Exception) as e: - assert photos[0].export(dest, filename, edited=True) - assert e.type == type(FileNotFoundError()) + assert photos[0].export(dest, filename, edited=True)[0] + assert e.type == ValueError def test_export_11(): @@ -313,7 +300,8 @@ def test_export_11(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) @@ -321,12 +309,9 @@ def test_export_11(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename, edited=True) + got_dest = photos[0].export(dest, filename, edited=True)[0] assert got_dest == expected_dest - # remove the temporary file - os.remove(got_dest) - def test_export_12(): # export edited file with default name @@ -337,7 +322,8 @@ def test_export_12(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) @@ -346,12 +332,9 @@ def test_export_12(): filename = pathlib.Path(photos[0].filename).stem + "_edited" + edited_suffix expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, edited=True) + got_dest = photos[0].export(dest, edited=True)[0] assert got_dest == expected_dest - # remove the temporary file - os.remove(got_dest) - def test_export_13(): # export to invalid destination @@ -362,7 +345,8 @@ def test_export_13(): import osxphotos - dest = tempfile.gettempdir() + tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") + dest = tempdir.name # create a folder that doesn't exist i = 0 @@ -377,7 +361,7 @@ def test_export_13(): expected_dest = os.path.join(dest, filename) with pytest.raises(Exception) as e: - assert photos[0].export(dest) + assert photos[0].export(dest)[0] assert e.type == type(FileNotFoundError()) @@ -390,8 +374,7 @@ def test_exiftool_json_sidecar(): json_expected = json.loads( """ - [{"File:FileName": "St James Park.jpg", - "XMP:Title": "St. James\'s Park", + [{"XMP:Title": "St. James\'s Park", "XMP:TagsList": ["London 2018", "St. James\'s Park", "England", "United Kingdom", "UK", "London"], "IPTC:Keywords": ["London 2018", "St. James\'s Park", "England", "United Kingdom", "UK", "London"], "XMP:Subject": ["London 2018", "St. James\'s Park", "England", "United Kingdom", "UK", "London"], diff --git a/tests/test_export_raw_catalina_10_15_1.py b/tests/test_export_raw_catalina_10_15_1.py index 70a818fc..b0b97038 100644 --- a/tests/test_export_raw_catalina_10_15_1.py +++ b/tests/test_export_raw_catalina_10_15_1.py @@ -31,7 +31,7 @@ def test_export_1(): filename = photos[0].filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest) + got_dest = photos[0].export(dest)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) @@ -55,7 +55,7 @@ def test_export_2(): filename = photos[0].original_filename expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename) + got_dest = photos[0].export(dest, filename)[0] assert got_dest == expected_dest assert os.path.isfile(got_dest) @@ -81,7 +81,7 @@ def test_export_edited_name(): filename = f"osxphotos-export-test-{timestamp}.jpg" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename, edited=True) + got_dest = photos[0].export(dest, filename, edited=True)[0] assert got_dest == expected_dest assert pathlib.Path(got_dest).name == filename @@ -100,7 +100,7 @@ def test_export_edited_default(): photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) - got_dest = photos[0].export(dest, edited=True) + got_dest = photos[0].export(dest, edited=True)[0] assert pathlib.Path(got_dest).name == FILENAME_DICT["current_edited"] @@ -125,7 +125,7 @@ def test_export_edited_wrong_suffix(caplog): filename = f"osxphotos-export-test-{timestamp}.cr2" expected_dest = os.path.join(dest, filename) - got_dest = photos[0].export(dest, filename, edited=True) + got_dest = photos[0].export(dest, filename, edited=True)[0] assert "Invalid destination suffix" in caplog.text assert got_dest == expected_dest assert pathlib.Path(got_dest).name == filename diff --git a/tests/test_live_catalina_10_15_1.py b/tests/test_live_catalina_10_15_1.py index 6a63ec1e..b6fdc770 100644 --- a/tests/test_live_catalina_10_15_1.py +++ b/tests/test_live_catalina_10_15_1.py @@ -46,9 +46,8 @@ def test_export_live_1(): filename = photos[0].filename expected_dest = os.path.join(dest.name, filename) - got_dest = photos[0].export(dest.name, live_photo=True) + got_dest = photos[0].export(dest.name, live_photo=True)[0] got_movie = f"{pathlib.Path(got_dest).parent / pathlib.Path(got_dest).stem}.mov" - expected_dest = os.path.join(dest.name, filename) files = glob.glob(os.path.join(dest.name, "*")) assert len(files) == 2 @@ -73,7 +72,7 @@ def test_export_live_2(): filename = photos[0].filename expected_dest = os.path.join(dest.name, filename) - got_dest = photos[0].export(dest.name, live_photo=False) + got_dest = photos[0].export(dest.name, live_photo=False)[0] got_movie = f"{pathlib.Path(got_dest).parent / pathlib.Path(got_dest).stem}.mov" files = glob.glob(os.path.join(dest.name, "*")) @@ -83,6 +82,34 @@ def test_export_live_2(): assert got_movie not in files +def test_export_live_3(): + # export a live photo and associated .mov, + # check list return of export + import glob + import os.path + import pathlib + import tempfile + + import osxphotos + + dest = tempfile.TemporaryDirectory(prefix="osxphotos_") + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + photos = photosdb.photos(uuid=[UUID_DICT["live"]]) + + filename = photos[0].filename + expected_dest = os.path.join(dest.name, filename) + expected_mov = f"{dest.name}/{pathlib.Path(expected_dest).stem}.mov" + got_files = photos[0].export(dest.name, live_photo=True) + # got_dest = got_files[0] + # got_movie = f"{pathlib.Path(got_dest).parent / pathlib.Path(got_dest).stem}.mov" + # files = glob.glob(os.path.join(dest.name, "*")) + + assert len(got_files) == 2 + assert expected_dest in got_files + assert expected_mov in got_files + + # def test_export_live_3(): # # export a live photo and associated .mov and edited file # import glob