Compare commits

..

6 Commits

Author SHA1 Message Date
Rhet Turnbull
ae5b02f563 Added additional test for {photo} template 2021-04-11 23:49:54 -07:00
Rhet Turnbull
aa1a96d201 Added {photo} template, partial fix for issue #417 2021-04-11 23:36:17 -07:00
Rhet Turnbull
d9f24307ac Added {favorite} template, partial fix for #289 2021-04-11 19:45:50 -07:00
Rhet Turnbull
958f8c343a Doc updates 2021-04-09 07:36:02 -07:00
Rhet Turnbull
70cf4c9f92 Updated CHANGELOG.md, [skip ci] 2021-04-09 06:51:35 -07:00
Rhet Turnbull
2d3344ee34 Updated docs for --query-eval 2021-04-09 06:37:51 -07:00
21 changed files with 190 additions and 39 deletions

View File

@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [v0.41.10](https://github.com/RhetTbull/osxphotos/compare/v0.41.9...v0.41.10)
> 9 April 2021
- Added --query-eval, implements #280 [`b4bc906`](https://github.com/RhetTbull/osxphotos/commit/b4bc906b6a1c3444c5f5a5d9d908ab8c955c8f7e)
#### [v0.41.9](https://github.com/RhetTbull/osxphotos/compare/v0.41.8...v0.41.9)
> 5 April 2021

View File

@@ -317,14 +317,16 @@ Options:
--not-in-album Search for photos that are not in any albums.
--query-eval CRITERIA Evaluate CRITERIA to filter photos. CRITERIA
will be evaluated in context of the following
list comprehension: `photos = [photo for photo
in photos if CRITERIA]` where photo represents
a PhotoInfo object. For example: `--query-eval
photo.favorite` returns all photos that have
been favorited and is equivalent to
--favorite. You may specify more than one
CRITERIA by using --query-eval multiple times.
See https://rhettbull.github.io/osxphotos/ for
python list comprehension: `photos = [photo
for photo in photos if CRITERIA]` where photo
represents a PhotoInfo object. For example:
`--query-eval photo.favorite` returns all
photos that have been favorited and is
equivalent to --favorite. You may specify more
than one CRITERIA by using --query-eval
multiple times. CRITERIA must be a valid
python expression. See
https://rhettbull.github.io/osxphotos/ for
additional documentation on the PhotoInfo
class.
@@ -960,6 +962,10 @@ Substitution Description
True/False value, use in format
'{edited?VALUE_IF_TRUE,VALUE_IF_FALSE}'
{favorite} Photo has been marked as favorite?; True/False
value, use in format
'{favorite?VALUE_IF_TRUE,VALUE_IF_FALSE}'
{created.date} Photo's creation date in ISO format, e.g.
'2020-03-22'
@@ -1207,6 +1213,18 @@ Substitution Description
'Restaurant'; (Photos 5+ only, applied automatically
by Photos' image categorization algorithms).
{photo} Provides direct access to the PhotoInfo object for
the photo. Must be used in format '{photo.property}'
where 'property' represents a PhotoInfo property. For
example: '{photo.favorite}' is the same as
'{favorite}' and '{photo.place.name}' is the same as
'{place.name}'. '{photo}' provides access to
properties that are not available as separate
template fields but it assumes some knowledge of the
underlying PhotoInfo class. See
https://rhettbull.github.io/osxphotos/ for additional
documentation on the PhotoInfo class.
```
@@ -2703,6 +2721,7 @@ The following template field substitutions are availabe for use with `PhotoInfo.
|{photo_or_video}|'photo' or 'video' depending on what type the image is. To customize, use default value as in '{photo_or_video,photo=fotos;video=videos}'|
|{hdr}|Photo is HDR?; True/False value, use in format '{hdr?VALUE_IF_TRUE,VALUE_IF_FALSE}'|
|{edited}|Photo has been edited (has adjustments)?; True/False value, use in format '{edited?VALUE_IF_TRUE,VALUE_IF_FALSE}'|
|{favorite}|Photo has been marked as favorite?; True/False value, use in format '{favorite?VALUE_IF_TRUE,VALUE_IF_FALSE}'|
|{created.date}|Photo's creation date in ISO format, e.g. '2020-03-22'|
|{created.year}|4-digit year of photo creation time|
|{created.yy}|2-digit year of photo creation time|
@@ -2781,6 +2800,7 @@ The following template field substitutions are availabe for use with `PhotoInfo.
|{searchinfo.activity}|Activities associated with a photo, e.g. 'Sporting Event'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).|
|{searchinfo.venue}|Venues associated with a photo, e.g. name of restaurant; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).|
|{searchinfo.venue_type}|Venue types associated with a photo, e.g. 'Restaurant'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).|
|{photo}|Provides direct access to the PhotoInfo object for the photo. Must be used in format '{photo.property}' where 'property' represents a PhotoInfo property. For example: '{photo.favorite}' is the same as '{favorite}' and '{photo.place.name}' is the same as '{place.name}'. '{photo}' provides access to properties that are not available as separate template fields but it assumes some knowledge of the underlying PhotoInfo class. See https://rhettbull.github.io/osxphotos/ for additional documentation on the PhotoInfo class.|
<!-- OSXPHOTOS-TEMPLATE-TABLE:END -->
### Utility Functions

View File

@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 83db317a0b058d0bba826496215f3269
config: 0179796ca3088aa7a0ec190387bfe684
tags: 645f666f9bcd5a90fca523b33c5a78b7

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Overview: module code &#8212; osxphotos 0.41.6 documentation</title>
<title>Overview: module code &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photoinfo._photoinfo_export &#8212; osxphotos 0.41.6 documentation</title>
<title>osxphotos.photoinfo._photoinfo_export &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
@@ -1693,7 +1693,7 @@
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
<span class="n">exif</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="s2">&quot; &quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="nb">type</span><span class="p">(</span><span class="n">val</span><span class="p">)</span> <span class="o">==</span> <span class="nb">list</span><span class="p">:</span>
<span class="n">exif</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">v</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="s2">&quot; &quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">val</span><span class="p">]</span>
<span class="n">exif</span><span class="p">[</span><span class="n">field</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">,</span> <span class="s2">&quot; &quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">val</span> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">]</span>
<span class="k">return</span> <span class="n">exif</span>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.41.4 documentation</title>
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
@@ -1861,7 +1861,6 @@
<span class="c1"># get details about photos</span>
<span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Processing photo details.&quot;</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Getting information about photos&quot;</span><span class="p">)</span>
<span class="n">c</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;&quot;&quot;SELECT </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID, </span>
<span class="s2"> ZADDITIONALASSETATTRIBUTES.ZMASTERFINGERPRINT, </span>
@@ -2769,8 +2768,6 @@
<span class="c1"># an empty album will be in _dbalbum_titles but not _dbalbums_album</span>
<span class="k">pass</span>
<span class="n">album_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">title_set</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not find album &#39;</span><span class="si">{</span><span class="n">album</span><span class="si">}</span><span class="s2">&#39; in database&quot;</span><span class="p">)</span>
<span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">album_set</span><span class="p">)</span>
<span class="k">if</span> <span class="n">uuid</span><span class="p">:</span>
@@ -2778,8 +2775,6 @@
<span class="k">for</span> <span class="n">u</span> <span class="ow">in</span> <span class="n">uuid</span><span class="p">:</span>
<span class="k">if</span> <span class="n">u</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">:</span>
<span class="n">uuid_set</span><span class="o">.</span><span class="n">update</span><span class="p">([</span><span class="n">u</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not find uuid &#39;</span><span class="si">{</span><span class="n">u</span><span class="si">}</span><span class="s2">&#39; in database&quot;</span><span class="p">)</span>
<span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">uuid_set</span><span class="p">)</span>
<span class="k">if</span> <span class="n">keywords</span><span class="p">:</span>
@@ -2787,8 +2782,6 @@
<span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">keywords</span><span class="p">:</span>
<span class="k">if</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">:</span>
<span class="n">keyword_set</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbkeywords_keyword</span><span class="p">[</span><span class="n">keyword</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not find keyword &#39;</span><span class="si">{</span><span class="n">keyword</span><span class="si">}</span><span class="s2">&#39; in database&quot;</span><span class="p">)</span>
<span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">keyword_set</span><span class="p">)</span>
<span class="k">if</span> <span class="n">persons</span><span class="p">:</span>
@@ -2801,8 +2794,6 @@
<span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
<span class="c1"># some persons have zero photos so they won&#39;t be in _dbfaces_pk</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not find person &#39;</span><span class="si">{</span><span class="n">person</span><span class="si">}</span><span class="s2">&#39; in database&quot;</span><span class="p">)</span>
<span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">person_set</span><span class="p">)</span>
<span class="k">if</span> <span class="n">from_date</span> <span class="ow">or</span> <span class="n">to_date</span><span class="p">:</span> <span class="c1"># sourcery off</span>
@@ -2813,14 +2804,10 @@
<span class="n">dsel</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">dsel</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">v</span><span class="p">[</span><span class="s2">&quot;imageDate&quot;</span><span class="p">]</span> <span class="o">&gt;=</span> <span class="n">from_date</span>
<span class="p">}</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Found %i items with from_date </span><span class="si">{</span><span class="n">from_date</span><span class="si">}</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">dsel</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">to_date</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">datetime_has_tz</span><span class="p">(</span><span class="n">to_date</span><span class="p">):</span>
<span class="n">to_date</span> <span class="o">=</span> <span class="n">datetime_naive_to_local</span><span class="p">(</span><span class="n">to_date</span><span class="p">)</span>
<span class="n">dsel</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">dsel</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">v</span><span class="p">[</span><span class="s2">&quot;imageDate&quot;</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">to_date</span><span class="p">}</span>
<span class="n">logging</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Found %i items with to_date </span><span class="si">{</span><span class="n">to_date</span><span class="si">}</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">dsel</span><span class="p">))</span>
<span class="n">photos_sets</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">dsel</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
<span class="n">photoinfo</span> <span class="o">=</span> <span class="p">[]</span>

View File

@@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.41.6',
VERSION: '0.41.10',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
BUILDER: 'html',

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos command line interface (CLI) &#8212; osxphotos 0.41.6 documentation</title>
<title>osxphotos command line interface (CLI) &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -183,6 +183,12 @@ to modify this behavior.</p>
<dd><p>Search for photos in an album in folder FOLDER. If more than one folder, treated as “OR”, e.g. find photos in any FOLDER. Only searches top level folders (e.g. does not look at subfolders)</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-export-name">
<code class="sig-name descname"><span class="pre">--name</span></code><code class="sig-prename descclassname"> <span class="pre">&lt;FILENAME&gt;</span></code><a class="headerlink" href="#cmdoption-osxphotos-export-name" title="Permalink to this definition"></a></dt>
<dd><p>Search for photos with filename matching FILENAME. If more than one name options is specified, they are treated as “OR”, e.g. find photos matching any FILENAME.</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-export-uuid">
<code class="sig-name descname"><span class="pre">--uuid</span></code><code class="sig-prename descclassname"> <span class="pre">&lt;UUID&gt;</span></code><a class="headerlink" href="#cmdoption-osxphotos-export-uuid" title="Permalink to this definition"></a></dt>
@@ -489,6 +495,12 @@ to modify this behavior.</p>
<dd><p>Search for photos that are not in any albums.</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-export-query-eval">
<code class="sig-name descname"><span class="pre">--query-eval</span></code><code class="sig-prename descclassname"> <span class="pre">&lt;CRITERIA&gt;</span></code><a class="headerlink" href="#cmdoption-osxphotos-export-query-eval" title="Permalink to this definition"></a></dt>
<dd><p>Evaluate CRITERIA to filter photos. CRITERIA will be evaluated in context of the following python list comprehension: <cite>photos = [photo for photo in photos if CRITERIA]</cite> where photo represents a PhotoInfo object. For example: <cite>query-eval photo.favorite</cite> returns all photos that have been favorited and is equivalent to favorite. You may specify more than one CRITERIA by using query-eval multiple times. CRITERIA must be a valid python expression. See <a class="reference external" href="https://rhettbull.github.io/osxphotos/">https://rhettbull.github.io/osxphotos/</a> for additional documentation on the PhotoInfo class.</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-export-missing">
<code class="sig-name descname"><span class="pre">--missing</span></code><code class="sig-prename descclassname"></code><a class="headerlink" href="#cmdoption-osxphotos-export-missing" title="Permalink to this definition"></a></dt>
@@ -1023,6 +1035,12 @@ if more than one option is provided, they are treated as “AND”
<dd><p>Search for photos in an album in folder FOLDER. If more than one folder, treated as “OR”, e.g. find photos in any FOLDER. Only searches top level folders (e.g. does not look at subfolders)</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-query-name">
<code class="sig-name descname"><span class="pre">--name</span></code><code class="sig-prename descclassname"> <span class="pre">&lt;FILENAME&gt;</span></code><a class="headerlink" href="#cmdoption-osxphotos-query-name" title="Permalink to this definition"></a></dt>
<dd><p>Search for photos with filename matching FILENAME. If more than one name options is specified, they are treated as “OR”, e.g. find photos matching any FILENAME.</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-query-uuid">
<code class="sig-name descname"><span class="pre">--uuid</span></code><code class="sig-prename descclassname"> <span class="pre">&lt;UUID&gt;</span></code><a class="headerlink" href="#cmdoption-osxphotos-query-uuid" title="Permalink to this definition"></a></dt>
@@ -1329,6 +1347,12 @@ if more than one option is provided, they are treated as “AND”
<dd><p>Search for photos that are not in any albums.</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-query-query-eval">
<code class="sig-name descname"><span class="pre">--query-eval</span></code><code class="sig-prename descclassname"> <span class="pre">&lt;CRITERIA&gt;</span></code><a class="headerlink" href="#cmdoption-osxphotos-query-query-eval" title="Permalink to this definition"></a></dt>
<dd><p>Evaluate CRITERIA to filter photos. CRITERIA will be evaluated in context of the following python list comprehension: <cite>photos = [photo for photo in photos if CRITERIA]</cite> where photo represents a PhotoInfo object. For example: <cite>query-eval photo.favorite</cite> returns all photos that have been favorited and is equivalent to favorite. You may specify more than one CRITERIA by using query-eval multiple times. CRITERIA must be a valid python expression. See <a class="reference external" href="https://rhettbull.github.io/osxphotos/">https://rhettbull.github.io/osxphotos/</a> for additional documentation on the PhotoInfo class.</p>
</dd></dl>
<dl class="std option">
<dt id="cmdoption-osxphotos-query-deleted">
<code class="sig-name descname"><span class="pre">--deleted</span></code><code class="sig-prename descclassname"></code><a class="headerlink" href="#cmdoption-osxphotos-query-deleted" title="Permalink to this definition"></a></dt>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; osxphotos 0.41.6 documentation</title>
<title>Index &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
@@ -518,6 +518,15 @@
<li><a href="cli.html#cmdoption-osxphotos-export-missing">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-missing">osxphotos-query command line option</a>
</li>
</ul></li>
<li>
--name &lt;FILENAME&gt;
<ul>
<li><a href="cli.html#cmdoption-osxphotos-export-name">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-name">osxphotos-query command line option</a>
</li>
</ul></li>
<li>
@@ -785,6 +794,15 @@
<li><a href="cli.html#cmdoption-osxphotos-export-portrait">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-portrait">osxphotos-query command line option</a>
</li>
</ul></li>
<li>
--query-eval &lt;CRITERIA&gt;
<ul>
<li><a href="cli.html#cmdoption-osxphotos-export-query-eval">osxphotos-export command line option</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-query-eval">osxphotos-query command line option</a>
</li>
</ul></li>
<li>
@@ -1539,6 +1557,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-load-config">--load-config &lt;config file path&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-missing">--missing</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-name">--name &lt;FILENAME&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-no-comment">--no-comment</a>
</li>
@@ -1595,6 +1615,8 @@
<li><a href="cli.html#cmdoption-osxphotos-export-place">--place &lt;PLACE&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-portrait">--portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-query-eval">--query-eval &lt;CRITERIA&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-export-replace-keywords">--replace-keywords</a>
</li>
@@ -1791,6 +1813,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-live">--live</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-missing">--missing</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-name">--name &lt;FILENAME&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-no-comment">--no-comment</a>
</li>
@@ -1845,6 +1869,8 @@
<li><a href="cli.html#cmdoption-osxphotos-query-place">--place &lt;PLACE&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-portrait">--portrait</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-query-eval">--query-eval &lt;CRITERIA&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-query-screenshot">--screenshot</a>
</li>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Welcome to osxphotoss documentation! &#8212; osxphotos 0.41.6 documentation</title>
<title>Welcome to osxphotoss documentation! &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos &#8212; osxphotos 0.41.6 documentation</title>
<title>osxphotos &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>

Binary file not shown.

Binary file not shown.

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos package &#8212; osxphotos 0.41.6 documentation</title>
<title>osxphotos package &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &#8212; osxphotos 0.41.6 documentation</title>
<title>Search &#8212; osxphotos 0.41.10 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/alabaster.css" type="text/css" />

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.41.10"
__version__ = "0.41.11"

View File

@@ -452,12 +452,13 @@ def query_options(f):
metavar="CRITERIA",
multiple=True,
help="Evaluate CRITERIA to filter photos. "
"CRITERIA will be evaluated in context of the following list comprehension: "
"CRITERIA will be evaluated in context of the following python list comprehension: "
"`photos = [photo for photo in photos if CRITERIA]` "
"where photo represents a PhotoInfo object. "
"For example: `--query-eval photo.favorite` returns all photos that have been "
"favorited and is equivalent to --favorite. "
"You may specify more than one CRITERIA by using --query-eval multiple times. "
"CRITERIA must be a valid python expression. "
"See https://rhettbull.github.io/osxphotos/ for additional documentation on the PhotoInfo class.",
),
]

View File

@@ -48,6 +48,7 @@ TEMPLATE_SUBSTITUTIONS = {
"{photo_or_video}": "'photo' or 'video' depending on what type the image is. To customize, use default value as in '{photo_or_video,photo=fotos;video=videos}'",
"{hdr}": "Photo is HDR?; True/False value, use in format '{hdr?VALUE_IF_TRUE,VALUE_IF_FALSE}'",
"{edited}": "Photo has been edited (has adjustments)?; True/False value, use in format '{edited?VALUE_IF_TRUE,VALUE_IF_FALSE}'",
"{favorite}": "Photo has been marked as favorite?; True/False value, use in format '{favorite?VALUE_IF_TRUE,VALUE_IF_FALSE}'",
"{created.date}": "Photo's creation date in ISO format, e.g. '2020-03-22'",
"{created.year}": "4-digit year of photo creation time",
"{created.yy}": "2-digit year of photo creation time",
@@ -145,6 +146,11 @@ TEMPLATE_SUBSTITUTIONS_MULTI_VALUED = {
"{searchinfo.activity}": "Activities associated with a photo, e.g. 'Sporting Event'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).",
"{searchinfo.venue}": "Venues associated with a photo, e.g. name of restaurant; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).",
"{searchinfo.venue_type}": "Venue types associated with a photo, e.g. 'Restaurant'; (Photos 5+ only, applied automatically by Photos' image categorization algorithms).",
"{photo}": "Provides direct access to the PhotoInfo object for the photo. "
+ "Must be used in format '{photo.property}' where 'property' represents a PhotoInfo property. "
+ "For example: '{photo.favorite}' is the same as '{favorite}' and '{photo.place.name}' is the same as '{place.name}'. "
+ "'{photo}' provides access to properties that are not available as separate template fields but it assumes some knowledge of "
+ "the underlying PhotoInfo class. See https://rhettbull.github.io/osxphotos/ for additional documentation on the PhotoInfo class.",
}
FILTER_VALUES = {
@@ -362,7 +368,7 @@ class PhotoTemplate:
if ts.template:
# have a template field to process
field = ts.template.field
if field not in FIELD_NAMES:
if field not in FIELD_NAMES and not field.startswith("photo"):
unmatched.append(field)
return [], unmatched
@@ -442,7 +448,7 @@ class PhotoTemplate:
vals = self.get_template_value_exiftool(
subfield, filename=filename, dirname=dirname
)
elif field in MULTI_VALUE_SUBSTITUTIONS:
elif field in MULTI_VALUE_SUBSTITUTIONS or field.startswith("photo"):
vals = self.get_template_value_multi(
field, path_sep=path_sep, filename=filename, dirname=dirname
)
@@ -539,6 +545,8 @@ class PhotoTemplate:
value = "hdr" if self.photo.hdr else None
elif field == "edited":
value = "edited" if self.photo.hasadjustments else None
elif field == "favorite":
value = "favorite" if self.photo.favorite else None
elif field == "created.date":
value = DateTimeFormatter(self.photo.date).date
elif field == "created.year":
@@ -891,6 +899,32 @@ class PhotoTemplate:
values = (
self.photo.search_info.venue_types if self.photo.search_info else []
)
elif field.startswith("photo"):
# provide access to PhotoInfo object
properties = field.split(".")
if len(properties) <= 1:
raise ValueError(
"Missing property in {photo} template. Use in form {photo.property}."
)
obj = self.photo
for i in range(1, len(properties)):
property_ = properties[i]
try:
obj = getattr(obj, property_)
if obj is None:
break
except AttributeError:
raise ValueError(
"Invalid property for {photo} template: " + f"'{property_}'"
)
if obj is None:
values = []
elif isinstance(obj, bool):
values = [property_] if obj else []
elif isinstance(obj, (str, int, float)):
values = [str(obj)]
else:
values = [val for val in obj]
else:
raise ValueError(f"Unhandled template value: {field}")

View File

@@ -23,6 +23,14 @@ class PhotoInfoMock(PhotoInfo):
else self._photo.hdr
)
@property
def favorite(self):
return (
self._mock_favorite
if getattr(self, "_mock_favorite", None) is not None
else self._photo.favorite
)
@property
def hasadjustments(self):
return (

View File

@@ -28,6 +28,7 @@ UUID_DICT = {
"mojave_album_1": "15uNd7%8RguTEgNPKHfTWw",
"date_modified": "A9B73E13-A6F2-4915-8D67-7213B39BAE9F",
"date_not_modified": "128FB4C6-0B16-4E7D-9108-FB2E90DA1546",
"favorite": "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51",
}
UUID_MEDIA_TYPE = {
@@ -176,6 +177,8 @@ TEMPLATE_VALUES = {
"{exif.lens_model}": "iPhone 6s back camera 4.15mm f/2.2",
"{album?{folder_album},{created.year}/{created.mm}}": "2020/02",
"{title?Title is '{title} - {descr}',No Title}": "Title is 'Glen Ord - Jack Rose Dining Saloon'",
"{favorite}": "_",
"{favorite?FAV,NOTFAV}": "NOTFAV",
}
@@ -253,6 +256,33 @@ COMMENT_UUID_DICT = {
"4E4944A0-3E5C-4028-9600-A8709F2FA1DB": ["None: Nice trophy"],
}
UUID_PHOTO = {
"DC99FBDD-7A52-4100-A5BB-344131646C30": {
"{photo.title}": ["St. James's Park"],
"{photo.favorite?FAVORITE,NOTFAVORITE}": ["NOTFAVORITE"],
"{photo.hdr}": ["_"],
"{photo.keywords}": [
"England",
"London",
"London 2018",
"St. James's Park",
"UK",
"United Kingdom",
],
"{photo.keywords|lower}": [
"england",
"london",
"london 2018",
"st. james's park",
"uk",
"united kingdom",
],
},
"3DD2C897-F19E-4CA6-8C22-B027D5A71907": {"{photo.place.country_code}": ["AU"]},
"F12384F6-CD17-4151-ACBA-AE0E3688539E": {"{photo.place.name}": ["_"]},
"E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51": {"{photo.favorite}": ["favorite"]},
}
@pytest.fixture(scope="module")
def photosdb_places():
@@ -307,7 +337,7 @@ def test_lookup_multi(photosdb_places):
for subst in TEMPLATE_SUBSTITUTIONS_MULTI_VALUED:
lookup_str = re.match(r"\{([^\\,}]+)\}", subst).group(1)
if subst == "{exiftool}":
if subst in ["{exiftool}", "{photo}"]:
continue
lookup = template.get_template_value_multi(lookup_str, path_sep=os.path.sep)
assert isinstance(lookup, list)
@@ -831,6 +861,14 @@ def test_edited(photosdb):
assert rendered == ["edited"]
def test_favorite(photosdb):
""" Test favorite"""
photo = photosdb.get_photo(UUID_MULTI_KEYWORDS)
photomock = PhotoInfoMock(photo, favorite=True)
rendered, _ = photomock.render_template("{favorite}")
assert rendered == ["favorite"]
def test_nested_template_bool(photosdb):
photo = photosdb.get_photo(UUID_MULTI_KEYWORDS)
template = "{hdr?{edited?HDR_EDITED,HDR_NOT_EDITED},{edited?NOT_HDR_EDITED,NOT_HDR_NOT_EDITED}}"
@@ -868,3 +906,10 @@ def test_punctuation(photosdb):
rendered, _ = photo.render_template("{" + punc + "}")
assert rendered[0] == PUNCTUATION[punc]
def test_photo_template(photosdb):
for uuid in UUID_PHOTO:
photo = photosdb.get_photo(uuid)
for template in UUID_PHOTO[uuid]:
rendered, _ = photo.render_template(template)
assert sorted(rendered) == sorted(UUID_PHOTO[uuid][template])