Compare commits

..

29 Commits

Author SHA1 Message Date
Rhet Turnbull
7d923590ae Updated dependencies for pyobjc 8.0 2021-11-25 08:34:55 -08:00
Rhet Turnbull
5383ced1ca Updated CHANGELOG.md [skip ci] 2021-11-11 11:05:19 -08:00
Rhet Turnbull
0e6c92dbd9 Fix for --use-photokit with --skip-live, #537 2021-11-11 10:54:48 -08:00
Rhet Turnbull
b00978c61a Updated CHANGELOG.md [skip ci] 2021-11-07 21:35:46 -08:00
Rhet Turnbull
fb583e28e0 Updated docs [skip ci] 2021-11-07 21:31:27 -08:00
Rhet Turnbull
760386e3d7 Updated tested versions 2021-11-07 21:21:50 -08:00
Rhet Turnbull
51ba54971a Test fixes for Monterey/M1 2021-11-07 08:33:08 -08:00
Rhet Turnbull
2ffcf1e82b Updated OTL to MTL 2021-11-06 07:13:02 -07:00
Rhet Turnbull
818f4f45a4 Dependency update for Monterey 2021-10-30 07:37:23 -07:00
Rhet Turnbull
2cf19f6af1 Updated docs [skip ci] 2021-10-30 07:25:26 -07:00
Rhet Turnbull
ef82c6e32b Updated for Monterey 12.0.1 release 2021-10-28 22:05:17 -07:00
Rhet Turnbull
0e9b9d6251 Updated docs [skip ci] 2021-10-15 05:45:17 -07:00
Rhet Turnbull
419b34ea73 Fix for #526 with --update 2021-10-15 05:36:41 -07:00
Rhet Turnbull
f64c4ed374 Fixed FileUtil to use correct import 2021-10-14 21:29:45 -07:00
Rhet Turnbull
1677f404d2 Updated CHANGELOG.md [skip ci] 2021-10-11 18:07:36 -07:00
allcontributors[bot]
a612a363ed docs: add spencerc99 as a contributor for bug (#527)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2021-10-11 18:03:50 -07:00
Rhet Turnbull
202bc1144b Fix for #526 2021-10-11 17:50:07 -07:00
Rhet Turnbull
a0c654e43f Updated README.md [skip ci] 2021-10-11 17:03:45 -07:00
Rhet Turnbull
2bb677dc19 Updated docs [skip ci] 2021-10-11 16:52:22 -07:00
Rhet Turnbull
e33805fe42 Merge branch 'master' of github.com:RhetTbull/osxphotos 2021-10-11 16:00:05 -07:00
Rhet Turnbull
04ac0a1121 Fix for #524 2021-10-11 15:59:40 -07:00
Rhet Turnbull
d2b0bd4e28 Fix for #525 2021-10-11 15:59:02 -07:00
allcontributors[bot]
d754899563 docs: add oPromessa as a contributor for bug (#525)
* docs: update README.md [skip ci]

* docs: update .all-contributorsrc [skip ci]

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2021-10-11 15:55:49 -07:00
Rhet Turnbull
4a81e643a7 Updated CHANGELOG.md [skip ci] 2021-10-11 07:35:51 -07:00
Rhet Turnbull
b23e74f8f5 Updated docs [skip ci] 2021-10-11 07:32:15 -07:00
Rhet Turnbull
5dc766249a Updated dependencies 2021-10-10 23:05:53 -07:00
Rhet Turnbull
a895833c7f Updated dependencies 2021-10-10 22:27:00 -07:00
Rhet Turnbull
3f81a3c179 Added python 3.10 to supported versions 2021-10-09 09:39:23 -07:00
Rhet Turnbull
f1235f745f Updated CHANGELOG.md [skip ci] 2021-09-30 06:13:40 -07:00
39 changed files with 378 additions and 250 deletions

View File

@@ -250,6 +250,24 @@
"contributions": [
"bug"
]
},
{
"login": "oPromessa",
"name": "oPromessa",
"avatar_url": "https://avatars.githubusercontent.com/u/21261491?v=4",
"profile": "https://github.com/oPromessa",
"contributions": [
"bug"
]
},
{
"login": "spencerc99",
"name": "Spencer Chang",
"avatar_url": "https://avatars.githubusercontent.com/u/14796580?v=4",
"profile": "http://spencerchang.me",
"contributions": [
"bug"
]
}
],
"contributorsPerLine": 7,

View File

@@ -4,6 +4,73 @@ 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.43.4](https://github.com/RhetTbull/osxphotos/compare/v0.43.3...v0.43.4)
> 11 November 2021
- Fix for --use-photokit with --skip-live, #537 [`0e6c92d`](https://github.com/RhetTbull/osxphotos/commit/0e6c92dbd951dd0e63cfb8b6d64e6ab96ece5955)
#### [v0.43.3](https://github.com/RhetTbull/osxphotos/compare/v0.43.1...v0.43.3)
> 7 November 2021
- Updated docs [skip ci] [`fb583e2`](https://github.com/RhetTbull/osxphotos/commit/fb583e28e0fc2c23bf24052db8a5ee669d8c92f5)
- Updated OTL to MTL [`2ffcf1e`](https://github.com/RhetTbull/osxphotos/commit/2ffcf1e82bfc013a4a9e0e7a709a7c1395c074ce)
- Test fixes for Monterey/M1 [`51ba549`](https://github.com/RhetTbull/osxphotos/commit/51ba54971a874cfce00368aa5be5380b3439c254)
#### [v0.43.1](https://github.com/RhetTbull/osxphotos/compare/v0.43.0...v0.43.1)
> 30 October 2021
- Dependency update for Monterey [`818f4f4`](https://github.com/RhetTbull/osxphotos/commit/818f4f45a4ce520b0ba1c688eabd2f4311be9540)
- Updated docs [skip ci] [`2cf19f6`](https://github.com/RhetTbull/osxphotos/commit/2cf19f6af1a03767e4d53eee556c4d3ed9af1776)
#### [v0.43.0](https://github.com/RhetTbull/osxphotos/compare/v0.42.94...v0.43.0)
> 28 October 2021
- Updated for Monterey 12.0.1 release [`ef82c6e`](https://github.com/RhetTbull/osxphotos/commit/ef82c6e32b536b0677530133892f95b852c6dce0)
#### [v0.42.94](https://github.com/RhetTbull/osxphotos/compare/v0.42.93...v0.42.94)
> 15 October 2021
- docs: add spencerc99 as a contributor for bug [`#527`](https://github.com/RhetTbull/osxphotos/pull/527)
- Fix for #526 with --update [`419b34e`](https://github.com/RhetTbull/osxphotos/commit/419b34ea73f15ccbe29f51896e11e9735ea5786b)
- Updated docs [skip ci] [`0e9b9d6`](https://github.com/RhetTbull/osxphotos/commit/0e9b9d625190b94c1dd68276e3b0e5367002d87c)
- Fixed FileUtil to use correct import [`f64c4ed`](https://github.com/RhetTbull/osxphotos/commit/f64c4ed374c120a95fe8adea26bd44852ca67e31)
#### [v0.42.93](https://github.com/RhetTbull/osxphotos/compare/v0.42.92...v0.42.93)
> 11 October 2021
- Fix for #526 [`202bc11`](https://github.com/RhetTbull/osxphotos/commit/202bc1144bc842ddec825eef0745830d56170aba)
- Updated README.md [skip ci] [`a0c654e`](https://github.com/RhetTbull/osxphotos/commit/a0c654e43f4aa5389a96c3c84fd7037c33d23404)
#### [v0.42.92](https://github.com/RhetTbull/osxphotos/compare/v0.42.91...v0.42.92)
> 11 October 2021
- docs: add oPromessa as a contributor for bug [`#525`](https://github.com/RhetTbull/osxphotos/pull/525)
- Fix for #524 [`04ac0a1`](https://github.com/RhetTbull/osxphotos/commit/04ac0a11215b275178013e60c6a61b9f1b3603c9)
- Fix for #525 [`d2b0bd4`](https://github.com/RhetTbull/osxphotos/commit/d2b0bd4e28cfdf3c930aa6ae3317549327b0e29c)
- Updated docs [skip ci] [`2bb677d`](https://github.com/RhetTbull/osxphotos/commit/2bb677dc19abaf254bc66e2cd788676e0613e548)
#### [v0.42.91](https://github.com/RhetTbull/osxphotos/compare/v0.42.90...v0.42.91)
> 11 October 2021
- Updated docs [skip ci] [`b23e74f`](https://github.com/RhetTbull/osxphotos/commit/b23e74f8f5a8387564108c330c3f8ac11189860d)
- Added python 3.10 to supported versions [`3f81a3c`](https://github.com/RhetTbull/osxphotos/commit/3f81a3c179dde37e9811ef19c847920bb3bd514c)
- Updated dependencies [`a895833`](https://github.com/RhetTbull/osxphotos/commit/a895833c7f0a264488e671f1735f9e10d2618e2d)
#### [v0.42.90](https://github.com/RhetTbull/osxphotos/compare/v0.42.89...v0.42.90)
> 30 September 2021
- Updated REPL, now with more cowbell [`c472698`](https://github.com/RhetTbull/osxphotos/commit/c472698b1d0d8ff9f4d1bde715859bf766f99290)
- Updated docs [skip ci] [`1ddb1de`](https://github.com/RhetTbull/osxphotos/commit/1ddb1de99841e65b690ffc1cbcc5e42e6e25f727)
#### [v0.42.89](https://github.com/RhetTbull/osxphotos/compare/v0.42.88...v0.42.89)
> 26 September 2021

View File

@@ -4,7 +4,9 @@
[![tests](https://github.com/RhetTbull/osxphotos/workflows/Tests/badge.svg)](https://github.com/RhetTbull/osxphotos/workflows/Tests/badge.svg)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/osxphotos)
[![Downloads](https://static.pepy.tech/personalized-badge/osxphotos?period=month&units=international_system&left_color=black&right_color=brightgreen&left_text=downloads/month)](https://pepy.tech/project/osxphotos)
[![All Contributors](https://img.shields.io/badge/all_contributors-26-orange.svg?style=flat)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-28-orange.svg?style=flat)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
OSXPhotos provides the ability to interact with and query Apple's Photos.app library on macOS. You can query the Photos library database — for example, file name, file path, and metadata such as keywords/tags, persons/faces, albums, etc. You can also easily export both the original and edited photos.
@@ -1258,8 +1260,8 @@ s
** Templating System **
The templating system converts one or template statements, written in osxphotos
templating language, to one or more rendered values using information from the
photo being processed.
metadata templating language, to one or more rendered values using information
from the photo being processed.
In its simplest form, a template statement has the form: "{template_field}", for
example "{title}" which would resolve to the title of the photo.
@@ -1702,7 +1704,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.90'
{osxphotos_version} The osxphotos version, e.g. '0.43.4'
{osxphotos_cmd_line} The full command line used to run osxphotos
The following substitutions may result in multiple values. Thus if specified for
@@ -2773,7 +2775,7 @@ If overwrite=False and increment=False, export will fail if destination file alr
Render template string for photo. none_str is used if template substitution results in None value and no default specified.
- `template_str`: str in osxphotos template language (OTL) format. See also [Template System](#template-system) table. See notes below regarding specific details of the syntax.
- `template_str`: str in metadata template language (MTL) format. See also [Template System](#template-system) table. See notes below regarding specific details of the syntax.
- `options`: an optional osxphotos.phototemplate.RenderOptions object specifying the options to pass to the rendering engine.
`RenderOptions` has the following properties:
@@ -3269,7 +3271,6 @@ The following additional properties are also available but are not yet fully doc
- `manual`:
- `face_type`:
- `age_type`:
- `bald_type`:
- `eye_makeup_type`:
- `eye_state`:
- `facial_hair_type`:
@@ -3352,7 +3353,7 @@ To get the path of every raw photo, whether it's a single raw photo or a raw+JPE
### Template System
<!-- OSXPHOTOS-TEMPLATE-HELP:START - Do not remove or modify this section -->
The templating system converts one or template statements, written in osxphotos templating language, to one or more rendered values using information from the photo being processed.
The templating system converts one or template statements, written in osxphotos metadata templating language, to one or more rendered values using information from the photo being processed.
In its simplest form, a template statement has the form: `"{template_field}"`, for example `"{title}"` which would resolve to the title of the photo.
@@ -3573,7 +3574,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.90'|
|{osxphotos_version}|The osxphotos version, e.g. '0.43.4'|
|{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|
@@ -3797,6 +3798,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/mkirkland4874"><img src="https://avatars.githubusercontent.com/u/36466711?v=4?s=75" width="75px;" alt=""/><br /><sub><b>mkirkland4874</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Amkirkland4874" title="Bug reports">🐛</a> <a href="#example-mkirkland4874" title="Examples">💡</a></td>
<td align="center"><a href="https://github.com/jcommisso07"><img src="https://avatars.githubusercontent.com/u/3111054?v=4?s=75" width="75px;" alt=""/><br /><sub><b>Joseph Commisso</b></sub></a><br /><a href="#data-jcommisso07" title="Data">🔣</a></td>
<td align="center"><a href="https://github.com/dssinger"><img src="https://avatars.githubusercontent.com/u/1817903?v=4?s=75" width="75px;" alt=""/><br /><sub><b>David Singer</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Adssinger" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/oPromessa"><img src="https://avatars.githubusercontent.com/u/21261491?v=4?s=75" width="75px;" alt=""/><br /><sub><b>oPromessa</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3AoPromessa" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://spencerchang.me"><img src="https://avatars.githubusercontent.com/u/14796580?v=4?s=75" width="75px;" alt=""/><br /><sub><b>Spencer Chang</b></sub></a><br /><a href="https://github.com/RhetTbull/osxphotos/issues?q=author%3Aspencerc99" title="Bug reports">🐛</a></td>
</tr>
</table>

View File

@@ -7,5 +7,6 @@
rm -rf dist; rm -rf build
python3 utils/update_readme.py
(cd docsrc && make github && make pdf)
python3 setup.py sdist bdist_wheel
# python3 setup.py sdist bdist_wheel
python3 -m build
./make_cli_exe.sh

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: a12da50d91232e075b2c9df2935d2e62
config: 7a3415c9b6b46da1269550f16ddeb35c
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.42.90 documentation</title>
<title>Overview: module code &#8212; osxphotos 0.43.4 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>

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.42.84 documentation</title>
<title>osxphotos.photoinfo._photoinfo_export &#8212; osxphotos 0.43.4 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>
@@ -945,7 +945,14 @@
<span class="n">preview_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path_derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">preview_ext</span> <span class="o">=</span> <span class="n">preview_path</span><span class="o">.</span><span class="n">suffix</span>
<span class="n">preview_name</span> <span class="o">=</span> <span class="n">dest</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dest</span><span class="o">.</span><span class="n">stem</span><span class="si">}{</span><span class="n">preview_suffix</span><span class="si">}{</span><span class="n">preview_ext</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">preview_name</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">increment_filename</span><span class="p">(</span><span class="n">preview_name</span><span class="p">))</span>
<span class="c1"># if original is missing, the filename won&#39;t have been incremented so</span>
<span class="c1"># need to check here to make sure there aren&#39;t duplicate preview files in</span>
<span class="c1"># the export directory</span>
<span class="n">preview_name</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">preview_name</span>
<span class="k">if</span> <span class="n">overwrite</span> <span class="ow">or</span> <span class="n">update</span>
<span class="k">else</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">increment_filename</span><span class="p">(</span><span class="n">preview_name</span><span class="p">))</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">preview_path</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_export_photo</span><span class="p">(</span>
<span class="n">preview_path</span><span class="p">,</span>
@@ -1292,6 +1299,7 @@
<span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="n">PHOTOS_VERSION_CURRENT</span><span class="p">,</span>
<span class="n">overwrite</span><span class="o">=</span><span class="n">overwrite</span><span class="p">,</span>
<span class="n">video</span><span class="o">=</span><span class="n">live_photo</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">all_results</span><span class="o">.</span><span class="n">exported</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">exported</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
@@ -1339,6 +1347,7 @@
<span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="n">PHOTOS_VERSION_ORIGINAL</span><span class="p">,</span>
<span class="n">overwrite</span><span class="o">=</span><span class="n">overwrite</span><span class="p">,</span>
<span class="n">video</span><span class="o">=</span><span class="n">live_photo</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">all_results</span><span class="o">.</span><span class="n">exported</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">exported</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</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.42.87 documentation</title>
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.42.92 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>
@@ -3329,9 +3329,9 @@
<span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">regex</span><span class="p">:</span>
<span class="n">flags</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span> <span class="k">if</span> <span class="n">options</span><span class="o">.</span><span class="n">ignore_case</span> <span class="k">else</span> <span class="mi">0</span>
<span class="n">render_options</span> <span class="o">=</span> <span class="n">RenderOptions</span><span class="p">(</span><span class="n">none_str</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="n">photo_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">regex</span><span class="p">,</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">regex</span><span class="p">:</span>
<span class="n">regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">flags</span><span class="p">)</span>
<span class="n">photo_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span><span class="p">:</span>
<span class="n">rendered</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">render_template</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">render_options</span><span class="p">)</span>
<span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">rendered</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.42.90',
VERSION: '0.43.4',
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.42.90 documentation</title>
<title>osxphotos command line interface (CLI) &#8212; osxphotos 0.43.4 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>

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.42.90 documentation</title>
<title>Index &#8212; osxphotos 0.43.4 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>

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.42.90 documentation</title>
<title>Welcome to osxphotoss documentation! &#8212; osxphotos 0.43.4 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>

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.42.90 documentation</title>
<title>osxphotos &#8212; osxphotos 0.43.4 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>

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.42.90 documentation</title>
<title>osxphotos package &#8212; osxphotos 0.43.4 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>

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.42.90 documentation</title>
<title>Search &#8212; osxphotos 0.43.4 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />

View File

@@ -95,6 +95,7 @@ _TESTED_OS_VERSIONS = [
("11", "3"),
("11", "4"),
("11", "5"),
("11", "6"),
]
# Photos 5 has persons who are empty string if unidentified face
@@ -276,12 +277,15 @@ POST_COMMAND_CATEGORIES = {
# "deleted_directories": "When used with '--cleanup', all directories deleted during the export",
}
class AlbumSortOrder(Enum):
"""Album Sort Order"""
UNKNOWN = 0
MANUAL = 1
NEWEST_FIRST = 2
OLDEST_FIRST = 3
TITLE = 5
TEXT_DETECTION_CONFIDENCE_THRESHOLD = 0.75
TEXT_DETECTION_CONFIDENCE_THRESHOLD = 0.75

View File

@@ -1,4 +1,3 @@
""" version info """
__version__ = "0.42.90"
__version__ = "0.43.5"

View File

@@ -7,7 +7,7 @@ import subprocess
import sys
from abc import ABC, abstractmethod
import CoreFoundation
import Foundation
from .imageconverter import ImageConverter
@@ -114,7 +114,7 @@ class FileUtilMacOS(FileUtilABC):
if dest.is_dir():
dest /= src.name
filemgr = CoreFoundation.NSFileManager.defaultManager()
filemgr = Foundation.NSFileManager.defaultManager()
error = filemgr.copyItemAtPath_toPath_error_(str(src), str(dest), None)
# error is a tuple of (bool, error_string)
# error[0] is True if copy succeeded

View File

@@ -141,7 +141,7 @@ class FaceInfo:
self.manual = face["manual"]
self.face_type = face["facetype"]
self.age_type = face["agetype"]
self.bald_type = face["baldtype"]
# self.bald_type = face["baldtype"]
self.eye_makeup_type = face["eyemakeuptype"]
self.eye_state = face["eyestate"]
self.facial_hair_type = face["facialhairtype"]
@@ -438,7 +438,7 @@ class FaceInfo:
"manual": self.manual,
"face_type": self.face_type,
"age_type": self.age_type,
"bald_type": self.bald_type,
# "bald_type": self.bald_type,
"eye_makeup_type": self.eye_makeup_type,
"eye_state": self.eye_state,
"facial_hair_type": self.facial_hair_type,

View File

@@ -912,7 +912,14 @@ def export2(
preview_path = pathlib.Path(self.path_derivatives[0])
preview_ext = preview_path.suffix
preview_name = dest.parent / f"{dest.stem}{preview_suffix}{preview_ext}"
preview_name = pathlib.Path(increment_filename(preview_name))
# if original is missing, the filename won't have been incremented so
# need to check here to make sure there aren't duplicate preview files in
# the export directory
preview_name = (
preview_name
if overwrite or update
else pathlib.Path(increment_filename(preview_name))
)
if preview_path is not None:
results = self._export_photo(
preview_path,
@@ -1259,6 +1266,7 @@ def _export_photo_with_photos_export(
dest.name,
version=PHOTOS_VERSION_CURRENT,
overwrite=overwrite,
video=live_photo,
)
all_results.exported.extend(exported)
except Exception as e:
@@ -1306,6 +1314,7 @@ def _export_photo_with_photos_export(
dest.name,
version=PHOTOS_VERSION_ORIGINAL,
overwrite=overwrite,
video=live_photo,
)
all_results.exported.extend(exported)
except Exception as e:

View File

@@ -6,8 +6,6 @@
"""
# NOTES:
# - This likely leaks memory like a sieve as I need to ensure all the
# Objective C objects are cleaned up.
# - There are several techniques used for handling PhotoKit's various
# asynchronous calls used in this code: event loop+notification, threading
# event, while loop. I've experimented with each to find the one that works.
@@ -200,16 +198,6 @@ class PHAssetResourceData:
self.data = b""
# class LivePhotoData:
# """ Simple class to hold the data passed to the handler for
# requestLivePhotoForAsset:targetSize:contentMode:options:resultHandler:
# """
# def __init__(self):
# self.live_photo = None
# self.info = None
class PhotoKitNotificationDelegate(NSObject):
"""Handles notifications from NotificationCenter;
used with asynchronous PhotoKit requests to stop event loop when complete
@@ -487,6 +475,7 @@ class PhotoAsset:
version=PHOTOS_VERSION_CURRENT,
overwrite=False,
raw=False,
**kwargs,
):
"""Export image to path
@@ -496,6 +485,7 @@ class PhotoAsset:
version: which version of image (PHOTOS_VERSION_ORIGINAL or PHOTOS_VERSION_CURRENT)
overwrite: bool, if True, overwrites destination file if it already exists; default is False
raw: bool, if True, export RAW component of RAW+JPEG pair, default is False
**kwargs: used only to avoid issues with each asset type having slightly different export arguments
Returns:
List of path to exported image(s)
@@ -504,9 +494,6 @@ class PhotoAsset:
ValueError if dest is not a valid directory
"""
# if self.live:
# raise NotImplementedError("Live photos not implemented yet")
with objc.autorelease_pool():
filename = (
pathlib.Path(filename)
@@ -615,9 +602,7 @@ class PhotoAsset:
nonlocal requestdata
options = {}
# pylint: disable=no-member
options[Quartz.kCGImageSourceShouldCache] = Foundation.kCFBooleanFalse
options = {Quartz.kCGImageSourceShouldCache: Foundation.kCFBooleanFalse}
imgSrc = Quartz.CGImageSourceCreateWithData(imageData, options)
requestdata.metadata = Quartz.CGImageSourceCopyPropertiesAtIndex(
imgSrc, 0, options
@@ -701,9 +686,7 @@ class PhotoAsset:
nonlocal data
options = {}
# pylint: disable=no-member
options[Quartz.kCGImageSourceShouldCache] = Foundation.kCFBooleanFalse
options = {Quartz.kCGImageSourceShouldCache: Foundation.kCFBooleanFalse}
imgSrc = Quartz.CGImageSourceCreateWithData(imageData, options)
data.metadata = Quartz.CGImageSourceCopyPropertiesAtIndex(
imgSrc, 0, options
@@ -789,7 +772,6 @@ class SlowMoVideoExporter(NSObject):
self.url = None
self.done = None
self.nc = None
# super(NSObject, self).dealloc()
class VideoAsset(PhotoAsset):
@@ -801,7 +783,12 @@ class VideoAsset(PhotoAsset):
# https://developer.apple.com/documentation/photokit/phimagemanager/1616981-requestexportsessionforvideo?language=objc
# above 10.15 only
def export(
self, dest, filename=None, version=PHOTOS_VERSION_CURRENT, overwrite=False
self,
dest,
filename=None,
version=PHOTOS_VERSION_CURRENT,
overwrite=False,
**kwargs,
):
"""Export video to path
@@ -810,6 +797,7 @@ class VideoAsset(PhotoAsset):
filename: str, optional name of exported file; if not provided, defaults to asset's original filename
version: which version of image (PHOTOS_VERSION_ORIGINAL or PHOTOS_VERSION_CURRENT)
overwrite: bool, if True, overwrites destination file if it already exists; default is False
**kwargs: used only to avoid issues with each asset type having slightly different export arguments
Returns:
List of path to exported image(s)
@@ -1043,6 +1031,7 @@ class LivePhotoAsset(PhotoAsset):
overwrite=False,
photo=True,
video=True,
**kwargs,
):
"""Export image to path
@@ -1053,6 +1042,7 @@ class LivePhotoAsset(PhotoAsset):
overwrite: bool, if True, overwrites destination file if it already exists; default is False
photo: bool, if True, export photo component of live photo
video: bool, if True, export live video component of live photo
**kwargs: used only to avoid issues with each asset type having slightly different export arguments
Returns:
list of [path to exported image and/or video]
@@ -1104,39 +1094,6 @@ class LivePhotoAsset(PhotoAsset):
photo_output_file = pathlib.Path(increment_filename(photo_output_file))
video_output_file = pathlib.Path(increment_filename(video_output_file))
# def handler(error):
# if error:
# raise PhotoKitExportError(f"writeDataForAssetResource error: {error}")
# resource_manager = Photos.PHAssetResourceManager.defaultManager()
# options = Photos.PHAssetResourceRequestOptions.alloc().init()
# options.setNetworkAccessAllowed_(True)
# exported = []
# Note: Tried writeDataForAssetResource_toFile_options_completionHandler_ which works
# but sets quarantine flag and for reasons I can't determine (maybe quarantine flag)
# causes pathlib.Path().is_file() to fail in tests
# if photo:
# photo_output_url = path_to_NSURL(photo_output_file)
# resource_manager.writeDataForAssetResource_toFile_options_completionHandler_(
# photo_resource, photo_output_url, options, handler
# )
# exported.append(str(photo_output_file))
# if video:
# video_output_url = path_to_NSURL(video_output_file)
# resource_manager.writeDataForAssetResource_toFile_options_completionHandler_(
# video_resource, video_output_url, options, handler
# )
# exported.append(str(video_output_file))
# def completion_handler(error):
# if error:
# raise PhotoKitExportError(f"writeDataForAssetResource error: {error}")
# would be nice to be able to usewriteDataForAssetResource_toFile_options_completionHandler_
# but it sets quarantine flags that cause issues so instead, request the data and write the files directly
exported = []
if photo:
data = self._request_resource_data(photo_resource)
@@ -1155,41 +1112,6 @@ class LivePhotoAsset(PhotoAsset):
request.dealloc()
return exported
# def request_image_data(self, version=PHOTOS_VERSION_CURRENT):
# # Returns an NSImage which isn't overly useful
# # https://developer.apple.com/documentation/photokit/phimagemanager/1616964-requestimageforasset?language=objc
# # requestImageForAsset:targetSize:contentMode:options:resultHandler:
# options = Photos.PHImageRequestOptions.alloc().init()
# options.setVersion_(version)
# options.setNetworkAccessAllowed_(True)
# options.setSynchronous_(True)
# options.setDeliveryMode_(
# Photos.PHImageRequestOptionsDeliveryModeHighQualityFormat
# )
# event = threading.Event()
# image_data = ImageData()
# def handler(result, info):
# nonlocal image_data
# if not info["PHImageResultIsDegradedKey"]:
# image_data.image_data = result
# image_data.info = info
# event.set()
# self._manager.requestImageForAsset_targetSize_contentMode_options_resultHandler_(
# self._phasset,
# Photos.PHImageManagerMaximumSize,
# Photos.PHImageContentModeDefault,
# options,
# handler,
# )
# event.wait()
# options.dealloc()
# return image_data
class PhotoLibrary:
"""Interface to PhotoKit PHImageManager and PHPhotoLibrary"""

View File

@@ -146,7 +146,6 @@ def _process_faceinfo_4(photosdb):
# Photos 5 only
face["agetype"] = None
face["baldtype"] = None
face["eyemakeuptype"] = None
face["eyestate"] = None
face["facialhairtype"] = None
@@ -194,7 +193,7 @@ def _process_faceinfo_5(photosdb):
ZDETECTEDFACE.ZPERSON,
ZPERSON.ZFULLNAME,
ZDETECTEDFACE.ZAGETYPE,
ZDETECTEDFACE.ZBALDTYPE,
NULL, -- ZDETECTEDFACE.ZBALDTYPE (Removed in Monterey)
ZDETECTEDFACE.ZEYEMAKEUPTYPE,
ZDETECTEDFACE.ZEYESSTATE,
ZDETECTEDFACE.ZFACIALHAIRTYPE,
@@ -239,7 +238,7 @@ def _process_faceinfo_5(photosdb):
# 3 ZDETECTEDFACE.ZPERSON,
# 4 ZPERSON.ZFULLNAME,
# 5 ZDETECTEDFACE.ZAGETYPE,
# 6 ZDETECTEDFACE.ZBALDTYPE,
# 6 ZDETECTEDFACE.ZBALDTYPE, (Not available on Monterey)
# 7 ZDETECTEDFACE.ZEYEMAKEUPTYPE,
# 8 ZDETECTEDFACE.ZEYESSTATE,
# 9 ZDETECTEDFACE.ZFACIALHAIRTYPE,
@@ -284,7 +283,6 @@ def _process_faceinfo_5(photosdb):
face["person"] = person_pk
face["fullname"] = normalize_unicode(row[4])
face["agetype"] = row[5]
face["baldtype"] = row[6]
face["eyemakeuptype"] = row[7]
face["eyestate"] = row[8]
face["facialhairtype"] = row[9]

View File

@@ -3296,9 +3296,9 @@ class PhotosDB:
if options.regex:
flags = re.IGNORECASE if options.ignore_case else 0
render_options = RenderOptions(none_str="")
photo_list = []
for regex, template in options.regex:
regex = re.compile(regex, flags)
photo_list = []
for p in photos:
rendered, _ = p.render_template(template, render_options)
for value in rendered:

View File

@@ -1,4 +1,4 @@
The templating system converts one or template statements, written in osxphotos templating language, to one or more rendered values using information from the photo being processed.
The templating system converts one or template statements, written in osxphotos metadata templating language, to one or more rendered values using information from the photo being processed.
In its simplest form, a template statement has the form: `"{template_field}"`, for example `"{title}"` which would resolve to the title of the photo.

View File

@@ -1,4 +1,4 @@
""" Custom template system for osxphotos, implements osxphotos template language (OTL) """
""" Custom template system for osxphotos, implements metadata template language (MTL) """
import datetime
import json
@@ -27,7 +27,7 @@ from .utils import expand_and_validate_filepath, load_function
# ensure locale set to user's locale
locale.setlocale(locale.LC_ALL, "")
OTL_GRAMMAR_MODEL = str(pathlib.Path(__file__).parent / "phototemplate.tx")
MTL_GRAMMAR_MODEL = str(pathlib.Path(__file__).parent / "phototemplate.tx")
"""TextX metamodel for osxphotos template language """
@@ -324,7 +324,7 @@ class PhotoTemplateParser:
if hasattr(self, "metamodel"):
return
self.metamodel = metamodel_from_file(OTL_GRAMMAR_MODEL, skipws=False)
self.metamodel = metamodel_from_file(MTL_GRAMMAR_MODEL, skipws=False)
def parse(self, template_statement):
"""Parse a template_statement string"""

View File

@@ -1,4 +1,4 @@
// OSXPhotos Template Language (OTL)
// OSXPhotos Metadata Template Language (MTL)
// a TemplateString has format:
// pre{delim+template_field:subfield|filter(path_sep)[find,replace] conditional?bool_value,default}post
// a TemplateStatement may contain zero or more TemplateStrings

View File

@@ -1,25 +1,26 @@
pyobjc-core>=7.2,<8.0
pyobjc-framework-AppleScriptKit>=7.2,<8.0
pyobjc-framework-AppleScriptObjC>=7.2,<8.0
pyobjc-framework-Photos>=7.2,<8.0
pyobjc-framework-Quartz>=7.2,<8.0
pyobjc-framework-AVFoundation>=7.2,<8.0
pyobjc-framework-CoreServices>=7.2,<8.0
pyobjc-framework-Metal>=7.2,<8.0
pyobjc-framework-Vision>=7.2,<8.0
Click>=8.0.1,<9.0
PyYAML>=5.4.1<5.5.0
Mako>=1.1.4,<1.2.0
bpylist2==3.0.2
pathvalidate>=2.4.1,<2.5.0
dataclasses==0.7;python_version<'3.7'
wurlitzer>=2.1.0,<2.2.0
photoscript>=0.1.4,<0.2.0
toml>=0.10.2,<0.11.0
osxmetadata>=0.99.33,<1.0.0
textx>=2.3.0,<2.4.0
rich>=10.6.0,<=11.0.0
PyYAML>=5.4.1<5.5.0
bitmath>=1.3.3.1,<1.4.0.0
bpylist2==3.0.2
dataclasses==0.7;python_version<'3.7'
more-itertools>=8.8.0,<9.0.0
objexplore>=1.5.5,<1.6.0
ptpython>=3.0.20,<3.1.0
osxmetadata>=0.99.34,<1.0.0
pathvalidate>=2.4.1,<2.5.0
photoscript>=0.1.4,<0.2.0
ptpython>=3.0.20,<3.1.0
pyobjc-core>=7.3,<9.0
pyobjc-framework-AVFoundation>=7.3,<9.0
pyobjc-framework-AppleScriptKit>=7.3,<9.0
pyobjc-framework-AppleScriptObjC>=7.3,<9.0
pyobjc-framework-Cocoa>=7.3,<9.0
pyobjc-framework-CoreServices>=7.2,<9.0
pyobjc-framework-Metal>=7.3,<9.0
pyobjc-framework-Photos>=7.3,<9.0
pyobjc-framework-Quartz>=7.3,<9.0
pyobjc-framework-Vision>=7.3,<9.0
rich>=10.6.0,<=11.0.0
textx>=2.3.0,<2.4.0
toml>=0.10.2,<0.11.0
wurlitzer>=2.1.0,<2.2.0

View File

@@ -1,8 +1,9 @@
sphinx_click
pytest==6.2.4
pytest-mock
build
m2r2
pyinstaller==4.4
pytest-mock
pytest==6.2.4
sphinx_click
sphinx_rtd_theme
wheel
twine
wheel

View File

@@ -70,34 +70,36 @@ setup(
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Software Development :: Libraries :: Python Modules",
],
install_requires=[
"pyobjc-core>=7.2,<8.0",
"pyobjc-framework-AppleScriptKit>=7.2,<8.0",
"pyobjc-framework-AppleScriptObjC>=7.2,<8.0",
"pyobjc-framework-Photos>=7.2,<8.0",
"pyobjc-framework-Quartz>=7.2,<8.0",
"pyobjc-framework-AVFoundation>=7.2,<8.0",
"pyobjc-framework-CoreServices>=7.2,<8.0",
"pyobjc-framework-Metal>=7.2,<8.0",
"pyobjc-framework-Vision>=7.2,<8.0",
"Click>=8.0.1,<9.0",
"PyYAML>=5.4.1,<5.5.0",
"Mako>=1.1.4,<1.2.0",
"bpylist2==3.0.2",
"pathvalidate>=2.4.1,<2.5.0",
"dataclasses==0.7;python_version<'3.7'",
"wurlitzer>=2.1.0,<2.2.0",
"photoscript>=0.1.4,<0.2.0",
"toml>=0.10.2,<0.11.0",
"osxmetadata>=0.99.33,<1.0.0",
"textx>=2.3.0,<2.4.0",
"rich>=10.6.0,<=11.0.0",
"PyYAML>=5.4.1,<5.5.0",
"bitmath>=1.3.3.1,<1.4.0.0",
"bpylist2==3.0.2",
"dataclasses==0.7;python_version<'3.7'",
"more-itertools>=8.8.0,<9.0.0",
"objexplore>=1.5.5,<1.6.0",
"ptpython>=3.0.20,<3.1.0",
"osxmetadata>=0.99.34,<1.0.0",
"pathvalidate>=2.4.1,<3.0.0",
"photoscript>=0.1.4,<0.2.0",
"ptpython>=3.0.20,<4.0.0",
"pyobjc-core>=7.3,<9.0",
"pyobjc-framework-AVFoundation>=7.3,<9.0",
"pyobjc-framework-AppleScriptKit>=7.3,<9.0",
"pyobjc-framework-AppleScriptObjC>=7.3,<9.0",
"pyobjc-framework-Cocoa>=7.3,<9.0",
"pyobjc-framework-CoreServices>=7.2,<9.0",
"pyobjc-framework-Metal>=7.3,<9.0",
"pyobjc-framework-Photos>=7.3,<9.0",
"pyobjc-framework-Quartz>=7.3,<9.0",
"pyobjc-framework-Vision>=7.3,<9.0",
"rich>=10.6.0,<=11.0.0",
"textx>=2.3.0,<3.0.0",
"toml>=0.10.2,<0.11.0",
"wurlitzer>=2.1.0,<3.0.0",
],
entry_points={"console_scripts": ["osxphotos=osxphotos.__main__:cli"]},
include_package_data=True,

View File

@@ -252,7 +252,7 @@ UUID_NOT_REFERENCE = "F12384F6-CD17-4151-ACBA-AE0E3688539E"
UUID_DUPLICATE = ""
UUID_DETECTED_TEXT = {
"E2078879-A29C-4D6F-BACB-E3BBE6C3EB91": "osxphotos",
"E2078879-A29C-4D6F-BACB-E3BBE6C3EB91": "OPEN",
"A92D9C26-3A50-4197-9388-CB5F7DB9FA91": None,
}

View File

@@ -40,6 +40,11 @@ UUID_BURST_ALBUM = {
],
}
UUID_SKIP_LIVE_PHOTOKIT = {
"54A01B04-16D7-4FDE-8860-19F2A641E433": ["IMG_3203_edited.jpeg"],
"1F3DF341-B822-4531-999E-724D642FD8E7": ["IMG_4179.jpeg"],
}
UUID_DOWNLOAD_MISSING = "C6C712C5-9316-408D-A3C3-125661422DA9" # IMG_8844.JPG
UUID_FILE = "tests/uuid_from_file.txt"
@@ -1483,6 +1488,94 @@ def test_export_preview_if_missing():
assert sorted(files) == sorted(expected_files)
def test_export_preview_overwrite():
"""test export with --preview and --overwrite (#526)"""
import glob
import os
import os.path
import osxphotos
from osxphotos.cli import export
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",
"--preview",
"--uuid",
CLI_EXPORT_UUID,
],
)
assert result.exit_code == 0
# export again
result = runner.invoke(
export,
[
os.path.join(cwd, CLI_PHOTOS_DB),
".",
"-V",
"--preview",
"--uuid",
CLI_EXPORT_UUID,
"--overwrite",
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert len(files) == 2 # preview + original
def test_export_preview_update():
"""test export with --preview and --update (#526)"""
import glob
import os
import os.path
import osxphotos
from osxphotos.cli import export
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",
"--preview",
"--uuid",
CLI_EXPORT_UUID,
],
)
assert result.exit_code == 0
# export again
result = runner.invoke(
export,
[
os.path.join(cwd, CLI_PHOTOS_DB),
".",
"-V",
"--preview",
"--uuid",
CLI_EXPORT_UUID,
"--update",
],
)
assert result.exit_code == 0
files = glob.glob("*")
assert len(files) == 2 # preview + original
def test_export_as_hardlink():
import glob
import os
@@ -6557,6 +6650,43 @@ def test_export_download_missing_file_exists():
assert "exported: 1" in result.output
@pytest.mark.skipif(
"OSXPHOTOS_TEST_EXPORT" not in os.environ,
reason="Skip if not running on author's personal library.",
)
def test_export_skip_live_photokit():
"""test that --skip-live works with --use-photokit (issue #537)"""
import os
import os.path
import pathlib
from osxphotos.cli import export
runner = CliRunner()
cwd = os.getcwd()
# pylint: disable=not-context-manager
for uuid in UUID_SKIP_LIVE_PHOTOKIT:
with runner.isolated_filesystem():
result = runner.invoke(
export,
[
os.path.join(cwd, PHOTOS_DB_RHET),
".",
"-V",
"--uuid",
uuid,
"--use-photos-export",
"--use-photokit",
"--skip-live",
"--skip-original-if-edited",
"--convert-to-jpeg",
],
)
assert result.exit_code == 0
files = [str(p) for p in pathlib.Path(".").glob("IMG*")]
assert sorted(files) == sorted(UUID_SKIP_LIVE_PHOTOKIT[uuid])
def test_query_name():
"""test query --name"""
import json
@@ -6928,6 +7058,37 @@ def test_query_regex_4():
assert len(json_got) == 2
def test_query_regex_multiple():
"""test query multiple --regex values (#525)"""
import json
import os
import os.path
import osxphotos
from osxphotos.cli import query
runner = CliRunner()
cwd = os.getcwd()
result = runner.invoke(
query,
[
"--json",
"--db",
os.path.join(cwd, PHOTOS_DB_15_7),
"--regex",
"I found",
"{title}",
"--regex",
"carry",
"{title}",
],
)
assert result.exit_code == 0
json_got = json.loads(result.output)
assert len(json_got) == 2
def test_query_function():
"""test query --query-function"""
import json

View File

@@ -109,8 +109,6 @@ def test_export_edited(photosdb):
import pathlib
import tempfile
import osxphotos
tempdir = tempfile.TemporaryDirectory(prefix="osxphotos_")
dest = tempdir.name
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])

View File

@@ -58,7 +58,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -120,7 +119,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -182,7 +180,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -244,7 +241,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -306,7 +302,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -368,7 +363,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -430,7 +424,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -492,7 +485,6 @@ UUID_LIST_4 = [
"manual": 1,
"face_type": 2,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -554,7 +546,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -616,7 +607,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 2,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -678,7 +668,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -740,7 +729,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -802,7 +790,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -864,7 +851,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 2,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -926,7 +912,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 2,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -988,7 +973,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1050,7 +1034,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1108,7 +1091,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1170,7 +1152,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 2,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1232,7 +1213,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1294,7 +1274,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 1,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1356,7 +1335,6 @@ UUID_LIST_4 = [
"manual": 0,
"face_type": 0,
"age_type": None,
"bald_type": None,
"eye_makeup_type": None,
"eye_state": None,
"facial_hair_type": None,
@@ -1421,7 +1399,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -1483,7 +1460,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 5,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 2,
@@ -1545,7 +1521,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -1603,7 +1578,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -1665,7 +1639,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -1727,7 +1700,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 1,
"facial_hair_type": 1,
@@ -1789,7 +1761,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -1851,7 +1822,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -1913,7 +1883,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -1975,7 +1944,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -2037,7 +2005,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2099,7 +2066,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 5,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 2,
@@ -2161,7 +2127,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2219,7 +2184,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2281,7 +2245,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 2,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -2343,7 +2306,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2405,7 +2367,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2463,7 +2424,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2525,7 +2485,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2587,7 +2546,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2645,7 +2603,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2707,7 +2664,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 5,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -2769,7 +2725,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -2831,7 +2786,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2893,7 +2847,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -2951,7 +2904,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3013,7 +2965,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3075,7 +3026,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3133,7 +3083,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3195,7 +3144,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3257,7 +3205,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3315,7 +3262,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3377,7 +3323,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3435,7 +3380,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3497,7 +3441,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -3559,7 +3502,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 5,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 3,
@@ -3621,7 +3563,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3679,7 +3620,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3741,7 +3681,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3803,7 +3742,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -3865,7 +3803,6 @@ UUID_LIST_5 = [
"manual": 1,
"face_type": None,
"age_type": 0,
"bald_type": 0,
"eye_makeup_type": 0,
"eye_state": 0,
"facial_hair_type": 0,
@@ -3927,7 +3864,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 5,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,
@@ -3985,7 +3921,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 4,
"bald_type": 2,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 2,
@@ -4047,7 +3982,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 5,
"bald_type": 2,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 2,
@@ -4109,7 +4043,6 @@ UUID_LIST_5 = [
"manual": 0,
"face_type": None,
"age_type": 3,
"bald_type": 3,
"eye_makeup_type": 0,
"eye_state": 2,
"facial_hair_type": 1,

View File

@@ -266,8 +266,8 @@ TEMPLATE_VALUES_DATE_NOT_MODIFIED = {
UUID_DETECTED_TEXT = "E2078879-A29C-4D6F-BACB-E3BBE6C3EB91"
TEMPLATE_VALUES_DETECTED_TEXT = {
"{detected_text}": "osxphotos",
"{;+detected_text:0.5}": "osxphotos;",
"{detected_text}": "OPEN",
"{;+detected_text:0.5}": "OPEN",
}
COMMENT_UUID_DICT = {

View File

@@ -25,7 +25,7 @@ def test_get_uti_for_extension():
assert get_uti_for_extension(ext) == EXT_DICT[ext]
def test_get_preferred_uti_extension_no_obj():
def test_get_preferred_uti_extension_no_objc():
"""test get_preferred_uti_extension when running on macOS >= 12"""
OLD_VER = osxphotos.uti.OS_VER
osxphotos.uti.OS_VER = 12
@@ -34,7 +34,7 @@ def test_get_preferred_uti_extension_no_obj():
osxphotos.uti.OS_VER = OLD_VER
def test_get_uti_for_extension_no_obj():
def test_get_uti_for_extension_no_objc():
"""get get_uti_for_extension when running on macOS >= 12"""
OLD_VER = osxphotos.uti.OS_VER
osxphotos.uti.OS_VER = 12

View File

@@ -2,9 +2,11 @@
# in multiple virtualenvs. This configuration file will run the
# test suite on all supported python versions. To use it, "pip install tox"
# and then run "tox" from this directory.
# To use with pyenv, install pip install tox-pyenv then set local versions with pyenv local, e.g.:
# pyenv local osxphotos-3.9.5 3.10.0rc1 3.8.12 3.7.11
[tox]
envlist = py37, py38
envlist = py37, py38, py39, py310
[testenv]
deps =