* Added query_command and example * Refactored QUERY_OPTIONS, added query_command, refactored verbose, #930, #931 * Added query options to debug-dump, #966 * Refactored query, #602 * Added precedence test for --load-config * Refactored handling of query options * Refactored export_photo * Removed extraneous print * Updated API_README * Updated examples
161 lines
6.0 KiB
Python
161 lines
6.0 KiB
Python
"""Sample query command for osxphotos
|
|
|
|
This shows how simple it is to create a command line tool using osxphotos to process your photos.
|
|
|
|
Using the @query_command decorator turns your function to a full-fledged command line app that
|
|
can be run via `osxphotos run cli_example_2.py` or `python cli_example_2.py` if you have pip installed osxphotos.
|
|
|
|
Using this decorator makes it very easy to create a quick command line tool that can operate on
|
|
a subset of your photos. Additionally, writing a command in this way makes it easy to later
|
|
incorporate the command into osxphotos as a full-fledged command.
|
|
|
|
The decorator will add all the query options available in `osxphotos query` as command line options
|
|
as well as the following options:
|
|
--verbose
|
|
--timestamp
|
|
--theme
|
|
--db
|
|
--debug (hidden, won't show in help)
|
|
|
|
The decorated function will perform the query and pass the list of filtered PhotoInfo objects
|
|
to your function. You can then do whatever you want with the photos.
|
|
|
|
For example, to run the command on only selected photos:
|
|
|
|
osxphotos run cli_example_2.py --selected
|
|
|
|
To run the command on all photos with the keyword "foo":
|
|
|
|
osxphotos run cli_example_2.py --keyword foo
|
|
|
|
The following helper functions may be useful and can be imported from osxphotos.cli:
|
|
|
|
abort(message: str, exit_code: int = 1)
|
|
Abort with error message and exit code
|
|
echo(message: str)
|
|
Print message to stdout using rich formatting
|
|
echo_error(message: str)
|
|
Print message to stderr using rich formatting
|
|
logger: logging.Logger
|
|
Python logger for osxphotos; for example, logger.debug("debug message")
|
|
verbose(*args, level: int = 1)
|
|
Print args to stdout if --verbose option is set
|
|
query_command: decorator to create an osxphotos query command
|
|
kvstore(name: str) -> SQLiteKVStore useful for storing state between runs
|
|
|
|
The verbose, echo, and echo_error functions use rich formatting to print messages to stdout and stderr.
|
|
See https://github.com/Textualize/rich for more information on rich formatting.
|
|
|
|
In addition to standard rich formatting styles, the following styles will be defined
|
|
(and can be changed using --theme):
|
|
|
|
[change]: something change
|
|
[no_change]: indicate no change
|
|
[count]: a count
|
|
[error]: an error
|
|
[filename]: a filename
|
|
[filepath]: a filepath
|
|
[num]: a number
|
|
[time]: a time or date
|
|
[tz]: a timezone
|
|
[warning]: a warning
|
|
[uuid]: a uuid
|
|
|
|
The tags should be closed with [/] to end the style. For example:
|
|
|
|
echo("[filename]foo[/] [time]bar[/]")
|
|
|
|
For simpler examples, see `cli_example_1.py`
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import datetime
|
|
|
|
import click
|
|
|
|
import osxphotos
|
|
from osxphotos.cli import (
|
|
abort,
|
|
echo,
|
|
echo_error,
|
|
kvstore,
|
|
logger,
|
|
query_command,
|
|
verbose,
|
|
)
|
|
|
|
|
|
@query_command()
|
|
@click.option(
|
|
"--resume",
|
|
is_flag=True,
|
|
help="Resume processing from last run, do not reprocess photos",
|
|
)
|
|
@click.option(
|
|
"--dry-run", is_flag=True, help="Do a dry run, don't actually do anything"
|
|
)
|
|
def example(resume, dry_run, photos: list[osxphotos.PhotoInfo], **kwargs):
|
|
"""Sample query command for osxphotos. Prints out the filename and date of each photo.
|
|
|
|
Whatever text you put in the function's docstring here, will be used as the command's
|
|
help text when run via `osxphotos run cli_example_2.py --help` or `python cli_example_2.py --help`
|
|
|
|
The @query_command decorator returns a click.command so you can add additional options
|
|
using standard click decorators. For example, the --resume and --dry-run options.
|
|
For more information on click, see https://palletsprojects.com/p/click/.
|
|
"""
|
|
|
|
# abort will print the message to stderr and exit with the given exit code
|
|
if not photos:
|
|
abort("Nothing to do!", 1)
|
|
|
|
# verbose() will print to stdout if --verbose option is set
|
|
# you can optionally provide a level (default is 1) to print only if --verbose is set to that level
|
|
# for example: -VV or --verbose --verbose == level 2
|
|
verbose(f"Found [count]{len(photos)}[/] photos")
|
|
verbose("This message will only be printed if verbose level 2 is set", level=2)
|
|
|
|
# the logger is a python logging.Logger object
|
|
# debug messages will only be printed if --debug option is set
|
|
logger.debug(f"{kwargs=}")
|
|
|
|
# kvstore() returns a SQLiteKVStore object for storing state between runs
|
|
# this is basically a persistent dictionary that can be used to store state
|
|
# see https://github.com/RhetTbull/sqlitekvstore for more information
|
|
kv = kvstore("cli_example_2")
|
|
verbose(f"Using key-value cache: {kv.path}")
|
|
|
|
# do something with photos here
|
|
for photo in photos:
|
|
# photos is a list of PhotoInfo objects
|
|
# see: https://rhettbull.github.io/osxphotos/reference.html#osxphotos.PhotoInfo
|
|
if resume and photo.uuid in kv:
|
|
echo(
|
|
f"Skipping processed photo [filename]{photo.original_filename}[/] ([uuid]{photo.uuid}[/])"
|
|
)
|
|
continue
|
|
|
|
# store the uuid and current time in the kvstore
|
|
# the key and value must be a type supported by SQLite: int, float, str, bytes, bool, None
|
|
# if you need to store other values, you should serialize them to a string or bytes first
|
|
# for example, using json.dumps() or pickle.dumps()
|
|
kv[photo.uuid] = datetime.datetime.now().isoformat()
|
|
echo(f"Processing [filename]{photo.original_filename}[/] [time]{photo.date}[/]")
|
|
if not dry_run:
|
|
# do something with the photo here
|
|
echo(f"Doing something with [filename]{photo.original_filename}[/]")
|
|
|
|
# echo_error will print to stderr
|
|
# if you add [warning] or [error], it will be formatted accordingly
|
|
# and include an emoji to make the message stand out
|
|
echo_error("[warning]This is a warning message!")
|
|
echo_error("[error]This is an error message!")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# call your function here
|
|
# you do not need to pass any arguments to the function
|
|
# as the decorator will handle parsing the command line arguments
|
|
example()
|