Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d923590ae | ||
|
|
5383ced1ca | ||
|
|
0e6c92dbd9 | ||
|
|
b00978c61a | ||
|
|
fb583e28e0 | ||
|
|
760386e3d7 | ||
|
|
51ba54971a | ||
|
|
2ffcf1e82b | ||
|
|
818f4f45a4 | ||
|
|
2cf19f6af1 | ||
|
|
ef82c6e32b | ||
|
|
0e9b9d6251 | ||
|
|
419b34ea73 | ||
|
|
f64c4ed374 | ||
|
|
1677f404d2 | ||
|
|
a612a363ed | ||
|
|
202bc1144b | ||
|
|
a0c654e43f | ||
|
|
2bb677dc19 | ||
|
|
e33805fe42 | ||
|
|
04ac0a1121 | ||
|
|
d2b0bd4e28 | ||
|
|
d754899563 | ||
|
|
4a81e643a7 | ||
|
|
b23e74f8f5 | ||
|
|
5dc766249a | ||
|
|
a895833c7f | ||
|
|
3f81a3c179 | ||
|
|
f1235f745f | ||
|
|
1ddb1de998 | ||
|
|
c472698b1d | ||
|
|
4e021a0731 | ||
|
|
bfbc156821 | ||
|
|
bfd6274602 | ||
|
|
3abaa5ae84 | ||
|
|
65115a50a9 | ||
|
|
06138e15d0 | ||
|
|
14710e3178 | ||
|
|
f705f09749 | ||
|
|
82c445f41e | ||
|
|
1b40e9d65f | ||
|
|
725f7c8735 | ||
|
|
7cc8578148 | ||
|
|
6adafb8ce7 | ||
|
|
ac47df8475 | ||
|
|
f680cf78ab | ||
|
|
c86e84c534 | ||
|
|
3fb611825c | ||
|
|
1cfdad0176 |
@@ -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,
|
||||
|
||||
101
CHANGELOG.md
101
CHANGELOG.md
@@ -4,6 +4,107 @@ 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
|
||||
|
||||
- Updated docs [skip ci] [`bfbc156`](https://github.com/RhetTbull/osxphotos/commit/bfbc156821d2d262b7bd9c4437e23e310da10769)
|
||||
- Updated docs [skip ci] [`3abaa5a`](https://github.com/RhetTbull/osxphotos/commit/3abaa5ae84ca44cd900f1e3af4532ab405d41a09)
|
||||
- Fixed AlbumInfo.owner, #239 [`bfd6274`](https://github.com/RhetTbull/osxphotos/commit/bfd627460255c65f870bca6d036401e8792d29d5)
|
||||
|
||||
#### [v0.42.88](https://github.com/RhetTbull/osxphotos/compare/v0.42.87...v0.42.88)
|
||||
|
||||
> 26 September 2021
|
||||
|
||||
- Performance fix for #239, owner [`14710e3`](https://github.com/RhetTbull/osxphotos/commit/14710e31789d71b2c948a37722fb6054aca4d85e)
|
||||
- version bump [`06138e1`](https://github.com/RhetTbull/osxphotos/commit/06138e15d0b87e4865a9ef0cc542303edb44c861)
|
||||
|
||||
#### [v0.42.87](https://github.com/RhetTbull/osxphotos/compare/v0.42.86...v0.42.87)
|
||||
|
||||
> 26 September 2021
|
||||
|
||||
#### [v0.42.86](https://github.com/RhetTbull/osxphotos/compare/v0.42.85...v0.42.86)
|
||||
|
||||
> 26 September 2021
|
||||
|
||||
- Fix for #517, #239 [`ac47df8`](https://github.com/RhetTbull/osxphotos/commit/ac47df8475762fe8c8f63ad5ffa83b1e20d116b8)
|
||||
- Fixed formatting [`6adafb8`](https://github.com/RhetTbull/osxphotos/commit/6adafb8ce70e95a9f0bec1a3db6362742fcd1b0d)
|
||||
- Updated docs [skip ci] [`725f7c8`](https://github.com/RhetTbull/osxphotos/commit/725f7c87351353efeee8c43c3c7f8a95acb14490)
|
||||
|
||||
#### [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
|
||||
|
||||
23
README.md
23
README.md
@@ -4,7 +4,9 @@
|
||||
[](https://github.com/RhetTbull/osxphotos/workflows/Tests/badge.svg)
|
||||

|
||||
[](https://pepy.tech/project/osxphotos)
|
||||
[](#contributors)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#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.85'
|
||||
{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
|
||||
@@ -2373,6 +2375,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.
|
||||
@@ -2771,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:
|
||||
@@ -3267,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`:
|
||||
@@ -3350,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.
|
||||
|
||||
@@ -3571,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.85'|
|
||||
|{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|
|
||||
@@ -3795,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>
|
||||
|
||||
@@ -3836,6 +3841,8 @@ For additional details about how osxphotos is implemented or if you would like t
|
||||
- [textx](https://github.com/textX/textX)
|
||||
- [bitmath](https://github.com/tbielawa/bitmath)
|
||||
- [more-itertools](https://github.com/more-itertools/more-itertools)
|
||||
- [ptpython](https://github.com/prompt-toolkit/ptpython)
|
||||
- [objexplore](https://github.com/kylepollina/objexplore)
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
3
build.sh
3
build.sh
@@ -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
|
||||
|
||||
@@ -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: 11213341ff264627411779714707b4d3
|
||||
config: 7a3415c9b6b46da1269550f16ddeb35c
|
||||
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.85 documentation</title>
|
||||
<title>Overview: module code — 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>
|
||||
|
||||
@@ -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 — osxphotos 0.42.84 documentation</title>
|
||||
<title>osxphotos.photoinfo._photoinfo_export — 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">"</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">"</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't have been incremented so</span>
|
||||
<span class="c1"># need to check here to make sure there aren'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>
|
||||
|
||||
@@ -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.85 documentation</title>
|
||||
<title>osxphotos.photoinfo.photoinfo — osxphotos 0.42.87 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>
|
||||
@@ -1141,11 +1141,15 @@
|
||||
<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">try</span><span class="p">:</span>
|
||||
<span class="n">personid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">"cloudownerhashedpersonid"</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="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_hashed_person_id</span><span class="p">[</span><span class="n">personid</span><span class="p">][</span><span class="s2">"full_name"</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">personid</span>
|
||||
<span class="k">else</span> <span class="kc">None</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyError</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="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>
|
||||
|
||||
@@ -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.84 documentation</title>
|
||||
<title>osxphotos.photosdb.photosdb — 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>
|
||||
@@ -1232,6 +1232,9 @@
|
||||
<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">"import_uuid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">44</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">"fok_import_session"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># photos 5+ only, for shared photos</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">"cloudownerhashedpersonid"</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># compute signatures for finding possible duplicates</span>
|
||||
<span class="n">signature</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_duplicate_signature</span><span class="p">(</span><span class="n">uuid</span><span class="p">)</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
@@ -1960,7 +1963,8 @@
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZTRASHEDDATE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZSAVEDASSETTYPE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZADDEDDATE,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK,</span>
|
||||
<span class="s2"> </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZCLOUDOWNERHASHEDPERSONID</span>
|
||||
<span class="s2"> FROM </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2"> </span>
|
||||
<span class="s2"> JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.Z_PK </span>
|
||||
<span class="s2"> ORDER BY </span><span class="si">{</span><span class="n">asset_table</span><span class="si">}</span><span class="s2">.ZUUID """</span>
|
||||
@@ -2010,6 +2014,7 @@
|
||||
<span class="c1"># 40 ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported</span>
|
||||
<span class="c1"># 41 ZGENERICASSET.ZADDEDDATE -- date item added to the library</span>
|
||||
<span class="c1"># 42 ZGENERICASSET.Z_PK -- primary key</span>
|
||||
<span class="c1"># 43 ZGENERICASSET.ZCLOUDOWNERHASHEDPERSONID -- used to look up owner name (for shared photos)</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">c</span><span class="p">:</span>
|
||||
<span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
@@ -2195,6 +2200,7 @@
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"added_date"</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="p">(</span><span class="mi">1970</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
|
||||
<span class="n">info</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">42</span><span class="p">]</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"cloudownerhashedpersonid"</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="mi">43</span><span class="p">]</span>
|
||||
|
||||
<span class="c1"># initialize import session info which will be filled in later</span>
|
||||
<span class="c1"># not every photo has an import session so initialize all records now</span>
|
||||
@@ -3323,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">""</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>
|
||||
|
||||
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.85',
|
||||
VERSION: '0.43.4',
|
||||
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.85 documentation</title>
|
||||
<title>osxphotos command line interface (CLI) — 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>
|
||||
@@ -1561,7 +1561,7 @@ if more than one option is provided, they are treated as “AND”
|
||||
</div>
|
||||
<div class="section" id="osxphotos-repl">
|
||||
<h3>repl<a class="headerlink" href="#osxphotos-repl" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Run interactive osxphotos shell</p>
|
||||
<p>Run interactive osxphotos REPL shell (useful for debugging, prototyping, and inspecting your Photos library)</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>osxphotos repl <span class="o">[</span>OPTIONS<span class="o">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -1572,6 +1572,12 @@ if more than one option is provided, they are treated as “AND”
|
||||
<dd><p>Specify Photos database path. Path to Photos library/database can be specified using either –db or directly as PHOTOS_LIBRARY positional argument. If neither –db or PHOTOS_LIBRARY provided, will attempt to find the library to use in the following order: 1. last opened library, 2. system library, 3. ~/Pictures/Photos Library.photoslibrary</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="std option">
|
||||
<dt class="sig sig-object std" id="cmdoption-osxphotos-repl-emacs">
|
||||
<span class="sig-name descname"><span class="pre">--emacs</span></span><span class="sig-prename descclassname"></span><a class="headerlink" href="#cmdoption-osxphotos-repl-emacs" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Launch REPL with Emacs keybindings (default is vi bindings)</p>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
<div class="section" id="osxphotos-tutorial">
|
||||
<h3>tutorial<a class="headerlink" href="#osxphotos-tutorial" title="Permalink to this headline">¶</a></h3>
|
||||
|
||||
@@ -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.85 documentation</title>
|
||||
<title>Index — 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>
|
||||
@@ -254,6 +254,13 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-export-edited-suffix">osxphotos-export command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
--emacs
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-repl-emacs">osxphotos-repl command line option</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
@@ -2104,6 +2111,8 @@
|
||||
|
||||
<ul>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-repl-db">--db <Photos database path></a>
|
||||
</li>
|
||||
<li><a href="cli.html#cmdoption-osxphotos-repl-emacs">--emacs</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
<li>
|
||||
|
||||
@@ -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.85 documentation</title>
|
||||
<title>Welcome to osxphotos’s documentation! — 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>
|
||||
|
||||
@@ -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.85 documentation</title>
|
||||
<title>osxphotos — 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>
|
||||
|
||||
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.85 documentation</title>
|
||||
<title>osxphotos package — 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>
|
||||
|
||||
@@ -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.85 documentation</title>
|
||||
<title>Search — 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" />
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -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
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.42.85"
|
||||
|
||||
__version__ = "0.43.5"
|
||||
|
||||
@@ -141,11 +141,17 @@ class AlbumInfoBaseClass:
|
||||
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
|
||||
try:
|
||||
personid = self._db._dbalbum_details[self.uuid][
|
||||
"cloudownerhashedpersonid"
|
||||
]
|
||||
self._owner = (
|
||||
self._db._db_hashed_person_id[personid]["full_name"]
|
||||
if personid
|
||||
else None
|
||||
)
|
||||
except KeyError:
|
||||
self._owner = None
|
||||
return self._owner
|
||||
|
||||
def __len__(self):
|
||||
|
||||
106
osxphotos/cli.py
106
osxphotos/cli.py
@@ -55,10 +55,11 @@ from .exiftool import get_exiftool_path
|
||||
from .export_db import ExportDB, ExportDBInMemory
|
||||
from .fileutil import FileUtil, FileUtilNoOp
|
||||
from .path_utils import is_valid_filepath, sanitize_filename, sanitize_filepath
|
||||
from .photoinfo import ExportResults
|
||||
from .photoinfo import ExportResults, PhotoInfo
|
||||
from .photokit import check_photokit_authorization, request_photokit_authorization
|
||||
from .photosalbum import PhotosAlbum
|
||||
from .phototemplate import PhotoTemplate, RenderOptions
|
||||
from .pyrepl import embed_repl
|
||||
from .queryoptions import QueryOptions
|
||||
from .uti import get_preferred_uti_extension
|
||||
from .utils import expand_and_validate_filepath, load_function
|
||||
@@ -4011,6 +4012,32 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
osxphotos uses the following 3rd party software licensed under the BSD-3-Clause License:
|
||||
Click (Copyright 2014 Pallets), ptpython (Copyright (c) 2015, Jonathan Slenders)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
of conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without specific prior
|
||||
written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
click.echo(f"osxphotos, version {__version__}")
|
||||
click.echo("")
|
||||
@@ -4032,7 +4059,7 @@ def tutorial(ctx, cli_obj, width):
|
||||
click.echo_via_pager(tutorial_help(width=width))
|
||||
|
||||
|
||||
def _show_photo(photo):
|
||||
def _show_photo(photo: PhotoInfo):
|
||||
"""open image with default image viewer
|
||||
|
||||
Note: This is for debugging only -- it will actually open any filetype which could
|
||||
@@ -4078,16 +4105,34 @@ def _get_selected(photosdb):
|
||||
return get_selected
|
||||
|
||||
|
||||
def _spotlight_photo(photo: PhotoInfo):
|
||||
photo_ = photoscript.Photo(photo.uuid)
|
||||
photo_.spotlight()
|
||||
|
||||
|
||||
@cli.command()
|
||||
@DB_OPTION
|
||||
@click.pass_obj
|
||||
@click.pass_context
|
||||
def repl(ctx, cli_obj, db):
|
||||
"""Run interactive osxphotos shell"""
|
||||
@click.option(
|
||||
"--emacs",
|
||||
required=False,
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Launch REPL with Emacs keybindings (default is vi bindings)",
|
||||
)
|
||||
def repl(ctx, cli_obj, db, emacs):
|
||||
"""Run interactive osxphotos REPL shell (useful for debugging, prototyping, and inspecting your Photos library)"""
|
||||
|
||||
from osxphotos import PhotosDB, PhotoInfo, ExifTool
|
||||
from objexplore import explore
|
||||
from photoscript import Album, Photo, PhotosLibrary
|
||||
from rich import inspect as _inspect
|
||||
|
||||
from osxphotos import ExifTool, PhotoInfo, PhotosDB
|
||||
from osxphotos.albuminfo import AlbumInfo
|
||||
from osxphotos.placeinfo import PlaceInfo
|
||||
from osxphotos.queryoptions import QueryOptions
|
||||
|
||||
pretty.install()
|
||||
print(f"python version: {sys.version}")
|
||||
print(f"osxphotos version: {osxphotos._version.__version__}")
|
||||
@@ -4102,6 +4147,7 @@ def repl(ctx, cli_obj, db):
|
||||
# shortcut for helper functions
|
||||
get_photo = photosdb.get_photo
|
||||
show = _show_photo
|
||||
spotlight = _spotlight_photo
|
||||
get_selected = _get_selected(photosdb)
|
||||
try:
|
||||
selected = get_selected()
|
||||
@@ -4113,17 +4159,9 @@ def repl(ctx, cli_obj, db):
|
||||
"""inspect object"""
|
||||
return _inspect(obj, methods=True)
|
||||
|
||||
class ReprQuit:
|
||||
def __repr__(self):
|
||||
sys.exit(0)
|
||||
|
||||
def __call__(self):
|
||||
sys.exit(0)
|
||||
|
||||
quit = ReprQuit()
|
||||
q = ReprQuit()
|
||||
|
||||
print(f"Found {len(photos)} photos in {tictoc:0.2f} seconds")
|
||||
print(f"Found {len(photos)} photos in {tictoc:0.2f} seconds\n")
|
||||
print("The following classes have been imported from osxphotos:")
|
||||
print("- AlbumInfo, ExifTool, PhotoInfo, PhotosDB, PlaceInfo, QueryOptions\n")
|
||||
print("The following variables are defined:")
|
||||
print(f"- photosdb: PhotosDB() instance for {photosdb.library_path}")
|
||||
print(
|
||||
@@ -4133,16 +4171,34 @@ def repl(ctx, cli_obj, db):
|
||||
f"- selected: list of PhotoInfo objects for any photos selected in Photos (len={len(selected)})"
|
||||
)
|
||||
print(f"\nThe following functions may be helpful:")
|
||||
print(f"- get_photo(uuid): return a PhotoInfo object for photo with uuid")
|
||||
print(
|
||||
f"- get_selected(): return list of PhotoInfo objects for photos selected in Photos"
|
||||
)
|
||||
print(f"- show(photo): open a photo object in the default viewer")
|
||||
print(
|
||||
f"- help(object): print help text including list of methods for object; for example, help(PhotosDB)"
|
||||
f"- get_photo(uuid): return a PhotoInfo object for photo with uuid; e.g. get_photo('B13F4485-94E0-41CD-AF71-913095D62E31')"
|
||||
)
|
||||
print(
|
||||
f"- inspect(object): print information about an object; for example inspect(photosdb)"
|
||||
f"- get_selected(); return list of PhotoInfo objects for photos selected in Photos"
|
||||
)
|
||||
print(
|
||||
f"- show(photo): open a photo object in the default viewer; e.g. show(selected[0])"
|
||||
)
|
||||
print(
|
||||
f"- show(path): open a file at path in the default viewer; e.g. show('/path/to/photo.jpg')"
|
||||
)
|
||||
print(f"- spotlight(photo): open a photo and spotlight it in Photos")
|
||||
# print(
|
||||
# f"- help(object): print help text including list of methods for object; for example, help(PhotosDB)"
|
||||
# )
|
||||
print(
|
||||
f"- inspect(object): print information about an object; e.g. inspect(PhotoInfo)"
|
||||
)
|
||||
print(
|
||||
f"- explore(object): interactively explore an object with objexplore; e.g. explore(PhotoInfo)"
|
||||
)
|
||||
print(f"- q, quit, quit(), exit, exit(): exit this interactive shell\n")
|
||||
|
||||
embed_repl(
|
||||
globals=globals(),
|
||||
locals=locals(),
|
||||
history_filename=str(pathlib.Path.home() / ".osxphotos_repl_history"),
|
||||
quit_words=["q", "quit", "exit"],
|
||||
vi_mode=not emacs,
|
||||
)
|
||||
print(f"- q, quit, or quit(): exit this interactive shell\n")
|
||||
code.interact(banner="", local=locals())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1108,11 +1108,15 @@ class PhotoInfo:
|
||||
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
|
||||
try:
|
||||
personid = self._info["cloudownerhashedpersonid"]
|
||||
self._owner = (
|
||||
self._db._db_hashed_person_id[personid]["full_name"]
|
||||
if personid
|
||||
else None
|
||||
)
|
||||
except KeyError:
|
||||
self._owner = None
|
||||
return self._owner
|
||||
|
||||
def render_template(
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -1199,6 +1199,9 @@ class PhotosDB:
|
||||
self._dbphotos[uuid]["import_uuid"] = row[44]
|
||||
self._dbphotos[uuid]["fok_import_session"] = None
|
||||
|
||||
# photos 5+ only, for shared photos
|
||||
self._dbphotos[uuid]["cloudownerhashedpersonid"] = None
|
||||
|
||||
# compute signatures for finding possible duplicates
|
||||
signature = self._duplicate_signature(uuid)
|
||||
try:
|
||||
@@ -1927,7 +1930,8 @@ class PhotosDB:
|
||||
{asset_table}.ZTRASHEDDATE,
|
||||
{asset_table}.ZSAVEDASSETTYPE,
|
||||
{asset_table}.ZADDEDDATE,
|
||||
{asset_table}.Z_PK
|
||||
{asset_table}.Z_PK,
|
||||
{asset_table}.ZCLOUDOWNERHASHEDPERSONID
|
||||
FROM {asset_table}
|
||||
JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = {asset_table}.Z_PK
|
||||
ORDER BY {asset_table}.ZUUID """
|
||||
@@ -1977,6 +1981,7 @@ class PhotosDB:
|
||||
# 40 ZGENERICASSET.ZSAVEDASSETTYPE -- how item imported
|
||||
# 41 ZGENERICASSET.ZADDEDDATE -- date item added to the library
|
||||
# 42 ZGENERICASSET.Z_PK -- primary key
|
||||
# 43 ZGENERICASSET.ZCLOUDOWNERHASHEDPERSONID -- used to look up owner name (for shared photos)
|
||||
|
||||
for row in c:
|
||||
uuid = row[0]
|
||||
@@ -2162,6 +2167,7 @@ class PhotosDB:
|
||||
info["added_date"] = datetime(1970, 1, 1)
|
||||
|
||||
info["pk"] = row[42]
|
||||
info["cloudownerhashedpersonid"] = row[43]
|
||||
|
||||
# initialize import session info which will be filled in later
|
||||
# not every photo has an import session so initialize all records now
|
||||
@@ -3290,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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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
|
||||
|
||||
131
osxphotos/pyrepl.py
Normal file
131
osxphotos/pyrepl.py
Normal file
@@ -0,0 +1,131 @@
|
||||
""" Custom Python REPL based on ptpython that allows quitting with custom keywords instead of `quit()` """
|
||||
|
||||
""" This file is distributed under the same license as the ptpython package:
|
||||
|
||||
Copyright (c) 2015, Jonathan Slenders (ptpython), (c) 2021 Rhet Turnbull (this file)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the {organization} nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from typing import Callable, List, Optional
|
||||
|
||||
from ptpython.repl import (
|
||||
ContextManager,
|
||||
DummyContext,
|
||||
PythonRepl,
|
||||
builtins,
|
||||
patch_stdout_context,
|
||||
)
|
||||
|
||||
|
||||
class PyReplQuitter(PythonRepl):
|
||||
"""Custom pypython repl that allows quitting REPL with custom commands"""
|
||||
|
||||
def __init__(self, *args, quit_words: Optional[List[str]] = None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.quit_words = quit_words or ["quit", "q"]
|
||||
|
||||
def eval(self, line: str) -> object:
|
||||
if line.strip() in self.quit_words:
|
||||
sys.exit(0)
|
||||
return super().eval(line)
|
||||
|
||||
|
||||
def embed_repl(
|
||||
globals=None,
|
||||
locals=None,
|
||||
configure: Optional[Callable[[PythonRepl], None]] = None,
|
||||
vi_mode: bool = False,
|
||||
history_filename: Optional[str] = None,
|
||||
title: Optional[str] = None,
|
||||
startup_paths=None,
|
||||
patch_stdout: bool = False,
|
||||
return_asyncio_coroutine: bool = False,
|
||||
quit_words: Optional[List[str]] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Call this to embed Python shell at the current point in your program.
|
||||
It's similar to `IPython.embed` and `bpython.embed`. ::
|
||||
from prompt_toolkit.contrib.repl import embed
|
||||
embed(globals(), locals())
|
||||
:param vi_mode: Boolean. Use Vi instead of Emacs key bindings.
|
||||
:param configure: Callable that will be called with the `PythonRepl` as a first
|
||||
argument, to trigger configuration.
|
||||
:param title: Title to be displayed in the terminal titlebar. (None or string.)
|
||||
:param patch_stdout: When true, patch `sys.stdout` so that background
|
||||
threads that are printing will print nicely above the prompt.
|
||||
"""
|
||||
# Default globals/locals
|
||||
if globals is None:
|
||||
globals = {
|
||||
"__name__": "__main__",
|
||||
"__package__": None,
|
||||
"__doc__": None,
|
||||
"__builtins__": builtins,
|
||||
}
|
||||
|
||||
locals = locals or globals
|
||||
|
||||
def get_globals():
|
||||
return globals
|
||||
|
||||
def get_locals():
|
||||
return locals
|
||||
|
||||
# Create REPL.
|
||||
repl = PyReplQuitter(
|
||||
get_globals=get_globals,
|
||||
get_locals=get_locals,
|
||||
vi_mode=vi_mode,
|
||||
history_filename=history_filename,
|
||||
startup_paths=startup_paths,
|
||||
quit_words=quit_words,
|
||||
)
|
||||
|
||||
if title:
|
||||
repl.terminal_title = title
|
||||
|
||||
if configure:
|
||||
configure(repl)
|
||||
|
||||
# Start repl.
|
||||
patch_context: ContextManager = (
|
||||
patch_stdout_context() if patch_stdout else DummyContext()
|
||||
)
|
||||
|
||||
if return_asyncio_coroutine:
|
||||
|
||||
async def coroutine():
|
||||
with patch_context:
|
||||
await repl.run_async()
|
||||
|
||||
return coroutine()
|
||||
else:
|
||||
with patch_context:
|
||||
repl.run()
|
||||
@@ -1,25 +1,23 @@
|
||||
-- Get the owner name of person who owns a photo in a shared album
|
||||
WITH case1 AS
|
||||
(
|
||||
-- Case where someone has invited you to a shared album
|
||||
-- Need to get the owner of the shared album
|
||||
SELECT ZGENERICALBUM.ZCLOUDOWNERFULLNAME as OWNER_FULLNAME
|
||||
FROM ZGENERICALBUM
|
||||
JOIN ${asset_table} ON ${asset_table}.ZCLOUDOWNERHASHEDPERSONID = ZGENERICALBUM.ZCLOUDOWNERHASHEDPERSONID
|
||||
WHERE ${asset_table}.ZUUID = "${uuid}"
|
||||
),
|
||||
case2 AS
|
||||
(
|
||||
-- Case where you have invited someone to a shared album
|
||||
-- Need to get the data for person who was invited to the album
|
||||
SELECT
|
||||
ZCLOUDSHAREDALBUMINVITATIONRECORD.ZINVITEEFULLNAME AS OWNER_FULLNAME
|
||||
FROM ZCLOUDSHAREDALBUMINVITATIONRECORD
|
||||
JOIN ${asset_table} ON ${asset_table}.ZCLOUDOWNERHASHEDPERSONID = ZCLOUDSHAREDALBUMINVITATIONRECORD.ZINVITEEHASHEDPERSONID
|
||||
WHERE ${asset_table}.ZUUID = "${uuid}"
|
||||
ORDER BY ZCLOUDSHAREDALBUMINVITATIONRECORD.Z_PK
|
||||
LIMIT 1
|
||||
)
|
||||
SELECT * FROM case1
|
||||
--
|
||||
-- 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
|
||||
SELECT * FROM case2 WHERE NOT EXISTS (SELECT * FROM case1)
|
||||
-- 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)"
|
||||
@@ -1,23 +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
|
||||
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
|
||||
@@ -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
|
||||
42
setup.py
42
setup.py
@@ -70,32 +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",
|
||||
"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,
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ pytestmark = pytest.mark.skipif(
|
||||
)
|
||||
|
||||
UUID_DICT = {
|
||||
"has_adjustments": "C925CFDC-FF2B-4E71-AC9D-C669B6453A8B",
|
||||
"no_adjustments": "16A6AF6B-D8FC-4256-AE33-889733E3EEAB",
|
||||
"live": "8EC216A2-0032-4934-BD3F-04C6259B3304",
|
||||
"has_adjustments": "C925CFDC-FF2B-4E71-AC9D-C669B6453A8B", # IMG_1929.JPG
|
||||
"no_adjustments": "16A6AF6B-D8FC-4256-AE33-889733E3EEAB", # IMG_9847.JPG
|
||||
"live": "8EC216A2-0032-4934-BD3F-04C6259B3304", # IMG_3259.HEIC
|
||||
}
|
||||
|
||||
UUID_BURSTS = {
|
||||
@@ -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"]])
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -266,13 +266,13 @@ 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 = {
|
||||
"4AD7C8EF-2991-4519-9D3A-7F44A6F031BE": [
|
||||
"None: Nice photo!",
|
||||
"Rhet Turnbull: Nice photo!",
|
||||
"None: Wish I was back here!",
|
||||
],
|
||||
"CCBE0EB9-AE9F-4479-BFFD-107042C75227": ["_"],
|
||||
|
||||
@@ -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
|
||||
|
||||
4
tox.ini
4
tox.ini
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user