Added comments/likes, implements #214
This commit is contained in:
parent
4fe58bf2af
commit
23de6b5890
30
README.md
30
README.md
@ -21,6 +21,8 @@
|
|||||||
+ [ScoreInfo](#scoreinfo)
|
+ [ScoreInfo](#scoreinfo)
|
||||||
+ [PersonInfo](#personinfo)
|
+ [PersonInfo](#personinfo)
|
||||||
+ [FaceInfo](#faceinfo)
|
+ [FaceInfo](#faceinfo)
|
||||||
|
+ [CommentInfo](#commentinfo)
|
||||||
|
+ [LikeInfo](#likeinfo)
|
||||||
+ [Raw Photos](#raw-photos)
|
+ [Raw Photos](#raw-photos)
|
||||||
+ [Template Substitutions](#template-substitutions)
|
+ [Template Substitutions](#template-substitutions)
|
||||||
+ [Utility Functions](#utility-functions)
|
+ [Utility Functions](#utility-functions)
|
||||||
@ -539,6 +541,7 @@ Substitution Description
|
|||||||
{label} Image categorization label associated with a photo
|
{label} Image categorization label associated with a photo
|
||||||
(Photos 5 only)
|
(Photos 5 only)
|
||||||
{label_normalized} All lower case version of 'label' (Photos 5 only)
|
{label_normalized} All lower case version of 'label' (Photos 5 only)
|
||||||
|
{comment} Comment(s) on shared Photos; format is 'Person name:
|
||||||
```
|
```
|
||||||
|
|
||||||
Example: export all photos to ~/Desktop/export group in folders by date created
|
Example: export all photos to ~/Desktop/export group in folders by date created
|
||||||
@ -1157,7 +1160,17 @@ Returns a [PlaceInfo](#PlaceInfo) object with reverse geolocation data or None i
|
|||||||
#### `shared`
|
#### `shared`
|
||||||
Returns True if photo is in a shared album, otherwise False.
|
Returns True if photo is in a shared album, otherwise False.
|
||||||
|
|
||||||
**Note**: *Only valid on Photos 5 / MacOS 10.15*; on Photos <= 4, returns None instead of True/False.
|
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns None instead of True/False.
|
||||||
|
|
||||||
|
#### `comments`
|
||||||
|
Returns list of [CommentInfo](#commentinfo) objects for comments on shared photos or empty list if no comments.
|
||||||
|
|
||||||
|
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns empty list.
|
||||||
|
|
||||||
|
#### `likes`
|
||||||
|
Returns list of [LikeInfo](#likeinfo) objects for likes on shared photos or empty list if no likes.
|
||||||
|
|
||||||
|
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns empty list.
|
||||||
|
|
||||||
#### `isphoto`
|
#### `isphoto`
|
||||||
Returns True if type is photo/still image, otherwise False
|
Returns True if type is photo/still image, otherwise False
|
||||||
@ -1746,6 +1759,21 @@ Returns a dictionary representation of the FaceInfo instance.
|
|||||||
#### `json()`
|
#### `json()`
|
||||||
Returns a JSON representation of the FaceInfo instance.
|
Returns a JSON representation of the FaceInfo instance.
|
||||||
|
|
||||||
|
### CommentInfo
|
||||||
|
[PhotoInfo.comments](#comments) returns a list of CommentInfo objects for comments on shared photos. (Photos 5/MacOS 10.15+ only). The list of CommentInfo objects will be sorted in ascending order by date comment was made. CommentInfo contains the following fields:
|
||||||
|
|
||||||
|
- `datetime`: `datetime.datetime`, date/time comment was made
|
||||||
|
- `user`: `str`, name of user who made the comment
|
||||||
|
- `ismine`: `bool`, True if comment was made by person who owns the Photos library being operated on
|
||||||
|
- `text`: `str`, text of the actual comment
|
||||||
|
|
||||||
|
### LikeInfo
|
||||||
|
[PhotoInfo.likes](#likes) returns a list of LikeInfo objects for "likes" on shared photos. (Photos 5/MacOS 10.15+ only). The list of LikeInfo objects will be sorted in ascending order by date like was made. LikeInfo contains the following fields:
|
||||||
|
|
||||||
|
- `datetime`: `datetime.datetime`, date/time like was made
|
||||||
|
- `user`: `str`, name of user who made the like
|
||||||
|
- `ismine`: `bool`, True if like was made by person who owns the Photos library being operated on
|
||||||
|
|
||||||
### Raw Photos
|
### Raw Photos
|
||||||
Handling raw photos in `osxphotos` requires a bit of extra work. Raw photos in Photos can be imported in two different ways: 1) a single raw photo with no associated JPEG image is imported 2) a raw+JPEG pair is imported -- two separate images with same file stem (e.g. `IMG_0001.CR2` and `IMG_001.JPG`) are imported.
|
Handling raw photos in `osxphotos` requires a bit of extra work. Raw photos in Photos can be imported in two different ways: 1) a single raw photo with no associated JPEG image is imported 2) a raw+JPEG pair is imported -- two separate images with same file stem (e.g. `IMG_0001.CR2` and `IMG_001.JPG`) are imported.
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ def main():
|
|||||||
if db:
|
if db:
|
||||||
print("loading database")
|
print("loading database")
|
||||||
tic = time.perf_counter()
|
tic = time.perf_counter()
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=db)
|
photosdb = osxphotos.PhotosDB(dbfile=db, verbose=print)
|
||||||
toc = time.perf_counter()
|
toc = time.perf_counter()
|
||||||
print(f"done: took {toc-tic} seconds")
|
print(f"done: took {toc-tic} seconds")
|
||||||
return photosdb
|
return photosdb
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import logging
|
|
||||||
|
|
||||||
from ._version import __version__
|
from ._version import __version__
|
||||||
from .photoinfo import PhotoInfo
|
from .photoinfo import PhotoInfo
|
||||||
from .photosdb import PhotosDB
|
from .photosdb import PhotosDB
|
||||||
|
from .photosdb._photosdb_process_comments import CommentInfo, LikeInfo
|
||||||
from .phototemplate import PhotoTemplate
|
from .phototemplate import PhotoTemplate
|
||||||
from .utils import _debug, _get_logger, _set_debug
|
from .utils import _debug, _get_logger, _set_debug
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.35.9"
|
__version__ = "0.36.0"
|
||||||
|
|
||||||
|
|||||||
17
osxphotos/photoinfo/_photoinfo_comments.py
Normal file
17
osxphotos/photoinfo/_photoinfo_comments.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
""" PhotoInfo methods to expose comments and likes for shared photos """
|
||||||
|
|
||||||
|
@property
|
||||||
|
def comments(self):
|
||||||
|
""" Returns list of Comment objects for any comments on the photo (sorted by date) """
|
||||||
|
try:
|
||||||
|
return self._db._db_comments_uuid[self.uuid]["comments"]
|
||||||
|
except:
|
||||||
|
return []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def likes(self):
|
||||||
|
""" Returns list of Like objects for any likes on the photo (sorted by date) """
|
||||||
|
try:
|
||||||
|
return self._db._db_comments_uuid[self.uuid]["likes"]
|
||||||
|
except:
|
||||||
|
return []
|
||||||
@ -59,6 +59,7 @@ class PhotoInfo:
|
|||||||
ExportResults,
|
ExportResults,
|
||||||
)
|
)
|
||||||
from ._photoinfo_scoreinfo import score, ScoreInfo
|
from ._photoinfo_scoreinfo import score, ScoreInfo
|
||||||
|
from ._photoinfo_comments import comments, likes
|
||||||
|
|
||||||
def __init__(self, db=None, uuid=None, info=None):
|
def __init__(self, db=None, uuid=None, info=None):
|
||||||
self._uuid = uuid
|
self._uuid = uuid
|
||||||
|
|||||||
150
osxphotos/photosdb/_photosdb_process_comments.py
Normal file
150
osxphotos/photosdb/_photosdb_process_comments.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
""" PhotosDB method for processing comments and likes on shared photos.
|
||||||
|
Do not import this module directly """
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from .._constants import _DB_TABLE_NAMES, _PHOTOS_4_VERSION, TIME_DELTA
|
||||||
|
from ..utils import _open_sql_file, normalize_unicode
|
||||||
|
|
||||||
|
|
||||||
|
def _process_comments(self):
|
||||||
|
""" load the comments and likes data from the database
|
||||||
|
this is a PhotosDB method that should be imported in
|
||||||
|
the PhotosDB class definition in photosdb.py
|
||||||
|
"""
|
||||||
|
self._db_hashed_person_id = {}
|
||||||
|
self._db_comments_uuid = {}
|
||||||
|
if self._db_version <= _PHOTOS_4_VERSION:
|
||||||
|
_process_comments_4(self)
|
||||||
|
else:
|
||||||
|
_process_comments_5(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CommentInfo:
|
||||||
|
""" Class for shared photo comments """
|
||||||
|
|
||||||
|
datetime: datetime.datetime
|
||||||
|
user: str
|
||||||
|
ismine: bool
|
||||||
|
text: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class LikeInfo:
|
||||||
|
""" Class for shared photo likes """
|
||||||
|
|
||||||
|
datetime: datetime.datetime
|
||||||
|
user: str
|
||||||
|
ismine: bool
|
||||||
|
|
||||||
|
|
||||||
|
# The following methods do not get imported into PhotosDB
|
||||||
|
# but will get called by _process_comments
|
||||||
|
def _process_comments_4(photosdb):
|
||||||
|
""" process comments and likes info for Photos <= 4
|
||||||
|
photosdb: PhotosDB instance """
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"Not implemented for database version {photosdb._db_version}."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _process_comments_5(photosdb):
|
||||||
|
""" process comments and likes info for Photos >= 5
|
||||||
|
photosdb: PhotosDB instance """
|
||||||
|
|
||||||
|
db = photosdb._tmp_db
|
||||||
|
|
||||||
|
asset_table = _DB_TABLE_NAMES[photosdb._photos_ver]["ASSET"]
|
||||||
|
|
||||||
|
(conn, cursor) = _open_sql_file(db)
|
||||||
|
|
||||||
|
results = conn.execute(
|
||||||
|
"""
|
||||||
|
SELECT DISTINCT
|
||||||
|
ZINVITEEHASHEDPERSONID,
|
||||||
|
ZINVITEEFIRSTNAME,
|
||||||
|
ZINVITEELASTNAME,
|
||||||
|
ZINVITEEFULLNAME
|
||||||
|
FROM
|
||||||
|
ZCLOUDSHAREDALBUMINVITATIONRECORD
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
# order of results
|
||||||
|
# 0: ZINVITEEHASHEDPERSONID,
|
||||||
|
# 1: ZINVITEEFIRSTNAME,
|
||||||
|
# 2: ZINVITEELASTNAME,
|
||||||
|
# 3: ZINVITEEFULLNAME
|
||||||
|
|
||||||
|
photosdb._db_hashed_person_id = {}
|
||||||
|
for row in results.fetchall():
|
||||||
|
person_id = row[0]
|
||||||
|
photosdb._db_hashed_person_id[person_id] = {
|
||||||
|
"first_name": normalize_unicode(row[1]),
|
||||||
|
"last_name": normalize_unicode(row[2]),
|
||||||
|
"full_name": normalize_unicode(row[3]),
|
||||||
|
}
|
||||||
|
|
||||||
|
results = conn.execute(
|
||||||
|
f"""
|
||||||
|
SELECT
|
||||||
|
{asset_table}.ZUUID, -- UUID of the photo
|
||||||
|
ZCLOUDSHAREDCOMMENT.ZISLIKE, -- comment is actually a "like"
|
||||||
|
ZCLOUDSHAREDCOMMENT.ZCOMMENTDATE, -- date of comment
|
||||||
|
ZCLOUDSHAREDCOMMENT.ZCOMMENTTEXT, -- text of comment
|
||||||
|
ZCLOUDSHAREDCOMMENT.ZCOMMENTERHASHEDPERSONID, -- hashed ID of person who made comment/like
|
||||||
|
ZCLOUDSHAREDCOMMENT.ZISMYCOMMENT -- is my (this user's) comment
|
||||||
|
FROM ZCLOUDSHAREDCOMMENT
|
||||||
|
JOIN {asset_table} ON
|
||||||
|
{asset_table}.Z_PK = ZCLOUDSHAREDCOMMENT.ZCOMMENTEDASSET
|
||||||
|
OR
|
||||||
|
{asset_table}.Z_PK = ZCLOUDSHAREDCOMMENT.ZLIKEDASSET
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
# order of results
|
||||||
|
# 0: ZGENERICASSET.ZUUID, -- UUID of the photo
|
||||||
|
# 1: ZCLOUDSHAREDCOMMENT.ZISLIKE, -- comment is actually a "like"
|
||||||
|
# 2: ZCLOUDSHAREDCOMMENT.ZCOMMENTDATE, -- date of comment
|
||||||
|
# 3: ZCLOUDSHAREDCOMMENT.ZCOMMENTTEXT, -- text of comment
|
||||||
|
# 4: ZCLOUDSHAREDCOMMENT.ZCOMMENTERHASHEDPERSONID, -- hashed ID of person who made comment/like
|
||||||
|
# 5: ZCLOUDSHAREDCOMMENT.ZISMYCOMMENT -- is my (this user's) comment
|
||||||
|
|
||||||
|
photosdb._db_comments_uuid = {}
|
||||||
|
for row in results:
|
||||||
|
uuid = row[0]
|
||||||
|
is_like = bool(row[1])
|
||||||
|
text = normalize_unicode(row[3])
|
||||||
|
try:
|
||||||
|
user_name = photosdb._db_hashed_person_id[row[4]]["full_name"]
|
||||||
|
except KeyError:
|
||||||
|
user_name = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
dt = datetime.datetime.fromtimestamp(row[2] + TIME_DELTA)
|
||||||
|
except:
|
||||||
|
dt = datetime.datetime(1970, 1, 1)
|
||||||
|
|
||||||
|
ismine = bool(row[5])
|
||||||
|
|
||||||
|
try:
|
||||||
|
db_comments = photosdb._db_comments_uuid[uuid]
|
||||||
|
except KeyError:
|
||||||
|
photosdb._db_comments_uuid[uuid] = {"likes": [], "comments": []}
|
||||||
|
db_comments = photosdb._db_comments_uuid[uuid]
|
||||||
|
|
||||||
|
if is_like:
|
||||||
|
db_comments["likes"].append(LikeInfo(dt, user_name, ismine))
|
||||||
|
elif text:
|
||||||
|
db_comments["comments"].append(CommentInfo(dt, user_name, ismine, text))
|
||||||
|
|
||||||
|
# sort results
|
||||||
|
for uuid in photosdb._db_comments_uuid:
|
||||||
|
if photosdb._db_comments_uuid[uuid]["likes"]:
|
||||||
|
photosdb._db_comments_uuid[uuid]["likes"].sort(key=lambda x: x.datetime)
|
||||||
|
if photosdb._db_comments_uuid[uuid]["comments"]:
|
||||||
|
photosdb._db_comments_uuid[uuid]["comments"].sort(key=lambda x: x.datetime)
|
||||||
|
|
||||||
|
conn.close()
|
||||||
@ -68,6 +68,7 @@ class PhotosDB:
|
|||||||
labels_normalized_as_dict,
|
labels_normalized_as_dict,
|
||||||
)
|
)
|
||||||
from ._photosdb_process_scoreinfo import _process_scoreinfo
|
from ._photosdb_process_scoreinfo import _process_scoreinfo
|
||||||
|
from ._photosdb_process_comments import _process_comments
|
||||||
|
|
||||||
def __init__(self, dbfile=None, verbose=None):
|
def __init__(self, dbfile=None, verbose=None):
|
||||||
""" Create a new PhotosDB object.
|
""" Create a new PhotosDB object.
|
||||||
@ -2278,6 +2279,10 @@ class PhotosDB:
|
|||||||
verbose("Processing computed aesthetic scores.")
|
verbose("Processing computed aesthetic scores.")
|
||||||
self._process_scoreinfo()
|
self._process_scoreinfo()
|
||||||
|
|
||||||
|
# process shared comments/likes
|
||||||
|
verbose("Processing comments and likes for shared photos.")
|
||||||
|
self._process_comments()
|
||||||
|
|
||||||
# done processing, dump debug data if requested
|
# done processing, dump debug data if requested
|
||||||
verbose("Done processing details from Photos library.")
|
verbose("Done processing details from Photos library.")
|
||||||
if _debug():
|
if _debug():
|
||||||
|
|||||||
@ -102,6 +102,7 @@ TEMPLATE_SUBSTITUTIONS_MULTI_VALUED = {
|
|||||||
"{person}": "Person(s) / face(s) in a photo",
|
"{person}": "Person(s) / face(s) in a photo",
|
||||||
"{label}": "Image categorization label associated with a photo (Photos 5 only)",
|
"{label}": "Image categorization label associated with a photo (Photos 5 only)",
|
||||||
"{label_normalized}": "All lower case version of 'label' (Photos 5 only)",
|
"{label_normalized}": "All lower case version of 'label' (Photos 5 only)",
|
||||||
|
"{comment}": "Comment(s) on shared Photos; format is 'Person name: comment text' (Photos 5 only)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Just the multi-valued substitution names without the braces
|
# Just the multi-valued substitution names without the braces
|
||||||
@ -244,14 +245,14 @@ class PhotoTemplate:
|
|||||||
# '2011/Album2/keyword1/person1',
|
# '2011/Album2/keyword1/person1',
|
||||||
# '2011/Album2/keyword2/person1',]
|
# '2011/Album2/keyword2/person1',]
|
||||||
|
|
||||||
rendered_strings = set([rendered])
|
rendered_strings = [rendered]
|
||||||
for field in MULTI_VALUE_SUBSTITUTIONS:
|
for field in MULTI_VALUE_SUBSTITUTIONS:
|
||||||
# Build a regex that matches only the field being processed
|
# Build a regex that matches only the field being processed
|
||||||
re_str = r"(?<!\\)\{(" + field + r")(,(([\w\-\%. ]{0,})))?\}"
|
re_str = r"(?<!\\)\{(" + field + r")(,(([\w\-\%. ]{0,})))?\}"
|
||||||
regex_multi = re.compile(re_str)
|
regex_multi = re.compile(re_str)
|
||||||
|
|
||||||
# holds each of the new rendered_strings, set() to avoid duplicates
|
# holds each of the new rendered_strings, dict to avoid repeats (dict.keys())
|
||||||
new_strings = set()
|
new_strings = {}
|
||||||
|
|
||||||
for str_template in rendered_strings:
|
for str_template in rendered_strings:
|
||||||
if regex_multi.search(str_template):
|
if regex_multi.search(str_template):
|
||||||
@ -307,10 +308,10 @@ class PhotoTemplate:
|
|||||||
self, none_str, get_func=lookup_template_value_multi
|
self, none_str, get_func=lookup_template_value_multi
|
||||||
)
|
)
|
||||||
new_string = regex_multi.sub(subst, str_template)
|
new_string = regex_multi.sub(subst, str_template)
|
||||||
new_strings.add(new_string)
|
new_strings[new_string] = 1
|
||||||
|
|
||||||
# update rendered_strings for the next field to process
|
# update rendered_strings for the next field to process
|
||||||
rendered_strings = new_strings
|
rendered_strings = list(new_strings.keys())
|
||||||
|
|
||||||
# find any {fields} that weren't replaced
|
# find any {fields} that weren't replaced
|
||||||
unmatched = []
|
unmatched = []
|
||||||
@ -637,6 +638,8 @@ class PhotoTemplate:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
values.append(album.title)
|
values.append(album.title)
|
||||||
|
elif field == "comment":
|
||||||
|
values = [f"{comment.user}: {comment.text}" for comment in self.photo.comments]
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unhandled template value: {field}")
|
raise ValueError(f"Unhandled template value: {field}")
|
||||||
|
|
||||||
|
|||||||
71
tests/test_comments.py
Normal file
71
tests/test_comments.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
""" Test comments and likes """
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
import osxphotos
|
||||||
|
from osxphotos import CommentInfo, LikeInfo
|
||||||
|
|
||||||
|
PHOTOS_DB = "tests/Test-Cloud-10.15.6.photoslibrary"
|
||||||
|
|
||||||
|
COMMENT_UUID_DICT = {
|
||||||
|
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||||
|
CommentInfo(
|
||||||
|
datetime=datetime.datetime(2020, 9, 18, 10, 28, 41, 552000),
|
||||||
|
user=None,
|
||||||
|
ismine=False,
|
||||||
|
text="Nice photo!",
|
||||||
|
),
|
||||||
|
CommentInfo(
|
||||||
|
datetime=datetime.datetime(2020, 9, 19, 22, 52, 20, 12014),
|
||||||
|
user=None,
|
||||||
|
ismine=True,
|
||||||
|
text="Wish I was back here!",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
"CCBE0EB9-AE9F-4479-BFFD-107042C75227": [],
|
||||||
|
"4E4944A0-3E5C-4028-9600-A8709F2FA1DB": [
|
||||||
|
CommentInfo(
|
||||||
|
datetime=datetime.datetime(2020, 9, 19, 22, 54, 12, 947978),
|
||||||
|
user=None,
|
||||||
|
ismine=True,
|
||||||
|
text="Nice trophy",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
LIKE_UUID_DICT = {
|
||||||
|
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||||
|
LikeInfo(
|
||||||
|
datetime=datetime.datetime(2020, 9, 18, 10, 28, 43, 335000),
|
||||||
|
user=None,
|
||||||
|
ismine=False,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
"CCBE0EB9-AE9F-4479-BFFD-107042C75227": [],
|
||||||
|
"65BADBD7-A50C-4956-96BA-1BB61155DA17": [
|
||||||
|
LikeInfo(
|
||||||
|
datetime=datetime.datetime(2020, 9, 18, 10, 28, 52, 570000),
|
||||||
|
user=None,
|
||||||
|
ismine=False,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def photosdb():
|
||||||
|
return osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
|
|
||||||
|
|
||||||
|
def test_comments(photosdb):
|
||||||
|
for uuid in COMMENT_UUID_DICT:
|
||||||
|
photo = photosdb.get_photo(uuid)
|
||||||
|
assert photo.comments == COMMENT_UUID_DICT[uuid]
|
||||||
|
|
||||||
|
|
||||||
|
def test_likes(photosdb):
|
||||||
|
for uuid in LIKE_UUID_DICT:
|
||||||
|
photo = photosdb.get_photo(uuid)
|
||||||
|
assert photo.likes == LIKE_UUID_DICT[uuid]
|
||||||
@ -8,6 +8,8 @@ PHOTOS_DB_15_1 = "./tests/Test-10.15.1.photoslibrary/database/photos.db"
|
|||||||
PHOTOS_DB_15_4 = "./tests/Test-10.15.4.photoslibrary/database/photos.db"
|
PHOTOS_DB_15_4 = "./tests/Test-10.15.4.photoslibrary/database/photos.db"
|
||||||
PHOTOS_DB_14_6 = "./tests/Test-10.14.6.photoslibrary/database/photos.db"
|
PHOTOS_DB_14_6 = "./tests/Test-10.14.6.photoslibrary/database/photos.db"
|
||||||
|
|
||||||
|
PHOTOS_DB_COMMENTS = "tests/Test-Cloud-10.15.6.photoslibrary"
|
||||||
|
|
||||||
UUID_DICT = {
|
UUID_DICT = {
|
||||||
"place_dc": "128FB4C6-0B16-4E7D-9108-FB2E90DA1546",
|
"place_dc": "128FB4C6-0B16-4E7D-9108-FB2E90DA1546",
|
||||||
"1_1_2": "1EB2B765-0765-43BA-A90C-0D0580E6172C",
|
"1_1_2": "1EB2B765-0765-43BA-A90C-0D0580E6172C",
|
||||||
@ -99,6 +101,15 @@ TEMPLATE_VALUES_DEU = {
|
|||||||
"{place.address.country_code}": "US",
|
"{place.address.country_code}": "US",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMENT_UUID_DICT = {
|
||||||
|
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||||
|
"None: Nice photo!",
|
||||||
|
"None: Wish I was back here!",
|
||||||
|
],
|
||||||
|
"CCBE0EB9-AE9F-4479-BFFD-107042C75227": ["_"],
|
||||||
|
"4E4944A0-3E5C-4028-9600-A8709F2FA1DB": ["None: Nice trophy"],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_lookup():
|
def test_lookup():
|
||||||
""" Test that a lookup is returned for every possible value """
|
""" Test that a lookup is returned for every possible value """
|
||||||
@ -502,3 +513,13 @@ def test_subst_expand_inplace_3():
|
|||||||
template, expand_inplace=True, inplace_sep="; "
|
template, expand_inplace=True, inplace_sep="; "
|
||||||
)
|
)
|
||||||
assert sorted(rendered) == sorted(expected)
|
assert sorted(rendered) == sorted(expected)
|
||||||
|
|
||||||
|
|
||||||
|
def test_comment():
|
||||||
|
import osxphotos
|
||||||
|
|
||||||
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_COMMENTS)
|
||||||
|
for uuid in COMMENT_UUID_DICT:
|
||||||
|
photo = photosdb.get_photo(uuid)
|
||||||
|
comments = photo.render_template("{comment}")
|
||||||
|
assert comments[0] == COMMENT_UUID_DICT[uuid]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user