Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b40e9d65f | ||
|
|
725f7c8735 | ||
|
|
7cc8578148 | ||
|
|
6adafb8ce7 | ||
|
|
ac47df8475 | ||
|
|
f680cf78ab | ||
|
|
c86e84c534 | ||
|
|
3fb611825c | ||
|
|
1cfdad0176 | ||
|
|
59ba325273 | ||
|
|
c4b7c2623f | ||
|
|
e5b2d2ee45 |
15
CHANGELOG.md
15
CHANGELOG.md
@@ -4,6 +4,21 @@ 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.42.85](https://github.com/RhetTbull/osxphotos/compare/v0.42.84...v0.42.85)
|
||||
|
||||
> 25 September 2021
|
||||
|
||||
- Implemented PhotoInfo.owner, AlbumInfo.owner, #216, #239 [`c4b7c26`](https://github.com/RhetTbull/osxphotos/commit/c4b7c2623f077d9964d5d578ce6c01bb83fab088)
|
||||
- Updated docs [skip ci] [`59ba325`](https://github.com/RhetTbull/osxphotos/commit/59ba325273b2f16935be944fd46c1237ce637bb8)
|
||||
|
||||
#### [v0.42.84](https://github.com/RhetTbull/osxphotos/compare/v0.42.83...v0.42.84)
|
||||
|
||||
> 25 September 2021
|
||||
|
||||
- Fix for #516 [`e3e1da2`](https://github.com/RhetTbull/osxphotos/commit/e3e1da2fd898896595fc851288f905bd4e2150f8)
|
||||
- Updated docs [skip ci] [`64c226b`](https://github.com/RhetTbull/osxphotos/commit/64c226b85529581e393a2d0604b41c37a8dc2eaf)
|
||||
- Update docs [`c429a86`](https://github.com/RhetTbull/osxphotos/commit/c429a860b1ebeb77f3c3e36e9660fc9153d85d11)
|
||||
|
||||
#### [v0.42.83](https://github.com/RhetTbull/osxphotos/compare/v0.42.82...v0.42.83)
|
||||
|
||||
> 15 September 2021
|
||||
|
||||
@@ -2,4 +2,5 @@ include README.md
|
||||
include README.rst
|
||||
include osxphotos/templates/*
|
||||
include osxphotos/phototemplate.tx
|
||||
include osxphotos/phototemplate.md
|
||||
include osxphotos/phototemplate.md
|
||||
include osxphotos/queries/*
|
||||
18
README.md
18
README.md
@@ -1702,7 +1702,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.84'
|
||||
{osxphotos_version} The osxphotos version, e.g. '0.42.86'
|
||||
{osxphotos_cmd_line} The full command line used to run osxphotos
|
||||
|
||||
The following substitutions may result in multiple values. Thus if specified for
|
||||
@@ -2373,6 +2373,8 @@ For example, in my library, Photos says I have 19,386 photos and 474 movies. Ho
|
||||
#### <a name="getphoto">`get_photo(uuid)`</A>
|
||||
Returns a single PhotoInfo instance for photo with UUID matching `uuid` or None if no photo is found matching `uuid`. If you know the UUID of a photo, `get_photo()` is much faster than `photos`. See also [photos()](#photos).
|
||||
|
||||
#### `execute(sql)`
|
||||
Execute sql statement against the Photos database and return a sqlite cursor with the results.
|
||||
|
||||
### PhotoInfo
|
||||
PhotosDB.photos() returns a list of PhotoInfo objects. Each PhotoInfo object represents a single photo in the Photos library.
|
||||
@@ -2516,7 +2518,12 @@ Returns a [PlaceInfo](#PlaceInfo) object with reverse geolocation data or None i
|
||||
#### `shared`
|
||||
Returns True if photo is in a shared album, otherwise False.
|
||||
|
||||
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns None instead of True/False.
|
||||
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns None.
|
||||
|
||||
#### `owner`
|
||||
Returns full name of the photo owner (person who shared the photo) for shared photos or None if photo is not shared. Also returns None if you are the person who shared the photo.
|
||||
|
||||
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns None.
|
||||
|
||||
#### `comments`
|
||||
Returns list of [CommentInfo](#commentinfo) objects for comments on shared photos or empty list if no comments.
|
||||
@@ -2890,6 +2897,11 @@ Photos Library
|
||||
#### `parent`
|
||||
Returns a [FolderInfo](#FolderInfo) object representing the albums parent folder or `None` if album is not a in a folder.
|
||||
|
||||
#### `owner`
|
||||
Returns full name of the album owner (person who shared the album) for shared albums or None if album is not shared.
|
||||
|
||||
**Note**: *Only valid on Photos 5 / MacOS 10.15+; on Photos <= 4, returns None.
|
||||
|
||||
### ImportInfo
|
||||
PhotosDB.import_info returns a list of ImportInfo objects. Each ImportInfo object represents an import session in the library. PhotoInfo.import_info returns a single ImportInfo object representing the import session for the photo (or `None` if no associated import session).
|
||||
|
||||
@@ -3561,7 +3573,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.84'|
|
||||
|{osxphotos_version}|The osxphotos version, e.g. '0.42.86'|
|
||||
|{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|
|
||||
|
||||
@@ -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: c8c78e92de35f8ff4cf0b9d6bd35d796
|
||||
config: 68de544013fe1e61b68c366a1cc4b278
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Overview: module code — osxphotos 0.42.84 documentation</title>
|
||||
<title>Overview: module code — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../_static/alabaster.css" />
|
||||
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.42.83 documentation</title>
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.42.85 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
|
||||
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -71,6 +71,7 @@
|
||||
<span class="kn">from</span> <span class="nn">..personinfo</span> <span class="kn">import</span> <span class="n">FaceInfo</span><span class="p">,</span> <span class="n">PersonInfo</span>
|
||||
<span class="kn">from</span> <span class="nn">..phototemplate</span> <span class="kn">import</span> <span class="n">PhotoTemplate</span><span class="p">,</span> <span class="n">RenderOptions</span>
|
||||
<span class="kn">from</span> <span class="nn">..placeinfo</span> <span class="kn">import</span> <span class="n">PlaceInfo4</span><span class="p">,</span> <span class="n">PlaceInfo5</span>
|
||||
<span class="kn">from</span> <span class="nn">..query_builder</span> <span class="kn">import</span> <span class="n">get_query</span>
|
||||
<span class="kn">from</span> <span class="nn">..text_detection</span> <span class="kn">import</span> <span class="n">detect_text</span>
|
||||
<span class="kn">from</span> <span class="nn">..uti</span> <span class="kn">import</span> <span class="n">get_preferred_uti_extension</span><span class="p">,</span> <span class="n">get_uti_for_extension</span>
|
||||
<span class="kn">from</span> <span class="nn">..utils</span> <span class="kn">import</span> <span class="n">_debug</span><span class="p">,</span> <span class="n">_get_resource_loc</span><span class="p">,</span> <span class="n">findfiles</span>
|
||||
@@ -1131,6 +1132,22 @@
|
||||
<span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Did not find signature for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2"> in _db_signatures"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">duplicates</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">owner</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Return name of photo owner for shared photos (Photos 5+ only), or None if not shared"""</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_version</span> <span class="o"><=</span> <span class="n">_PHOTOS_4_VERSION</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_owner</span>
|
||||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||||
<span class="n">query</span> <span class="o">=</span> <span class="n">get_query</span><span class="p">(</span>
|
||||
<span class="s2">"shared_owner"</span><span class="p">,</span> <span class="n">photos_ver</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_photos_ver</span><span class="p">,</span> <span class="n">uuid</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_owner</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">result</span> <span class="k">else</span> <span class="kc">None</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_owner</span>
|
||||
|
||||
<div class="viewcode-block" id="PhotoInfo.render_template"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotoInfo.render_template">[docs]</a> <span class="k">def</span> <span class="nf">render_template</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="p">,</span> <span class="n">template_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">RenderOptions</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="p">):</span>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.42.80 documentation</title>
|
||||
<title>osxphotos.photosdb.photosdb — osxphotos 0.42.84 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
|
||||
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
|
||||
@@ -363,6 +363,8 @@
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_process_database5</span><span class="p">()</span>
|
||||
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_db_connection</span><span class="p">()</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">keywords_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""return keywords as dict of keyword, count in reverse sorted order (descending)"""</span>
|
||||
@@ -823,8 +825,8 @@
|
||||
<span class="s2">"creation_date"</span><span class="p">:</span> <span class="n">album</span><span class="p">[</span><span class="mi">8</span><span class="p">],</span>
|
||||
<span class="s2">"start_date"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"end_date"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"customsortascending"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"customsortkey"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"customsortascending"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="s2">"customsortkey"</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span> <span class="c1"># Photos 5 only</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="c1"># get details about folders</span>
|
||||
@@ -1137,7 +1139,9 @@
|
||||
<span class="c1"># get info on special types</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"specialType"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"masterModelID"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"pk"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span> <span class="c1"># same as masterModelID, to match Photos 5</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"pk"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span>
|
||||
<span class="mi">26</span>
|
||||
<span class="p">]</span> <span class="c1"># same as masterModelID, to match Photos 5</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"panorama"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span> <span class="k">else</span> <span class="kc">False</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"slow_mo"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span> <span class="k">else</span> <span class="kc">False</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">"time_lapse"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="mi">25</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span> <span class="k">else</span> <span class="kc">False</span>
|
||||
@@ -3387,6 +3391,10 @@
|
||||
|
||||
<span class="k">return</span> <span class="n">photos</span></div>
|
||||
|
||||
<div class="viewcode-block" id="PhotosDB.execute"><a class="viewcode-back" href="../../../reference.html#osxphotos.PhotosDB.execute">[docs]</a> <span class="k">def</span> <span class="nf">execute</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sql</span><span class="p">):</span>
|
||||
<span class="sd">"""Execute sql statement and return cursor"""</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span></div>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_duplicate_signature</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">):</span>
|
||||
<span class="sd">"""Compute a signature for finding possible duplicates"""</span>
|
||||
<span class="k">return</span> <span class="p">(</span>
|
||||
@@ -3412,7 +3420,11 @@
|
||||
<span class="sd">"""Returns number of photos in the database</span>
|
||||
<span class="sd"> Includes recently deleted photos and non-selected burst images</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">)</span></div>
|
||||
<span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__del__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">"_db_connection"</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db_connection</span><span class="o">.</span><span class="n">close</span><span class="p">()</span></div>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">_get_photos_by_attribute</span><span class="p">(</span><span class="n">photos</span><span class="p">,</span> <span class="n">attribute</span><span class="p">,</span> <span class="n">values</span><span class="p">,</span> <span class="n">ignore_case</span><span class="p">):</span>
|
||||
|
||||
2
docs/_static/documentation_options.js
vendored
2
docs/_static/documentation_options.js
vendored
@@ -1,6 +1,6 @@
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
|
||||
VERSION: '0.42.84',
|
||||
VERSION: '0.42.86',
|
||||
LANGUAGE: 'None',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
@@ -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) — osxphotos 0.42.84 documentation</title>
|
||||
<title>osxphotos command line interface (CLI) — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Index — osxphotos 0.42.84 documentation</title>
|
||||
<title>Index — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
@@ -1333,14 +1333,16 @@
|
||||
<h2 id="E">E</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotosDB.execute">execute() (osxphotos.PhotosDB method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.exif_info">exif_info (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.exiftool">exiftool (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.export">export() (osxphotos.PhotoInfo method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.export">export() (osxphotos.PhotoInfo method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.export2">export2() (osxphotos.PhotoInfo method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ExifInfo.exposure_bias">exposure_bias (osxphotos.PhotoInfo.ExifInfo attribute)</a>
|
||||
@@ -2112,6 +2114,8 @@
|
||||
</li>
|
||||
</ul></li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.ScoreInfo.overall">overall (osxphotos.PhotoInfo.ScoreInfo attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#osxphotos.PhotoInfo.owner">owner (osxphotos.PhotoInfo property)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.42.84 documentation</title>
|
||||
<title>Welcome to osxphotos’s documentation! — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos — osxphotos 0.42.84 documentation</title>
|
||||
<title>osxphotos — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
|
||||
BIN
docs/objects.inv
BIN
docs/objects.inv
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>osxphotos package — osxphotos 0.42.84 documentation</title>
|
||||
<title>osxphotos package — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
@@ -90,6 +90,12 @@ valid only on Photos 5; on Photos <= 4, prints warning and returns empty dict
|
||||
<dd><p>return the database version as stored in LiGlobals table</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.execute">
|
||||
<span class="sig-name descname"><span class="pre">execute</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">sql</span></span></em><span class="sig-paren">)</span><a class="reference internal" href="_modules/osxphotos/photosdb/photosdb.html#PhotosDB.execute"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#osxphotos.PhotosDB.execute" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Execute sql statement and return cursor</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotosDB.folder_info">
|
||||
<em class="property"><span class="pre">property</span> </em><span class="sig-name descname"><span class="pre">folder_info</span></span><a class="headerlink" href="#osxphotos.PhotosDB.folder_info" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -1143,6 +1149,12 @@ Photos 5 mangles filenames upon import</p>
|
||||
<dd><p>returns width of the original photo version in pixels</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.owner">
|
||||
<em class="property"><span class="pre">property</span> </em><span class="sig-name descname"><span class="pre">owner</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.owner" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Return name of photo owner for shared photos (Photos 5+ only), or None if not shared</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="osxphotos.PhotoInfo.panorama">
|
||||
<em class="property"><span class="pre">property</span> </em><span class="sig-name descname"><span class="pre">panorama</span></span><a class="headerlink" href="#osxphotos.PhotoInfo.panorama" title="Permalink to this definition">¶</a></dt>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — osxphotos 0.42.84 documentation</title>
|
||||
<title>Search — osxphotos 0.42.86 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +1,4 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.42.84"
|
||||
__version__ = "0.42.86"
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ from ._constants import (
|
||||
AlbumSortOrder,
|
||||
)
|
||||
from .datetime_utils import get_local_tz
|
||||
from .query_builder import get_query
|
||||
|
||||
|
||||
def sort_list_by_keys(values, sort_keys):
|
||||
@@ -131,6 +132,22 @@ class AlbumInfoBaseClass:
|
||||
def photos(self):
|
||||
return []
|
||||
|
||||
@property
|
||||
def owner(self):
|
||||
"""Return name of photo owner for shared album (Photos 5+ only), or None if not shared"""
|
||||
if self._db._db_version <= _PHOTOS_4_VERSION:
|
||||
return None
|
||||
|
||||
try:
|
||||
return self._owner
|
||||
except AttributeError:
|
||||
query = get_query(
|
||||
"cloud_album_owner", photos_ver=self._db._photos_ver, uuid=self.uuid
|
||||
)
|
||||
result = self._db.execute(query).fetchone()
|
||||
self._owner = result[0] if result else None
|
||||
return self._owner
|
||||
|
||||
def __len__(self):
|
||||
"""return number of photos contained in album"""
|
||||
return len(self.photos)
|
||||
|
||||
@@ -4103,7 +4103,11 @@ def repl(ctx, cli_obj, db):
|
||||
get_photo = photosdb.get_photo
|
||||
show = _show_photo
|
||||
get_selected = _get_selected(photosdb)
|
||||
selected = get_selected()
|
||||
try:
|
||||
selected = get_selected()
|
||||
except Exception:
|
||||
# get_selected sometimes fails
|
||||
selected = []
|
||||
|
||||
def inspect(obj):
|
||||
"""inspect object"""
|
||||
|
||||
@@ -38,6 +38,7 @@ from ..albuminfo import AlbumInfo, ImportInfo
|
||||
from ..personinfo import FaceInfo, PersonInfo
|
||||
from ..phototemplate import PhotoTemplate, RenderOptions
|
||||
from ..placeinfo import PlaceInfo4, PlaceInfo5
|
||||
from ..query_builder import get_query
|
||||
from ..text_detection import detect_text
|
||||
from ..uti import get_preferred_uti_extension, get_uti_for_extension
|
||||
from ..utils import _debug, _get_resource_loc, findfiles
|
||||
@@ -1098,6 +1099,22 @@ class PhotoInfo:
|
||||
logging.warning(f"Did not find signature for {self.uuid} in _db_signatures")
|
||||
return duplicates
|
||||
|
||||
@property
|
||||
def owner(self):
|
||||
"""Return name of photo owner for shared photos (Photos 5+ only), or None if not shared"""
|
||||
if self._db._db_version <= _PHOTOS_4_VERSION:
|
||||
return None
|
||||
|
||||
try:
|
||||
return self._owner
|
||||
except AttributeError:
|
||||
query = get_query(
|
||||
"shared_owner", photos_ver=self._db._photos_ver, uuid=self.uuid
|
||||
)
|
||||
result = self._db.execute(query).fetchone()
|
||||
self._owner = result[0] if result else None
|
||||
return self._owner
|
||||
|
||||
def render_template(
|
||||
self, template_str: str, options: Optional[RenderOptions] = None
|
||||
):
|
||||
|
||||
@@ -70,12 +70,24 @@ def _process_comments_5(photosdb):
|
||||
results = conn.execute(
|
||||
"""
|
||||
SELECT DISTINCT
|
||||
ZINVITEEHASHEDPERSONID,
|
||||
ZINVITEEFIRSTNAME,
|
||||
ZINVITEELASTNAME,
|
||||
ZINVITEEFULLNAME
|
||||
FROM
|
||||
ZCLOUDSHAREDALBUMINVITATIONRECORD
|
||||
ZINVITEEHASHEDPERSONID AS HASHEDPERSONID,
|
||||
ZINVITEEFIRSTNAME AS FIRSTNAME,
|
||||
ZINVITEELASTNAME AS LASTNAME,
|
||||
ZINVITEEFULLNAME AS FULLNAME
|
||||
FROM ZCLOUDSHAREDALBUMINVITATIONRECORD
|
||||
WHERE HASHEDPERSONID IS NOT NULL
|
||||
AND HASHEDPERSONID != ""
|
||||
AND NOT (FIRSTNAME IS NULL AND LASTNAME IS NULL)
|
||||
UNION
|
||||
SELECT DISTINCT
|
||||
ZCLOUDOWNERHASHEDPERSONID AS HASHEDPERSONID,
|
||||
ZCLOUDOWNERFIRSTNAME AS FIRSTNAME,
|
||||
ZCLOUDOWNERLASTNAME AS LASTNAME,
|
||||
ZCLOUDOWNERFULLNAME AS FULLNAME
|
||||
FROM ZGENERICALBUM
|
||||
WHERE HASHEDPERSONID IS NOT NULL
|
||||
AND HASHEDPERSONID != ""
|
||||
AND NOT (FIRSTNAME IS NULL AND LASTNAME IS NULL)
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -148,10 +160,10 @@ def _process_comments_5(photosdb):
|
||||
db_comments["comments"].append(CommentInfo(dt, user_name, ismine, text))
|
||||
|
||||
# sort results
|
||||
for uuid in photosdb._db_comments_uuid:
|
||||
for uuid, value in photosdb._db_comments_uuid.items():
|
||||
if photosdb._db_comments_uuid[uuid]["likes"]:
|
||||
photosdb._db_comments_uuid[uuid]["likes"].sort(key=lambda x: x.datetime)
|
||||
if photosdb._db_comments_uuid[uuid]["comments"]:
|
||||
photosdb._db_comments_uuid[uuid]["comments"].sort(key=lambda x: x.datetime)
|
||||
value["comments"].sort(key=lambda x: x.datetime)
|
||||
|
||||
conn.close()
|
||||
|
||||
@@ -330,6 +330,8 @@ class PhotosDB:
|
||||
else:
|
||||
self._process_database5()
|
||||
|
||||
self._db_connection, _ = self.get_db_connection()
|
||||
|
||||
@property
|
||||
def keywords_as_dict(self):
|
||||
"""return keywords as dict of keyword, count in reverse sorted order (descending)"""
|
||||
@@ -790,8 +792,8 @@ class PhotosDB:
|
||||
"creation_date": album[8],
|
||||
"start_date": None, # Photos 5 only
|
||||
"end_date": None, # Photos 5 only
|
||||
"customsortascending": None, # Photos 5 only
|
||||
"customsortkey": None, # Photos 5 only
|
||||
"customsortascending": None, # Photos 5 only
|
||||
"customsortkey": None, # Photos 5 only
|
||||
}
|
||||
|
||||
# get details about folders
|
||||
@@ -1104,7 +1106,9 @@ class PhotosDB:
|
||||
# get info on special types
|
||||
self._dbphotos[uuid]["specialType"] = row[25]
|
||||
self._dbphotos[uuid]["masterModelID"] = row[26]
|
||||
self._dbphotos[uuid]["pk"] = row[26] # same as masterModelID, to match Photos 5
|
||||
self._dbphotos[uuid]["pk"] = row[
|
||||
26
|
||||
] # same as masterModelID, to match Photos 5
|
||||
self._dbphotos[uuid]["panorama"] = True if row[25] == 1 else False
|
||||
self._dbphotos[uuid]["slow_mo"] = True if row[25] == 2 else False
|
||||
self._dbphotos[uuid]["time_lapse"] = True if row[25] == 3 else False
|
||||
@@ -3354,6 +3358,10 @@ class PhotosDB:
|
||||
|
||||
return photos
|
||||
|
||||
def execute(self, sql):
|
||||
"""Execute sql statement and return cursor"""
|
||||
return self._db_connection.cursor().execute(sql)
|
||||
|
||||
def _duplicate_signature(self, uuid):
|
||||
"""Compute a signature for finding possible duplicates"""
|
||||
return (
|
||||
@@ -3381,6 +3389,10 @@ class PhotosDB:
|
||||
"""
|
||||
return len(self._dbphotos)
|
||||
|
||||
def __del__(self):
|
||||
if getattr(self, "_db_connection", None):
|
||||
self._db_connection.close()
|
||||
|
||||
|
||||
def _get_photos_by_attribute(photos, attribute, values, ignore_case):
|
||||
"""Search for photos based on values being in PhotoInfo.attribute
|
||||
|
||||
5
osxphotos/queries/README.md
Normal file
5
osxphotos/queries/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Query templates
|
||||
|
||||
This folder contains sql query templates for getting various photo properties
|
||||
|
||||
The query templates must be rendered with mako (see query_builder.py)
|
||||
4
osxphotos/queries/cloud_album_owner.sql.mako
Normal file
4
osxphotos/queries/cloud_album_owner.sql.mako
Normal file
@@ -0,0 +1,4 @@
|
||||
-- Get owner name for shared iCloud album
|
||||
SELECT ZGENERICALBUM.ZCLOUDOWNERFULLNAME AS OWNER_FULLNAME
|
||||
FROM ZGENERICALBUM
|
||||
WHERE ZGENERICALBUM.ZUUID = '${uuid}'
|
||||
23
osxphotos/queries/shared_owner.sql.mako
Normal file
23
osxphotos/queries/shared_owner.sql.mako
Normal file
@@ -0,0 +1,23 @@
|
||||
-- Get the owner name of person who owns a photo in a shared album
|
||||
--
|
||||
-- Case where someone has invited you to a shared album
|
||||
-- Need to get the owner of the shared album
|
||||
SELECT DISTINCT
|
||||
ZGENERICALBUM.ZCLOUDOWNERFULLNAME as OWNER_FULLNAME
|
||||
FROM ZGENERICALBUM
|
||||
JOIN ${asset_table} ON ${asset_table}.ZCLOUDOWNERHASHEDPERSONID = ZGENERICALBUM.ZCLOUDOWNERHASHEDPERSONID
|
||||
WHERE ${asset_table}.ZUUID = "${uuid}"
|
||||
AND ZGENERICALBUM.ZCLOUDOWNERHASHEDPERSONID IS NOT NULL
|
||||
AND ZGENERICALBUM.ZCLOUDOWNERHASHEDPERSONID != ""
|
||||
AND OWNER_FULLNAME != "(null) (null)"
|
||||
UNION
|
||||
-- Case where you have invited someone to a shared album
|
||||
-- Need to get the data for person who was invited to the album
|
||||
SELECT DISTINCT
|
||||
ZCLOUDSHAREDALBUMINVITATIONRECORD.ZINVITEEFULLNAME AS OWNER_FULLNAME
|
||||
FROM ZCLOUDSHAREDALBUMINVITATIONRECORD
|
||||
JOIN ${asset_table} ON ${asset_table}.ZCLOUDOWNERHASHEDPERSONID = ZCLOUDSHAREDALBUMINVITATIONRECORD.ZINVITEEHASHEDPERSONID
|
||||
WHERE ${asset_table}.ZUUID = "${uuid}"
|
||||
AND ZCLOUDSHAREDALBUMINVITATIONRECORD.ZINVITEEHASHEDPERSONID IS NOT NULL
|
||||
AND ZCLOUDSHAREDALBUMINVITATIONRECORD.ZINVITEEHASHEDPERSONID != ""
|
||||
AND OWNER_FULLNAME != "(null) (null)"
|
||||
6
osxphotos/queries/title.sql.mako
Normal file
6
osxphotos/queries/title.sql.mako
Normal file
@@ -0,0 +1,6 @@
|
||||
-- Get title of a photo with given UUID
|
||||
SELECT
|
||||
ZADDITIONALASSETATTRIBUTES.ZTITLE
|
||||
FROM ZADDITIONALASSETATTRIBUTES
|
||||
JOIN ${asset_table} ON ${asset_table}.Z_PK = ZADDITIONALASSETATTRIBUTES.ZASSET
|
||||
WHERE ${asset_table}.ZUUID = "${uuid}"
|
||||
36
osxphotos/query_builder.py
Normal file
36
osxphotos/query_builder.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Build sql queries from template to retrieve info from the database"""
|
||||
|
||||
import os.path
|
||||
import pathlib
|
||||
from functools import lru_cache
|
||||
|
||||
from mako.template import Template
|
||||
|
||||
from ._constants import _DB_TABLE_NAMES
|
||||
|
||||
QUERY_DIR = os.path.join(os.path.dirname(__file__), "queries")
|
||||
|
||||
|
||||
def get_query(query_name, photos_ver, **kwargs):
|
||||
"""Return sqlite query string for an attribute and a given database version"""
|
||||
|
||||
# there can be a single query for multiple database versions or separate queries for each version
|
||||
# try generic version first (most common case), if that fails, look for version specific query
|
||||
query_string = _get_query_string(query_name, photos_ver)
|
||||
asset_table = _DB_TABLE_NAMES[photos_ver]["ASSET"]
|
||||
query_template = Template(query_string)
|
||||
return query_template.render(asset_table=asset_table, **kwargs)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _get_query_string(query_name, photos_ver):
|
||||
"""Return sqlite query string for an attribute and a given database version"""
|
||||
query_file = pathlib.Path(QUERY_DIR) / f"{query_name}.sql.mako"
|
||||
if not query_file.is_file():
|
||||
query_file = pathlib.Path(QUERY_DIR) / f"{query_name}_{photos_ver}.sql.mako"
|
||||
if not query_file.is_file():
|
||||
raise FileNotFoundError(f"Query file '{query_file}' not found")
|
||||
|
||||
with open(query_file, "r") as f:
|
||||
query_string = f.read()
|
||||
return query_string
|
||||
@@ -337,7 +337,7 @@ def test_attributes(photosdb):
|
||||
|
||||
|
||||
def test_attributes_2(photosdb):
|
||||
""" Test attributes including height, width, etc """
|
||||
"""Test attributes including height, width, etc"""
|
||||
import datetime
|
||||
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||
@@ -517,39 +517,39 @@ def test_count(photosdb):
|
||||
|
||||
|
||||
def test_photos_intrash_1(photosdb):
|
||||
""" test PhotosDB.photos(intrash=True) """
|
||||
"""test PhotosDB.photos(intrash=True)"""
|
||||
photos = photosdb.photos(intrash=True)
|
||||
assert len(photos) == PHOTOS_IN_TRASH_LEN
|
||||
|
||||
|
||||
def test_photos_intrash_2(photosdb):
|
||||
""" test PhotosDB.photos(intrash=True) """
|
||||
"""test PhotosDB.photos(intrash=True)"""
|
||||
photos = photosdb.photos(intrash=True)
|
||||
for p in photos:
|
||||
assert p.intrash
|
||||
|
||||
|
||||
def test_photos_intrash_3(photosdb):
|
||||
""" test PhotosDB.photos(intrash=False) """
|
||||
"""test PhotosDB.photos(intrash=False)"""
|
||||
photos = photosdb.photos(intrash=False)
|
||||
for p in photos:
|
||||
assert not p.intrash
|
||||
|
||||
|
||||
def test_photoinfo_intrash_1(photosdb):
|
||||
""" Test PhotoInfo.intrash """
|
||||
"""Test PhotoInfo.intrash"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["intrash"]], intrash=True)[0]
|
||||
assert p.intrash
|
||||
|
||||
|
||||
def test_photoinfo_intrash_2(photosdb):
|
||||
""" Test PhotoInfo.intrash and intrash=default"""
|
||||
"""Test PhotoInfo.intrash and intrash=default"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["intrash"]])
|
||||
assert not p
|
||||
|
||||
|
||||
def test_photoinfo_intrash_3(photosdb):
|
||||
""" Test PhotoInfo.intrash and photo has keyword and person """
|
||||
"""Test PhotoInfo.intrash and photo has keyword and person"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["intrash_person_keywords"]], intrash=True)[0]
|
||||
assert p.intrash
|
||||
assert "Maria" in p.persons
|
||||
@@ -557,7 +557,7 @@ def test_photoinfo_intrash_3(photosdb):
|
||||
|
||||
|
||||
def test_photoinfo_intrash_4(photosdb):
|
||||
""" Test PhotoInfo.intrash and photo has keyword and person """
|
||||
"""Test PhotoInfo.intrash and photo has keyword and person"""
|
||||
p = photosdb.photos(persons=["Maria"], intrash=True)[0]
|
||||
assert p.intrash
|
||||
assert "Maria" in p.persons
|
||||
@@ -565,7 +565,7 @@ def test_photoinfo_intrash_4(photosdb):
|
||||
|
||||
|
||||
def test_photoinfo_intrash_5(photosdb):
|
||||
""" Test PhotoInfo.intrash and photo has keyword and person """
|
||||
"""Test PhotoInfo.intrash and photo has keyword and person"""
|
||||
p = photosdb.photos(keywords=["wedding"], intrash=True)[0]
|
||||
assert p.intrash
|
||||
assert "Maria" in p.persons
|
||||
@@ -573,7 +573,7 @@ def test_photoinfo_intrash_5(photosdb):
|
||||
|
||||
|
||||
def test_photoinfo_not_intrash(photosdb):
|
||||
""" Test PhotoInfo.intrash """
|
||||
"""Test PhotoInfo.intrash"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["not_intrash"]])[0]
|
||||
assert not p.intrash
|
||||
|
||||
@@ -594,7 +594,7 @@ def test_keyword_not_in_album(photosdb):
|
||||
|
||||
|
||||
def test_album_folder_name(photosdb):
|
||||
"""Test query with album name same as a folder name """
|
||||
"""Test query with album name same as a folder name"""
|
||||
|
||||
photos = photosdb.photos(albums=["Pumpkin Farm"])
|
||||
assert sorted(p.uuid for p in photos) == sorted(UUID_PUMPKIN_FARM)
|
||||
@@ -617,7 +617,7 @@ def test_get_library_path(photosdb):
|
||||
|
||||
|
||||
def test_get_db_connection(photosdb):
|
||||
""" Test PhotosDB.get_db_connection """
|
||||
"""Test PhotosDB.get_db_connection"""
|
||||
import sqlite3
|
||||
|
||||
conn, cursor = photosdb.get_db_connection()
|
||||
@@ -926,7 +926,7 @@ def test_export_14(caplog, photosdb):
|
||||
|
||||
|
||||
def test_eq(photosdb):
|
||||
""" Test equality of two PhotoInfo objects """
|
||||
"""Test equality of two PhotoInfo objects"""
|
||||
import osxphotos
|
||||
|
||||
photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
@@ -936,7 +936,7 @@ def test_eq(photosdb):
|
||||
|
||||
|
||||
def test_eq_2(photosdb):
|
||||
""" Test equality of two PhotoInfo objects when one has memoized property """
|
||||
"""Test equality of two PhotoInfo objects when one has memoized property"""
|
||||
import osxphotos
|
||||
|
||||
photosdb2 = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
@@ -960,7 +960,7 @@ def test_photosdb_repr():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photosdb2 = eval(repr(photosdb))
|
||||
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name"]
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name", "_db_connection"]
|
||||
assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
|
||||
k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
|
||||
}
|
||||
@@ -999,7 +999,7 @@ def test_from_to_date(photosdb):
|
||||
|
||||
|
||||
def test_date_invalid():
|
||||
""" Test date is invalid """
|
||||
"""Test date is invalid"""
|
||||
# doesn't run correctly with the module-level fixture
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import osxphotos
|
||||
@@ -1016,7 +1016,7 @@ def test_date_invalid():
|
||||
|
||||
|
||||
def test_date_modified_invalid(photosdb):
|
||||
""" Test date modified is invalid """
|
||||
"""Test date modified is invalid"""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
# UUID_DICT["date_invalid"] has an invalid modified date that's
|
||||
@@ -1028,7 +1028,7 @@ def test_date_modified_invalid(photosdb):
|
||||
|
||||
|
||||
def test_uti(photosdb):
|
||||
""" test uti """
|
||||
"""test uti"""
|
||||
|
||||
for uuid, uti in UTI_DICT.items():
|
||||
photo = photosdb.get_photo(uuid)
|
||||
@@ -1037,7 +1037,7 @@ def test_uti(photosdb):
|
||||
|
||||
|
||||
def test_raw(photosdb):
|
||||
""" Test various raw properties """
|
||||
"""Test various raw properties"""
|
||||
|
||||
for uuid, rawinfo in RAW_DICT.items():
|
||||
photo = photosdb.get_photo(uuid)
|
||||
@@ -1050,7 +1050,7 @@ def test_raw(photosdb):
|
||||
|
||||
|
||||
def test_is_reference(photosdb):
|
||||
""" test isreference """
|
||||
"""test isreference"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_IS_REFERENCE)
|
||||
assert photo.isreference
|
||||
@@ -1059,7 +1059,7 @@ def test_is_reference(photosdb):
|
||||
|
||||
|
||||
def test_adjustments(photosdb):
|
||||
""" test adjustments/AdjustmentsInfo """
|
||||
"""test adjustments/AdjustmentsInfo"""
|
||||
from osxphotos.adjustmentsinfo import AdjustmentsInfo
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["adjustments_info"])
|
||||
@@ -1121,7 +1121,7 @@ def test_adjustments(photosdb):
|
||||
|
||||
|
||||
def test_no_adjustments(photosdb):
|
||||
""" test adjustments when photo has no adjusments"""
|
||||
"""test adjustments when photo has no adjusments"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["no_adjustments"])
|
||||
assert photo.adjustments is None
|
||||
|
||||
@@ -1066,7 +1066,7 @@ def test_photosdb_repr():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photosdb2 = eval(repr(photosdb))
|
||||
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name"]
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name", "_db_connection"]
|
||||
assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
|
||||
k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
|
||||
}
|
||||
|
||||
43
tests/test_cloud_owner_catalina.py
Normal file
43
tests/test_cloud_owner_catalina.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# Test cloud photos and album owner
|
||||
|
||||
import pytest
|
||||
|
||||
import osxphotos
|
||||
|
||||
PHOTOS_DB_CLOUD = "./tests/Test-Cloud-10.15.6.photoslibrary/"
|
||||
PHOTOS_DB_NOT_CLOUD = "./tests/Test-10.15.6.photoslibrary/"
|
||||
|
||||
UUID_DICT = {
|
||||
"not_cloudasset": "6191423D-8DB8-4D4C-92BE-9BBBA308AAC4",
|
||||
"owner": "7572C53E-1D6A-410C-A2B1-18CCA3B5AD9F",
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def photosdb_cloud():
|
||||
return osxphotos.PhotosDB(dbfile=PHOTOS_DB_CLOUD)
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def photosdb_nocloud():
|
||||
return osxphotos.PhotosDB(dbfile=PHOTOS_DB_NOT_CLOUD)
|
||||
|
||||
|
||||
def test_album_owner_cloud(photosdb_cloud):
|
||||
album = [a for a in photosdb_cloud.album_info_shared if a.title == "osxphotos"][0]
|
||||
assert album.owner == "Rhet Turnbull"
|
||||
|
||||
|
||||
def test_album_owner_not_cloud(photosdb_nocloud):
|
||||
album = [a for a in photosdb_nocloud.album_info if a.title == "Test Album"][0]
|
||||
assert album.owner is None
|
||||
|
||||
|
||||
def test_photo_owner_cloud(photosdb_cloud):
|
||||
photo = photosdb_cloud.get_photo(UUID_DICT["owner"])
|
||||
assert photo.owner == "Rhet Turnbull"
|
||||
|
||||
|
||||
def test_photo_owner_nocloud(photosdb_nocloud):
|
||||
photo = photosdb_nocloud.get_photo(UUID_DICT["not_cloudasset"])
|
||||
assert photo.owner is None
|
||||
@@ -13,7 +13,7 @@ COMMENT_UUID_DICT = {
|
||||
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||
CommentInfo(
|
||||
datetime=datetime.datetime(2020, 9, 18, 10, 28, 41, 552000),
|
||||
user=None,
|
||||
user="Rhet Turnbull",
|
||||
ismine=False,
|
||||
text="Nice photo!",
|
||||
),
|
||||
@@ -39,7 +39,7 @@ LIKE_UUID_DICT = {
|
||||
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||
LikeInfo(
|
||||
datetime=datetime.datetime(2020, 9, 18, 10, 28, 43, 335000),
|
||||
user=None,
|
||||
user="Rhet Turnbull",
|
||||
ismine=False,
|
||||
)
|
||||
],
|
||||
@@ -47,7 +47,7 @@ LIKE_UUID_DICT = {
|
||||
"65BADBD7-A50C-4956-96BA-1BB61155DA17": [
|
||||
LikeInfo(
|
||||
datetime=datetime.datetime(2020, 9, 18, 10, 28, 52, 570000),
|
||||
user=None,
|
||||
user="Rhet Turnbull",
|
||||
ismine=False,
|
||||
)
|
||||
],
|
||||
@@ -65,7 +65,7 @@ COMMENT_UUID_ASDICT = {
|
||||
LIKE_UUID_ASDICT = {
|
||||
"65BADBD7-A50C-4956-96BA-1BB61155DA17": {
|
||||
"datetime": datetime.datetime(2020, 9, 18, 10, 28, 52, 570000),
|
||||
"user": None,
|
||||
"user": "Rhet Turnbull",
|
||||
"ismine": False,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +266,7 @@ def test_attributes(photosdb):
|
||||
|
||||
|
||||
def test_attributes_2(photosdb):
|
||||
""" Test attributes including height, width, etc """
|
||||
"""Test attributes including height, width, etc"""
|
||||
import datetime
|
||||
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||
@@ -338,7 +338,7 @@ def test_not_hidden(photosdb):
|
||||
|
||||
|
||||
def test_visible(photosdb):
|
||||
""" test visible """
|
||||
"""test visible"""
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["not_hidden"]])
|
||||
assert len(photos) == 1
|
||||
p = photos[0]
|
||||
@@ -346,7 +346,7 @@ def test_visible(photosdb):
|
||||
|
||||
|
||||
def test_not_burst(photosdb):
|
||||
""" test not burst """
|
||||
"""test not burst"""
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["not_hidden"]])
|
||||
assert len(photos) == 1
|
||||
p = photos[0]
|
||||
@@ -448,13 +448,13 @@ def test_count(photosdb):
|
||||
|
||||
|
||||
def test_photos_intrash_1(photosdb):
|
||||
""" test PhotosDB.photos(intrash=True) """
|
||||
"""test PhotosDB.photos(intrash=True)"""
|
||||
photos = photosdb.photos(intrash=True)
|
||||
assert len(photos) == PHOTOS_IN_TRASH_LEN
|
||||
|
||||
|
||||
def test_photos_intrash_2(photosdb):
|
||||
""" test PhotosDB.photos(intrash=True) """
|
||||
"""test PhotosDB.photos(intrash=True)"""
|
||||
photos = photosdb.photos(intrash=True)
|
||||
for p in photos:
|
||||
assert p.intrash
|
||||
@@ -462,7 +462,7 @@ def test_photos_intrash_2(photosdb):
|
||||
|
||||
|
||||
def test_photos_not_intrash(photosdb):
|
||||
""" test PhotosDB.photos(intrash=False) """
|
||||
"""test PhotosDB.photos(intrash=False)"""
|
||||
photos = photosdb.photos(intrash=False)
|
||||
for p in photos:
|
||||
assert not p.intrash
|
||||
@@ -470,19 +470,19 @@ def test_photos_not_intrash(photosdb):
|
||||
|
||||
|
||||
def test_photoinfo_intrash_1(photosdb):
|
||||
""" Test PhotoInfo.intrash """
|
||||
"""Test PhotoInfo.intrash"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["intrash"]], intrash=True)[0]
|
||||
assert p.intrash
|
||||
|
||||
|
||||
def test_photoinfo_intrash_2(photosdb):
|
||||
""" Test PhotoInfo.intrash and intrash=default"""
|
||||
"""Test PhotoInfo.intrash and intrash=default"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["intrash"]])
|
||||
assert not p
|
||||
|
||||
|
||||
def test_photoinfo_not_intrash(photosdb):
|
||||
""" Test PhotoInfo.intrash """
|
||||
"""Test PhotoInfo.intrash"""
|
||||
p = photosdb.photos(uuid=[UUID_DICT["not_intrash"]])[0]
|
||||
assert not p.intrash
|
||||
|
||||
@@ -517,7 +517,7 @@ def test_photosdb_repr():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photosdb2 = eval(repr(photosdb))
|
||||
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name"]
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name", "_db_connection"]
|
||||
assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
|
||||
k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
|
||||
}
|
||||
@@ -562,7 +562,7 @@ def test_multi_person(photosdb):
|
||||
|
||||
|
||||
def test_date_invalid(photosdb):
|
||||
""" Test date is invalid """
|
||||
"""Test date is invalid"""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]])
|
||||
@@ -574,7 +574,7 @@ def test_date_invalid(photosdb):
|
||||
|
||||
|
||||
def test_date_modified_invalid(photosdb):
|
||||
""" Test date modified is invalid """
|
||||
"""Test date modified is invalid"""
|
||||
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["date_invalid"]])
|
||||
assert len(photos) == 1
|
||||
@@ -583,7 +583,7 @@ def test_date_modified_invalid(photosdb):
|
||||
|
||||
|
||||
def test_date_modified(photosdb):
|
||||
""" Test date modified for photo that has been edited """
|
||||
"""Test date modified for photo that has been edited"""
|
||||
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||
p = photos[0]
|
||||
@@ -600,7 +600,7 @@ def test_date_modified(photosdb):
|
||||
|
||||
|
||||
def test_date_modified_none(photosdb):
|
||||
""" Test date modified for a photo that hasn't been edited """
|
||||
"""Test date modified for a photo that hasn't been edited"""
|
||||
|
||||
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
|
||||
p = photos[0]
|
||||
@@ -638,7 +638,7 @@ def test_raw(photosdb):
|
||||
|
||||
|
||||
def test_raw():
|
||||
""" Test various raw properties """
|
||||
"""Test various raw properties"""
|
||||
import osxphotos
|
||||
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
@@ -654,7 +654,7 @@ def test_raw():
|
||||
|
||||
|
||||
def test_is_reference(photosdb):
|
||||
""" test isreference """
|
||||
"""test isreference"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_IS_REFERENCE)
|
||||
assert photo.isreference
|
||||
@@ -663,7 +663,7 @@ def test_is_reference(photosdb):
|
||||
|
||||
|
||||
def test_adjustments(photosdb):
|
||||
""" test adjustments/AdjustmentsInfo (not implemented for 10.14) """
|
||||
"""test adjustments/AdjustmentsInfo (not implemented for 10.14)"""
|
||||
from osxphotos.adjustmentsinfo import AdjustmentsInfo
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["has_adjustments"])
|
||||
@@ -671,7 +671,7 @@ def test_adjustments(photosdb):
|
||||
|
||||
|
||||
def test_no_adjustments(photosdb):
|
||||
""" test adjustments when photo has no adjusments"""
|
||||
"""test adjustments when photo has no adjusments"""
|
||||
|
||||
photo = photosdb.get_photo(UUID_DICT["no_adjustments"])
|
||||
assert photo.adjustments is None
|
||||
|
||||
@@ -1033,7 +1033,7 @@ def test_photosdb_repr():
|
||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||
photosdb2 = eval(repr(photosdb))
|
||||
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name"]
|
||||
ignore_keys = ["_tmp_db", "_tempdir", "_tempdir_name", "_db_connection"]
|
||||
assert {k: v for k, v in photosdb.__dict__.items() if k not in ignore_keys} == {
|
||||
k: v for k, v in photosdb2.__dict__.items() if k not in ignore_keys
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ TEMPLATE_VALUES_DETECTED_TEXT = {
|
||||
|
||||
COMMENT_UUID_DICT = {
|
||||
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||
"None: Nice photo!",
|
||||
"Rhet Turnbull: Nice photo!",
|
||||
"None: Wish I was back here!",
|
||||
],
|
||||
"CCBE0EB9-AE9F-4479-BFFD-107042C75227": ["_"],
|
||||
|
||||
Reference in New Issue
Block a user