From 4b4252a73c647da64727d369d5f0929e131fcdce Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Mon, 10 Apr 2023 20:49:19 -0700 Subject: [PATCH] Release 0.59.3 (#1053) --- .bumpversion.cfg | 2 +- API_README.md | 2 +- README.md | 4 +- docs/.buildinfo | 2 +- docs/_modules/index.html | 6 +- docs/_modules/osxphotos/albuminfo.html | 13 +- docs/_modules/osxphotos/photoexporter.html | 6 +- docs/_modules/osxphotos/photoinfo.html | 214 +++++++----------- .../_modules/osxphotos/photosdb/photosdb.html | 20 +- docs/_sources/template_help.rst.txt | 2 +- docs/_static/documentation_options.js | 2 +- docs/cli.html | 6 +- docs/genindex.html | 6 +- docs/index.html | 6 +- docs/overview.html | 6 +- docs/package_overview.html | 6 +- docs/py-modindex.html | 6 +- docs/reference.html | 32 ++- docs/search.html | 6 +- docs/searchindex.js | 2 +- docs/template_help.html | 8 +- docs/tutorial.html | 6 +- docsrc/source/template_help.rst | 2 +- osxphotos/_version.py | 2 +- osxphotos/docs/docs.zip | Bin 1466587 -> 1466350 bytes 25 files changed, 164 insertions(+), 203 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7e69d37f..e4b2d4e5 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.59.2 +current_version = 0.59.3 parse = (?P\d+)\.(?P\d+)\.(?P\d+) serialize = {major}.{minor}.{patch} diff --git a/API_README.md b/API_README.md index 9d0ec3bc..8c3cabe6 100644 --- a/API_README.md +++ b/API_README.md @@ -2456,7 +2456,7 @@ cog.out(get_template_field_table()) |{cr}|A carriage return: '\r'| |{crlf}|A carriage return + line feed: '\r\n'| |{tab}|:A tab: '\t'| -|{osxphotos_version}|The osxphotos version, e.g. '0.59.2'| +|{osxphotos_version}|The osxphotos version, e.g. '0.59.3'| |{osxphotos_cmd_line}|The full command line used to run osxphotos| |{album}|Album(s) photo is contained in| |{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder| diff --git a/README.md b/README.md index 597007f1..e93fd55a 100644 --- a/README.md +++ b/README.md @@ -2094,7 +2094,7 @@ Substitution Description {cr} A carriage return: '\r' {crlf} A carriage return + line feed: '\r\n' {tab} :A tab: '\t' -{osxphotos_version} The osxphotos version, e.g. '0.59.2' +{osxphotos_version} The osxphotos version, e.g. '0.59.3' {osxphotos_cmd_line} The full command line used to run osxphotos The following substitutions may result in multiple values. Thus if specified @@ -2581,7 +2581,7 @@ The following template field substitutions are availabe for use the templating s |{cr}|A carriage return: '\r'| |{crlf}|A carriage return + line feed: '\r\n'| |{tab}|:A tab: '\t'| -|{osxphotos_version}|The osxphotos version, e.g. '0.59.2'| +|{osxphotos_version}|The osxphotos version, e.g. '0.59.3'| |{osxphotos_cmd_line}|The full command line used to run osxphotos| |{album}|Album(s) photo is contained in| |{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder| diff --git a/docs/.buildinfo b/docs/.buildinfo index 11a25e39..b43e19e8 100644 --- a/docs/.buildinfo +++ b/docs/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 489a07f374a4d2bd9d01fa1d929e40e0 +config: c9decb5b6d226b940d02770bb432ca41 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_modules/index.html b/docs/_modules/index.html index eacabe5b..fb14b942 100644 --- a/docs/_modules/index.html +++ b/docs/_modules/index.html @@ -5,7 +5,7 @@ - Overview: module code - osxphotos 0.59.2 documentation + Overview: module code - osxphotos 0.59.3 documentation @@ -123,7 +123,7 @@
@@ -146,7 +146,7 @@
[docs] def asdict(self): - """Return album info as a dict""" + """Return album info as a dict; does not include photos""" dict_data = super().asdict() dict_data["title"] = self.title dict_data["folder_names"] = self.folder_names @@ -559,14 +557,13 @@ return self._photos
[docs] def asdict(self): - """Return import info as a dict""" + """Return import info as a dict; does not include photos""" return { "uuid": self.uuid, "creation_date": self.creation_date, "start_date": self.start_date, "end_date": self.end_date, "title": self.title, - "photos": [p.uuid for p in self.photos], }
def __bool__(self): diff --git a/docs/_modules/osxphotos/photoexporter.html b/docs/_modules/osxphotos/photoexporter.html index 75f4d670..bc5526f1 100644 --- a/docs/_modules/osxphotos/photoexporter.html +++ b/docs/_modules/osxphotos/photoexporter.html @@ -1718,10 +1718,10 @@ if not options.dry_run: warning_, error_ = self._write_exif_data(src, options=options) if warning_: - exiftool_results.exiftool_warning.append((dest, warning_)) + exiftool_results.exiftool_warning.append((str(dest), str(warning_))) if error_: - exiftool_results.exiftool_error.append((dest, error_)) - exiftool_results.error.append((dest, error_)) + exiftool_results.exiftool_error.append((str(dest), str(error_))) + exiftool_results.error.append((str(dest), str(error_))) exiftool_results.exif_updated.append(dest) exiftool_results.to_touch.append(dest) diff --git a/docs/_modules/osxphotos/photoinfo.html b/docs/_modules/osxphotos/photoinfo.html index 1264ab4c..b81de934 100644 --- a/docs/_modules/osxphotos/photoinfo.html +++ b/docs/_modules/osxphotos/photoinfo.html @@ -714,39 +714,26 @@ @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 + return [PersonInfo(db=self._db, pk=pk) for pk in self._info["persons"]] @property def face_info(self): """list of FaceInfo objects for faces in picture""" try: - return self._faceinfo - except AttributeError: - try: - faces = self._db._db_faceinfo_uuid[self._uuid] - self._faceinfo = [FaceInfo(db=self._db, pk=pk) for pk in faces] - except KeyError: - # no faces - self._faceinfo = [] - return self._faceinfo + faces = self._db._db_faceinfo_uuid[self._uuid] + self._faceinfo = [FaceInfo(db=self._db, pk=pk) for pk in faces] + except KeyError: + # no faces + self._faceinfo = [] + return self._faceinfo @property def moment_info(self): """Moment photo belongs to""" try: - return self._moment - except AttributeError: - try: - self._moment = MomentInfo(db=self._db, moment_pk=self._info["momentID"]) - except ValueError: - self._moment = None - return self._moment + return MomentInfo(db=self._db, moment_pk=self._info["momentID"]) + except ValueError: + return None @property def albums(self): @@ -763,65 +750,41 @@ @property def burst_albums(self): """If photo is burst photo, list of albums it is contained in as well as any albums the key photo is contained in, otherwise returns self.albums""" - try: - return self._burst_albums - except AttributeError: - burst_albums = list(self.albums) - for photo in self.burst_photos: - if photo.burst_key: - burst_albums.extend(photo.albums) - self._burst_albums = list(set(burst_albums)) - return self._burst_albums + burst_albums = list(self.albums) + for photo in self.burst_photos: + if photo.burst_key: + burst_albums.extend(photo.albums) + return list(set(burst_albums)) @property def album_info(self): """list of AlbumInfo objects representing albums the photo is contained in""" - try: - return self._album_info - except AttributeError: - album_uuids = self._get_album_uuids() - self._album_info = [ - AlbumInfo(db=self._db, uuid=album) for album in album_uuids - ] - return self._album_info + album_uuids = self._get_album_uuids() + return [AlbumInfo(db=self._db, uuid=album) for album in album_uuids] @property def burst_album_info(self): """If photo is a burst photo, returns list of AlbumInfo objects representing albums the photo is contained in as well as albums the burst key photo is contained in, otherwise returns self.album_info.""" - try: - return self._burst_album_info - except AttributeError: - burst_album_info = list(self.album_info) - for photo in self.burst_photos: - if photo.burst_key: - burst_album_info.extend(photo.album_info) - self._burst_album_info = list(set(burst_album_info)) - return self._burst_album_info + burst_album_info = list(self.album_info) + for photo in self.burst_photos: + if photo.burst_key: + burst_album_info.extend(photo.album_info) + return list(set(burst_album_info)) @property def import_info(self): """ImportInfo object representing import session for the photo or None if no import session""" - try: - return self._import_info - except AttributeError: - self._import_info = ( - ImportInfo(db=self._db, uuid=self._info["import_uuid"]) - if self._info["import_uuid"] is not None - else None - ) - return self._import_info + return ( + ImportInfo(db=self._db, uuid=self._info["import_uuid"]) + if self._info["import_uuid"] is not None + else None + ) @property def project_info(self): """list of AlbumInfo objects representing projects for the photo or None if no projects""" - try: - return self._project_info - except AttributeError: - project_uuids = self._get_album_uuids(project=True) - self._project_info = [ - ProjectInfo(db=self._db, uuid=album) for album in project_uuids - ] - return self._project_info + project_uuids = self._get_album_uuids(project=True) + return [ProjectInfo(db=self._db, uuid=album) for album in project_uuids] @property def keywords(self): @@ -835,8 +798,7 @@ # in this case, return None so result is the same as if title had never been set (which returns NULL) # issue #512 title = self._info["name"] - title = None if title == "" else title - return title + return None if title == "" else title @property def uuid(self): @@ -1974,41 +1936,31 @@ } return yaml.dump(info, sort_keys=False) -
[docs] def asdict(self): - """return dict representation""" +
[docs] def asdict(self, shallow: bool = True) -> dict[str, Any]: + """Return dict representation of PhotoInfo object. + + Args: + shallow: if True, return shallow representation (does not contain folder_info, person_info, etc.) + + Returns: + dict representation of PhotoInfo object + + Note: + The shallow representation is used internally by export as it contains only the subset of data needed for export. + """ - adjustments = self.adjustments.asdict() if self.adjustments else {} - album_info = [album.asdict() for album in self.album_info] - burst_album_info = [a.asdict() for a in self.burst_album_info] - burst_photos = [p.uuid for p in self.burst_photos] comments = [comment.asdict() for comment in self.comments] exif_info = dataclasses.asdict(self.exif_info) if self.exif_info else {} face_info = [face.asdict() for face in self.face_info] folders = {album.title: album.folder_names for album in self.album_info} - import_info = self.import_info.asdict() if self.import_info else {} likes = [like.asdict() for like in self.likes] - person_info = [p.asdict() for p in self.person_info] place = self.place.asdict() if self.place else {} - project_info = [p.asdict() for p in self.project_info] score = dataclasses.asdict(self.score) if self.score else {} - search_info = self.search_info.asdict() if self.search_info else {} - search_info_normalized = ( - self.search_info_normalized.asdict() if self.search_info_normalized else {} - ) - return { - "adjustments": adjustments, - "album_info": album_info, + dict_data = { "albums": self.albums, - "burst_album_info": burst_album_info, - "burst_albums": self.burst_albums, - "burst_default_pick": self.burst_default_pick, - "burst_key": self.burst_key, - "burst_photos": burst_photos, - "burst_selected": self.burst_selected, "burst": self.burst, "cloud_guid": self.cloud_guid, - "cloud_metadata": self.cloud_metadata, "cloud_owner_hashed_id": self.cloud_owner_hashed_id, "comments": comments, "date_added": self.date_added, @@ -2028,7 +1980,6 @@ "hdr": self.hdr, "height": self.height, "hidden": self.hidden, - "import_info": import_info, "incloud": self.incloud, "intrash": self.intrash, "iscloudasset": self.iscloudasset, @@ -2038,7 +1989,6 @@ "israw": self.israw, "isreference": self.isreference, "keywords": self.keywords, - "labels_normalized": self.labels_normalized, "labels": self.labels, "latitude": self._latitude, "library": self._db._library_path, @@ -2054,22 +2004,17 @@ "original_width": self.original_width, "owner": self.owner, "panorama": self.panorama, - "path_derivatives": self.path_derivatives, "path_edited_live_photo": self.path_edited_live_photo, "path_edited": self.path_edited, "path_live_photo": self.path_live_photo, "path_raw": self.path_raw, "path": self.path, - "person_info": person_info, "persons": self.persons, "place": place, "portrait": self.portrait, - "project_info": project_info, "raw_original": self.raw_original, "score": score, "screenshot": self.screenshot, - "search_info_normalized": search_info_normalized, - "search_info": search_info, "selfie": self.selfie, "shared": self.shared, "slow_mo": self.slow_mo, @@ -2083,9 +2028,40 @@ "uuid": self.uuid, "visible": self.visible, "width": self.width, - }
+ } -
[docs] def json(self, indent: int | None = None, shallow: bool = False) -> str: + # non-shallow keys + if not shallow: + dict_data["album_info"] = [album.asdict() for album in self.album_info] + dict_data["path_derivatives"] = self.path_derivatives + dict_data["adjustments"] = ( + self.adjustments.asdict() if self.adjustments else {} + ) + dict_data["burst_album_info"] = [a.asdict() for a in self.burst_album_info] + dict_data["burst_albums"] = self.burst_albums + dict_data["burst_default_pick"] = self.burst_default_pick + dict_data["burst_key"] = self.burst_key + dict_data["burst_photos"] = [p.uuid for p in self.burst_photos] + dict_data["burst_selected"] = self.burst_selected + dict_data["cloud_metadata"] = self.cloud_metadata + dict_data["import_info"] = ( + self.import_info.asdict() if self.import_info else {} + ) + dict_data["labels_normalized"] = self.labels_normalized + dict_data["person_info"] = [p.asdict() for p in self.person_info] + dict_data["project_info"] = [p.asdict() for p in self.project_info] + dict_data["search_info"] = ( + self.search_info.asdict() if self.search_info else {} + ) + dict_data["search_info_normalized"] = ( + self.search_info_normalized.asdict() + if self.search_info_normalized + else {} + ) + + return dict_data
+ +
[docs] def json(self, indent: int | None = None, shallow: bool = True) -> str: """Return JSON representation Args: @@ -2094,36 +2070,16 @@ Returns: JSON string + + Note: + The shallow representation is used internally by export as it contains only the subset of data needed for export. """ def default(o): if isinstance(o, (datetime.date, datetime.datetime)): return o.isoformat() - dict_data = self.asdict() - - if shallow: - # delete items that are not needed for shallow JSON - # these are removed to match behavior of osxphotos < 0.59.0 (See #999, #1039) - for key in [ - "adjustments", - "album_info", - "burst_album_info", - "burst_albums", - "burst_default_pick", - "burst_key", - "burst_photos", - "burst_selected", - "cloud_metadata", - "import_info", - "labels_normalized", - "path_derivatives", - "person_info", - "project_info", - "search_info_normalized", - "search_info", - ]: - del dict_data[key] + dict_data = self.asdict(shallow=True) if shallow else self.asdict(shallow=False) for k, v in dict_data.items(): # sort lists such as keywords so JSON is consistent @@ -2146,15 +2102,9 @@ if isinstance(o, (datetime.date, datetime.datetime)): return o.isoformat() - dict_data = self.asdict() + dict_data = self.asdict(shallow=True) - for k in [ - "album_info", - "burst_album_info", - "face_info", - "person_info", - "visible", - ]: + for k in ["face_info", "visible"]: del dict_data[k] for k, v in dict_data.items(): diff --git a/docs/_modules/osxphotos/photosdb/photosdb.html b/docs/_modules/osxphotos/photosdb/photosdb.html index 504667b9..2d4f8d7b 100644 --- a/docs/_modules/osxphotos/photosdb/photosdb.html +++ b/docs/_modules/osxphotos/photosdb/photosdb.html @@ -713,7 +713,8 @@ @property def album_info_shared(self): """return list of AlbumInfo objects for each shared album in the photos database - only valid for Photos 5; on Photos <= 4, prints warning and returns empty list""" + only valid for Photos 5; on Photos <= 4, prints warning and returns empty list + """ # if _dbalbum_details[key]["cloudownerhashedpersonid"] is not None, then it's a shared album try: return self._album_info_shared @@ -740,7 +741,8 @@ @property def albums_shared(self): """return list of shared albums found in photos database - only valid for Photos 5; on Photos <= 4, prints warning and returns empty list""" + only valid for Photos 5; on Photos <= 4, prints warning and returns empty list + """ # Could be more than one album with same name # Right now, they are treated as same album and photos are combined from albums with same name @@ -3250,7 +3252,6 @@ except KeyError: return None
- # TODO: add to docs and test
[docs] 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. @@ -3263,14 +3264,11 @@ 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
+ return [ + PhotoInfo(db=self, uuid=uuid, info=self._dbphotos[uuid]) + for uuid in uuids + if uuid in self._dbphotos + ]
[docs] def query(self, options: QueryOptions) -> List[PhotoInfo]: """Run a query against PhotosDB to extract the photos based on user supplied options diff --git a/docs/_sources/template_help.rst.txt b/docs/_sources/template_help.rst.txt index bf422478..37b327f8 100644 --- a/docs/_sources/template_help.rst.txt +++ b/docs/_sources/template_help.rst.txt @@ -361,7 +361,7 @@ Template Substitutions * - {tab} - :A tab: '\t' * - {osxphotos_version} - - The osxphotos version, e.g. '0.59.2' + - The osxphotos version, e.g. '0.59.3' * - {osxphotos_cmd_line} - The full command line used to run osxphotos * - {album} diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js index c57f0a02..0b5a3f9d 100644 --- a/docs/_static/documentation_options.js +++ b/docs/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.59.2', + VERSION: '0.59.3', LANGUAGE: 'en', COLLAPSE_INDEX: false, BUILDER: 'html', diff --git a/docs/cli.html b/docs/cli.html index c556e99e..ecb3db1e 100644 --- a/docs/cli.html +++ b/docs/cli.html @@ -6,7 +6,7 @@ - OSXPhotos Command Line Interface (CLI) - osxphotos 0.59.2 documentation + OSXPhotos Command Line Interface (CLI) - osxphotos 0.59.3 documentation @@ -124,7 +124,7 @@
@@ -147,7 +147,7 @@
@@ -145,7 +145,7 @@
@@ -147,7 +147,7 @@
@@ -147,7 +147,7 @@
@@ -147,7 +147,7 @@
@@ -145,7 +145,7 @@
@@ -147,7 +147,7 @@
@@ -144,7 +144,7 @@
@@ -147,7 +147,7 @@
@@ -147,7 +147,7 @@