diff --git a/README.md b/README.md index 638b5dd0..a797e191 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ + [FolderInfo](#folderinfo) + [PlaceInfo](#placeinfo) + [ScoreInfo](#scoreinfo) + + [PersonInfo](#personinfo) + [Template Substitutions](#template-substitutions) + [Utility Functions](#utility-functions) * [Examples](#examples) @@ -790,7 +791,15 @@ Returns a list names of top level folder names in the database. persons = photosdb.persons ``` -Returns a list of the persons (faces) found in the Photos library +Returns a list of the person names (faces) found in the Photos library. **Note**: It is of course possible to have more than one person with the same name, e.g. "Maria Smith", in the database. `persons` assumes these are the same person and will list only one person named "Maria Smith". If you need more information about persons in the database, see [person_info](#dbpersoninfo). + +#### `person_info` +```python +# assumes photosdb is a PhotosDB object (see above) +person_info = photosdb.person_info +``` + +Returns a list of [PersonInfo](#personinfo) objects representing persons who appear in photos in the database. #### `keywords_as_dict` ```python @@ -806,7 +815,8 @@ Returns a dictionary of keywords found in the Photos library where key is the ke persons_dict = photosdb.persons_as_dict ``` -Returns a dictionary of persons (faces) found in the Photos library where key is the person name and value is the count of how many times that person appears in the library (ie. how many photos are tagged with the person). Resulting dictionary is in reverse sorted order (e.g. person who appears in the most photos is listed first). +Returns a dictionary of persons (faces) found in the Photos library where key is the person name and value is the count of how many times that person appears in the library (ie. how many photos are tagged with the person). Resulting dictionary is in reverse sorted order (e.g. person who appears in the most photos is listed first). **Note**: It is of course possible to have more than one person with the same name, e.g. "Maria Smith", in the database. `persons_as_dict` assumes these are the same person and will list only one person named "Maria Smith". If you need more information about persons in the database, see [person_info](#dbpersoninfo). + #### `albums_as_dict` ```python @@ -892,8 +902,7 @@ for row in results: conn.close() ``` - -#### ` photos(keywords=None, uuid=None, persons=None, albums=None, images=True, movies=True, from_date=None, to_date=None, intrash=False)` +#### `photos(keywords=None, uuid=None, persons=None, albums=None, images=True, movies=True, from_date=None, to_date=None, intrash=False)` ```python # assumes photosdb is a PhotosDB object (see above) @@ -929,6 +938,8 @@ photos = photosdb.photos( - ```to_date```: datetime.datetime; if provided, finds photos where creation date <= to_date; default is None - ```intrash```: if True, finds only photos in the "Recently Deleted" or trash folder, if False does not find any photos in the trash; default is False +See also [get_photo()](#getphoto) which is much faster for retrieving a single photo. + If more than one of (keywords, uuid, persons, albums,from_date, to_date) is provided, they are treated as "and" criteria. E.g. Finds all photos with (keyword = "wedding" or "birthday") and (persons = "Juan Rodriguez") @@ -1003,6 +1014,9 @@ For example, in my library, Photos says I have 19,386 photos and 474 movies. Ho >>> ``` +#### `get_photo(uuid)` +Returns a single PhotoInfo instance for photo with UUID matching `uuid` or None if no photo is found matching `uuid`. If you know the UUID of a photo, `get_photo()` is much faster than `photos`. See also [photos()](#photos). + ### PhotoInfo PhotosDB.photos() returns a list of PhotoInfo objects. Each PhotoInfo object represents a single photo in the Photos library. @@ -1040,6 +1054,9 @@ Returns a list of [AlbumInfo](#AlbumInfo) objects representing the albums the ph #### `persons` Returns a list of the names of the persons in the photo +#### `person_info` +Returns a list of [PersonInfo](#personinfo) objects representing persons in the photo. + #### `path` Returns the absolute path to the photo on disk as a string. **Note**: this returns the path to the *original* unedited file (see [hasadjustments](#hasadjustments)). If the file is missing on disk, path=`None` (see [ismissing](#ismissing)). @@ -1353,7 +1370,7 @@ Returns the universally unique identifier (uuid) of the album. This is how Phot #### `title` Returns the title or name of the album. -#### `photos` +#### `photos` Returns a list of [PhotoInfo](#PhotoInfo) objects representing each photo contained in the album sorted in the same order as in Photos. (e.g. if photos were manually sorted in the Photos albums, photos returned by `photos` will be in same order as they appear in the Photos album) #### `folder_list` @@ -1528,6 +1545,31 @@ Example: find your "best" photo of food >>> best_food_photo = sorted([p for p in photos if "food" in p.labels_normalized], key=lambda p: p.score.overall, reverse=True)[0] ``` +### PersonInfo +[PhotosDB.person_info](#dbpersoninfo) and [PhotoInfo.person_info](#photopersoninfo) return a list of PersonInfo objects represents persons in the database and in a photo, respectively. The PersonInfo class has the following properties and methods. + +#### `name` +Returns the full name of the person represented in the photo. For example, "Maria Smith". + +#### `display_name` +Returns the display name of the person represented in the photo. For example, "Maria". + +#### `uuid` +Returns the UUID of the person as stored in the Photos library database. + +#### `keyphoto` +Returns a PhotoInfo instance for the photo designated as the key photo for the person. This is the Photos uses to display the person's face thumbnail in Photos' "People" view. + +#### `facecount` +Returns a count of how many times this person appears in images in the database. + +#### photos` +Returns a list of PhotoInfo objects representing all photos the person appears in. + +#### `json()` +Returns a json string representation of the PersonInfo instance. + + ### Template Substitutions The following substitutions are availabe for use with `PhotoInfo.render_template()` diff --git a/examples/photos_repl.py b/examples/photos_repl.py index e41dbaa5..2502c484 100755 --- a/examples/photos_repl.py +++ b/examples/photos_repl.py @@ -58,5 +58,6 @@ if __name__ == "__main__": print("getting photos") tic = time.perf_counter() photos = photosdb.photos(images=True, movies=True) + photos.extend(photosdb.photos(images=True, movies=True, intrash=True)) toc = time.perf_counter() print(f"found {len(photos)} photos in {toc-tic} seconds") diff --git a/osxphotos/_version.py b/osxphotos/_version.py index ff38ad1a..eaf92b90 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.30.10" +__version__ = "0.30.11" diff --git a/osxphotos/albuminfo.py b/osxphotos/albuminfo.py index 40ce5d72..def724e2 100644 --- a/osxphotos/albuminfo.py +++ b/osxphotos/albuminfo.py @@ -55,7 +55,9 @@ class AlbumInfo: # so need to build photo list one a time # sort uuids by sort order sorted_uuid = sorted(zip(sort_order, uuid)) - self._photos = [self._db.photos(uuid=[uuid])[0] for _, uuid in sorted_uuid] + self._photos = [ + self._db.photos(uuid=[uuid])[0] for _, uuid in sorted_uuid + ] else: self._photos = [] return self._photos diff --git a/osxphotos/personinfo.py b/osxphotos/personinfo.py new file mode 100644 index 00000000..56efd0c4 --- /dev/null +++ b/osxphotos/personinfo.py @@ -0,0 +1,77 @@ +""" PhotoInfo methods to expose info about person in the Photos library """ + +import json +import logging + + +class PersonInfo: + """ Info about a person in the Photos library + """ + + def __init__(self, db=None, pk=None): + """ Creates a new PersonInfo instance + + Arguments: + db: instance of PhotosDB object + pk: primary key value of person to initialize PersonInfo with + + Returns: + PersonInfo instance + """ + self._db = db + self._pk = pk + + person = self._db._dbpersons_pk[pk] + self.uuid = person["uuid"] + self.name = person["fullname"] + self.display_name = person["displayname"] + self.keyface = person["keyface"] + self.facecount = person["facecount"] + + @property + def keyphoto(self): + try: + return self._keyphoto + except AttributeError: + person = self._db._dbpersons_pk[self._pk] + if person["photo_uuid"]: + try: + key_photo = self._db.get_photo(person["photo_uuid"]) + except IndexError: + key_photo = None + else: + key_photo = None + self._keyphoto = key_photo + return self._keyphoto + + @property + def photos(self): + """ Returns list of PhotoInfo objects associated with this person """ + return self._db.photos_by_uuid(self._db._dbfaces_pk[self._pk]) + + def json(self): + """ Returns JSON representation of class instance """ + keyphoto = self.keyphoto.uuid if self.keyphoto is not None else None + person = { + "uuid": self.uuid, + "name": self.name, + "displayname": self.display_name, + "keyface": self.keyface, + "facecount": self.facecount, + "keyphoto": keyphoto, + } + return json.dumps(person) + + def __str__(self): + return f"PersonInfo(name={self.name}, display_name={self.display_name}, uuid={self.uuid}, facecount={self.facecount})" + + def __eq__(self, other): + if not isinstance(other, type(self)): + return False + + return all( + getattr(self, field) == getattr(other, field) for field in ["_db", "_pk"] + ) + + def __ne__(self, other): + return not self.__eq__(other) diff --git a/osxphotos/photoinfo/_photoinfo_exiftool.py b/osxphotos/photoinfo/_photoinfo_exiftool.py index 689c210d..74e10da0 100644 --- a/osxphotos/photoinfo/_photoinfo_exiftool.py +++ b/osxphotos/photoinfo/_photoinfo_exiftool.py @@ -5,6 +5,7 @@ import os from ..exiftool import ExifTool, get_exiftool_path + @property def exiftool(self): """ Returns an ExifTool object for the photo @@ -26,8 +27,9 @@ def exiftool(self): except FileNotFoundError: # get_exiftool_path raises FileNotFoundError if exiftool not found exiftool = None - logging.warning(f"exiftool not in path; download and install from https://exiftool.org/") + logging.warning( + f"exiftool not in path; download and install from https://exiftool.org/" + ) self._exiftool = exiftool return self._exiftool - diff --git a/osxphotos/photoinfo/photoinfo.py b/osxphotos/photoinfo/photoinfo.py index 79aa4a78..a1fcfa94 100644 --- a/osxphotos/photoinfo/photoinfo.py +++ b/osxphotos/photoinfo/photoinfo.py @@ -29,6 +29,7 @@ from .._constants import ( _PHOTOS_5_SHARED_PHOTO_PATH, ) from ..albuminfo import AlbumInfo +from ..personinfo import PersonInfo from ..phototemplate import PhotoTemplate from ..placeinfo import PlaceInfo4, PlaceInfo5 from ..utils import _debug, _get_resource_loc, findfiles, get_preferred_uti_extension @@ -339,7 +340,18 @@ class PhotoInfo: @property def persons(self): """ list of persons in picture """ - return [self._db._dbpersons_pk[k]["fullname"] for k in self._info["persons"]] + return [self._db._dbpersons_pk[pk]["fullname"] for pk in self._info["persons"]] + + @property + def person_info(self): + """ list of PersonInfo objects for person in picture """ + try: + return self._personinfo + except AttributeError: + self._personinfo = [ + PersonInfo(db=self._db, pk=pk) for pk in self._info["persons"] + ] + return self._personinfo @property def albums(self): diff --git a/osxphotos/photosdb/_photosdb_process_exif.py b/osxphotos/photosdb/_photosdb_process_exif.py index 001afb7d..809ae635 100644 --- a/osxphotos/photosdb/_photosdb_process_exif.py +++ b/osxphotos/photosdb/_photosdb_process_exif.py @@ -34,7 +34,7 @@ def _process_exifinfo_5(photosdb): photosdb: PhotosDB instance """ db = photosdb._tmp_db - + (conn, cursor) = _open_sql_file(db) result = conn.execute( diff --git a/osxphotos/photosdb/photosdb.py b/osxphotos/photosdb/photosdb.py index d1dcc4be..bfea61ed 100644 --- a/osxphotos/photosdb/photosdb.py +++ b/osxphotos/photosdb/photosdb.py @@ -34,6 +34,7 @@ from .._constants import ( ) from .._version import __version__ from ..albuminfo import AlbumInfo, FolderInfo +from ..personinfo import PersonInfo from ..photoinfo import PhotoInfo from ..utils import ( _check_file_exists, @@ -44,7 +45,6 @@ from ..utils import ( get_last_library_path, ) - # TODO: Add test for imageTimeZoneOffsetSeconds = None # TODO: Add test for __str__ # TODO: Add special albums and magic albums @@ -87,6 +87,7 @@ class PhotosDB: # set up the data structures used to store all the Photo database info + # TODO: I don't think these keywords flags are actually used # if True, will treat persons as keywords when exporting metadata self.use_persons_as_keywords = False @@ -372,6 +373,17 @@ class PhotosDB: persons = {self._dbpersons_pk[k]["fullname"] for k in self._dbfaces_pk} return list(persons) + @property + def person_info(self): + """ return list of PersonInfo objects for each person in the photos database """ + try: + return self._person_info + except AttributeError: + self._person_info = [ + PersonInfo(db=self, pk=pk) for pk in self._dbpersons_pk + ] + return self._person_info + @property def folder_info(self): """ return list FolderInfo objects representing top-level folders in the photos database """ @@ -561,7 +573,8 @@ class PhotosDB: RKPerson.uuid, RKPerson.name, RKPerson.faceCount, - RKPerson.displayName + RKPerson.displayName, + RKPerson.representativeFaceId FROM RKPerson """ ) @@ -571,6 +584,7 @@ class PhotosDB: # 2 RKPerson.name, # 3 RKPerson.faceCount, # 4 RKPerson.displayName + # 5 RKPerson.representativeFaceId for person in c: pk = person[0] @@ -580,14 +594,43 @@ class PhotosDB: "uuid": person[1], "fullname": fullname, "facecount": person[3], - "keyface": None, + "keyface": person[5], "displayname": person[4], + "photo_uuid": None, + "keyface_uuid": None, } try: self._dbpersons_fullname[fullname].append(pk) except KeyError: self._dbpersons_fullname[fullname] = [pk] + # get info on key face + c.execute( + """ SELECT + RKPerson.modelID, + RKPerson.representativeFaceId, + RKVersion.uuid, + RKFace.uuid + FROM RKPerson, RKFace, RKVersion + WHERE + RKFace.modelId = RKPerson.representativeFaceId AND + RKVersion.modelId = RKFace.ImageModelId + """ + ) + + # 0 RKPerson.modelID, + # 1 RKPerson.representativeFaceId + # 2 RKVersion.uuid, + # 3 RKFace.uuid + + for person in c: + pk = person[0] + try: + self._dbpersons_pk[pk]["photo_uuid"] = person[2] + self._dbpersons_pk[pk]["keyface_uuid"] = person[3] + except KeyError: + logging.debug(f"Unexpected KeyError _dbpersons_pk[{pk}]") + # get information on detected faces c.execute( """ SELECT @@ -632,8 +675,8 @@ class PhotosDB: RKVersion.uuid, RKCustomSortOrder.orderNumber FROM RKVersion - JOIN RKCustomSortOrder on RKCustomSortOrder.objectUuid = RKVersion.uuid - JOIN RKAlbum on RKAlbum.uuid = RKCustomSortOrder.containerUuid + JOIN RKCustomSortOrder on RKCustomSortOrder.objectUuid = RKVersion.uuid + JOIN RKAlbum on RKAlbum.uuid = RKCustomSortOrder.containerUuid """ ) @@ -1417,7 +1460,7 @@ class PhotosDB: # 2 ZPERSON.ZFULLNAME, # 3 ZPERSON.ZFACECOUNT, # 4 ZPERSON.ZKEYFACE, - # 5 ZPERSON.ZDISPLAYNAME, + # 5 ZPERSON.ZDISPLAYNAME for person in c: pk = person[0] @@ -1429,12 +1472,41 @@ class PhotosDB: "facecount": person[3], "keyface": person[4], "displayname": person[5], + "photo_uuid": None, + "keyface_uuid": None, } try: self._dbpersons_fullname[fullname].append(pk) except KeyError: self._dbpersons_fullname[fullname] = [pk] + # get info on keyface -- some photos have null keyface so can't do a single query + # (at least not with my SQL skills) + c.execute( + """ SELECT + ZPERSON.Z_PK, + ZPERSON.ZKEYFACE, + ZGENERICASSET.ZUUID, + ZDETECTEDFACE.ZUUID + FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET + WHERE ZDETECTEDFACE.Z_PK = ZPERSON.ZKEYFACE AND + ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK + """ + ) + + # 0 ZPERSON.Z_PK, + # 1 ZPERSON.ZKEYFACE, + # 2 ZGENERICASSET.ZUUID, + # 3 ZDETECTEDFACE.ZUUID + + for person in c: + pk = person[0] + try: + self._dbpersons_pk[pk]["photo_uuid"] = person[2] + self._dbpersons_pk[pk]["keyface_uuid"] = person[3] + except KeyError: + logging.debug(f"Unexpected KeyError _dbpersons_pk[{pk}]") + # get information on detected faces c.execute( """ SELECT @@ -1442,7 +1514,7 @@ class PhotosDB: ZGENERICASSET.ZUUID FROM ZPERSON, ZDETECTEDFACE, ZGENERICASSET WHERE ZDETECTEDFACE.ZPERSON = ZPERSON.Z_PK AND - ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK; + ZDETECTEDFACE.ZASSET = ZGENERICASSET.Z_PK """ ) @@ -1474,7 +1546,7 @@ class PhotosDB: """ SELECT ZGENERICALBUM.ZUUID, ZGENERICASSET.ZUUID, - Z_26ASSETS.Z_FOK_34ASSETS + Z_26ASSETS.Z_FOK_34ASSETS FROM ZGENERICASSET JOIN Z_26ASSETS ON Z_26ASSETS.Z_34ASSETS = ZGENERICASSET.Z_PK JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS @@ -1483,7 +1555,7 @@ class PhotosDB: # 0 ZGENERICALBUM.ZUUID, # 1 ZGENERICASSET.ZUUID, - # 2 Z_26ASSETS.Z_FOK_34ASSETS + # 2 Z_26ASSETS.Z_FOK_34ASSETS for album in c: # store by uuid in _dbalbums_uuid and by album in _dbalbums_album @@ -1633,15 +1705,15 @@ class PhotosDB: ZGENERICASSET.ZCLOUDBATCHPUBLISHDATE, ZGENERICASSET.ZKIND, ZGENERICASSET.ZUNIFORMTYPEIDENTIFIER, - ZGENERICASSET.ZAVALANCHEUUID, - ZGENERICASSET.ZAVALANCHEPICKTYPE, + ZGENERICASSET.ZAVALANCHEUUID, + ZGENERICASSET.ZAVALANCHEPICKTYPE, ZGENERICASSET.ZKINDSUBTYPE, ZGENERICASSET.ZCUSTOMRENDEREDVALUE, ZADDITIONALASSETATTRIBUTES.ZCAMERACAPTUREDEVICE, ZGENERICASSET.ZCLOUDASSETGUID, ZADDITIONALASSETATTRIBUTES.ZREVERSELOCATIONDATA, ZGENERICASSET.ZMOMENT, - ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE, + ZADDITIONALASSETATTRIBUTES.ZORIGINALRESOURCECHOICE, ZGENERICASSET.ZTRASHEDSTATE, ZGENERICASSET.ZHEIGHT, ZGENERICASSET.ZWIDTH, @@ -2437,7 +2509,11 @@ class PhotosDB: for person in persons: if person in self._dbpersons_fullname: for pk in self._dbpersons_fullname[person]: - person_set.update(self._dbfaces_pk[pk]) + try: + person_set.update(self._dbfaces_pk[pk]) + except KeyError: + # some persons have zero photos so they won't be in _dbfaces_pk + pass else: logging.debug(f"Could not find person '{person}' in database") photos_sets.append(person_set) @@ -2476,6 +2552,42 @@ class PhotosDB: return photoinfo + def get_photo(self, uuid): + """ Returns a single photo matching uuid + + Arguments: + uuid: the UUID of photo to get + + Returns: + PhotoInfo instance for photo with UUID matching uuid or None if no match + """ + try: + return PhotoInfo(db=self, uuid=uuid, info=self._dbphotos[uuid]) + except KeyError: + return None + + # TODO: add to docs and test + def photos_by_uuid(self, uuids): + """ Returns a list of photos with UUID in uuids. + Does not generate error if invalid or missing UUID passed. + This is faster than using PhotosDB.photos if you have list of UUIDs. + Returns photos regardless of intrash state. + + Arguments: + uuid: list of UUIDs of photos to get + + Returns: + list of PhotoInfo instance for photo with UUID matching uuid or [] if no match + """ + photos = [] + for uuid in uuids: + try: + photos.append(PhotoInfo(db=self, uuid=uuid, info=self._dbphotos[uuid])) + except KeyError: + # ignore missing/invlaid UUID + pass + return photos + def __repr__(self): return f"osxphotos.{self.__class__.__name__}(dbfile='{self.db_path}')" diff --git a/tests/Test-10.14.6.photoslibrary/database/RKVersion_searchIndexText.skindex b/tests/Test-10.14.6.photoslibrary/database/RKVersion_searchIndexText.skindex index f16fff11..0befdb5e 100644 Binary files a/tests/Test-10.14.6.photoslibrary/database/RKVersion_searchIndexText.skindex and b/tests/Test-10.14.6.photoslibrary/database/RKVersion_searchIndexText.skindex differ diff --git a/tests/Test-10.14.6.photoslibrary/database/photos.db b/tests/Test-10.14.6.photoslibrary/database/photos.db index cdabc0ac..86e1eb95 100644 Binary files a/tests/Test-10.14.6.photoslibrary/database/photos.db and b/tests/Test-10.14.6.photoslibrary/database/photos.db differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist index 2c06b90f..c116163f 100644 --- a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist +++ b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist @@ -3,8 +3,8 @@ PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate - 2020-04-25T23:54:43Z + 2020-07-16T04:41:20Z PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate - 2020-07-06T16:39:04Z + 2020-07-16T04:41:20Z diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/liveupdate-photosgraph.graphdb b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/liveupdate-photosgraph.graphdb index 20f03954..229d7b37 100644 Binary files a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/liveupdate-photosgraph.graphdb and b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/liveupdate-photosgraph.graphdb differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb index 7d70f7bd..c927d1de 100644 Binary files a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb and b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/2E578BF2-718A-43E1-81BA-80AC61004DCF.cmap b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/2E578BF2-718A-43E1-81BA-80AC61004DCF.cmap deleted file mode 100644 index 4aaf1638..00000000 Binary files a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/2E578BF2-718A-43E1-81BA-80AC61004DCF.cmap and /dev/null differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/C7589FFF-A378-4059-ABDC-19C4316A8B69.cmap b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/314037FD-9637-4CB2-840D-EB3DD8EE3918.cmap similarity index 98% rename from tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/C7589FFF-A378-4059-ABDC-19C4316A8B69.cmap rename to tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/314037FD-9637-4CB2-840D-EB3DD8EE3918.cmap index 1d6b6446..1f4aaba7 100644 Binary files a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/C7589FFF-A378-4059-ABDC-19C4316A8B69.cmap and b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/314037FD-9637-4CB2-840D-EB3DD8EE3918.cmap differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/AlgoFaceClusterCache.data b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/AlgoFaceClusterCache.data index 1f14d535..46f753f1 100644 Binary files a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/AlgoFaceClusterCache.data and b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/AlgoFaceClusterCache.data differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/D19BA43B-4C25-4930-ABA4-4F9C7796CF6E.cmap b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/D19BA43B-4C25-4930-ABA4-4F9C7796CF6E.cmap new file mode 100644 index 00000000..43ebcf6f Binary files /dev/null and b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/D19BA43B-4C25-4930-ABA4-4F9C7796CF6E.cmap differ diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/faceWorkerState.plist b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/faceWorkerState.plist index 736db69d..d3a45dcf 100644 --- a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/faceWorkerState.plist +++ b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/VisionService/faceWorkerState.plist @@ -3,7 +3,7 @@ IncrementalPersonProcessingStage - 0 + 4 PersonBuilderLastMinimumFaceGroupSizeForCreatingMergeCandidates 15 PersonBuilderMergeCandidatesEnabled diff --git a/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist b/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist index a17f4bfd..21b854e6 100644 --- a/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist +++ b/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist @@ -11,6 +11,6 @@ PLLastRevGeoForcedProviderOutOfDateCheckVersionKey 1 PLLastRevGeoVerFileFetchDateKey - 2020-07-06T16:39:09Z + 2020-07-16T04:41:16Z diff --git a/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist b/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist index 7334451b..c9df3009 100644 --- a/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist +++ b/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist @@ -3,7 +3,7 @@ LastHistoryRowId - 664 + 707 LibraryBuildTag D8C4AAA1-3AB6-4A65-BEBD-99CC3E5D433E LibrarySchemaVersion diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist b/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist index dd219b43..a8cbdf41 100644 --- a/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist +++ b/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist @@ -9,7 +9,7 @@ HistoricalMarker LastHistoryRowId - 664 + 707 LibraryBuildTag D8C4AAA1-3AB6-4A65-BEBD-99CC3E5D433E LibrarySchemaVersion @@ -24,7 +24,7 @@ SnapshotCompletedDate 2019-07-27T13:16:43Z SnapshotLastValidated - 2020-07-06T16:39:02Z + 2020-07-16T04:41:16Z SnapshotTables diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFace/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFace/0000000000.lij index bfc7e6ea..e3c2adac 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFace/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFace/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceCrop/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceCrop/0000000000.lij new file mode 100644 index 00000000..060f2c71 Binary files /dev/null and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceCrop/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceGroup/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceGroup/0000000000.lij index ea33f762..5cca4c4f 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceGroup/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFaceGroup/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFacePrint/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFacePrint/0000000000.lij index fca406bf..14468c47 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFacePrint/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKFacePrint/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPerson/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPerson/0000000000.lij index 29ce3a59..f3b0a2a0 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPerson/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPerson/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPersonMergeCandidatePerson/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPersonMergeCandidatePerson/0000000000.lij index 94ff1216..aa747e74 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPersonMergeCandidatePerson/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKPersonMergeCandidatePerson/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij index 29a1beff..26652c8e 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij differ diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersionAnalysisState/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersionAnalysisState/0000000000.lij index 362411ae..9f6eaa3e 100644 Binary files a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersionAnalysisState/0000000000.lij and b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKVersionAnalysisState/0000000000.lij differ diff --git a/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-shm b/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-shm index c5ee28a9..70bdbd55 100644 Binary files a/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-wal b/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-wal index dd7a111b..148a8397 100644 Binary files a/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite.lock b/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite.lock index 654e61b9..96bac838 100644 --- a/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite.lock +++ b/tests/Test-10.15.5.photoslibrary/database/Photos.sqlite.lock @@ -7,7 +7,7 @@ hostuuid 9575E48B-8D5F-5654-ABAC-4431B1167324 pid - 1743 + 3125 processname photolibraryd uid diff --git a/tests/Test-10.15.5.photoslibrary/database/search/psi.sqlite b/tests/Test-10.15.5.photoslibrary/database/search/psi.sqlite index 1e04d109..3f06de8f 100644 Binary files a/tests/Test-10.15.5.photoslibrary/database/search/psi.sqlite and b/tests/Test-10.15.5.photoslibrary/database/search/psi.sqlite differ diff --git a/tests/Test-10.15.5.photoslibrary/database/search/zeroKeywords.data b/tests/Test-10.15.5.photoslibrary/database/search/zeroKeywords.data index 8f6208e3..5d03620c 100644 Binary files a/tests/Test-10.15.5.photoslibrary/database/search/zeroKeywords.data and b/tests/Test-10.15.5.photoslibrary/database/search/zeroKeywords.data differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm index 64549f0d..cedebe22 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-wal b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-wal index f4a44bf4..a7b2e264 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm index c86081de..027227fd 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal index 891a7c36..1dfac4fe 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm index a42cf7b6..55b5f8b3 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-wal b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-wal index 00799a13..4b43a04c 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm index 210117cf..960f24bf 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal index 96097a4d..6f88eabe 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm index b8726b14..02fdeb9f 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-wal b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-wal index 8642f789..05d5fb6f 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSPublicEventCache.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm index ce2f18a9..49a21280 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal index 8cc3bd3e..d2e08b8f 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb index bc28cd4b..6cdd833f 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb differ diff --git a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist index 735c11c1..8eb87588 100644 Binary files a/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist and b/tests/Test-10.15.5.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist differ diff --git a/tests/Test-10.15.5.photoslibrary/resources/journals/Asset-change.plj b/tests/Test-10.15.5.photoslibrary/resources/journals/Asset-change.plj index 47fc317c..a0f1aa26 100644 Binary files a/tests/Test-10.15.5.photoslibrary/resources/journals/Asset-change.plj and b/tests/Test-10.15.5.photoslibrary/resources/journals/Asset-change.plj differ diff --git a/tests/Test-10.15.5.photoslibrary/resources/journals/DetectedFace-change.plj b/tests/Test-10.15.5.photoslibrary/resources/journals/DetectedFace-change.plj index 44c762c2..c86a4796 100644 Binary files a/tests/Test-10.15.5.photoslibrary/resources/journals/DetectedFace-change.plj and b/tests/Test-10.15.5.photoslibrary/resources/journals/DetectedFace-change.plj differ diff --git a/tests/Test-10.15.5.photoslibrary/resources/journals/HistoryToken.plist b/tests/Test-10.15.5.photoslibrary/resources/journals/HistoryToken.plist index 1460656c..8b132c68 100644 Binary files a/tests/Test-10.15.5.photoslibrary/resources/journals/HistoryToken.plist and b/tests/Test-10.15.5.photoslibrary/resources/journals/HistoryToken.plist differ diff --git a/tests/Test-10.15.5.photoslibrary/resources/journals/Person-change.plj b/tests/Test-10.15.5.photoslibrary/resources/journals/Person-change.plj index 1d5b020f..bb5e8461 100644 Binary files a/tests/Test-10.15.5.photoslibrary/resources/journals/Person-change.plj and b/tests/Test-10.15.5.photoslibrary/resources/journals/Person-change.plj differ diff --git a/tests/test_catalina_10_15_4.py b/tests/test_catalina_10_15_4.py index 5e935e45..820febc3 100644 --- a/tests/test_catalina_10_15_4.py +++ b/tests/test_catalina_10_15_4.py @@ -25,7 +25,7 @@ ALBUMS = [ "Pumpkin Farm", "Test Album", "AlbumInFolder", - "Raw" + "Raw", ] # Note: there are 2 albums named "Test Album" for testing duplicate album names KEYWORDS_DICT = { "Kids": 4, @@ -110,14 +110,14 @@ def test_init4(): def test_init5(mocker): # test failed get_last_library_path import osxphotos - + def bad_library(): return None # get_last_library actually in utils but need to patch it in photosdb because it's imported into photosdb # because of the layout of photosdb/ need to patch it this way...don't really understand why, but it works mocker.patch("osxphotos.photosdb.photosdb.get_last_library_path", new=bad_library) - + with pytest.raises(Exception): assert osxphotos.PhotosDB() @@ -127,7 +127,7 @@ def test_db_len(): photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS - assert len(photosdb) == 12 + assert len(photosdb) == 12 def test_db_version(): @@ -379,7 +379,7 @@ def test_count(): photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos() - assert len(photos) == 12 + assert len(photos) == 12 def test_keyword_2(): @@ -782,7 +782,7 @@ def test_from_to_date(): photosdb = osxphotos.PhotosDB(PHOTOS_DB) photos = photosdb.photos(from_date=dt.datetime(2018, 10, 28)) - assert len(photos) ==6 + assert len(photos) == 6 photos = photosdb.photos(to_date=dt.datetime(2018, 10, 28)) assert len(photos) == 6 diff --git a/tests/test_catalina_10_15_5.py b/tests/test_catalina_10_15_5.py index aa1cbc2a..efbb2214 100644 --- a/tests/test_catalina_10_15_5.py +++ b/tests/test_catalina_10_15_5.py @@ -81,12 +81,13 @@ UUID_PUMPKIN_FARM = [ ] ALBUM_SORT_ORDER = [ -"1EB2B765-0765-43BA-A90C-0D0580E6172C", -"F12384F6-CD17-4151-ACBA-AE0E3688539E", -"D79B8D77-BFFC-460B-9312-034F2877D35B", + "1EB2B765-0765-43BA-A90C-0D0580E6172C", + "F12384F6-CD17-4151-ACBA-AE0E3688539E", + "D79B8D77-BFFC-460B-9312-034F2877D35B", ] ALBUM_KEY_PHOTO = "D79B8D77-BFFC-460B-9312-034F2877D35B" + def test_init1(): # test named argument import osxphotos @@ -223,6 +224,7 @@ def test_albums_as_dict(): assert albums["Pumpkin Farm"] == 3 assert albums == ALBUM_DICT + def test_album_sort_order(): import osxphotos @@ -233,6 +235,7 @@ def test_album_sort_order(): uuids = [p.uuid for p in photos] assert uuids == ALBUM_SORT_ORDER + def test_album_empty_album(): import osxphotos @@ -241,6 +244,7 @@ def test_album_empty_album(): photos = album.photos assert photos == [] + def test_attributes(): import datetime import osxphotos @@ -583,6 +587,7 @@ def test_album_folder_name(): photos = photosdb.photos(albums=["Pumpkin Farm"]) assert sorted(p.uuid for p in photos) == sorted(UUID_PUMPKIN_FARM) + def test_multi_person(): import osxphotos @@ -590,7 +595,8 @@ def test_multi_person(): photos = photosdb.photos(persons=["Katie", "Suzy"]) assert len(photos) == 3 - + + def test_get_db_path(): import osxphotos @@ -1068,4 +1074,3 @@ def test_date_modified_invalid(): assert len(photos) == 1 p = photos[0] assert p.date_modified is None - diff --git a/tests/test_cli.py b/tests/test_cli.py index e7b317de..322ff219 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -231,12 +231,18 @@ CLI_EXIFTOOL = { LABELS_JSON = { "labels": { - "Plant": 5, + "Plant": 7, + "Outdoor": 4, + "Sky": 3, "Tree": 2, - "Sky": 2, - "Outdoor": 2, "Art": 2, "Foliage": 2, + "People": 2, + "Agriculture": 2, + "Farm": 2, + "Food": 2, + "Vegetable": 2, + "Pumpkin": 2, "Waterways": 1, "River": 1, "Cloudy": 1, @@ -254,6 +260,10 @@ LABELS_JSON = { "Vase": 1, "Container": 1, "Camera": 1, + "Child": 1, + "Clothing": 1, + "Jeans": 1, + "Straw Hay": 1, } } @@ -971,7 +981,7 @@ def test_query_label_4(): ) assert result.exit_code == 0 json_got = json.loads(result.output) - assert len(json_got) == 6 + assert len(json_got) == 8 def test_query_deleted_deleted_only(): diff --git a/tests/test_export_catalina_10_15_1.py b/tests/test_export_catalina_10_15_1.py index 826a8969..a99ecf62 100644 --- a/tests/test_export_catalina_10_15_1.py +++ b/tests/test_export_catalina_10_15_1.py @@ -825,4 +825,3 @@ def test_xmp_sidecar_gps(): sorted(xmp_expected_lines), sorted(xmp_got_lines) ): assert line_expected == line_got - diff --git a/tests/test_incloud_catalina_10_15_1.py b/tests/test_incloud_catalina_10_15_1.py index 9e6913f1..7ca362be 100644 --- a/tests/test_incloud_catalina_10_15_1.py +++ b/tests/test_incloud_catalina_10_15_1.py @@ -57,4 +57,3 @@ def test_cloudasset_3(): photos = photosdb.photos(uuid=[UUID_DICT["not_cloudasset"]]) assert not photos[0].iscloudasset - diff --git a/tests/test_incloud_mojave_10_14_6.py b/tests/test_incloud_mojave_10_14_6.py index 630df102..ac13b6b8 100644 --- a/tests/test_incloud_mojave_10_14_6.py +++ b/tests/test_incloud_mojave_10_14_6.py @@ -57,4 +57,3 @@ def test_cloudasset_3(): photos = photosdb.photos(uuid=[UUID_DICT["not_cloudasset"]]) assert not photos[0].iscloudasset - diff --git a/tests/test_modified_date_catalina_10_15_1.py b/tests/test_modified_date_catalina_10_15_1.py index a4556284..5544e581 100644 --- a/tests/test_modified_date_catalina_10_15_1.py +++ b/tests/test_modified_date_catalina_10_15_1.py @@ -26,4 +26,3 @@ def test_not_modified(): photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photos = photosdb.photos(uuid=[UUID_DICT["not_modified"]]) assert photos[0].date_modified is None - diff --git a/tests/test_modified_date_mojave_10_14_6.py b/tests/test_modified_date_mojave_10_14_6.py index 9d4b0c0a..40569794 100644 --- a/tests/test_modified_date_mojave_10_14_6.py +++ b/tests/test_modified_date_mojave_10_14_6.py @@ -27,4 +27,3 @@ def test_modified(): # photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # photos = photosdb.photos(uuid=[UUID_DICT["not_modified"]]) # assert photos[0].date_modified is None - diff --git a/tests/test_mojave_10_14_6.py b/tests/test_mojave_10_14_6.py index 14f0389c..c47c6632 100644 --- a/tests/test_mojave_10_14_6.py +++ b/tests/test_mojave_10_14_6.py @@ -554,4 +554,3 @@ def test_date_modified_invalid(): assert len(photos) == 1 p = photos[0] assert p.date_modified is None - diff --git a/tests/test_personinfo.py b/tests/test_personinfo.py new file mode 100644 index 00000000..2c2108f3 --- /dev/null +++ b/tests/test_personinfo.py @@ -0,0 +1,150 @@ +""" Test PersonInfo class """ + +import pytest + +PHOTOS_DB_5 = "tests/Test-10.15.5.photoslibrary" +PHOTOS_DB_4 = "tests/Test-10.14.6.photoslibrary" + +UUID_DICT = { + "katie_5": "0FFCE0A2-BE93-4661-A783-957BE54072E4", + "katie_4": "D%zgor6TRmGng5V75UBy5A", +} +PHOTO_DICT = { + "katie_5": [ + "1EB2B765-0765-43BA-A90C-0D0580E6172C", + "F12384F6-CD17-4151-ACBA-AE0E3688539E", + "D79B8D77-BFFC-460B-9312-034F2877D35B", + ], + "katie_4": [ + "8SOE9s0XQVGsuq4ONohTng", + "HrK3ZQdlQ7qpDA0FgOYXLA", + "15uNd7%8RguTEgNPKHfTWw", + ], +} + +KEY_DICT = { + "katie_5": "F12384F6-CD17-4151-ACBA-AE0E3688539E", + "katie_4": "8SOE9s0XQVGsuq4ONohTng", +} + +STR_DICT = { + "katie_5": "PersonInfo(name=Katie, display_name=Katie, uuid=0FFCE0A2-BE93-4661-A783-957BE54072E4, facecount=3)", + "katie_4": "PersonInfo(name=Katie, display_name=Katie, uuid=D%zgor6TRmGng5V75UBy5A, facecount=3)", +} + +JSON_DICT = { + "katie_5": { + "uuid": "0FFCE0A2-BE93-4661-A783-957BE54072E4", + "name": "Katie", + "displayname": "Katie", + "keyface": 2, + "facecount": 3, + "keyphoto": "F12384F6-CD17-4151-ACBA-AE0E3688539E", + }, + "katie_4": { + "uuid": "D%zgor6TRmGng5V75UBy5A", + "name": "Katie", + "displayname": "Katie", + "keyface": 7, + "facecount": 3, + "keyphoto": "8SOE9s0XQVGsuq4ONohTng", + }, +} + + +@pytest.fixture +def photosdb5(): + import osxphotos + + return osxphotos.PhotosDB(dbfile=PHOTOS_DB_5) + + +@pytest.fixture +def photosdb4(): + import osxphotos + + return osxphotos.PhotosDB(dbfile=PHOTOS_DB_4) + + +def test_person_info_photosdb_v5(photosdb5): + """ Test PersonInfo object """ + import json + + test_key = "katie_5" + katie = [p for p in photosdb5.person_info if p.uuid == UUID_DICT[test_key]][0] + + assert katie.facecount == 3 + assert katie.name == "Katie" + assert katie.display_name == "Katie" + photos = katie.photos + assert len(photos) == 3 + uuid = [p.uuid for p in photos] + assert sorted(uuid) == sorted(PHOTO_DICT[test_key]) + assert str(katie) == STR_DICT[test_key] + assert json.loads(katie.json()) == JSON_DICT[test_key] + + +def test_person_info_photosinfo_v5(photosdb5): + """ Test PersonInfo object """ + import json + + test_key = "katie_5" + photo = photosdb5.photos(uuid=[KEY_DICT[test_key]])[0] + assert "Katie" in photo.persons + + person_info = photo.person_info + assert len(person_info) == 2 + + katie = [p for p in person_info if p.name == "Katie"][0] + + assert katie.facecount == 3 + assert katie.name == "Katie" + assert katie.display_name == "Katie" + photos = katie.photos + assert len(photos) == 3 + uuid = [p.uuid for p in photos] + assert sorted(uuid) == sorted(PHOTO_DICT[test_key]) + assert katie.keyphoto.uuid == KEY_DICT[test_key] + assert str(katie) == STR_DICT[test_key] + assert json.loads(katie.json()) == JSON_DICT[test_key] + + +def test_person_info_photosdb_v4(photosdb4): + """ Test PersonInfo object """ + import json + + test_key = "katie_4" + katie = [p for p in photosdb4.person_info if p.uuid == UUID_DICT[test_key]][0] + + assert katie.facecount == 3 + assert katie.name == "Katie" + assert katie.display_name == "Katie" + photos = katie.photos + assert len(photos) == 3 + uuid = [p.uuid for p in photos] + assert sorted(uuid) == sorted(PHOTO_DICT[test_key]) + assert katie.keyphoto.uuid == KEY_DICT[test_key] + assert json.loads(katie.json()) == JSON_DICT[test_key] + + +def test_person_info_photosinfo_v4(photosdb4): + """ Test PersonInfo object """ + import json + + test_key = "katie_4" + photo = photosdb4.photos(uuid=[KEY_DICT[test_key]])[0] + assert "Katie" in photo.persons + + person_info = photo.person_info + assert len(person_info) == 2 + + katie = [p for p in person_info if p.name == "Katie"][0] + assert katie.facecount == 3 + assert katie.name == "Katie" + assert katie.display_name == "Katie" + photos = katie.photos + assert len(photos) == 3 + uuid = [p.uuid for p in photos] + assert sorted(uuid) == sorted(PHOTO_DICT[test_key]) + assert katie.keyphoto.uuid == KEY_DICT[test_key] + assert json.loads(katie.json()) == JSON_DICT[test_key] diff --git a/tests/test_places_mojave_10_14_6.py b/tests/test_places_mojave_10_14_6.py index ad4e7945..ee980b9a 100644 --- a/tests/test_places_mojave_10_14_6.py +++ b/tests/test_places_mojave_10_14_6.py @@ -87,6 +87,7 @@ def test_place_str(): "field16=[], street_address=[], body_of_water=[])', country_code='GB')" ) + def test_place_as_dict(): # test PlaceInfo.as_dict() import osxphotos diff --git a/tests/test_search_info_10_15_5.py b/tests/test_search_info_10_15_5.py index c15e5c1d..0d277389 100644 --- a/tests/test_search_info_10_15_5.py +++ b/tests/test_search_info_10_15_5.py @@ -20,7 +20,17 @@ LABELS_DICT = { "Tree", ], # F12384F6-CD17-4151-ACBA-AE0E3688539E Pumkins1.jpg Can we carry this? Girls with pumpkins [] False - "F12384F6-CD17-4151-ACBA-AE0E3688539E": [], + "F12384F6-CD17-4151-ACBA-AE0E3688539E": [ + "Vegetable", + "Pumpkin", + "Farm", + "Food", + "Outdoor", + "Agriculture", + "People", + "Plant", + "Straw Hay", + ], # D79B8D77-BFFC-460B-9312-034F2877D35B Pumkins2.jpg I found one! Girl holding pumpkin [] False "D79B8D77-BFFC-460B-9312-034F2877D35B": [], # D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068 DSC03584.dng None RAW only [] False @@ -49,7 +59,20 @@ LABELS_DICT = { "Plant", ], # 1EB2B765-0765-43BA-A90C-0D0580E6172C Pumpkins3.jpg None Kids in pumpkin field [] False - "1EB2B765-0765-43BA-A90C-0D0580E6172C": [], + "1EB2B765-0765-43BA-A90C-0D0580E6172C": [ + "Child", + "Sky", + "Plant", + "People", + "Clothing", + "Jeans", + "Outdoor", + "Agriculture", + "Farm", + "Food", + "Vegetable", + "Pumpkin", + ], # DC99FBDD-7A52-4100-A5BB-344131646C30 St James Park.jpg St. James's Park None ['Tree', 'Plant', 'Waterways', 'River', 'Sky', 'Cloudy', 'Land', 'Water Body', 'Water', 'Outdoor'] False "DC99FBDD-7A52-4100-A5BB-344131646C30": [ "Tree", @@ -117,8 +140,33 @@ LABELS_NORMALIZED_DICT = { ], # D79B8D77-BFFC-460B-9312-034F2877D35B Pumkins2.jpg I found one! Girl holding pumpkin [] False "D79B8D77-BFFC-460B-9312-034F2877D35B": [], + # 1EB2B765-0765-43BA-A90C-0D0580E6172C Pumpkins3.jpg None Kids in pumpkin field [] False + "1EB2B765-0765-43BA-A90C-0D0580E6172C": [ + "child", + "sky", + "plant", + "people", + "clothing", + "jeans", + "outdoor", + "agriculture", + "farm", + "food", + "vegetable", + "pumpkin", + ], # F12384F6-CD17-4151-ACBA-AE0E3688539E Pumkins1.jpg Can we carry this? Girls with pumpkins [] False - "F12384F6-CD17-4151-ACBA-AE0E3688539E": [], + "F12384F6-CD17-4151-ACBA-AE0E3688539E": [ + "vegetable", + "pumpkin", + "farm", + "food", + "outdoor", + "agriculture", + "people", + "plant", + "straw hay", + ], # A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C Pumpkins4.jpg Pumpkin heads None [] True "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C": [], } @@ -155,6 +203,16 @@ LABELS = [ "Vase", "Container", "Camera", + "Child", + "People", + "Clothing", + "Jeans", + "Agriculture", + "Farm", + "Food", + "Vegetable", + "Pumpkin", + "Straw Hay", ] LABELS_NORMALIZED = [ @@ -181,15 +239,31 @@ LABELS_NORMALIZED = [ "vase", "container", "camera", + "child", + "people", + "clothing", + "jeans", + "agriculture", + "farm", + "food", + "vegetable", + "pumpkin", + "straw hay", ] LABELS_AS_DICT = { - "Plant": 5, + "Plant": 7, + "Outdoor": 4, + "Sky": 3, "Tree": 2, - "Sky": 2, - "Outdoor": 2, "Art": 2, "Foliage": 2, + "People": 2, + "Agriculture": 2, + "Farm": 2, + "Food": 2, + "Vegetable": 2, + "Pumpkin": 2, "Waterways": 1, "River": 1, "Cloudy": 1, @@ -207,15 +281,25 @@ LABELS_AS_DICT = { "Vase": 1, "Container": 1, "Camera": 1, + "Child": 1, + "Clothing": 1, + "Jeans": 1, + "Straw Hay": 1, } LABELS_NORMALIZED_AS_DICT = { - "plant": 5, + "plant": 7, + "outdoor": 4, + "sky": 3, "tree": 2, - "sky": 2, - "outdoor": 2, "art": 2, "foliage": 2, + "people": 2, + "agriculture": 2, + "farm": 2, + "food": 2, + "vegetable": 2, + "pumpkin": 2, "waterways": 1, "river": 1, "cloudy": 1, @@ -233,6 +317,10 @@ LABELS_NORMALIZED_AS_DICT = { "vase": 1, "container": 1, "camera": 1, + "child": 1, + "clothing": 1, + "jeans": 1, + "straw hay": 1, } diff --git a/tests/test_template.py b/tests/test_template.py index 1c634ccc..574dbc37 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -502,4 +502,3 @@ def test_subst_expand_inplace_3(): template, expand_inplace=True, inplace_sep="; " ) assert sorted(rendered) == sorted(expected) -