From 870a59a2fa10766361b384216594af36d3605850 Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sun, 20 Jun 2021 15:33:03 -0700 Subject: [PATCH] Added --location, --no-location, #474 --- README.md | 8 ++++-- osxphotos/_version.py | 2 +- osxphotos/cli.py | 22 +++++++++++++++ osxphotos/photosdb/photosdb.py | 5 ++++ osxphotos/queryoptions.py | 2 ++ tests/test_cli.py | 49 ++++++++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 01892b3d..1359bd46 100644 --- a/README.md +++ b/README.md @@ -616,6 +616,10 @@ Options: geolocation info --no-place Search for photos with no associated place name info (no reverse geolocation info) + --location Search for photos with associated location + info (e.g. GPS coordinates) + --no-location Search for photos with no associated location + info (e.g. no GPS coordinates) --label LABEL Search for photos with image classification label LABEL (Photos 5 only). If more than one label, treated as "OR", e.g. find photos @@ -1583,7 +1587,7 @@ Substitution Description {lf} A line feed: '\n', alias for {newline} {cr} A carriage return: '\r' {crlf} a carriage return + line feed: '\r\n' -{osxphotos_version} The osxphotos version, e.g. '0.42.43' +{osxphotos_version} The osxphotos version, e.g. '0.42.44' {osxphotos_cmd_line} The full command line used to run osxphotos The following substitutions may result in multiple values. Thus if specified for @@ -3382,7 +3386,7 @@ The following template field substitutions are availabe for use the templating s |{lf}|A line feed: '\n', alias for {newline}| |{cr}|A carriage return: '\r'| |{crlf}|a carriage return + line feed: '\r\n'| -|{osxphotos_version}|The osxphotos version, e.g. '0.42.43'| +|{osxphotos_version}|The osxphotos version, e.g. '0.42.44'| |{osxphotos_cmd_line}|The full command line used to run osxphotos| |{album}|Album(s) photo is contained in| |{folder_album}|Folder path + album photo is contained in. e.g. 'Folder/Subfolder/Album' or just 'Album' if no enclosing folder| diff --git a/osxphotos/_version.py b/osxphotos/_version.py index d092fb10..b4a9a0c2 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.42.43" +__version__ = "0.42.44" diff --git a/osxphotos/cli.py b/osxphotos/cli.py index 222437e8..2b0859f2 100644 --- a/osxphotos/cli.py +++ b/osxphotos/cli.py @@ -332,6 +332,16 @@ def QUERY_OPTIONS(f): is_flag=True, help="Search for photos with no associated place name info (no reverse geolocation info)", ), + o( + "--location", + is_flag=True, + help="Search for photos with associated location info (e.g. GPS coordinates)", + ), + o( + "--no-location", + is_flag=True, + help="Search for photos with no associated location info (e.g. no GPS coordinates)", + ), o( "--label", metavar="LABEL", @@ -1104,6 +1114,8 @@ def export( original_suffix, place, no_place, + location, + no_location, has_comment, no_comment, has_likes, @@ -1263,6 +1275,8 @@ def export( original_suffix = cfg.original_suffix place = cfg.place no_place = cfg.no_place + location = cfg.location + no_location = cfg.no_location has_comment = cfg.has_comment no_comment = cfg.no_comment has_likes = cfg.has_likes @@ -1323,6 +1337,7 @@ def export( ("has_comment", "no_comment"), ("has_likes", "no_likes"), ("in_album", "not_in_album"), + ("location", "no_location"), ] dependent_options = [ ("missing", ("download_missing", "use_photos_export")), @@ -1576,6 +1591,8 @@ def export( has_raw=has_raw, place=place, no_place=no_place, + location=location, + no_location=no_location, label=label, deleted=deleted, deleted_only=deleted_only, @@ -1979,6 +1996,8 @@ def query( has_raw, place, no_place, + location, + no_location, label, deleted, deleted_only, @@ -2051,6 +2070,7 @@ def query( (has_comment, no_comment), (has_likes, no_likes), (in_album, not_in_album), + (location, no_location), ] # print help if no non-exclusive term or a double exclusive term is given if any(all(bb) for bb in exclusive) or not any( @@ -2136,6 +2156,8 @@ def query( has_raw=has_raw, place=place, no_place=no_place, + location=location, + no_location=no_location, label=label, deleted=deleted, deleted_only=deleted_only, diff --git a/osxphotos/photosdb/photosdb.py b/osxphotos/photosdb/photosdb.py index 90927e05..28c94bff 100644 --- a/osxphotos/photosdb/photosdb.py +++ b/osxphotos/photosdb/photosdb.py @@ -3254,6 +3254,11 @@ class PhotosDB: if options.deleted_only: photos = [p for p in photos if p.intrash] + if options.location: + photos = [p for p in photos if p.location != (None, None)] + elif options.no_location: + photos = [p for p in photos if p.location == (None, None)] + return photos def _duplicate_signature(self, uuid): diff --git a/osxphotos/queryoptions.py b/osxphotos/queryoptions.py index d488c22a..3171d7ac 100644 --- a/osxphotos/queryoptions.py +++ b/osxphotos/queryoptions.py @@ -79,6 +79,8 @@ class QueryOptions: regex: Optional[Iterable[Tuple[str, str]]] = None query_eval: Optional[Iterable[str]] = None duplicate: Optional[bool] = None + location: Optional[bool] = None + no_location: Optional[bool] = None def asdict(self): return asdict(self) diff --git a/tests/test_cli.py b/tests/test_cli.py index d7f0111c..c787e42f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -771,6 +771,9 @@ UUID_DUPLICATES = [ "52083079-73D5-4921-AC1B-FE76F279133F", ] +UUID_LOCATION = "D79B8D77-BFFC-460B-9312-034F2877D35B" # Pumkins2.jpg +UUID_NO_LOCATION = "6191423D-8DB8-4D4C-92BE-9BBBA308AAC4" # Tulips.jpg" + def modify_file(filename): """appends data to a file to modify it""" @@ -1147,6 +1150,52 @@ def test_query_duplicate(): assert sorted(uuid_got) == sorted(UUID_DUPLICATES) +def test_query_location(): + """Test query with --location""" + import json + import os + import os.path + + from osxphotos.cli import query + + runner = CliRunner() + cwd = os.getcwd() + result = runner.invoke( + query, + ["--json", "--db", os.path.join(cwd, CLI_PHOTOS_DB), "--location"], + ) + 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 UUID_LOCATION in uuid_got + assert UUID_NO_LOCATION not in uuid_got + + +def test_query_no_location(): + """Test query with --no-location""" + import json + import os + import os.path + + from osxphotos.cli import query + + runner = CliRunner() + cwd = os.getcwd() + result = runner.invoke( + query, + ["--json", "--db", os.path.join(cwd, CLI_PHOTOS_DB), "--no-location"], + ) + 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 UUID_NO_LOCATION in uuid_got + assert UUID_LOCATION not in uuid_got + + def test_export(): import glob import os