Added isreference property and --is-reference, #321

This commit is contained in:
Rhet Turnbull
2021-01-15 21:20:08 -08:00
parent 248c95237c
commit 651ed50a07
10 changed files with 191 additions and 265 deletions

View File

@@ -269,6 +269,9 @@ Options:
--no-comment Search for photos with no comments. --no-comment Search for photos with no comments.
--has-likes Search for photos that have likes. --has-likes Search for photos that have likes.
--no-likes Search for photos with no likes. --no-likes Search for photos with no likes.
--is-reference Search for photos that were imported as
referenced files (not copied into Photos
library).
--missing Export only photos missing from the Photos --missing Export only photos missing from the Photos
library; must be used with --download-missing. library; must be used with --download-missing.
--deleted Include photos from the 'Recently Deleted' --deleted Include photos from the 'Recently Deleted'
@@ -1601,6 +1604,9 @@ Returns list of [LikeInfo](#likeinfo) objects for likes on shared photos or empt
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns empty list. **Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns empty list.
#### `isreference`
Returns `True` if the original image file is a referenced file (imported without copying to the Photos library) otherwise returns `False`.
#### `isphoto` #### `isphoto`
Returns True if type is photo/still image, otherwise False Returns True if type is photo/still image, otherwise False

View File

@@ -674,6 +674,11 @@ def query_options(f):
o("--no-comment", is_flag=True, help="Search for photos with no comments."), o("--no-comment", is_flag=True, help="Search for photos with no comments."),
o("--has-likes", is_flag=True, help="Search for photos that have likes."), o("--has-likes", is_flag=True, help="Search for photos that have likes."),
o("--no-likes", is_flag=True, help="Search for photos with no likes."), o("--no-likes", is_flag=True, help="Search for photos with no likes."),
o(
"--is-reference",
is_flag=True,
help="Search for photos that were imported as referenced files (not copied into Photos library).",
),
] ]
for o in options[::-1]: for o in options[::-1]:
f = o(f) f = o(f)
@@ -1166,6 +1171,7 @@ def export(
exportdb, exportdb,
load_config, load_config,
save_config, save_config,
is_reference,
): ):
"""Export photos from the Photos database. """Export photos from the Photos database.
Export path DEST is required. Export path DEST is required.
@@ -1590,6 +1596,7 @@ def export(
no_comment=no_comment, no_comment=no_comment,
has_likes=has_likes, has_likes=has_likes,
no_likes=no_likes, no_likes=no_likes,
is_reference=is_reference,
) )
if photos: if photos:
@@ -1865,6 +1872,7 @@ def query(
no_comment, no_comment,
has_likes, has_likes,
no_likes, no_likes,
is_reference,
): ):
"""Query the Photos database using 1 or more search options; """Query the Photos database using 1 or more search options;
if more than one option is provided, they are treated as "AND" if more than one option is provided, they are treated as "AND"
@@ -1887,6 +1895,7 @@ def query(
from_date, from_date,
to_date, to_date,
label, label,
is_reference,
] ]
exclusive = [ exclusive = [
(favorite, not_favorite), (favorite, not_favorite),
@@ -2002,6 +2011,7 @@ def query(
no_comment=no_comment, no_comment=no_comment,
has_likes=has_likes, has_likes=has_likes,
no_likes=no_likes, no_likes=no_likes,
is_reference=is_reference,
) )
# below needed for to make CliRunner work for testing # below needed for to make CliRunner work for testing
@@ -2172,6 +2182,7 @@ def _query(
no_comment=False, no_comment=False,
has_likes=False, has_likes=False,
no_likes=False, no_likes=False,
is_reference=False,
): ):
"""Run a query against PhotosDB to extract the photos based on user supply criteria used by query and export commands """Run a query against PhotosDB to extract the photos based on user supply criteria used by query and export commands
@@ -2316,9 +2327,9 @@ def _query(
photos = [p for p in photos if not p.hidden] photos = [p for p in photos if not p.hidden]
if missing: if missing:
photos = [p for p in photos if p.ismissing] photos = [p for p in photos if not p.path]
elif not_missing: elif not_missing:
photos = [p for p in photos if not p.ismissing] photos = [p for p in photos if p.path]
if shared: if shared:
photos = [p for p in photos if p.shared] photos = [p for p in photos if p.shared]
@@ -2401,6 +2412,9 @@ def _query(
elif no_likes: elif no_likes:
photos = [p for p in photos if not p.likes] photos = [p for p in photos if not p.likes]
if is_reference:
photos = [p for p in photos if p.isreference]
return photos return photos
@@ -3760,5 +3774,6 @@ SOFTWARE.
click.echo(f"Source code available at: {OSXPHOTOS_URL}") click.echo(f"Source code available at: {OSXPHOTOS_URL}")
click.echo(license) click.echo(license)
if __name__ == "__main__": if __name__ == "__main__":
cli() # pylint: disable=no-value-for-parameter cli() # pylint: disable=no-value-for-parameter

View File

@@ -138,6 +138,7 @@ class PhotoInfo:
except AttributeError: except AttributeError:
self._path = None self._path = None
photopath = None photopath = None
# TODO: should path try to return path even if ismissing?
if self._info["isMissing"] == 1: if self._info["isMissing"] == 1:
return photopath # path would be meaningless until downloaded return photopath # path would be meaningless until downloaded
@@ -643,6 +644,11 @@ class PhotoInfo:
else: else:
return True if self._info["cloudAssetGUID"] is not None else False return True if self._info["cloudAssetGUID"] is not None else False
@property
def isreference(self):
""" Returns True if photo is a reference (not copied to the Photos library), otherwise False """
return self._info["isreference"]
@property @property
def burst(self): def burst(self):
""" Returns True if photo is part of a Burst photo set, otherwise False """ """ Returns True if photo is part of a Burst photo set, otherwise False """
@@ -1033,6 +1039,7 @@ class PhotoInfo:
"path_live_photo": self.path_live_photo, "path_live_photo": self.path_live_photo,
"iscloudasset": self.iscloudasset, "iscloudasset": self.iscloudasset,
"incloud": self.incloud, "incloud": self.incloud,
"isreference": self.isreference,
"date_modified": self.date_modified, "date_modified": self.date_modified,
"portrait": self.portrait, "portrait": self.portrait,
"screenshot": self.screenshot, "screenshot": self.screenshot,

View File

@@ -889,7 +889,8 @@ class PhotosDB:
RKMaster.fileSize, RKMaster.fileSize,
RKVersion.subType, RKVersion.subType,
RKVersion.inTrashDate, RKVersion.inTrashDate,
RKVersion.showInLibrary RKVersion.showInLibrary,
RKMaster.fileIsReference
FROM RKVersion, RKMaster FROM RKVersion, RKMaster
WHERE RKVersion.masterUuid = RKMaster.uuid""" WHERE RKVersion.masterUuid = RKMaster.uuid"""
) )
@@ -919,7 +920,8 @@ class PhotosDB:
RKMaster.originalFileSize, RKMaster.originalFileSize,
RKVersion.subType, RKVersion.subType,
RKVersion.inTrashDate, RKVersion.inTrashDate,
RKVersion.showInLibrary RKVersion.showInLibrary,
RKMaster.fileIsReference
FROM RKVersion, RKMaster FROM RKVersion, RKMaster
WHERE RKVersion.masterUuid = RKMaster.uuid""" WHERE RKVersion.masterUuid = RKMaster.uuid"""
) )
@@ -968,6 +970,7 @@ class PhotosDB:
# 40 RKVersion.subType # 40 RKVersion.subType
# 41 RKVersion.inTrashDate # 41 RKVersion.inTrashDate
# 42 RKVersion.showInLibrary -- is item visible in library (e.g. non-selected burst images are not visible) # 42 RKVersion.showInLibrary -- is item visible in library (e.g. non-selected burst images are not visible)
# 43 RKMaster.fileIsReference -- file is reference (imported without copying to Photos library)
for row in c: for row in c:
uuid = row[0] uuid = row[0]
@@ -1164,6 +1167,10 @@ class PhotosDB:
self._dbphotos[uuid]["visibility_state"] = row[42] self._dbphotos[uuid]["visibility_state"] = row[42]
self._dbphotos[uuid]["visible"] = row[42] == 1 self._dbphotos[uuid]["visible"] = row[42] == 1
# file is reference (not copied into Photos library)
self._dbphotos[uuid]["isreference"] = row[43] == 1
self._dbphotos[uuid]["saved_asset_type"] = None # Photos 5+
# import session not yet handled for Photos 4 # import session not yet handled for Photos 4
self._dbphotos[uuid]["import_session"] = None self._dbphotos[uuid]["import_session"] = None
self._dbphotos[uuid]["import_uuid"] = None self._dbphotos[uuid]["import_uuid"] = None
@@ -1859,7 +1866,8 @@ class PhotosDB:
{depth_state}, {depth_state},
{asset_table}.ZADJUSTMENTTIMESTAMP, {asset_table}.ZADJUSTMENTTIMESTAMP,
{asset_table}.ZVISIBILITYSTATE, {asset_table}.ZVISIBILITYSTATE,
{asset_table}.ZTRASHEDDATE {asset_table}.ZTRASHEDDATE,
{asset_table}.ZSAVEDASSETTYPE
FROM {asset_table} FROM {asset_table}
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
ORDER BY {asset_table}.ZUUID """ ORDER BY {asset_table}.ZUUID """
@@ -1906,6 +1914,7 @@ class PhotosDB:
# 37 ZGENERICASSET.ZADJUSTMENTTIMESTAMP -- when was photo edited? # 37 ZGENERICASSET.ZADJUSTMENTTIMESTAMP -- when was photo edited?
# 38 ZGENERICASSET.ZVISIBILITYSTATE -- 0 if visible, 2 if not (e.g. a burst image) # 38 ZGENERICASSET.ZVISIBILITYSTATE -- 0 if visible, 2 if not (e.g. a burst image)
# 39 ZGENERICASSET.ZTRASHEDDATE -- date item placed in the trash or null if not in trash # 39 ZGENERICASSET.ZTRASHEDDATE -- date item placed in the trash or null if not in trash
# 40 ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported
for row in c: for row in c:
uuid = row[0] uuid = row[0]
@@ -2085,6 +2094,14 @@ class PhotosDB:
info["visibility_state"] = row[38] info["visibility_state"] = row[38]
info["visible"] = row[38] == 0 info["visible"] = row[38] == 0
# ZSAVEDASSETTYPE Values:
# 3: imported by copying to Photos library
# 4: shared iCloud photo
# 6: imported by iCloud (e.g. from iPhone)
# 10: referenced file (not copied to Photos library)
info["saved_asset_type"] = row[40]
info["isreference"] = row[40] == 10
# initialize import session info which will be filled in later # initialize import session info which will be filled in later
# not every photo has an import session so initialize all records now # not every photo has an import session so initialize all records now
info["import_session"] = None info["import_session"] = None

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +1,9 @@
import pytest
from collections import namedtuple from collections import namedtuple
from osxphotos._constants import _UNKNOWN_PERSON import pytest
import osxphotos
from osxphotos._constants import _UNKNOWN_PERSON
PHOTOS_DB = "tests/Test-10.16.0.1.photoslibrary/database/photos.db" PHOTOS_DB = "tests/Test-10.16.0.1.photoslibrary/database/photos.db"
PHOTOS_DB_PATH = "/Test-10.16.0.1.photoslibrary/database/photos.db" PHOTOS_DB_PATH = "/Test-10.16.0.1.photoslibrary/database/photos.db"
@@ -169,6 +169,15 @@ PATH_HEIC_EDITED = (
"resources/renders/7/7783E8E6-9CAC-40F3-BE22-81FB7051C266_1_201_a.heic" "resources/renders/7/7783E8E6-9CAC-40F3-BE22-81FB7051C266_1_201_a.heic"
) )
# file is reference (not copied to library)
UUID_IS_REFERENCE = "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C"
UUID_NOT_REFERENCE = "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51"
@pytest.fixture(scope="module")
def photosdb():
return osxphotos.PhotosDB(dbfile=PHOTOS_DB)
def test_init1(): def test_init1():
# test named argument # test named argument
@@ -230,80 +239,56 @@ def test_init5(mocker):
assert osxphotos.PhotosDB() assert osxphotos.PhotosDB()
def test_db_len(): def test_db_len(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
# assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS # assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS
assert len(photosdb) == PHOTOS_DB_LEN assert len(photosdb) == PHOTOS_DB_LEN
def test_db_version(): def test_db_version(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
# assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS # assert photosdb.db_version in osxphotos._TESTED_DB_VERSIONS
assert photosdb.db_version == "6000" assert photosdb.db_version == "6000"
def test_persons(): def test_persons(photosdb):
import osxphotos
import collections import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Katie" in photosdb.persons assert "Katie" in photosdb.persons
assert collections.Counter(PERSONS) == collections.Counter(photosdb.persons) assert collections.Counter(PERSONS) == collections.Counter(photosdb.persons)
def test_keywords(): def test_keywords(photosdb):
import osxphotos
import collections import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "wedding" in photosdb.keywords assert "wedding" in photosdb.keywords
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords) assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_album_names(): def test_album_names(photosdb):
import osxphotos
import collections import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums) assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
def test_keywords_dict(): def test_keywords_dict(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
keywords = photosdb.keywords_as_dict keywords = photosdb.keywords_as_dict
assert keywords["wedding"] == 3 assert keywords["wedding"] == 3
assert keywords == KEYWORDS_DICT assert keywords == KEYWORDS_DICT
def test_persons_as_dict(): def test_persons_as_dict(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
persons = photosdb.persons_as_dict persons = photosdb.persons_as_dict
assert persons["Maria"] == 2 assert persons["Maria"] == 2
assert persons == PERSONS_DICT assert persons == PERSONS_DICT
def test_albums_as_dict(): def test_albums_as_dict(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
albums = photosdb.albums_as_dict albums = photosdb.albums_as_dict
assert albums["Pumpkin Farm"] == 3 assert albums["Pumpkin Farm"] == 3
assert albums == ALBUM_DICT assert albums == ALBUM_DICT
def test_album_sort_order(): def test_album_sort_order(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
album = [a for a in photosdb.album_info if a.title == "Pumpkin Farm"][0] album = [a for a in photosdb.album_info if a.title == "Pumpkin Farm"][0]
photos = album.photos photos = album.photos
@@ -311,20 +296,15 @@ def test_album_sort_order():
assert uuids == ALBUM_SORT_ORDER assert uuids == ALBUM_SORT_ORDER
def test_album_empty_album(): def test_album_empty_album(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
album = [a for a in photosdb.album_info if a.title == "EmptyAlbum"][0] album = [a for a in photosdb.album_info if a.title == "EmptyAlbum"][0]
photos = album.photos photos = album.photos
assert photos == [] assert photos == []
def test_attributes(): def test_attributes(photosdb):
import datetime import datetime
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=["D79B8D77-BFFC-460B-9312-034F2877D35B"]) photos = photosdb.photos(uuid=["D79B8D77-BFFC-460B-9312-034F2877D35B"])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -344,12 +324,10 @@ def test_attributes():
assert p.ismissing == False assert p.ismissing == False
def test_attributes_2(): def test_attributes_2(photosdb):
""" Test attributes including height, width, etc """ """ Test attributes including height, width, etc """
import datetime import datetime
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -384,10 +362,7 @@ def test_attributes_2():
assert p.original_filesize == 460483 assert p.original_filesize == 460483
def test_missing(): def test_missing(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["missing"]]) photos = photosdb.photos(uuid=[UUID_DICT["missing"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -395,51 +370,36 @@ def test_missing():
assert p.ismissing == True assert p.ismissing == True
def test_favorite(): def test_favorite(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["favorite"]]) photos = photosdb.photos(uuid=[UUID_DICT["favorite"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
assert p.favorite == True assert p.favorite == True
def test_not_favorite(): def test_not_favorite(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["not_favorite"]]) photos = photosdb.photos(uuid=[UUID_DICT["not_favorite"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
assert p.favorite == False assert p.favorite == False
def test_hidden(): def test_hidden(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["hidden"]]) photos = photosdb.photos(uuid=[UUID_DICT["hidden"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
assert p.hidden == True assert p.hidden == True
def test_not_hidden(): def test_not_hidden(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["not_hidden"]]) photos = photosdb.photos(uuid=[UUID_DICT["not_hidden"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
assert p.hidden == False assert p.hidden == False
def test_location_1(): def test_location_1(photosdb):
# test photo with lat/lon info # test photo with lat/lon info
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["location"]]) photos = photosdb.photos(uuid=[UUID_DICT["location"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -448,11 +408,8 @@ def test_location_1():
assert lon == pytest.approx(-0.1318055) assert lon == pytest.approx(-0.1318055)
def test_location_2(): def test_location_2(photosdb):
# test photo with no location info # test photo with no location info
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["no_location"]]) photos = photosdb.photos(uuid=[UUID_DICT["no_location"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -461,33 +418,24 @@ def test_location_2():
assert lon is None assert lon is None
def test_hasadjustments1(): def test_hasadjustments1(photosdb):
# test hasadjustments == True # test hasadjustments == True
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
assert p.hasadjustments == True assert p.hasadjustments == True
def test_hasadjustments2(): def test_hasadjustments2(photosdb):
# test hasadjustments == False # test hasadjustments == False
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
assert p.hasadjustments == False assert p.hasadjustments == False
def test_external_edit1(): def test_external_edit1(photosdb):
# test image has been edited in external editor # test image has been edited in external editor
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["external_edit"]]) photos = photosdb.photos(uuid=[UUID_DICT["external_edit"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -495,11 +443,8 @@ def test_external_edit1():
assert p.external_edit == True assert p.external_edit == True
def test_external_edit2(): def test_external_edit2(photosdb):
# test image has not been edited in external editor # test image has not been edited in external editor
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["no_external_edit"]]) photos = photosdb.photos(uuid=[UUID_DICT["no_external_edit"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -507,12 +452,10 @@ def test_external_edit2():
assert p.external_edit == False assert p.external_edit == False
def test_path_edited_jpeg(): def test_path_edited_jpeg(photosdb):
# test a valid edited path # test a valid edited path
import os.path import os.path
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=["E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51"]) photos = photosdb.photos(uuid=["E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51"])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -523,22 +466,17 @@ def test_path_edited_jpeg():
assert os.path.exists(path) assert os.path.exists(path)
def test_path_edited_heic(): def test_path_edited_heic(photosdb):
# test a valid edited path for .heic image # test a valid edited path for .heic image
import pathlib import pathlib
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photo = photosdb.get_photo(UUID_HEIC_EDITED) photo = photosdb.get_photo(UUID_HEIC_EDITED)
assert photo.path_edited.endswith(PATH_HEIC_EDITED) assert photo.path_edited.endswith(PATH_HEIC_EDITED)
assert pathlib.Path(photo.path_edited).is_file() assert pathlib.Path(photo.path_edited).is_file()
def test_path_edited2(): def test_path_edited2(photosdb):
# test an invalid edited path # test an invalid edited path
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
assert len(photos) == 1 assert len(photos) == 1
p = photos[0] p = photos[0]
@@ -546,115 +484,79 @@ def test_path_edited2():
assert path is None assert path is None
def test_count(): def test_count(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos() photos = photosdb.photos()
assert len(photos) == PHOTOS_NOT_IN_TRASH_LEN assert len(photos) == PHOTOS_NOT_IN_TRASH_LEN
def test_photos_intrash_1(): def test_photos_intrash_1(photosdb):
""" test PhotosDB.photos(intrash=True) """ """ test PhotosDB.photos(intrash=True) """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(intrash=True) photos = photosdb.photos(intrash=True)
assert len(photos) == PHOTOS_IN_TRASH_LEN assert len(photos) == PHOTOS_IN_TRASH_LEN
def test_photos_intrash_2(): def test_photos_intrash_2(photosdb):
""" test PhotosDB.photos(intrash=True) """ """ test PhotosDB.photos(intrash=True) """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(intrash=True) photos = photosdb.photos(intrash=True)
for p in photos: for p in photos:
assert p.intrash assert p.intrash
def test_photos_intrash_3(): def test_photos_intrash_3(photosdb):
""" test PhotosDB.photos(intrash=False) """ """ test PhotosDB.photos(intrash=False) """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(intrash=False) photos = photosdb.photos(intrash=False)
for p in photos: for p in photos:
assert not p.intrash assert not p.intrash
def test_photoinfo_intrash_1(): def test_photoinfo_intrash_1(photosdb):
""" Test PhotoInfo.intrash """ """ Test PhotoInfo.intrash """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
p = photosdb.photos(uuid=[UUID_DICT["intrash"]], intrash=True)[0] p = photosdb.photos(uuid=[UUID_DICT["intrash"]], intrash=True)[0]
assert p.intrash assert p.intrash
def test_photoinfo_intrash_2(): def test_photoinfo_intrash_2(photosdb):
""" Test PhotoInfo.intrash and intrash=default""" """ Test PhotoInfo.intrash and intrash=default"""
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
p = photosdb.photos(uuid=[UUID_DICT["intrash"]]) p = photosdb.photos(uuid=[UUID_DICT["intrash"]])
assert not p assert not p
def test_photoinfo_intrash_3(): def test_photoinfo_intrash_3(photosdb):
""" Test PhotoInfo.intrash and photo has keyword and person """ """ Test PhotoInfo.intrash and photo has keyword and person """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
p = photosdb.photos(uuid=[UUID_DICT["intrash_person_keywords"]], intrash=True)[0] p = photosdb.photos(uuid=[UUID_DICT["intrash_person_keywords"]], intrash=True)[0]
assert p.intrash assert p.intrash
assert "Maria" in p.persons assert "Maria" in p.persons
assert "wedding" in p.keywords assert "wedding" in p.keywords
def test_photoinfo_intrash_4(): def test_photoinfo_intrash_4(photosdb):
""" Test PhotoInfo.intrash and photo has keyword and person """ """ Test PhotoInfo.intrash and photo has keyword and person """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
p = photosdb.photos(persons=["Maria"], intrash=True)[0] p = photosdb.photos(persons=["Maria"], intrash=True)[0]
assert p.intrash assert p.intrash
assert "Maria" in p.persons assert "Maria" in p.persons
assert "wedding" in p.keywords assert "wedding" in p.keywords
def test_photoinfo_intrash_5(): def test_photoinfo_intrash_5(photosdb):
""" Test PhotoInfo.intrash and photo has keyword and person """ """ Test PhotoInfo.intrash and photo has keyword and person """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
p = photosdb.photos(keywords=["wedding"], intrash=True)[0] p = photosdb.photos(keywords=["wedding"], intrash=True)[0]
assert p.intrash assert p.intrash
assert "Maria" in p.persons assert "Maria" in p.persons
assert "wedding" in p.keywords assert "wedding" in p.keywords
def test_photoinfo_not_intrash(): def test_photoinfo_not_intrash(photosdb):
""" Test PhotoInfo.intrash """ """ Test PhotoInfo.intrash """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
p = photosdb.photos(uuid=[UUID_DICT["not_intrash"]])[0] p = photosdb.photos(uuid=[UUID_DICT["not_intrash"]])[0]
assert not p.intrash assert not p.intrash
def test_keyword_2(): def test_keyword_2(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(keywords=["wedding"]) photos = photosdb.photos(keywords=["wedding"])
assert len(photos) == 2 # won't show the one in the trash assert len(photos) == 2 # won't show the one in the trash
def test_keyword_not_in_album(): def test_keyword_not_in_album(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
# find all photos with keyword "Kids" not in the album "Pumpkin Farm" # find all photos with keyword "Kids" not in the album "Pumpkin Farm"
photos1 = photosdb.photos(albums=["Pumpkin Farm"]) photos1 = photosdb.photos(albums=["Pumpkin Farm"])
@@ -664,47 +566,33 @@ def test_keyword_not_in_album():
assert photos3[0].uuid == "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C" assert photos3[0].uuid == "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C"
def test_album_folder_name(): def test_album_folder_name(photosdb):
"""Test query with album name same as a folder name """ """Test query with album name same as a folder name """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(albums=["Pumpkin Farm"]) photos = photosdb.photos(albums=["Pumpkin Farm"])
assert sorted(p.uuid for p in photos) == sorted(UUID_PUMPKIN_FARM) assert sorted(p.uuid for p in photos) == sorted(UUID_PUMPKIN_FARM)
def test_multi_person(): def test_multi_person(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(PHOTOS_DB)
photos = photosdb.photos(persons=["Katie", "Suzy"]) photos = photosdb.photos(persons=["Katie", "Suzy"])
assert len(photos) == 3 assert len(photos) == 3
def test_get_db_path(): def test_get_db_path(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
db_path = photosdb.db_path db_path = photosdb.db_path
assert db_path.endswith(PHOTOS_DB_PATH) assert db_path.endswith(PHOTOS_DB_PATH)
def test_get_library_path(): def test_get_library_path(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
lib_path = photosdb.library_path lib_path = photosdb.library_path
assert lib_path.endswith(PHOTOS_LIBRARY_PATH) assert lib_path.endswith(PHOTOS_LIBRARY_PATH)
def test_get_db_connection(): def test_get_db_connection(photosdb):
""" Test PhotosDB.get_db_connection """ """ Test PhotosDB.get_db_connection """
import osxphotos
import sqlite3 import sqlite3
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
conn, cursor = photosdb.get_db_connection() conn, cursor = photosdb.get_db_connection()
assert isinstance(conn, sqlite3.Connection) assert isinstance(conn, sqlite3.Connection)
@@ -717,18 +605,15 @@ def test_get_db_connection():
conn.close() conn.close()
def test_export_1(): def test_export_1(photosdb):
# test basic export # test basic export
# get an unedited image and export it using default filename # get an unedited image and export it using default filename
import os import os
import os.path import os.path
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
filename = photos[0].filename filename = photos[0].filename
@@ -739,18 +624,15 @@ def test_export_1():
assert os.path.isfile(got_dest) assert os.path.isfile(got_dest)
def test_export_2(): def test_export_2(photosdb):
# test export with user provided filename # test export with user provided filename
import os import os
import os.path import os.path
import tempfile import tempfile
import time import time
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
timestamp = time.time() timestamp = time.time()
@@ -762,18 +644,15 @@ def test_export_2():
assert os.path.isfile(got_dest) assert os.path.isfile(got_dest)
def test_export_3(): def test_export_3(photosdb):
# test file already exists and test increment=True (default) # test file already exists and test increment=True (default)
import os import os
import os.path import os.path
import pathlib import pathlib
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
filename = photos[0].filename filename = photos[0].filename
@@ -788,7 +667,7 @@ def test_export_3():
assert os.path.isfile(got_dest_2) assert os.path.isfile(got_dest_2)
def test_export_4(): def test_export_4(photosdb):
# test user supplied file already exists and test increment=True (default) # test user supplied file already exists and test increment=True (default)
import os import os
import os.path import os.path
@@ -796,11 +675,8 @@ def test_export_4():
import tempfile import tempfile
import time import time
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
timestamp = time.time() timestamp = time.time()
@@ -815,18 +691,15 @@ def test_export_4():
assert os.path.isfile(got_dest_2) assert os.path.isfile(got_dest_2)
def test_export_5(): def test_export_5(photosdb):
# test file already exists and test increment=True (default) # test file already exists and test increment=True (default)
# and overwrite = True # and overwrite = True
import os import os
import os.path import os.path
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
filename = photos[0].filename filename = photos[0].filename
@@ -840,7 +713,7 @@ def test_export_5():
assert os.path.isfile(got_dest_2) assert os.path.isfile(got_dest_2)
def test_export_6(): def test_export_6(photosdb):
# test user supplied file already exists and test increment=True (default) # test user supplied file already exists and test increment=True (default)
# and overwrite = True # and overwrite = True
import os import os
@@ -849,11 +722,8 @@ def test_export_6():
import tempfile import tempfile
import time import time
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
timestamp = time.time() timestamp = time.time()
@@ -868,18 +738,15 @@ def test_export_6():
assert os.path.isfile(got_dest_2) assert os.path.isfile(got_dest_2)
def test_export_7(): def test_export_7(photosdb):
# test file already exists and test increment=False (not default), overwrite=False (default) # test file already exists and test increment=False (not default), overwrite=False (default)
# should raise exception # should raise exception
import os import os
import os.path import os.path
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
filename = photos[0].filename filename = photos[0].filename
@@ -891,18 +758,15 @@ def test_export_7():
assert e.type == type(FileExistsError()) assert e.type == type(FileExistsError())
def test_export_8(): def test_export_8(photosdb):
# try to export missing file # try to export missing file
# should raise exception # should raise exception
import os import os
import os.path import os.path
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["missing"]]) photos = photosdb.photos(uuid=[UUID_DICT["missing"]])
filename = photos[0].filename filename = photos[0].filename
@@ -912,16 +776,13 @@ def test_export_8():
assert e.type == type(FileNotFoundError()) assert e.type == type(FileNotFoundError())
def test_export_9(): def test_export_9(photosdb):
# try to export edited file that's not edited # try to export edited file that's not edited
# should raise exception # should raise exception
import os import os
import os.path import os.path
import tempfile import tempfile
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
@@ -933,7 +794,7 @@ def test_export_9():
assert e.type == ValueError assert e.type == ValueError
def test_export_10(): def test_export_10(photosdb):
# try to export edited file that's not edited and name provided # try to export edited file that's not edited and name provided
# should raise exception # should raise exception
import os import os
@@ -941,9 +802,6 @@ def test_export_10():
import tempfile import tempfile
import time import time
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
@@ -956,18 +814,15 @@ def test_export_10():
assert e.type == ValueError assert e.type == ValueError
def test_export_11(): def test_export_11(photosdb):
# export edited file with name provided # export edited file with name provided
import os import os
import os.path import os.path
import tempfile import tempfile
import time import time
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
timestamp = time.time() timestamp = time.time()
@@ -978,18 +833,15 @@ def test_export_11():
assert got_dest == expected_dest assert got_dest == expected_dest
def test_export_12(): def test_export_12(photosdb):
# export edited file with default name # export edited file with default name
import os import os
import os.path import os.path
import pathlib import pathlib
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]]) photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
edited_name = pathlib.Path(photos[0].path_edited).name edited_name = pathlib.Path(photos[0].path_edited).name
@@ -1001,15 +853,13 @@ def test_export_12():
assert got_dest == expected_dest assert got_dest == expected_dest
def test_export_13(): def test_export_13(photosdb):
# export to invalid destination # export to invalid destination
# should raise exception # should raise exception
import os import os
import os.path import os.path
import tempfile import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
@@ -1019,7 +869,6 @@ def test_export_13():
dest = os.path.join(dest, str(i)) dest = os.path.join(dest, str(i))
i += 1 i += 1
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export"]]) photos = photosdb.photos(uuid=[UUID_DICT["export"]])
filename = photos[0].filename filename = photos[0].filename
@@ -1029,18 +878,15 @@ def test_export_13():
assert e.type == type(FileNotFoundError()) assert e.type == type(FileNotFoundError())
def test_export_14(caplog): def test_export_14(caplog, photosdb):
# test export with user provided filename with different (but valid) extension than source # test export with user provided filename with different (but valid) extension than source
import os import os
import os.path import os.path
import tempfile import tempfile
import time import time
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_") tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name dest = tempdir.name
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["export_tif"]]) photos = photosdb.photos(uuid=[UUID_DICT["export_tif"]])
timestamp = time.time() timestamp = time.time()
@@ -1054,24 +900,22 @@ def test_export_14(caplog):
assert "Invalid destination suffix" not in caplog.text assert "Invalid destination suffix" not in caplog.text
def test_eq(): def test_eq(photosdb):
""" Test equality of two PhotoInfo objects """ """ Test equality of two PhotoInfo objects """
import osxphotos import osxphotos
photosdb1 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos1 = photosdb1.photos(uuid=[UUID_DICT["export"]]) photos1 = photosdb.photos(uuid=[UUID_DICT["export"]])
photos2 = photosdb2.photos(uuid=[UUID_DICT["export"]]) photos2 = photosdb2.photos(uuid=[UUID_DICT["export"]])
assert photos1[0] == photos2[0] assert photos1[0] == photos2[0]
def test_eq_2(): def test_eq_2(photosdb):
""" Test equality of two PhotoInfo objects when one has memoized property """ """ Test equality of two PhotoInfo objects when one has memoized property """
import osxphotos import osxphotos
photosdb1 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos1 = photosdb1.photos(uuid=[UUID_DICT["in_album"]]) photos1 = photosdb.photos(uuid=[UUID_DICT["in_album"]])
photos2 = photosdb2.photos(uuid=[UUID_DICT["in_album"]]) photos2 = photosdb2.photos(uuid=[UUID_DICT["in_album"]])
# memoize a value # memoize a value
@@ -1081,18 +925,13 @@ def test_eq_2():
assert photos1[0] == photos2[0] assert photos1[0] == photos2[0]
def test_not_eq(): def test_not_eq(photosdb):
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos1 = photosdb.photos(uuid=[UUID_DICT["export"]]) photos1 = photosdb.photos(uuid=[UUID_DICT["export"]])
photos2 = photosdb.photos(uuid=[UUID_DICT["missing"]]) photos2 = photosdb.photos(uuid=[UUID_DICT["missing"]])
assert photos1[0] != photos2[0] assert photos1[0] != photos2[0]
def test_photosdb_repr(): def test_photosdb_repr():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photosdb2 = eval(repr(photosdb)) photosdb2 = eval(repr(photosdb))
@@ -1102,11 +941,9 @@ def test_photosdb_repr():
} }
def test_photosinfo_repr(): def test_photosinfo_repr(photosdb):
import osxphotos
import datetime import datetime
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos(uuid=[UUID_DICT["favorite"]]) photos = photosdb.photos(uuid=[UUID_DICT["favorite"]])
photo = photos[0] photo = photos[0]
photo2 = eval(repr(photo)) photo2 = eval(repr(photo))
@@ -1116,8 +953,7 @@ def test_photosinfo_repr():
} }
def test_from_to_date(): def test_from_to_date(photosdb):
import osxphotos
import datetime as dt import datetime as dt
import os import os
import time import time
@@ -1125,8 +961,6 @@ def test_from_to_date():
os.environ["TZ"] = "US/Pacific" os.environ["TZ"] = "US/Pacific"
time.tzset() time.tzset()
photosdb = osxphotos.PhotosDB(PHOTOS_DB)
photos = photosdb.photos(from_date=dt.datetime(2018, 10, 28)) photos = photosdb.photos(from_date=dt.datetime(2018, 10, 28))
assert len(photos) == 7 assert len(photos) == 7
@@ -1139,12 +973,10 @@ def test_from_to_date():
assert len(photos) == 4 assert len(photos) == 4
def test_date_invalid(): def test_date_invalid(photosdb):
""" Test date is invalid """ """ Test date is invalid """
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
# UUID_DICT["date_invalid"] has an invalid date that's # UUID_DICT["date_invalid"] has an invalid date that's
# been manually adjusted in the database # been manually adjusted in the database
photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]]) photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]])
@@ -1155,12 +987,10 @@ def test_date_invalid():
assert p.date == datetime(1970, 1, 1).astimezone(tz=tz) assert p.date == datetime(1970, 1, 1).astimezone(tz=tz)
def test_date_modified_invalid(): def test_date_modified_invalid(photosdb):
""" Test date modified is invalid """ """ Test date modified is invalid """
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
# UUID_DICT["date_invalid"] has an invalid modified date that's # UUID_DICT["date_invalid"] has an invalid modified date that's
# been manually adjusted in the database # been manually adjusted in the database
photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]]) photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]])
@@ -1169,11 +999,8 @@ def test_date_modified_invalid():
assert p.date_modified is None assert p.date_modified is None
def test_uti(): def test_uti(photosdb):
""" test uti """ """ test uti """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
for uuid, uti in UTI_DICT.items(): for uuid, uti in UTI_DICT.items():
photo = photosdb.get_photo(uuid) photo = photosdb.get_photo(uuid)
@@ -1181,11 +1008,8 @@ def test_uti():
assert photo.uti_original == UTI_ORIGINAL_DICT[uuid] assert photo.uti_original == UTI_ORIGINAL_DICT[uuid]
def test_raw(): def test_raw(photosdb):
""" Test various raw properties """ """ Test various raw properties """
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
for uuid, rawinfo in RAW_DICT.items(): for uuid, rawinfo in RAW_DICT.items():
photo = photosdb.get_photo(uuid) photo = photosdb.get_photo(uuid)
@@ -1195,3 +1019,12 @@ def test_raw():
assert photo.uti == rawinfo.uti assert photo.uti == rawinfo.uti
assert photo.uti_original == rawinfo.uti_original assert photo.uti_original == rawinfo.uti_original
assert photo.uti_raw == rawinfo.uti_raw assert photo.uti_raw == rawinfo.uti_raw
def test_is_reference(photosdb):
""" test isreference """
photo = photosdb.get_photo(UUID_IS_REFERENCE)
assert photo.isreference
photo = photosdb.get_photo(UUID_NOT_REFERENCE)
assert not photo.isreference

View File

@@ -198,6 +198,9 @@ ORIGINAL_FILENAME_DICT = {
"original_filename": "Pumkins2.jpg", "original_filename": "Pumkins2.jpg",
} }
UUID_IS_REFERENCE = "A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C"
UUID_NOT_REFERENCE = "F12384F6-CD17-4151-ACBA-AE0E3688539E"
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def photosdb(): def photosdb():
@@ -1185,3 +1188,11 @@ def test_visible_burst(photosdb_local):
assert photo.burst assert photo.burst
assert len(photo.burst_photos) == 4 assert len(photo.burst_photos) == 4
def test_is_reference(photosdb):
""" test isreference """
photo = photosdb.get_photo(UUID_IS_REFERENCE)
assert photo.isreference
photo = photosdb.get_photo(UUID_NOT_REFERENCE)
assert not photo.isreference

View File

@@ -573,6 +573,11 @@ UUID_JPEGS_DICT = {
UUID_HEIC = {"7783E8E6-9CAC-40F3-BE22-81FB7051C266": "IMG_3092"} UUID_HEIC = {"7783E8E6-9CAC-40F3-BE22-81FB7051C266": "IMG_3092"}
UUID_IS_REFERENCE = [
"8E1D7BC9-9321-44F9-8CFB-4083F6B9232A",
"A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
]
def modify_file(filename): def modify_file(filename):
""" appends data to a file to modify it """ """ appends data to a file to modify it """
@@ -857,6 +862,26 @@ def test_query_no_likes():
assert uuid not in UUID_HAS_LIKES assert uuid not in UUID_HAS_LIKES
def test_query_is_reference():
""" Test query with --is-reference """
import json
import os
import os.path
from osxphotos.__main__ import query
runner = CliRunner()
cwd = os.getcwd()
result = runner.invoke(
query, ["--json", "--db", os.path.join(cwd, PHOTOS_DB_15_7), "--is-reference"]
)
assert result.exit_code == 0
# build list of uuids we got from the output JSON
json_got = json.loads(result.output)
uuid_got = [photo["uuid"] for photo in json_got]
assert sorted(uuid_got) == sorted(UUID_IS_REFERENCE)
def test_export(): def test_export():
import glob import glob
import os import os

View File

@@ -623,3 +623,4 @@ def test_xmp_sidecar_keyword_template(photosdb):
keyword_template=["{created.year}", "{folder_album}"], extension="jpg" keyword_template=["{created.year}", "{folder_album}"], extension="jpg"
) )
assert xmp_got == xmp_expected assert xmp_got == xmp_expected

View File

@@ -100,6 +100,8 @@ PHOTOS_DB_LEN = 13
PHOTOS_NOT_IN_TRASH_LEN = 12 PHOTOS_NOT_IN_TRASH_LEN = 12
PHOTOS_IN_TRASH_LEN = 1 PHOTOS_IN_TRASH_LEN = 1
UUID_NOT_REFERENCE = "6bxcNnzRQKGnK4uPrCJ9UQ"
UUID_IS_REFERENCE = "od0fmC7NQx+ayVr+%i06XA"
RawInfo = namedtuple( RawInfo = namedtuple(
"RawInfo", "RawInfo",
@@ -595,7 +597,7 @@ def test_raw(photosdb):
photo = photosdb.get_photo(UUID_DICT["raw"]) photo = photosdb.get_photo(UUID_DICT["raw"])
# assert photo.israw # assert photo.israw
assert not photo.has_raw assert not photo.has_raw
assert photo.uti_raw == None assert photo.uti_raw is None
assert photo.uti == "com.adobe.raw-image" assert photo.uti == "com.adobe.raw-image"
assert photo.path_raw is None assert photo.path_raw is None
@@ -626,3 +628,12 @@ def test_raw():
assert photo.uti == rawinfo.uti assert photo.uti == rawinfo.uti
assert photo.uti_original == rawinfo.uti_original assert photo.uti_original == rawinfo.uti_original
assert photo.uti_raw == rawinfo.uti_raw assert photo.uti_raw == rawinfo.uti_raw
def test_is_reference(photosdb):
""" test isreference """
photo = photosdb.get_photo(UUID_IS_REFERENCE)
assert photo.isreference
photo = photosdb.get_photo(UUID_NOT_REFERENCE)
assert not photo.isreference