diff --git a/README.md b/README.md index b8da6b78..8a7869a6 100644 --- a/README.md +++ b/README.md @@ -554,22 +554,50 @@ keywords = photosdb.keywords Returns a list of the keywords found in the Photos library +#### `albums` +```python +# assumes photosdb is a PhotosDB object (see above) +albums = photosdb.albums +``` + +Returns a list of [AlbumInfo](#AlbumInfo) objects representing albums in the database or empty list if there are no albums. See also [album_names](#album_names). + #### `album_names` ```python # assumes photosdb is a PhotosDB object (see above) -albums = photosdb.album_names +album_names = photosdb.album_names ``` -Returns a list of the albums found in the Photos library. +Returns a list of the album names found in the Photos library. **Note**: In Photos 5.0 (MacOS 10.15/Catalina), It is possible to have more than one album with the same name in Photos. Albums with duplicate names are treated as a single album and the photos in each are combined. For example, if you have two albums named "Wedding" and each has 2 photos, osxphotos will treat this as a single album named "Wedding" with 4 photos in it. #### `album_names_shared` -Returns list of shared albums found in photos database (e.g. albums shared via iCloud photo sharing) +Returns list of shared album names found in photos database (e.g. albums shared via iCloud photo sharing) **Note**: *Only valid for Photos 5 / MacOS 10.15*; on Photos <= 4, prints warning and returns empty list. +#### `folders` +```python +# assumes photosdb is a PhotosDB object (see above) +folders = photosdb.folders +``` + +Returns a list of [FolderInfo](#FolderInfo) objects representing top level folders in the database or empty list if there are no folders. See also [folder_names](#folder_names). + +**Note**: Currently folders is only implemented for Photos 5 (Catalina); will return empty list and output warning if called on earlier database versions. + +#### `folder_names` +```python +# assumes photosdb is a PhotosDB object (see above) +folder_names = photosdb.folder_names +``` + +Returns a list names of top level folder names in the database. + +**Note**: Currently folders is only implemented for Photos 5 (Catalina); will return empty list and output warning if called on earlier database versions. + #### `persons` ```python # assumes photosdb is a PhotosDB object (see above) @@ -928,6 +956,82 @@ If overwrite=False and increment=False, export will fail if destination file alr **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. +### AlbumInfo +PhotosDB.albums returns a list of AlbumInfo objects. Each AlbumInfo object represents a single album in the Photos library. + +#### `uuid` +Returns the universally unique identifier (uuid) of the album. This is how Photos keeps track of individual objects within the database. + +#### `title` +Returns the title or name of the album. + +#### `photos` +Returns a list of [PhotoInfo](#PhotoInfo) objects representing each photo contained in the album. + +#### `folder_list` +Returns a hierarchical list of [FolderInfo](#FolderInfo) objects representing the folders the album is contained in. For example, if album "AlbumInFolder" is in SubFolder1 of Folder1 as illustrated below, would return a list of `FolderInfo` objects representing ["Folder1", "SubFolder2"] + +```txt +Photos Library +├── Folder1 +    ├── SubFolder1 +   ├── SubFolder2 +      └── AlbumInFolder +``` + +#### `folder_names` +Returns a hierarchical list of names of the folders the album is contained in. For example, if album is in SubFolder2 of Folder1 as illustrated below, would return ["Folder1", "SubFolder2"]. + +```txt +Photos Library +├── Folder1 +    ├── SubFolder1 +   ├── SubFolder2 +      └── AlbumInFolder +``` + +#### `parent` +Returns a [FolderInfo](#FolderInfo) object representing the albums parent folder or `None` if album is not a in a folder. + + +### FolderInfo +PhotosDB.folders returns a list of FolderInfo objects representing the top level folders in the library. Each FolderInfo object represents a single folder in the Photos library. + +#### `uuid` +Returns the universally unique identifier (uuid) of the folder. This is how Photos keeps track of individual objects within the database. + +#### `title` +Returns the title or name of the folder. + +#### `albums` +Returns a list of [AlbumInfo](#AlbumInfo) objects representing each album contained in the folder. + +#### `folders` +Returns a list of [FolderInfo](#FolderInfo) objects representing the sub-folders of the folder. + +#### `parent` +Returns a [FolderInfo](#FolderInfo) object representing the folder's parent folder or `None` if album is not a in a folder. + +**Note**: FolderInfo and AlbumInfo objects effectively work as a linked list. The children of a folder are contained in `folders` and `albums` and the parent object of both `AlbumInfo` and `FolderInfo` is represented by `parent`. For example: + +```python +>>> import osxphotos +>>> photosdb = osxphotos.PhotosDB() +>>> photosdb.folders +[] +>>> photosdb.folders[0].title +'Folder1' +>>> photosdb.folders[0].folders[1].title +'SubFolder2' +>>> photosdb.folders[0].folders[1].albums[0].title +'AlbumInFolder' +>>> photosdb.folders[0].folders[1].albums[0].parent.title +'SubFolder2' +>>> photosdb.folders[0].folders[1].albums[0].parent.albums[0].title +'AlbumInFolder' +``` + + ### PlaceInfo [PhotoInfo.place](#place) returns a PlaceInfo object if the photo contains valid reverse geolocation information. PlaceInfo has the following properties. diff --git a/osxphotos/_version.py b/osxphotos/_version.py index 3936fd64..230f175f 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.26.1" +__version__ = "0.27.0" diff --git a/osxphotos/albuminfo.py b/osxphotos/albuminfo.py index 5ea2e7fc..ac619fa4 100644 --- a/osxphotos/albuminfo.py +++ b/osxphotos/albuminfo.py @@ -10,7 +10,9 @@ Represents a single Folder in the Photos library and provides access to the fold PhotosDB.folders() returns a list of FolderInfo objects """ -from ._constants import _PHOTOS_5_ALBUM_KIND, _PHOTOS_5_FOLDER_KIND +import logging + +from ._constants import _PHOTOS_5_ALBUM_KIND, _PHOTOS_5_FOLDER_KIND, _PHOTOS_5_VERSION class AlbumInfo: @@ -50,6 +52,11 @@ class AlbumInfo: the folder list is in form: ["Top level folder", "sub folder 1", "sub folder 2", ...] returns empty list if album is not in any folders """ + + if self._db._db_version < _PHOTOS_5_VERSION: + logging.warning("Folders not yet implemented for this DB version") + return [] + try: return self._folder_names except AttributeError: @@ -57,11 +64,16 @@ class AlbumInfo: return self._folder_names @property - def folders(self): + def folder_list(self): """ return hierarchical list of folders the album is contained in as list of FolderInfo objects in form ["Top level folder", "sub folder 1", "sub folder 2", ...] returns empty list if album is not in any folders """ + + if self._db._db_version < _PHOTOS_5_VERSION: + logging.warning("Folders not yet implemented for this DB version") + return [] + try: return self._folders except AttributeError: @@ -71,6 +83,10 @@ class AlbumInfo: @property def parent(self): """ returns FolderInfo object for parent folder or None if no parent (e.g. top-level album) """ + if self._db._db_version < _PHOTOS_5_VERSION: + logging.warning("Folders not yet implemented for this DB version") + return None + try: return self._parent except AttributeError: diff --git a/osxphotos/photosdb.py b/osxphotos/photosdb.py index f39b0213..3d3335f4 100644 --- a/osxphotos/photosdb.py +++ b/osxphotos/photosdb.py @@ -343,7 +343,8 @@ class PhotosDB: def folders(self): """ return list of top-level folders in the photos database """ if self._db_version < _PHOTOS_5_VERSION: - raise AttributeError("Not yet implemented for this DB version") + logging.warning("Folders not yet implemented for this DB version") + return [] folders = [ FolderInfo(db=self, uuid=album) @@ -354,6 +355,23 @@ class PhotosDB: ] return folders + @property + def folder_names(self): + """ return list of top-level folder names in the photos database """ + if self._db_version < _PHOTOS_5_VERSION: + logging.warning("Folders not yet implemented for this DB version") + return [] + + folder_names = [ + detail["title"] + for detail in self._dbalbum_details.values() + if detail["intrash"] == 0 + and detail["kind"] == _PHOTOS_5_FOLDER_KIND + and detail["parentfolder"] == self._folder_root_pk + ] + return folder_names + + @property def albums(self): """ return list of AlbumInfo objects for each album in the photos database """ @@ -362,6 +380,7 @@ class PhotosDB: AlbumInfo(db=self, uuid=album) for album in self._dbalbums_album.keys() if self._dbalbum_details[album]["cloudownerhashedpersonid"] is None + and self._dbalbum_details[album]["intrash"] == 0 ] return albums @@ -381,6 +400,7 @@ class PhotosDB: AlbumInfo(db=self, uuid=album) for album in self._dbalbums_album.keys() if self._dbalbum_details[album]["cloudownerhashedpersonid"] is not None + and self._dbalbum_details[album]["intrash"] == 0 ] return albums_shared @@ -395,6 +415,7 @@ class PhotosDB: self._dbalbum_details[album]["title"] for album in self._dbalbums_album.keys() if self._dbalbum_details[album]["cloudownerhashedpersonid"] is None + and self._dbalbum_details[album]["intrash"] == 0 } return list(albums) @@ -418,6 +439,7 @@ class PhotosDB: self._dbalbum_details[album]["title"] for album in self._dbalbums_album.keys() if self._dbalbum_details[album]["cloudownerhashedpersonid"] is not None + and self._dbalbum_details[album]["intrash"] == 0 } return list(albums) diff --git a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite index ea66a287..3c834967 100644 Binary files a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite and b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite differ diff --git a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-shm b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-shm index 0d6390ee..e1585aeb 100644 Binary files a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-wal b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-wal index d6236f10..b1960e48 100644 Binary files a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-wal and b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite-wal differ diff --git a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite.lock b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite.lock index 217f6f2a..52712080 100644 --- a/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite.lock +++ b/tests/Test-10.15.4.photoslibrary/database/Photos.sqlite.lock @@ -7,7 +7,7 @@ hostuuid 9575E48B-8D5F-5654-ABAC-4431B1167324 pid - 1440 + 3212 processname photolibraryd uid diff --git a/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite b/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite index 0b05989d..0fe0beec 100644 Binary files a/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite and b/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite differ diff --git a/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite-shm b/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite-shm index 94eaa955..de8eca04 100644 Binary files a/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/database/search/psi.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/database/search/zeroKeywords.data b/tests/Test-10.15.4.photoslibrary/database/search/zeroKeywords.data index 67e4249a..ca7a6f09 100644 Binary files a/tests/Test-10.15.4.photoslibrary/database/search/zeroKeywords.data and b/tests/Test-10.15.4.photoslibrary/database/search/zeroKeywords.data differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.Photos/appPrivateData.plist b/tests/Test-10.15.4.photoslibrary/private/com.apple.Photos/appPrivateData.plist index dcb4bf3b..cb8ff0ae 100644 --- a/tests/Test-10.15.4.photoslibrary/private/com.apple.Photos/appPrivateData.plist +++ b/tests/Test-10.15.4.photoslibrary/private/com.apple.Photos/appPrivateData.plist @@ -6,7 +6,9 @@ ExpandedSidebarItemIdentifiers + 88A5F8B8-5B9A-43C7-BB85-3952B81580EB/L0/020 92D68107-B6C7-453B-96D2-97B0F26D5B8B/L0/020 + 29EF7A97-7E76-4D5F-A5E0-CC0A93E8524C/L0/020 Photos diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db b/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db index afebafd7..69a98fb3 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db and b/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm index 193b3574..771f125e 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm index 4dd987f7..1b559e69 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.AOI.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm index 983309ab..1d74065d 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal index 863e66e5..93252a9e 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm index 43966f3d..1ae819b4 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.ROI.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite index 24ae080e..4ab71e6c 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm index 68ffab73..af2a60d3 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal index 2026e9cf..53eb322e 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm index d5b25c8b..1d764f90 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal index 56f2957e..7e451c7e 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm index ab0c0af1..77f9a140 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal index 6095b980..45746915 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist index 501b60b6..63a62472 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGSearchComputationCache.plist differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist index 945a64bd..94406d68 100644 --- a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist +++ b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotoAnalysisServicePreferences.plist @@ -3,24 +3,24 @@ BackgroundHighlightCollection - 2020-04-04T17:34:35Z + 2020-04-11T20:00:25Z BackgroundHighlightEnrichment - 2020-04-04T17:34:34Z + 2020-04-11T20:00:25Z BackgroundJobAssetRevGeocode - 2020-04-04T20:16:33Z + 2020-04-11T20:00:25Z BackgroundJobSearch - 2020-04-04T17:34:35Z + 2020-04-11T20:00:25Z BackgroundPeopleSuggestion - 2020-04-04T17:34:34Z + 2020-04-11T20:00:24Z BackgroundUserBehaviorProcessor - 2020-04-04T13:56:56Z + 2020-04-11T20:00:25Z PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey - 2020-04-04T20:16:40Z + 2020-04-11T20:10:27Z PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate - 2020-04-04T13:56:49Z + 2020-04-11T20:00:24Z PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate - 2020-04-04T20:16:33Z + 2020-04-11T20:00:25Z SiriPortraitDonation - 2020-04-04T13:56:56Z + 2020-04-11T20:00:25Z diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb index 0f3f4275..64b2405b 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist index 4eddba28..9b379090 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/graph/changetoken.plist differ diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist index 742030cd..db8788e1 100644 --- a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist +++ b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist @@ -3,8 +3,8 @@ FaceIDModelLastGenerationKey - 2020-04-04T13:56:59Z + 2020-04-11T20:00:25Z LastContactClassificationKey - 2020-04-04T13:57:02Z + 2020-04-11T20:00:26Z diff --git a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin index 67284072..13f7d447 100644 Binary files a/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin and b/tests/Test-10.15.4.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin differ diff --git a/tests/Test-10.15.4.photoslibrary/resources/journals/Album-snapshot.plj b/tests/Test-10.15.4.photoslibrary/resources/journals/Album-snapshot.plj index 61d6f6bb..242008b2 100644 Binary files a/tests/Test-10.15.4.photoslibrary/resources/journals/Album-snapshot.plj and b/tests/Test-10.15.4.photoslibrary/resources/journals/Album-snapshot.plj differ diff --git a/tests/Test-10.15.4.photoslibrary/resources/journals/Album.plist b/tests/Test-10.15.4.photoslibrary/resources/journals/Album.plist index 4c0ce869..523b84b5 100644 --- a/tests/Test-10.15.4.photoslibrary/resources/journals/Album.plist +++ b/tests/Test-10.15.4.photoslibrary/resources/journals/Album.plist @@ -3,7 +3,7 @@ coalesceDate - 2019-12-08T18:06:37Z + 2020-04-11T19:26:12Z coalescePayloadVersion 1 currentPayloadVersion diff --git a/tests/Test-10.15.4.photoslibrary/resources/journals/Folder-snapshot.plj b/tests/Test-10.15.4.photoslibrary/resources/journals/Folder-snapshot.plj index d4b69d97..d1520b31 100644 Binary files a/tests/Test-10.15.4.photoslibrary/resources/journals/Folder-snapshot.plj and b/tests/Test-10.15.4.photoslibrary/resources/journals/Folder-snapshot.plj differ diff --git a/tests/Test-10.15.4.photoslibrary/resources/journals/Folder.plist b/tests/Test-10.15.4.photoslibrary/resources/journals/Folder.plist index 4c0ce869..523b84b5 100644 --- a/tests/Test-10.15.4.photoslibrary/resources/journals/Folder.plist +++ b/tests/Test-10.15.4.photoslibrary/resources/journals/Folder.plist @@ -3,7 +3,7 @@ coalesceDate - 2019-12-08T18:06:37Z + 2020-04-11T19:26:12Z coalescePayloadVersion 1 currentPayloadVersion diff --git a/tests/Test-10.15.4.photoslibrary/resources/journals/HistoryToken.plist b/tests/Test-10.15.4.photoslibrary/resources/journals/HistoryToken.plist index 53e278af..d19f3424 100644 Binary files a/tests/Test-10.15.4.photoslibrary/resources/journals/HistoryToken.plist and b/tests/Test-10.15.4.photoslibrary/resources/journals/HistoryToken.plist differ diff --git a/tests/test_albums_folders_catalina_10_15_4.py b/tests/test_albums_folders_catalina_10_15_4.py new file mode 100644 index 00000000..00afae11 --- /dev/null +++ b/tests/test_albums_folders_catalina_10_15_4.py @@ -0,0 +1,217 @@ +import pytest + +from osxphotos._constants import _UNKNOWN_PERSON + +PHOTOS_DB = "./tests/Test-10.15.4.photoslibrary/database/photos.db" + +TOP_LEVEL_FOLDERS = ["Folder1"] + +TOP_LEVEL_CHILDREN = ["SubFolder1", "SubFolder2"] + +FOLDER_ALBUM_DICT = {"Folder1": [], "SubFolder1": [], "SubFolder2": ["AlbumInFolder"]} + +ALBUM_NAMES = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album"] + +ALBUM_PARENT_DICT = { + "Pumpkin Farm": None, + "AlbumInFolder": "SubFolder2", + "Test Album": None, +} + +ALBUM_FOLDER_NAMES_DICT = { + "Pumpkin Farm": [], + "AlbumInFolder": ["Folder1", "SubFolder2"], + "Test Album": [], +} + +ALBUM_LEN_DICT = { + "Pumpkin Farm": 3, + "AlbumInFolder": 2, + "Test Album": 1, +} + +ALBUM_PHOTO_UUID_DICT = { + "Pumpkin Farm": [ + "F12384F6-CD17-4151-ACBA-AE0E3688539E", + "D79B8D77-BFFC-460B-9312-034F2877D35B", + "1EB2B765-0765-43BA-A90C-0D0580E6172C", + ], + "Test Album": [ + "F12384F6-CD17-4151-ACBA-AE0E3688539E", + "D79B8D77-BFFC-460B-9312-034F2877D35B", + ], + "AlbumInFolder": [ + "3DD2C897-F19E-4CA6-8C22-B027D5A71907", + "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51", + ], +} + +######### Test FolderInfo ########## + +def test_folders_1(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + assert len(folders) == 1 + + # check folder names + folder_names = [f.title for f in folders] + assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + +def test_folder_names(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # check folder names + folder_names = photosdb.folder_names + assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + + +def test_folders_len(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + assert len(folders[0]) == len(TOP_LEVEL_CHILDREN) + + +def test_folders_children(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + + # children of top level folder + children = folders[0].folders + children_names = [f.title for f in children] + assert sorted(children_names) == sorted(TOP_LEVEL_CHILDREN) + + for child in folders[0].folders: + # check valid children FolderInfo + assert child.parent + assert child.parent.uuid == folders[0].uuid + + # check folder names + folder_names = [f.title for f in folders] + assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + + +def test_folders_parent(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + + # parent of top level folder should be none + for folder in folders: + assert folder.parent is None + for child in folder.folders: + # children's parent uuid should match folder uuid + assert child.parent + assert child.parent.uuid == folder.uuid + + +def test_folders_albums(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + + for folder in folders: + name = folder.title + albums = [a.title for a in folder.albums] + assert sorted(albums) == sorted(FOLDER_ALBUM_DICT[name]) + for child in folder.folders: + name = child.title + albums = [a.title for a in child.albums] + assert sorted(albums) == sorted(FOLDER_ALBUM_DICT[name]) + +########## Test AlbumInfo ########## + +def test_albums_1(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + assert len(albums) == 4 + + # check names + album_names = [a.title for a in albums] + assert sorted(album_names) == sorted(ALBUM_NAMES) + + +def test_albums_parent(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + parent = album.parent.title if album.parent else None + assert parent == ALBUM_PARENT_DICT[album.title] + + +def test_albums_folder_names(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + folder_names = album.folder_names + assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] + + +def test_albums_folders(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + for album in albums: + folders = album.folder_list + folder_names = [f.title for f in folders] + assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] + + +def test_albums_len(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + assert len(album) == ALBUM_LEN_DICT[album.title] + + +def test_albums_photos(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + photos = album.photos + assert len(photos) == ALBUM_LEN_DICT[album.title] + assert len(photos) == len(album) + for photo in photos: + assert photo.uuid in ALBUM_PHOTO_UUID_DICT[album.title] + + diff --git a/tests/test_albums_folders_mojave_10_14_6.py b/tests/test_albums_folders_mojave_10_14_6.py new file mode 100644 index 00000000..d8f20424 --- /dev/null +++ b/tests/test_albums_folders_mojave_10_14_6.py @@ -0,0 +1,227 @@ +import pytest + +from osxphotos._constants import _UNKNOWN_PERSON + +PHOTOS_DB = "./tests/Test-10.14.6.photoslibrary/database/photos.db" + +# TOP_LEVEL_FOLDERS = ["Folder1"] + +# TOP_LEVEL_CHILDREN = ["SubFolder1", "SubFolder2"] + +# FOLDER_ALBUM_DICT = {"Folder1": [], "SubFolder1": [], "SubFolder2": ["AlbumInFolder"]} + +# ALBUM_NAMES = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album"] +ALBUM_NAMES = ["Pumpkin Farm", "Test Album", "Test Album (1)"] + +# ALBUM_PARENT_DICT = { +# "Pumpkin Farm": None, +# "AlbumInFolder": "SubFolder2", +# "Test Album": None, +# } + +# ALBUM_FOLDER_NAMES_DICT = { +# "Pumpkin Farm": [], +# "AlbumInFolder": ["Folder1", "SubFolder2"], +# "Test Album": [], +# } + +ALBUM_LEN_DICT = { + "Pumpkin Farm": 3, + "Test Album": 1, + "Test Album (1)": 1, + # "AlbumInFolder": 2, +} + +ALBUM_PHOTO_UUID_DICT = { + "Pumpkin Farm": ["HrK3ZQdlQ7qpDA0FgOYXLA","15uNd7%8RguTEgNPKHfTWw","8SOE9s0XQVGsuq4ONohTng"], + "Test Album": ["8SOE9s0XQVGsuq4ONohTng"], + "Test Album (1)": ["15uNd7%8RguTEgNPKHfTWw"], + # "AlbumInFolder": [ + # "3DD2C897-F19E-4CA6-8C22-B027D5A71907", + # "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51", + # ], +} + +######### Test FolderInfo ########## + + +def test_folders_1(caplog): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + folders = photosdb.folders + assert folders == [] + assert "Folders not yet implemented for this DB version" in caplog.text + + # # top level folders + # folders = photosdb.folders + # assert len(folders) == 1 + + # # check folder names + # folder_names = [f.title for f in folders] + # assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + +def test_folder_names(caplog): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # check folder names + folder_names = photosdb.folder_names + assert folder_names == [] + assert "Folders not yet implemented for this DB version" in caplog.text + # assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + +@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") +def test_folders_len(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + assert len(folders[0]) == len(TOP_LEVEL_CHILDREN) + + +@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") +def test_folders_children(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + + # children of top level folder + children = folders[0].folders + children_names = [f.title for f in children] + assert sorted(children_names) == sorted(TOP_LEVEL_CHILDREN) + + for child in folders[0].folders: + # check valid children FolderInfo + assert child.parent + assert child.parent.uuid == folders[0].uuid + + # check folder names + folder_names = [f.title for f in folders] + assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + + +@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") +def test_folders_parent(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + + # parent of top level folder should be none + for folder in folders: + assert folder.parent is None + for child in folder.folders: + # children's parent uuid should match folder uuid + assert child.parent + assert child.parent.uuid == folder.uuid + + +@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") +def test_folders_albums(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + # top level folders + folders = photosdb.folders + + for folder in folders: + name = folder.title + albums = [a.title for a in folder.albums] + assert sorted(albums) == sorted(FOLDER_ALBUM_DICT[name]) + for child in folder.folders: + name = child.title + albums = [a.title for a in child.albums] + assert sorted(albums) == sorted(FOLDER_ALBUM_DICT[name]) + + +########## Test AlbumInfo ########## + + +def test_albums_1(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + assert len(albums) == 3 + + # check names + album_names = [a.title for a in albums] + assert sorted(album_names) == sorted(ALBUM_NAMES) + + +def test_albums_parent(caplog): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + parent = album.parent.title if album.parent else None + assert "Folders not yet implemented for this DB version" in caplog.text + # assert parent == ALBUM_PARENT_DICT[album.title] + + +def test_albums_folder_names(caplog): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + folder_names = album.folder_names + assert "Folders not yet implemented for this DB version" in caplog.text + # assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] + + +def test_albums_folders(caplog): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + folders = album.folder_list + assert "Folders not yet implemented for this DB version" in caplog.text + # folder_names = [f.title for f in folders] + # assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] + + +def test_albums_len(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + assert len(album) == ALBUM_LEN_DICT[album.title] + + +def test_albums_photos(): + import osxphotos + + photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) + + albums = photosdb.albums + + for album in albums: + photos = album.photos + assert len(photos) == ALBUM_LEN_DICT[album.title] + assert len(photos) == len(album) + for photo in photos: + assert photo.uuid in ALBUM_PHOTO_UUID_DICT[album.title] diff --git a/tests/test_catalina_10_15_4.py b/tests/test_catalina_10_15_4.py index 74776ab3..e1a84034 100644 --- a/tests/test_catalina_10_15_4.py +++ b/tests/test_catalina_10_15_4.py @@ -24,6 +24,7 @@ PERSONS = ["Katie", "Suzy", "Maria", _UNKNOWN_PERSON] ALBUMS = [ "Pumpkin Farm", "Test Album", + "AlbumInFolder", ] # Note: there are 2 albums named "Test Album" for testing duplicate album names KEYWORDS_DICT = { "Kids": 4, @@ -40,6 +41,7 @@ PERSONS_DICT = {"Katie": 3, "Suzy": 2, "Maria": 1, _UNKNOWN_PERSON: 1} ALBUM_DICT = { "Pumpkin Farm": 3, "Test Album": 2, + "AlbumInFolder": 2, } # Note: there are 2 albums named "Test Album" for testing duplicate album names UUID_DICT = {