Skip to content

Commit

Permalink
Fixed bug in PhotosDB.__repr__ and added test for empty database
Browse files Browse the repository at this point in the history
  • Loading branch information
RhetTbull committed Dec 28, 2019
1 parent 5bec99e commit db34169
Show file tree
Hide file tree
Showing 34 changed files with 272 additions and 15 deletions.
29 changes: 20 additions & 9 deletions osxphotos/photosdb.py
Expand Up @@ -57,6 +57,8 @@ def __init__(self, *args, dbfile=None):

# Path to the Photos library database file
self._dbfile = None
# the actual file with library data which on Photos 5 is Photos.sqlite instead of photos.db
self._dbfile_actual = None
# Dict with information about all photos by uuid
self._dbphotos = {}
# Dict with information about all persons/photos by uuid
Expand Down Expand Up @@ -115,25 +117,27 @@ def __init__(self, *args, dbfile=None):

logging.debug(f"dbfile = {dbfile}")

self._dbfile = dbfile
self._dbfile = self._dbfile_actual = os.path.abspath(dbfile)

self._tmp_db = self._copy_db_file(self._dbfile)
self._db_version = self._get_db_version()

# If Photos >= 5, actual data isn't in photos.db but in Photos.sqlite
if int(self._db_version) >= int(_PHOTOS_5_VERSION):
logging.debug(f"version is {self._db_version}")
dbpath = pathlib.Path(self._dbfile).parent
dbfile = dbpath / "Photos.sqlite"
logging.debug(f"dbfile = {dbfile}")
if not _check_file_exists(dbfile):
sys.exit(f"dbfile {dbfile} does not exist")
else:
self._dbfile = dbfile
self._tmp_db = self._copy_db_file(self._dbfile)
self._tmp_db = self._copy_db_file(dbfile)
self._dbfile_actual = dbfile
logging.debug(
f"_dbfile = {self._dbfile}, _dbfile_actual = {self._dbfile_actual}"
)

# TODO: replace os.path with pathlib?
# TODO: clean this up -- library path computed twice
library_path = os.path.dirname(os.path.abspath(dbfile))
(library_path, _) = os.path.split(library_path)
(library_path, _) = os.path.split(library_path) # drop /database from path
self._library_path = library_path
if int(self._db_version) < int(_PHOTOS_5_VERSION):
masters_path = os.path.join(library_path, "Masters")
Expand Down Expand Up @@ -250,7 +254,7 @@ def persons(self):
@property
def albums(self):
""" return list of albums found in photos database """

# 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

Expand All @@ -268,7 +272,7 @@ def albums(self):
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 """

# 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

Expand Down Expand Up @@ -1119,3 +1123,10 @@ def photos(self, keywords=[], uuid=[], persons=[], albums=[]):

def __repr__(self):
return f"osxphotos.{self.__class__.__name__}(dbfile='{self.db_path}')"

# compare two PhotosDB objects for equality
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.__dict__ == other.__dict__

return False
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DatabaseMinorVersion</key>
<integer>1</integer>
<key>DatabaseVersion</key>
<integer>112</integer>
<key>LastOpenMode</key>
<integer>2</integer>
<key>LibrarySchemaVersion</key>
<integer>4025</integer>
<key>MetaSchemaVersion</key>
<integer>2</integer>
<key>createDate</key>
<date>2019-12-27T23:19:08Z</date>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
Empty file.
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Photos</key>
<dict>
<key>CollapsedSidebarSectionIdentifiers</key>
<array/>
<key>ExpandedSidebarItemIdentifiers</key>
<array>
<string>TopLevelAlbums</string>
<string>TopLevelSlideshows</string>
</array>
<key>lastKnownItemCounts</key>
<dict>
<key>other</key>
<integer>0</integer>
<key>photos</key>
<integer>0</integer>
<key>videos</key>
<integer>0</integer>
</dict>
</dict>
</dict>
</plist>
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
<date>2019-12-27T23:19:59Z</date>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PLLanguageAndLocaleKey</key>
<string>en-US:en_US</string>
<key>PLLastGeoProviderIdKey</key>
<string>7618</string>
<key>PLLastLocationInfoFormatVer</key>
<integer>12</integer>
<key>PLLastRevGeoForcedProviderOutOfDateCheckVersionKey</key>
<integer>1</integer>
</dict>
</plist>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LastHistoryRowId</key>
<integer>53</integer>
<key>LibraryBuildTag</key>
<string>F176BAF5-4B7A-4878-83C4-4D4175F299BF</string>
<key>LibrarySchemaVersion</key>
<integer>4025</integer>
</dict>
</plist>
Empty file.
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DatabaseMinorVersion</key>
<integer>1</integer>
<key>DatabaseVersion</key>
<integer>112</integer>
<key>HistoricalMarker</key>
<dict>
<key>LastHistoryRowId</key>
<integer>53</integer>
<key>LibraryBuildTag</key>
<string>F176BAF5-4B7A-4878-83C4-4D4175F299BF</string>
<key>LibrarySchemaVersion</key>
<integer>4025</integer>
</dict>
<key>LibrarySchemaVersion</key>
<integer>4025</integer>
<key>MetaSchemaVersion</key>
<integer>2</integer>
<key>SnapshotComplete</key>
<true/>
<key>SnapshotCompletedDate</key>
<date>2019-12-27T23:19:08Z</date>
<key>SnapshotLastValidated</key>
<date>2019-12-27T23:19:08Z</date>
<key>SnapshotTables</key>
<dict/>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
22 changes: 19 additions & 3 deletions tests/test_catalina_10_15_1.py
Expand Up @@ -5,7 +5,7 @@
# TODO: put some of this code into a pre-function

PHOTOS_DB = "./tests/Test-10.15.1.photoslibrary/database/photos.db"
PHOTOS_DB_PATH = "/Test-10.15.1.photoslibrary/database/Photos.sqlite"
PHOTOS_DB_PATH = "/Test-10.15.1.photoslibrary/database/photos.db"
PHOTOS_LIBRARY_PATH = "/Test-10.15.1.photoslibrary"

KEYWORDS = [
Expand Down Expand Up @@ -737,18 +737,34 @@ def test_export_13():
assert photos[0].export(dest)
assert e.type == type(FileNotFoundError())


def test_eq():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos1 = photosdb.photos(uuid=[UUID_DICT["export"]])
photos2 = photosdb.photos(uuid=[UUID_DICT["export"]])
assert photos1[0] == photos2[0]


def test_not_eq():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos1 = photosdb.photos(uuid=[UUID_DICT["export"]])
photos2 = photosdb.photos(uuid=[UUID_DICT["missing"]])
assert photos1[0] != photos2[0]


def test_photosdb_repr():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
print(repr(photosdb))
photosdb2 = eval(repr(photosdb))

ignore_keys = ["_tmp_db", "_tmp_files"]
assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
}

108 changes: 108 additions & 0 deletions tests/test_empty_library_4_0.py
@@ -0,0 +1,108 @@
import pytest

# test empty library

PHOTOS_DB = "./tests/Empty-Library-4.0-3461.7.150.photoslibrary/database/photos.db"
PHOTOS_DB_PATH = "/Empty-Library-4.0-3461.7.150.photoslibrary/database/photos.db"
PHOTOS_LIBRARY_PATH = "/Empty-Library-4.0-3461.7.150.photoslibrary"

KEYWORDS = []
PERSONS = []
ALBUMS = []
KEYWORDS_DICT = {}
PERSONS_DICT = {}
ALBUM_DICT = {}


def test_init():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert isinstance(photosdb, osxphotos.PhotosDB)


def test_db_version():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert photosdb.db_version in osxphotos._constants._TESTED_DB_VERSIONS
assert photosdb.db_version == "4025"


def test_os_version():
import osxphotos

(_, major, _) = osxphotos.utils._get_os_version()
assert major in osxphotos._constants._TESTED_OS_VERSIONS


def test_persons():
import osxphotos
import collections

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert photosdb.persons == []


def test_keywords():
import osxphotos
import collections

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert photosdb.keywords == []


def test_albums():
import osxphotos
import collections

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert photosdb.albums == []


def test_keywords_dict():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
keywords = photosdb.keywords_as_dict
assert keywords == {}


def test_persons_as_dict():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
persons = photosdb.persons_as_dict
assert persons == {}


def test_albums_as_dict():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
albums = photosdb.albums_as_dict
assert albums == {}


def test_count():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos()
assert len(photos) == 0


def test_get_db_path():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
db_path = photosdb.db_path
assert db_path.endswith(PHOTOS_DB_PATH)


def test_get_library_path():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
lib_path = photosdb.library_path
assert lib_path.endswith(PHOTOS_LIBRARY_PATH)
2 changes: 1 addition & 1 deletion tests/test_export_catalina_10_15_1.py
Expand Up @@ -6,7 +6,7 @@
# TODO: put some of this code into a pre-function

PHOTOS_DB = "./tests/Test-10.15.1.photoslibrary/database/photos.db"
PHOTOS_DB_PATH = "/Test-10.15.1.photoslibrary/database/Photos.sqlite"
PHOTOS_DB_PATH = "/Test-10.15.1.photoslibrary/database/photos.db"
PHOTOS_LIBRARY_PATH = "/Test-10.15.1.photoslibrary"

KEYWORDS = [
Expand Down
14 changes: 14 additions & 0 deletions tests/test_mojave_10_14_6.py
Expand Up @@ -324,3 +324,17 @@ def test_get_library_path():
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
lib_path = photosdb.library_path
assert lib_path.endswith(PHOTOS_LIBRARY_PATH)


def test_photosdb_repr():
import osxphotos

photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
print(repr(photosdb))
photosdb2 = eval(repr(photosdb))

ignore_keys = ["_tmp_db", "_tmp_files"]
assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
}

2 changes: 1 addition & 1 deletion tests/test_shared_catalina_10_15_1.py
Expand Up @@ -4,7 +4,7 @@
# TODO: put some of this code into a pre-function

PHOTOS_DB = "./tests/Test-Shared-10.15.1.photoslibrary/database/photos.db"
PHOTOS_DB_PATH = "/Test-Shared-10.15.1.photoslibrary/database/Photos.sqlite"
PHOTOS_DB_PATH = "/Test-Shared-10.15.1.photoslibrary/database/photos.db"
PHOTOS_LIBRARY_PATH = "/Test-Shared-10.15.1.photoslibrary"

KEYWORDS = ["portrait"]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_shared_mojave_10_14_6.py
Expand Up @@ -4,7 +4,7 @@
# TODO: put some of this code into a pre-function

PHOTOS_DB = "./tests/Test-10.14.6.photoslibrary/database/photos.db"
PHOTOS_DB_PATH = "/Test-10.14.6.photoslibrary/database/Photos.sqlite"
PHOTOS_DB_PATH = "/Test-10.14.6.photoslibrary/database/photos.db"
PHOTOS_LIBRARY_PATH = "/Test-10.14.6.photoslibrary"

ALBUMS = ["Pumpkin Farm", "Test Album", "Test Album (1)"]
Expand Down

0 comments on commit db34169

Please sign in to comment.