Compare commits

..

49 Commits

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

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

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

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

Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
2021-10-11 15:55:49 -07:00
Rhet Turnbull
4a81e643a7 Updated CHANGELOG.md [skip ci] 2021-10-11 07:35:51 -07:00
Rhet Turnbull
b23e74f8f5 Updated docs [skip ci] 2021-10-11 07:32:15 -07:00
Rhet Turnbull
5dc766249a Updated dependencies 2021-10-10 23:05:53 -07:00
Rhet Turnbull
a895833c7f Updated dependencies 2021-10-10 22:27:00 -07:00
Rhet Turnbull
3f81a3c179 Added python 3.10 to supported versions 2021-10-09 09:39:23 -07:00
Rhet Turnbull
f1235f745f Updated CHANGELOG.md [skip ci] 2021-09-30 06:13:40 -07:00
Rhet Turnbull
1ddb1de998 Updated docs [skip ci] 2021-09-30 06:11:00 -07:00
Rhet Turnbull
c472698b1d Updated REPL, now with more cowbell 2021-09-30 05:59:03 -07:00
Rhet Turnbull
4e021a0731 Updated CHANGELOG.md [skip ci] 2021-09-26 15:57:07 -07:00
Rhet Turnbull
bfbc156821 Updated docs [skip ci] 2021-09-26 15:55:03 -07:00
Rhet Turnbull
bfd6274602 Fixed AlbumInfo.owner, #239 2021-09-26 15:52:38 -07:00
Rhet Turnbull
3abaa5ae84 Updated docs [skip ci] 2021-09-26 15:43:22 -07:00
Rhet Turnbull
65115a50a9 Updated CHANGELOG.md [skip ci] 2021-09-26 15:00:34 -07:00
Rhet Turnbull
06138e15d0 version bump 2021-09-26 14:56:10 -07:00
Rhet Turnbull
14710e3178 Performance fix for #239, owner 2021-09-26 14:55:43 -07:00
Rhet Turnbull
f705f09749 Updated CHANGELOG.md [skip ci] 2021-09-26 14:54:59 -07:00
Rhet Turnbull
82c445f41e Updated CHANGELOG.md [skip ci] 2021-09-26 14:29:36 -07:00
Rhet Turnbull
1b40e9d65f Fixed tests for comment fix 2021-09-26 14:07:35 -07:00
Rhet Turnbull
725f7c8735 Updated docs [skip ci] 2021-09-26 14:00:46 -07:00
Rhet Turnbull
7cc8578148 Merge branch 'master' of github.com:RhetTbull/osxphotos 2021-09-26 13:53:32 -07:00
Rhet Turnbull
6adafb8ce7 Fixed formatting 2021-09-26 13:53:21 -07:00
Rhet Turnbull
ac47df8475 Fix for #517, #239 2021-09-26 13:51:47 -07:00
Rhet Turnbull
f680cf78ab Removed macOS-11, need to fix detected_text test 2021-09-26 09:06:17 -07:00
Rhet Turnbull
c86e84c534 Removed python 3.10-dev, not available in GH 2021-09-26 08:06:32 -07:00
Rhet Turnbull
3fb611825c Added python 3.10, macOS 11 2021-09-26 07:53:32 -07:00
Rhet Turnbull
1cfdad0176 Updated CHANGELOG.md [skip ci] 2021-09-25 22:51:30 -07:00
49 changed files with 740 additions and 332 deletions

View File

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

View File

@@ -4,6 +4,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

View File

@@ -4,7 +4,9 @@
[![tests](https://github.com/RhetTbull/osxphotos/workflows/Tests/badge.svg)](https://github.com/RhetTbull/osxphotos/workflows/Tests/badge.svg)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/osxphotos)
[![Downloads](https://static.pepy.tech/personalized-badge/osxphotos?period=month&units=international_system&left_color=black&right_color=brightgreen&left_text=downloads/month)](https://pepy.tech/project/osxphotos)
[![All Contributors](https://img.shields.io/badge/all_contributors-26-orange.svg?style=flat)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-28-orange.svg?style=flat)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
OSXPhotos provides the ability to interact with and query Apple's Photos.app library on macOS. You can query the Photos library database — for example, file name, file path, and metadata such as keywords/tags, persons/faces, albums, etc. You can also easily export both the original and edited photos.
@@ -1258,8 +1260,8 @@ s
** Templating System **
The templating system converts one or template statements, written in osxphotos
templating language, to one or more rendered values using information from the
photo being processed.
metadata templating language, to one or more rendered values using information
from the photo being processed.
In its simplest form, a template statement has the form: "{template_field}", for
example "{title}" which would resolve to the title of the photo.
@@ -1702,7 +1704,7 @@ Substitution Description
{lf} A line feed: '\n', alias for {newline}
{cr} A carriage return: '\r'
{crlf} a carriage return + line feed: '\r\n'
{osxphotos_version} The osxphotos version, e.g. '0.42.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

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photoinfo._photoinfo_export &#8212; osxphotos 0.42.84 documentation</title>
<title>osxphotos.photoinfo._photoinfo_export &#8212; osxphotos 0.43.4 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
@@ -945,7 +945,14 @@
<span class="n">preview_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path_derivatives</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="n">preview_ext</span> <span class="o">=</span> <span class="n">preview_path</span><span class="o">.</span><span class="n">suffix</span>
<span class="n">preview_name</span> <span class="o">=</span> <span class="n">dest</span><span class="o">.</span><span class="n">parent</span> <span class="o">/</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">dest</span><span class="o">.</span><span class="n">stem</span><span class="si">}{</span><span class="n">preview_suffix</span><span class="si">}{</span><span class="n">preview_ext</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">preview_name</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">increment_filename</span><span class="p">(</span><span class="n">preview_name</span><span class="p">))</span>
<span class="c1"># if original is missing, the filename won&#39;t have been incremented so</span>
<span class="c1"># need to check here to make sure there aren&#39;t duplicate preview files in</span>
<span class="c1"># the export directory</span>
<span class="n">preview_name</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">preview_name</span>
<span class="k">if</span> <span class="n">overwrite</span> <span class="ow">or</span> <span class="n">update</span>
<span class="k">else</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">increment_filename</span><span class="p">(</span><span class="n">preview_name</span><span class="p">))</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">preview_path</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_export_photo</span><span class="p">(</span>
<span class="n">preview_path</span><span class="p">,</span>
@@ -1292,6 +1299,7 @@
<span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="n">PHOTOS_VERSION_CURRENT</span><span class="p">,</span>
<span class="n">overwrite</span><span class="o">=</span><span class="n">overwrite</span><span class="p">,</span>
<span class="n">video</span><span class="o">=</span><span class="n">live_photo</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">all_results</span><span class="o">.</span><span class="n">exported</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">exported</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
@@ -1339,6 +1347,7 @@
<span class="n">dest</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="n">PHOTOS_VERSION_ORIGINAL</span><span class="p">,</span>
<span class="n">overwrite</span><span class="o">=</span><span class="n">overwrite</span><span class="p">,</span>
<span class="n">video</span><span class="o">=</span><span class="n">live_photo</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">all_results</span><span class="o">.</span><span class="n">exported</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">exported</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photoinfo.photoinfo &#8212; osxphotos 0.42.85 documentation</title>
<title>osxphotos.photoinfo.photoinfo &#8212; 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">&quot;shared_owner&quot;</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">&quot;cloudownerhashedpersonid&quot;</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">&quot;full_name&quot;</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>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.42.84 documentation</title>
<title>osxphotos.photosdb.photosdb &#8212; osxphotos 0.42.92 documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="../../../_static/alabaster.css" />
<script data-url_root="../../../" id="documentation_options" src="../../../_static/documentation_options.js"></script>
@@ -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">&quot;import_uuid&quot;</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">&quot;fok_import_session&quot;</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">&quot;cloudownerhashedpersonid&quot;</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 &quot;&quot;&quot;</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">&quot;added_date&quot;</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">&quot;pk&quot;</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">&quot;cloudownerhashedpersonid&quot;</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">&quot;&quot;</span><span class="p">)</span>
<span class="n">photo_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">regex</span><span class="p">,</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">options</span><span class="o">.</span><span class="n">regex</span><span class="p">:</span>
<span class="n">regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">flags</span><span class="p">)</span>
<span class="n">photo_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span><span class="p">:</span>
<span class="n">rendered</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">render_template</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">render_options</span><span class="p">)</span>
<span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">rendered</span><span class="p">:</span>

View File

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

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>osxphotos command line interface (CLI) &#8212; osxphotos 0.42.85 documentation</title>
<title>osxphotos command line interface (CLI) &#8212; osxphotos 0.43.4 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
@@ -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>

View File

@@ -5,7 +5,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &#8212; osxphotos 0.42.85 documentation</title>
<title>Index &#8212; osxphotos 0.43.4 documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/alabaster.css" />
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
@@ -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 &lt;Photos database path&gt;</a>
</li>
<li><a href="cli.html#cmdoption-osxphotos-repl-emacs">--emacs</a>
</li>
</ul></li>
<li>

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -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):

View File

@@ -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())

View File

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

View File

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

View File

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

View File

@@ -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(

View File

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

View File

@@ -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()

View File

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

View File

@@ -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:

View File

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

View File

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

View File

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

131
osxphotos/pyrepl.py Normal file
View 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()

View File

@@ -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)"

View File

@@ -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

View File

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

View File

@@ -70,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,

View File

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

View File

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

View File

@@ -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,
}
}

View File

@@ -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"]])

View File

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

View File

@@ -266,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": ["_"],

View File

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

View File

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