Added --not-edited option to query | Added corresponding tests for query and export (#956)
* Added --not-edited option to query Added --not-edited option to query (exclusive with --edited) to search for photos that have not been edited. Added test scenarios for --edited and -.-not-edited * Added --not-edited option to query Added --not-edited option to query (exclusive with --edited) to search for photos that have not been edited. Added query test scenarios for --edited and --not-edited Added export test scenarios for --edited and --not-edited * Added --not-edited option to query Added --not-edited option to query (exclusive with --edited) to search for photos that have not been edited. Added query test scenarios for --edited and --not-edited Added export test scenarios for --edited and --not-edited * Made edited/non-edited mutually exclusive in query() to match other filters Co-authored-by: Rhet Turnbull <rturnbull@gmail.com>
This commit is contained in:
@@ -289,6 +289,7 @@ def QUERY_OPTIONS(f):
|
|||||||
help="Case insensitive search for title, description, place, keyword, person, or album.",
|
help="Case insensitive search for title, description, place, keyword, person, or album.",
|
||||||
),
|
),
|
||||||
o("--edited", is_flag=True, help="Search for photos that have been edited."),
|
o("--edited", is_flag=True, help="Search for photos that have been edited."),
|
||||||
|
o("--not-edited", is_flag=True, help="Search for photos that have not been edited."),
|
||||||
o(
|
o(
|
||||||
"--external-edit",
|
"--external-edit",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
|
|||||||
@@ -805,6 +805,7 @@ def export(
|
|||||||
no_title,
|
no_title,
|
||||||
not_burst,
|
not_burst,
|
||||||
not_cloudasset,
|
not_cloudasset,
|
||||||
|
not_edited,
|
||||||
not_favorite,
|
not_favorite,
|
||||||
not_hdr,
|
not_hdr,
|
||||||
not_hidden,
|
not_hidden,
|
||||||
@@ -1024,6 +1025,7 @@ def export(
|
|||||||
no_title = cfg.no_title
|
no_title = cfg.no_title
|
||||||
not_burst = cfg.not_burst
|
not_burst = cfg.not_burst
|
||||||
not_cloudasset = cfg.not_cloudasset
|
not_cloudasset = cfg.not_cloudasset
|
||||||
|
not_edited = cfg.not_edited
|
||||||
not_favorite = cfg.not_favorite
|
not_favorite = cfg.not_favorite
|
||||||
not_hdr = cfg.not_hdr
|
not_hdr = cfg.not_hdr
|
||||||
not_hidden = cfg.not_hidden
|
not_hidden = cfg.not_hidden
|
||||||
@@ -1117,6 +1119,7 @@ def export(
|
|||||||
("cloudasset", "not_cloudasset"),
|
("cloudasset", "not_cloudasset"),
|
||||||
("deleted", "deleted_only"),
|
("deleted", "deleted_only"),
|
||||||
("description", "no_description"),
|
("description", "no_description"),
|
||||||
|
("edited", "not_edited"),
|
||||||
("export_as_hardlink", "convert_to_jpeg"),
|
("export_as_hardlink", "convert_to_jpeg"),
|
||||||
("export_as_hardlink", "download_missing"),
|
("export_as_hardlink", "download_missing"),
|
||||||
("export_as_hardlink", "exiftool"),
|
("export_as_hardlink", "exiftool"),
|
||||||
@@ -1398,6 +1401,7 @@ def export(
|
|||||||
no_title=no_title,
|
no_title=no_title,
|
||||||
not_burst=not_burst,
|
not_burst=not_burst,
|
||||||
not_cloudasset=not_cloudasset,
|
not_cloudasset=not_cloudasset,
|
||||||
|
not_edited = not_edited,
|
||||||
not_favorite=not_favorite,
|
not_favorite=not_favorite,
|
||||||
not_hdr=not_hdr,
|
not_hdr=not_hdr,
|
||||||
not_hidden=not_hidden,
|
not_hidden=not_hidden,
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ def query(
|
|||||||
no_title,
|
no_title,
|
||||||
not_burst,
|
not_burst,
|
||||||
not_cloudasset,
|
not_cloudasset,
|
||||||
|
not_edited,
|
||||||
not_favorite,
|
not_favorite,
|
||||||
not_hdr,
|
not_hdr,
|
||||||
not_hidden,
|
not_hidden,
|
||||||
@@ -183,7 +184,6 @@ def query(
|
|||||||
added_in_last,
|
added_in_last,
|
||||||
album,
|
album,
|
||||||
duplicate,
|
duplicate,
|
||||||
edited,
|
|
||||||
exif,
|
exif,
|
||||||
external_edit,
|
external_edit,
|
||||||
folder,
|
folder,
|
||||||
@@ -215,6 +215,7 @@ def query(
|
|||||||
(burst, not_burst),
|
(burst, not_burst),
|
||||||
(cloudasset, not_cloudasset),
|
(cloudasset, not_cloudasset),
|
||||||
(deleted, deleted_only),
|
(deleted, deleted_only),
|
||||||
|
(edited, not_edited),
|
||||||
(favorite, not_favorite),
|
(favorite, not_favorite),
|
||||||
(has_comment, no_comment),
|
(has_comment, no_comment),
|
||||||
(has_likes, no_likes),
|
(has_likes, no_likes),
|
||||||
@@ -318,6 +319,7 @@ def query(
|
|||||||
no_title=no_title,
|
no_title=no_title,
|
||||||
not_burst=not_burst,
|
not_burst=not_burst,
|
||||||
not_cloudasset=not_cloudasset,
|
not_cloudasset=not_cloudasset,
|
||||||
|
not_edited=not_edited,
|
||||||
not_favorite=not_favorite,
|
not_favorite=not_favorite,
|
||||||
not_hdr=not_hdr,
|
not_hdr=not_hdr,
|
||||||
not_hidden=not_hidden,
|
not_hidden=not_hidden,
|
||||||
|
|||||||
@@ -3264,6 +3264,8 @@ class PhotosDB:
|
|||||||
|
|
||||||
if options.edited:
|
if options.edited:
|
||||||
photos = [p for p in photos if p.hasadjustments]
|
photos = [p for p in photos if p.hasadjustments]
|
||||||
|
elif options.not_edited:
|
||||||
|
photos = [p for p in photos if not p.hasadjustments]
|
||||||
|
|
||||||
if options.external_edit:
|
if options.external_edit:
|
||||||
photos = [p for p in photos if p.external_edit]
|
photos = [p for p in photos if p.external_edit]
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class QueryOptions:
|
|||||||
no_title: search for photos with no title
|
no_title: search for photos with no title
|
||||||
not_burst: search for non-burst photos
|
not_burst: search for non-burst photos
|
||||||
not_cloudasset: search for photos that are not managed by iCloud
|
not_cloudasset: search for photos that are not managed by iCloud
|
||||||
|
not_edited: search for photos that have not been edited
|
||||||
not_favorite: search for non-favorite photos
|
not_favorite: search for non-favorite photos
|
||||||
not_hdr: search for non-HDR photos
|
not_hdr: search for non-HDR photos
|
||||||
not_hidden: search for non-hidden photos
|
not_hidden: search for non-hidden photos
|
||||||
@@ -143,6 +144,7 @@ class QueryOptions:
|
|||||||
no_title: Optional[bool] = None
|
no_title: Optional[bool] = None
|
||||||
not_burst: Optional[bool] = None
|
not_burst: Optional[bool] = None
|
||||||
not_cloudasset: Optional[bool] = None
|
not_cloudasset: Optional[bool] = None
|
||||||
|
not_edited: Optional[bool] = None
|
||||||
not_favorite: Optional[bool] = None
|
not_favorite: Optional[bool] = None
|
||||||
not_hdr: Optional[bool] = None
|
not_hdr: Optional[bool] = None
|
||||||
not_hidden: Optional[bool] = None
|
not_hidden: Optional[bool] = None
|
||||||
|
|||||||
@@ -875,6 +875,39 @@ UUID_IS_REFERENCE = [
|
|||||||
"A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
|
"A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
UUID_EDITED = [
|
||||||
|
"D1D4040D-D141-44E8-93EA-E403D9F63E07",
|
||||||
|
"7783E8E6-9CAC-40F3-BE22-81FB7051C266",
|
||||||
|
"E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
|
||||||
|
"6191423D-8DB8-4D4C-92BE-9BBBA308AAC4",
|
||||||
|
"1793FAAB-DE75-4E25-886C-2BD66C780D6A",
|
||||||
|
"DC99FBDD-7A52-4100-A5BB-344131646C30",
|
||||||
|
]
|
||||||
|
|
||||||
|
UUID_NOT_EDITED = [
|
||||||
|
"F12384F6-CD17-4151-ACBA-AE0E3688539E",
|
||||||
|
"7F74DD34-5920-4DA3-B284-479887A34F66",
|
||||||
|
"4D521201-92AC-43E5-8F7C-59BC41C37A96",
|
||||||
|
"54E76FCB-D353-4557-9997-0A457BCB4D48",
|
||||||
|
"8E1D7BC9-9321-44F9-8CFB-4083F6B9232A",
|
||||||
|
"F207D5DE-EFAD-4217-8424-0764AAC971D0",
|
||||||
|
"D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068",
|
||||||
|
"52083079-73D5-4921-AC1B-FE76F279133F",
|
||||||
|
"A92D9C26-3A50-4197-9388-CB5F7DB9FA91",
|
||||||
|
"3DD2C897-F19E-4CA6-8C22-B027D5A71907",
|
||||||
|
"7FD37B5F-6FAA-4DB1-8A29-BF9C37E38091",
|
||||||
|
"B13F4485-94E0-41CD-AF71-913095D62E31",
|
||||||
|
"A8266C97-9BAF-4AF4-99F3-0013832869B8",
|
||||||
|
"1EB2B765-0765-43BA-A90C-0D0580E6172C",
|
||||||
|
"E2078879-A29C-4D6F-BACB-E3BBE6C3EB91",
|
||||||
|
"D79B8D77-BFFC-460B-9312-034F2877D35B",
|
||||||
|
"8846E3E6-8AC8-4857-8448-E3D025784410",
|
||||||
|
"D1359D09-1373-4F3B-B0E3-1A4DE573E4A3",
|
||||||
|
"A1DD1F98-2ECD-431F-9AC9-5AFEFE2D3A5C",
|
||||||
|
"35329C57-B963-48D6-BB75-6AFF9370CBBC",
|
||||||
|
"2DFD33F1-A5D8-486F-A3A9-98C07995535A",
|
||||||
|
]
|
||||||
|
|
||||||
UUID_IN_ALBUM = [
|
UUID_IN_ALBUM = [
|
||||||
"1EB2B765-0765-43BA-A90C-0D0580E6172C",
|
"1EB2B765-0765-43BA-A90C-0D0580E6172C",
|
||||||
"2DFD33F1-A5D8-486F-A3A9-98C07995535A",
|
"2DFD33F1-A5D8-486F-A3A9-98C07995535A",
|
||||||
@@ -1250,6 +1283,38 @@ def test_query_is_reference():
|
|||||||
assert sorted(uuid_got) == sorted(UUID_IS_REFERENCE)
|
assert sorted(uuid_got) == sorted(UUID_IS_REFERENCE)
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_edited():
|
||||||
|
"""Test query with --edited"""
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
result = runner.invoke(
|
||||||
|
query, ["--json", "--db", os.path.join(cwd, CLI_PHOTOS_DB), "--edited"]
|
||||||
|
)
|
||||||
|
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_EDITED)
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_not_edited():
|
||||||
|
"""Test query with --not-edited"""
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
result = runner.invoke(
|
||||||
|
query, ["--json", "--db", os.path.join(cwd, CLI_PHOTOS_DB), "--not-edited"]
|
||||||
|
)
|
||||||
|
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_NOT_EDITED)
|
||||||
|
|
||||||
|
|
||||||
def test_query_in_album():
|
def test_query_in_album():
|
||||||
"""Test query with --in-album"""
|
"""Test query with --in-album"""
|
||||||
|
|
||||||
@@ -1835,6 +1900,45 @@ def test_export_skip_edited():
|
|||||||
assert "St James Park_edited.jpeg" not in files
|
assert "St James Park_edited.jpeg" not in files
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_edited():
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export, [os.path.join(cwd, CLI_PHOTOS_DB), ".", "--edited", "-V"]
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
files = glob.glob("*")
|
||||||
|
# make sure edited versions did get exported
|
||||||
|
assert "wedding_edited.jpeg" in files
|
||||||
|
assert "Tulips_edited.jpeg" in files
|
||||||
|
assert "St James Park_edited.jpeg" in files
|
||||||
|
|
||||||
|
|
||||||
|
def test_export_not_edited():
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
cwd = os.getcwd()
|
||||||
|
# pylint: disable=not-context-manager
|
||||||
|
with runner.isolated_filesystem():
|
||||||
|
result = runner.invoke(
|
||||||
|
export, [os.path.join(cwd, CLI_PHOTOS_DB), ".", "--not-edited", "-V"]
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
files = glob.glob("*")
|
||||||
|
# make sure not edited files were exported
|
||||||
|
assert "Pumkins1.jpg" in files
|
||||||
|
assert "Pumkins2.jpg" in files
|
||||||
|
assert "Jellyfish1.mp4" in files
|
||||||
|
|
||||||
|
# make sure edited versions did not get exported
|
||||||
|
assert "wedding_edited.jpeg" not in files
|
||||||
|
assert "Tulips_edited.jpeg" not in files
|
||||||
|
assert "St James Park_edited.jpeg" not in files
|
||||||
|
|
||||||
|
|
||||||
def test_export_skip_original_if_edited():
|
def test_export_skip_original_if_edited():
|
||||||
"""test export with --skip-original-if-edited"""
|
"""test export with --skip-original-if-edited"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user