Added --year query option, #593 (#670)

This commit is contained in:
Rhet Turnbull
2022-04-20 07:27:03 -06:00
committed by GitHub
parent 7e4977e2c5
commit 77433b01ed
10 changed files with 128 additions and 2 deletions

View File

@@ -738,6 +738,10 @@ Options:
or 12:00:00. or 12:00:00.
--to-time TIME Search by item end time of day, e.g. 12:00 or --to-time TIME Search by item end time of day, e.g. 12:00 or
12:00:00. 12:00:00.
--year INTEGER Search for items from a specific year, e.g.
--year 2022 to find all photos from the year
2022. May be repeated to search multiple
years.
--has-comment Search for photos that have comments. --has-comment Search for photos that have comments.
--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.

View File

@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.47.5 documentation</title> <title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.47.8 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" /> <link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
@@ -3322,6 +3322,9 @@
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">:</span> <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">&lt;=</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">]</span> <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">&lt;=</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">]</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">year</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">year</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">year</span><span class="p">]</span>
<span class="k">if</span> <span class="n">name</span><span class="p">:</span> <span class="k">if</span> <span class="n">name</span><span class="p">:</span>
<span class="c1"># search filename fields for text</span> <span class="c1"># search filename fields for text</span>
<span class="c1"># if more than one, find photos with all title values in filename</span> <span class="c1"># if more than one, find photos with all title values in filename</span>

View File

@@ -368,6 +368,13 @@ def QUERY_OPTIONS(f):
help="Search by item end time of day, e.g. 12:00 or 12:00:00.", help="Search by item end time of day, e.g. 12:00 or 12:00:00.",
type=TimeISO8601(), type=TimeISO8601(),
), ),
o(
"--year",
help="Search for items from a specific year, e.g. --year 2022 to find all photos from the year 2022. "
"May be repeated to search multiple years.",
multiple=True,
type=int,
),
o("--has-comment", is_flag=True, help="Search for photos that have comments."), o("--has-comment", is_flag=True, help="Search for photos that have comments."),
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."),

View File

@@ -697,6 +697,7 @@ def export(
to_date, to_date,
from_time, from_time,
to_time, to_time,
year,
verbose, verbose,
timestamp, timestamp,
no_progress, no_progress,
@@ -1018,6 +1019,7 @@ def export(
uuid_from_file = cfg.uuid_from_file uuid_from_file = cfg.uuid_from_file
verbose = cfg.verbose verbose = cfg.verbose
xattr_template = cfg.xattr_template xattr_template = cfg.xattr_template
year = cfg.year
# config file might have changed verbose # config file might have changed verbose
color_theme = get_theme(theme) color_theme = get_theme(theme)
@@ -1300,6 +1302,7 @@ def export(
to_date=to_date, to_date=to_date,
from_time=from_time, from_time=from_time,
to_time=to_time, to_time=to_time,
year=year,
portrait=portrait, portrait=portrait,
not_portrait=not_portrait, not_portrait=not_portrait,
screenshot=screenshot, screenshot=screenshot,

View File

@@ -111,6 +111,7 @@ def query(
to_date, to_date,
from_time, from_time,
to_time, to_time,
year,
portrait, portrait,
not_portrait, not_portrait,
screenshot, screenshot,
@@ -174,6 +175,7 @@ def query(
to_date, to_date,
from_time, from_time,
to_time, to_time,
year,
label, label,
is_reference, is_reference,
query_eval, query_eval,
@@ -280,6 +282,7 @@ def query(
to_date=to_date, to_date=to_date,
from_time=from_time, from_time=from_time,
to_time=to_time, to_time=to_time,
year=year,
portrait=portrait, portrait=portrait,
not_portrait=not_portrait, not_portrait=not_portrait,
screenshot=screenshot, screenshot=screenshot,

View File

@@ -256,6 +256,7 @@ def _query_options_from_kwargs(**kwargs) -> QueryOptions:
"to_date", "to_date",
"from_time", "from_time",
"to_time", "to_time",
"year",
"label", "label",
"is_reference", "is_reference",
"query_eval", "query_eval",

View File

@@ -5,7 +5,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.47.5 documentation</title> <title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.47.8 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" /> <link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script> <script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
@@ -3322,6 +3322,9 @@
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">:</span> <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">&lt;=</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">]</span> <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">&lt;=</span> <span class="n">options</span><span class="o">.</span><span class="n">to_time</span><span class="p">]</span>
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">year</span><span class="p">:</span>
<span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">year</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">year</span><span class="p">]</span>
<span class="k">if</span> <span class="n">name</span><span class="p">:</span> <span class="k">if</span> <span class="n">name</span><span class="p">:</span>
<span class="c1"># search filename fields for text</span> <span class="c1"># search filename fields for text</span>
<span class="c1"># if more than one, find photos with all title values in filename</span> <span class="c1"># if more than one, find photos with all title values in filename</span>

View File

@@ -3289,6 +3289,9 @@ class PhotosDB:
if options.to_time: if options.to_time:
photos = [p for p in photos if p.date.time() <= options.to_time] photos = [p for p in photos if p.date.time() <= options.to_time]
if options.year:
photos = [p for p in photos if p.date.year in options.year]
if name: if name:
# search filename fields for text # search filename fields for text
# if more than one, find photos with all title values in filename # if more than one, find photos with all title values in filename

View File

@@ -87,6 +87,7 @@ class QueryOptions:
function: Optional[List[Tuple[callable, str]]] = None function: Optional[List[Tuple[callable, str]]] = None
selected: Optional[bool] = None selected: Optional[bool] = None
exif: Optional[Iterable[Tuple[str, str]]] = None exif: Optional[Iterable[Tuple[str, str]]] = None
year: Optional[int] = None
def asdict(self): def asdict(self):
return asdict(self) return asdict(self)

View File

@@ -740,6 +740,8 @@ CLI_FINDER_TAGS = {
}, },
} }
CLI_EXPORT_YEAR_2017 = ["IMG_4547.jpg"]
LABELS_JSON = { LABELS_JSON = {
"labels": { "labels": {
"Water": 2, "Water": 2,
@@ -1494,6 +1496,28 @@ def test_export_skip_uuid():
assert skipped_file not in files assert skipped_file not in files
def test_export_year():
"""test export with --year"""
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),
".",
"-V",
"--year",
"2017",
"--skip-edited",
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert sorted(files) == sorted(CLI_EXPORT_YEAR_2017)
def test_export_preview(): def test_export_preview():
"""test export with --preview""" """test export with --preview"""
@@ -2572,6 +2596,80 @@ def test_query_time():
assert len(json_got) == 3 assert len(json_got) == 3
def test_query_year_1():
"""Test --year"""
os.environ["TZ"] = "US/Pacific"
time.tzset()
runner = CliRunner()
cwd = os.getcwd()
result = runner.invoke(
query,
[
"--json",
"--db",
os.path.join(cwd, CLI_PHOTOS_DB),
"--year",
2017,
],
)
assert result.exit_code == 0
json_got = json.loads(result.output)
assert len(json_got) == 1
def test_query_year_2():
"""Test --year with multiple years"""
os.environ["TZ"] = "US/Pacific"
time.tzset()
runner = CliRunner()
cwd = os.getcwd()
result = runner.invoke(
query,
[
"--json",
"--db",
os.path.join(cwd, CLI_PHOTOS_DB),
"--year",
2017,
"--year",
2018,
],
)
assert result.exit_code == 0
json_got = json.loads(result.output)
assert len(json_got) == 6
def test_query_year_3():
"""Test --year with invalid year"""
os.environ["TZ"] = "US/Pacific"
time.tzset()
runner = CliRunner()
cwd = os.getcwd()
result = runner.invoke(
query,
[
"--json",
"--db",
os.path.join(cwd, CLI_PHOTOS_DB),
"--year",
3000,
],
)
assert result.exit_code == 0
json_got = json.loads(result.output)
assert len(json_got) == 0
def test_query_keyword_1(): def test_query_keyword_1():
"""Test query --keyword""" """Test query --keyword"""