Implemented --ignore-signature, issue #286
14
README.md
@@ -236,6 +236,15 @@ Options:
|
|||||||
Deleted' folder.
|
Deleted' folder.
|
||||||
--update Only export new or updated files. See notes
|
--update Only export new or updated files. See notes
|
||||||
below on export and --update.
|
below on export and --update.
|
||||||
|
--ignore-signature When used with --update, ignores file
|
||||||
|
signature when updating files. This is
|
||||||
|
useful if you have processed or edited
|
||||||
|
exported photos changing the file signature
|
||||||
|
(size & modification date). In this case,
|
||||||
|
--update would normally re-export the
|
||||||
|
processed files but with --ignore-signature,
|
||||||
|
files which exist in the export directory
|
||||||
|
will not be re-exported.
|
||||||
--dry-run Dry run (test) the export but don't actually
|
--dry-run Dry run (test) the export but don't actually
|
||||||
export any files; most useful with
|
export any files; most useful with
|
||||||
--verbose.
|
--verbose.
|
||||||
@@ -439,7 +448,10 @@ the export folder. If a file is changed in the export folder (for example,
|
|||||||
you edited the exported image), osxphotos will detect this as a difference and
|
you edited the exported image), osxphotos will detect this as a difference and
|
||||||
re-export the original image from the library thus overwriting the changes.
|
re-export the original image from the library thus overwriting the changes.
|
||||||
If using --update, the exported library should be treated as a backup, not a
|
If using --update, the exported library should be treated as a backup, not a
|
||||||
working copy where you intend to make changes.
|
working copy where you intend to make changes. If you do edit or process the
|
||||||
|
exported files and do not want them to be overwritten withsubsequent --update,
|
||||||
|
use --ignore-signature which will match filename but not file signature when
|
||||||
|
exporting.
|
||||||
|
|
||||||
Note: The number of files reported for export and the number actually exported
|
Note: The number of files reported for export and the number actually exported
|
||||||
may differ due to live photos, associated raw images, and edited photos which
|
may differ due to live photos, associated raw images, and edited photos which
|
||||||
|
|||||||
@@ -146,6 +146,9 @@ class ExportCommand(click.Command):
|
|||||||
+ "exported image), osxphotos will detect this as a difference and re-export the original image "
|
+ "exported image), osxphotos will detect this as a difference and re-export the original image "
|
||||||
+ "from the library thus overwriting the changes. If using --update, the exported library "
|
+ "from the library thus overwriting the changes. If using --update, the exported library "
|
||||||
+ "should be treated as a backup, not a working copy where you intend to make changes. "
|
+ "should be treated as a backup, not a working copy where you intend to make changes. "
|
||||||
|
+ "If you do edit or process the exported files and do not want them to be overwritten with"
|
||||||
|
+ "subsequent --update, use --ignore-signature which will match filename but not file signature when "
|
||||||
|
+ "exporting."
|
||||||
)
|
)
|
||||||
formatter.write("\n")
|
formatter.write("\n")
|
||||||
formatter.write_text(
|
formatter.write_text(
|
||||||
@@ -1218,6 +1221,15 @@ def query(
|
|||||||
is_flag=True,
|
is_flag=True,
|
||||||
help="Only export new or updated files. See notes below on export and --update.",
|
help="Only export new or updated files. See notes below on export and --update.",
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"--ignore-signature",
|
||||||
|
is_flag=True,
|
||||||
|
help="When used with --update, ignores file signature when updating files. "
|
||||||
|
"This is useful if you have processed or edited exported photos changing the "
|
||||||
|
"file signature (size & modification date). In this case, --update would normally "
|
||||||
|
"re-export the processed files but with --ignore-signature, files which exist "
|
||||||
|
"in the export directory will not be re-exported.",
|
||||||
|
)
|
||||||
@click.option(
|
@click.option(
|
||||||
"--dry-run",
|
"--dry-run",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
@@ -1496,6 +1508,7 @@ def export(
|
|||||||
verbose,
|
verbose,
|
||||||
missing,
|
missing,
|
||||||
update,
|
update,
|
||||||
|
ignore_signature,
|
||||||
dry_run,
|
dry_run,
|
||||||
export_as_hardlink,
|
export_as_hardlink,
|
||||||
touch_file,
|
touch_file,
|
||||||
@@ -1621,6 +1634,7 @@ def export(
|
|||||||
verbose = cfg.verbose
|
verbose = cfg.verbose
|
||||||
missing = cfg.missing
|
missing = cfg.missing
|
||||||
update = cfg.update
|
update = cfg.update
|
||||||
|
ignore_signature = cfg.ignore_signature
|
||||||
dry_run = cfg.dry_run
|
dry_run = cfg.dry_run
|
||||||
export_as_hardlink = cfg.export_as_hardlink
|
export_as_hardlink = cfg.export_as_hardlink
|
||||||
touch_file = cfg.touch_file
|
touch_file = cfg.touch_file
|
||||||
@@ -1714,6 +1728,7 @@ def export(
|
|||||||
dependent_options = [
|
dependent_options = [
|
||||||
("missing", ("download_missing", "use_photos_export")),
|
("missing", ("download_missing", "use_photos_export")),
|
||||||
("jpeg_quality", ("convert_to_jpeg")),
|
("jpeg_quality", ("convert_to_jpeg")),
|
||||||
|
("ignore_signature", ("update")),
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
cfg.validate(exclusive=exclusive_options, dependent=dependent_options, cli=True)
|
cfg.validate(exclusive=exclusive_options, dependent=dependent_options, cli=True)
|
||||||
@@ -1932,6 +1947,7 @@ def export(
|
|||||||
export_by_date=export_by_date,
|
export_by_date=export_by_date,
|
||||||
sidecar=sidecar,
|
sidecar=sidecar,
|
||||||
update=update,
|
update=update,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
export_as_hardlink=export_as_hardlink,
|
export_as_hardlink=export_as_hardlink,
|
||||||
overwrite=overwrite,
|
overwrite=overwrite,
|
||||||
export_edited=export_edited,
|
export_edited=export_edited,
|
||||||
@@ -1990,6 +2006,7 @@ def export(
|
|||||||
export_by_date=export_by_date,
|
export_by_date=export_by_date,
|
||||||
sidecar=sidecar,
|
sidecar=sidecar,
|
||||||
update=update,
|
update=update,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
export_as_hardlink=export_as_hardlink,
|
export_as_hardlink=export_as_hardlink,
|
||||||
overwrite=overwrite,
|
overwrite=overwrite,
|
||||||
export_edited=export_edited,
|
export_edited=export_edited,
|
||||||
@@ -2560,6 +2577,7 @@ def export_photo(
|
|||||||
export_by_date=None,
|
export_by_date=None,
|
||||||
sidecar=None,
|
sidecar=None,
|
||||||
update=None,
|
update=None,
|
||||||
|
ignore_signature=None,
|
||||||
export_as_hardlink=None,
|
export_as_hardlink=None,
|
||||||
overwrite=None,
|
overwrite=None,
|
||||||
export_edited=None,
|
export_edited=None,
|
||||||
@@ -2766,6 +2784,7 @@ def export_photo(
|
|||||||
keyword_template=keyword_template,
|
keyword_template=keyword_template,
|
||||||
description_template=description_template,
|
description_template=description_template,
|
||||||
update=update,
|
update=update,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
export_db=export_db,
|
export_db=export_db,
|
||||||
fileutil=fileutil,
|
fileutil=fileutil,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
@@ -2872,6 +2891,7 @@ def export_photo(
|
|||||||
keyword_template=keyword_template,
|
keyword_template=keyword_template,
|
||||||
description_template=description_template,
|
description_template=description_template,
|
||||||
update=update,
|
update=update,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
export_db=export_db,
|
export_db=export_db,
|
||||||
fileutil=fileutil,
|
fileutil=fileutil,
|
||||||
dry_run=dry_run,
|
dry_run=dry_run,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.38.4"
|
__version__ = "0.38.5"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -285,7 +285,8 @@ def export(
|
|||||||
when exporting metadata with exiftool or sidecar
|
when exporting metadata with exiftool or sidecar
|
||||||
keyword_template: (list of strings); list of template strings that will be rendered as used as keywords
|
keyword_template: (list of strings); list of template strings that will be rendered as used as keywords
|
||||||
description_template: string; optional template string that will be rendered for use as photo description
|
description_template: string; optional template string that will be rendered for use as photo description
|
||||||
returns: list of photos exported
|
|
||||||
|
Returns: list of photos exported
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Implementation note: calls export2 to actually do the work
|
# Implementation note: calls export2 to actually do the work
|
||||||
@@ -333,6 +334,7 @@ def export2(
|
|||||||
keyword_template=None,
|
keyword_template=None,
|
||||||
description_template=None,
|
description_template=None,
|
||||||
update=False,
|
update=False,
|
||||||
|
ignore_signature=False,
|
||||||
export_db=None,
|
export_db=None,
|
||||||
fileutil=FileUtil,
|
fileutil=FileUtil,
|
||||||
dry_run=False,
|
dry_run=False,
|
||||||
@@ -376,6 +378,7 @@ def export2(
|
|||||||
description_template: string; optional template string that will be rendered for use as photo description
|
description_template: string; optional template string that will be rendered for use as photo description
|
||||||
update: (boolean, default=False); if True export will run in update mode, that is, it will
|
update: (boolean, default=False); if True export will run in update mode, that is, it will
|
||||||
not export the photo if the current version already exists in the destination
|
not export the photo if the current version already exists in the destination
|
||||||
|
ignore_signature: (bool, default=False), ignore file signature when used with update (look only at filename)
|
||||||
export_db: (ExportDB_ABC); instance of a class that conforms to ExportDB_ABC with methods
|
export_db: (ExportDB_ABC); instance of a class that conforms to ExportDB_ABC with methods
|
||||||
for getting/setting data related to exported files to compare update state
|
for getting/setting data related to exported files to compare update state
|
||||||
fileutil: (FileUtilABC); class that conforms to FileUtilABC with various file utilities
|
fileutil: (FileUtilABC); class that conforms to FileUtilABC with various file utilities
|
||||||
@@ -606,6 +609,7 @@ def export2(
|
|||||||
fileutil=fileutil,
|
fileutil=fileutil,
|
||||||
edited=edited,
|
edited=edited,
|
||||||
jpeg_quality=jpeg_quality,
|
jpeg_quality=jpeg_quality,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
)
|
)
|
||||||
exported_files = results.exported
|
exported_files = results.exported
|
||||||
update_new_files = results.new
|
update_new_files = results.new
|
||||||
@@ -631,6 +635,7 @@ def export2(
|
|||||||
touch_file,
|
touch_file,
|
||||||
False,
|
False,
|
||||||
fileutil=fileutil,
|
fileutil=fileutil,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
)
|
)
|
||||||
exported_files.extend(results.exported)
|
exported_files.extend(results.exported)
|
||||||
update_new_files.extend(results.new)
|
update_new_files.extend(results.new)
|
||||||
@@ -657,6 +662,7 @@ def export2(
|
|||||||
convert_to_jpeg,
|
convert_to_jpeg,
|
||||||
fileutil=fileutil,
|
fileutil=fileutil,
|
||||||
jpeg_quality=jpeg_quality,
|
jpeg_quality=jpeg_quality,
|
||||||
|
ignore_signature=ignore_signature,
|
||||||
)
|
)
|
||||||
exported_files.extend(results.exported)
|
exported_files.extend(results.exported)
|
||||||
update_new_files.extend(results.new)
|
update_new_files.extend(results.new)
|
||||||
@@ -963,6 +969,7 @@ def _export_photo(
|
|||||||
fileutil=FileUtil,
|
fileutil=FileUtil,
|
||||||
edited=False,
|
edited=False,
|
||||||
jpeg_quality=1.0,
|
jpeg_quality=1.0,
|
||||||
|
ignore_signature=None,
|
||||||
):
|
):
|
||||||
"""Helper function for export()
|
"""Helper function for export()
|
||||||
Does the actual copy or hardlink taking the appropriate
|
Does the actual copy or hardlink taking the appropriate
|
||||||
@@ -983,6 +990,7 @@ def _export_photo(
|
|||||||
fileutil: FileUtil class that conforms to fileutil.FileUtilABC
|
fileutil: FileUtil class that conforms to fileutil.FileUtilABC
|
||||||
edited: bool; set to True if exporting edited version of photo
|
edited: bool; set to True if exporting edited version of photo
|
||||||
jpeg_quality: float in range 0.0 <= jpeg_quality <= 1.0. A value of 1.0 specifies use best quality, a value of 0.0 specifies use maximum compression.
|
jpeg_quality: float in range 0.0 <= jpeg_quality <= 1.0. A value of 1.0 specifies use best quality, a value of 0.0 specifies use maximum compression.
|
||||||
|
ignore_signature: bool, ignore file signature when used with update (look only at filename)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ExportResults
|
ExportResults
|
||||||
@@ -1008,7 +1016,10 @@ def _export_photo(
|
|||||||
cmp_touch, cmp_orig = False, False
|
cmp_touch, cmp_orig = False, False
|
||||||
if dest_exists:
|
if dest_exists:
|
||||||
# update, destination exists, but we might not need to replace it...
|
# update, destination exists, but we might not need to replace it...
|
||||||
if exiftool:
|
if ignore_signature:
|
||||||
|
cmp_orig = True
|
||||||
|
cmp_touch = fileutil.cmp(src, dest, mtime1=int(self.date.timestamp()))
|
||||||
|
elif exiftool:
|
||||||
sig_exif = export_db.get_stat_exif_for_file(dest_str)
|
sig_exif = export_db.get_stat_exif_for_file(dest_str)
|
||||||
cmp_orig = fileutil.cmp_file_sig(dest_str, sig_exif)
|
cmp_orig = fileutil.cmp_file_sig(dest_str, sig_exif)
|
||||||
sig_exif = (sig_exif[0], sig_exif[1], int(self.date.timestamp()))
|
sig_exif = (sig_exif[0], sig_exif[1], int(self.date.timestamp()))
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<key>hostuuid</key>
|
<key>hostuuid</key>
|
||||||
<string>9575E48B-8D5F-5654-ABAC-4431B1167324</string>
|
<string>9575E48B-8D5F-5654-ABAC-4431B1167324</string>
|
||||||
<key>pid</key>
|
<key>pid</key>
|
||||||
<integer>464</integer>
|
<integer>485</integer>
|
||||||
<key>processname</key>
|
<key>processname</key>
|
||||||
<string>photolibraryd</string>
|
<string>photolibraryd</string>
|
||||||
<key>uid</key>
|
<key>uid</key>
|
||||||
|
|||||||
@@ -3,24 +3,24 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>BackgroundHighlightCollection</key>
|
<key>BackgroundHighlightCollection</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:43Z</date>
|
||||||
<key>BackgroundHighlightEnrichment</key>
|
<key>BackgroundHighlightEnrichment</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:42Z</date>
|
||||||
<key>BackgroundJobAssetRevGeocode</key>
|
<key>BackgroundJobAssetRevGeocode</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:43Z</date>
|
||||||
<key>BackgroundJobSearch</key>
|
<key>BackgroundJobSearch</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:43Z</date>
|
||||||
<key>BackgroundPeopleSuggestion</key>
|
<key>BackgroundPeopleSuggestion</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:41Z</date>
|
||||||
<key>BackgroundUserBehaviorProcessor</key>
|
<key>BackgroundUserBehaviorProcessor</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:43Z</date>
|
||||||
<key>PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey</key>
|
<key>PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey</key>
|
||||||
<date>2020-10-17T23:45:33Z</date>
|
<date>2020-10-17T23:45:33Z</date>
|
||||||
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
|
<key>PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate</key>
|
||||||
<date>2020-10-17T23:45:24Z</date>
|
<date>2020-10-17T23:45:24Z</date>
|
||||||
<key>PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate</key>
|
<key>PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate</key>
|
||||||
<date>2020-10-17T23:45:26Z</date>
|
<date>2020-12-16T05:41:44Z</date>
|
||||||
<key>SiriPortraitDonation</key>
|
<key>SiriPortraitDonation</key>
|
||||||
<date>2020-10-17T23:45:25Z</date>
|
<date>2020-12-16T05:41:43Z</date>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
@@ -21,7 +21,7 @@ PHOTOS_LIBRARY_PATH = "/Test-10.15.7.photoslibrary"
|
|||||||
PHOTOS_DB_LEN = 18
|
PHOTOS_DB_LEN = 18
|
||||||
PHOTOS_NOT_IN_TRASH_LEN = 16
|
PHOTOS_NOT_IN_TRASH_LEN = 16
|
||||||
PHOTOS_IN_TRASH_LEN = 2
|
PHOTOS_IN_TRASH_LEN = 2
|
||||||
PHOTOS_DB_IMPORT_SESSIONS = 12
|
PHOTOS_DB_IMPORT_SESSIONS = 13
|
||||||
|
|
||||||
KEYWORDS = [
|
KEYWORDS = [
|
||||||
"Kids",
|
"Kids",
|
||||||
@@ -93,7 +93,7 @@ UUID_DICT = {
|
|||||||
"not_intrash": "DC99FBDD-7A52-4100-A5BB-344131646C30",
|
"not_intrash": "DC99FBDD-7A52-4100-A5BB-344131646C30",
|
||||||
"intrash_person_keywords": "6FD38366-3BF2-407D-81FE-7153EB6125B6",
|
"intrash_person_keywords": "6FD38366-3BF2-407D-81FE-7153EB6125B6",
|
||||||
"import_session": "8846E3E6-8AC8-4857-8448-E3D025784410",
|
"import_session": "8846E3E6-8AC8-4857-8448-E3D025784410",
|
||||||
"movie": "2CE332F2-D578-4769-AEFA-7631BB77AA41",
|
"movie": "D1359D09-1373-4F3B-B0E3-1A4DE573E4A3",
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID_PUMPKIN_FARM = [
|
UUID_PUMPKIN_FARM = [
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ CLI_EXPORT_FILENAMES = [
|
|||||||
"wedding_edited.jpeg",
|
"wedding_edited.jpeg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CLI_EXPORT_IGNORE_SIGNATURE_FILENAMES = ["Tulips.jpg", "wedding.jpg"]
|
||||||
|
|
||||||
CLI_EXPORT_FILENAMES_ALBUM = ["Pumkins1.jpg", "Pumkins2.jpg", "Pumpkins3.jpg"]
|
CLI_EXPORT_FILENAMES_ALBUM = ["Pumkins1.jpg", "Pumkins2.jpg", "Pumpkins3.jpg"]
|
||||||
|
|
||||||
CLI_EXPORT_FILENAMES_ALBUM_UNICODE = ["IMG_4547.jpg"]
|
CLI_EXPORT_FILENAMES_ALBUM_UNICODE = ["IMG_4547.jpg"]
|
||||||
@@ -372,10 +374,10 @@ CLI_EXIFTOOL_QUICKTIME = {
|
|||||||
"QuickTime:CreateDate": "2020:01:05 22:13:13",
|
"QuickTime:CreateDate": "2020:01:05 22:13:13",
|
||||||
"QuickTime:ModifyDate": "2020:01:05 22:13:13",
|
"QuickTime:ModifyDate": "2020:01:05 22:13:13",
|
||||||
},
|
},
|
||||||
"2CE332F2-D578-4769-AEFA-7631BB77AA41": {
|
"D1359D09-1373-4F3B-B0E3-1A4DE573E4A3": {
|
||||||
"File:FileName": "Jellyfish.mp4",
|
"File:FileName": "Jellyfish1.mp4",
|
||||||
"XMP:Description": "Jellyfish Video",
|
"XMP:Description": "Jellyfish Video",
|
||||||
"XMP:Title": "Jellyfish",
|
"XMP:Title": "Jellyfish1",
|
||||||
"XMP:TagsList": "Travel",
|
"XMP:TagsList": "Travel",
|
||||||
"XMP:Subject": "Travel",
|
"XMP:Subject": "Travel",
|
||||||
"QuickTime:GPSCoordinates": "34.053345 -118.242349",
|
"QuickTime:GPSCoordinates": "34.053345 -118.242349",
|
||||||
@@ -516,6 +518,12 @@ UUID_NO_LIKES = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def modify_file(filename):
|
||||||
|
""" appends data to a file to modify it """
|
||||||
|
with open(filename, "ab") as fd:
|
||||||
|
fd.write(b"foo")
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def reset_globals():
|
def reset_globals():
|
||||||
""" reset globals in __main__ that tests may have changed """
|
""" reset globals in __main__ that tests may have changed """
|
||||||
@@ -3787,6 +3795,54 @@ def test_export_touch_files_exiftool_update():
|
|||||||
assert "skipped: 18" in result.output
|
assert "skipped: 18" in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_ignore_signature():
|
||||||
|
""" test export with --ignore-signature """
|
||||||
|
from osxphotos.__main__ import export
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
# first, export some files
|
||||||
|
result = runner.invoke(export, [os.path.join(cwd, PHOTOS_DB_15_7), ".", "-V"])
|
||||||
|
assert result.exit_code == 0
|
||||||
|
|
||||||
|
# modify a couple of files
|
||||||
|
for filename in CLI_EXPORT_IGNORE_SIGNATURE_FILENAMES:
|
||||||
|
modify_file(f"./{filename}")
|
||||||
|
|
||||||
|
# export with --update and --ignore-signature
|
||||||
|
# which should ignore the two modified files
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
os.path.join(cwd, PHOTOS_DB_15_7),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--update",
|
||||||
|
"--ignore-signature",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert "exported: 0, updated: 0" in result.output
|
||||||
|
|
||||||
|
# export with --update and not --ignore-signature
|
||||||
|
# which should updated the two modified files
|
||||||
|
result = runner.invoke(
|
||||||
|
export, [os.path.join(cwd, PHOTOS_DB_15_7), ".", "-V", "--update"]
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert "updated: 2" in result.output
|
||||||
|
|
||||||
|
# run --update again, should be 0 files exported
|
||||||
|
result = runner.invoke(
|
||||||
|
export, [os.path.join(cwd, PHOTOS_DB_15_7), ".", "-V", "--update"]
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert "exported: 0, updated: 0" in result.output
|
||||||
|
|
||||||
|
|
||||||
def test_labels():
|
def test_labels():
|
||||||
"""Test osxphotos labels """
|
"""Test osxphotos labels """
|
||||||
import json
|
import json
|
||||||
|
|||||||