Added --print to dump, added {tab}
This commit is contained in:
parent
320fb86559
commit
5eaeb72c3e
@ -3,11 +3,19 @@
|
||||
import click
|
||||
|
||||
import osxphotos
|
||||
from osxphotos.cli.click_rich_echo import (
|
||||
rich_click_echo,
|
||||
set_rich_console,
|
||||
set_rich_theme,
|
||||
)
|
||||
from osxphotos.phototemplate import RenderOptions
|
||||
from osxphotos.queryoptions import QueryOptions
|
||||
|
||||
from .color_themes import get_default_theme
|
||||
from .common import DB_ARGUMENT, DB_OPTION, DELETED_OPTIONS, JSON_OPTION, get_photos_db
|
||||
from .list import _list_libraries
|
||||
from .print_photo_info import print_photo_info
|
||||
from .verbose import get_verbose_console
|
||||
|
||||
|
||||
@click.command()
|
||||
@ -15,12 +23,30 @@ from .print_photo_info import print_photo_info
|
||||
@JSON_OPTION
|
||||
@DELETED_OPTIONS
|
||||
@DB_ARGUMENT
|
||||
@click.option(
|
||||
"--print",
|
||||
"print_template",
|
||||
metavar="TEMPLATE",
|
||||
multiple=True,
|
||||
help="Render TEMPLATE string for each photo queried and print to stdout. "
|
||||
"TEMPLATE is an osxphotos template string. "
|
||||
"This may be useful for creating custom reports, etc. "
|
||||
"If --print TEMPLATE is provided, regular output is suppressed "
|
||||
"and only the rendered TEMPLATE values are printed. "
|
||||
"May be repeated to print multiple template strings. ",
|
||||
)
|
||||
@click.pass_obj
|
||||
@click.pass_context
|
||||
def dump(ctx, cli_obj, db, json_, deleted, deleted_only, photos_library):
|
||||
def dump(
|
||||
ctx, cli_obj, db, json_, deleted, deleted_only, photos_library, print_template
|
||||
):
|
||||
"""Print list of all photos & associated info from the Photos library."""
|
||||
|
||||
db = get_photos_db(*photos_library, db, cli_obj.db)
|
||||
# below needed for to make CliRunner work for testing
|
||||
cli_db = cli_obj.db if cli_obj is not None else None
|
||||
cli_json = cli_obj.json if cli_obj is not None else None
|
||||
|
||||
db = get_photos_db(*photos_library, db, cli_db)
|
||||
if db is None:
|
||||
click.echo(ctx.obj.group.commands["dump"].get_help(ctx), err=True)
|
||||
click.echo("\n\nLocated the following Photos library databases: ", err=True)
|
||||
@ -33,6 +59,10 @@ def dump(ctx, cli_obj, db, json_, deleted, deleted_only, photos_library):
|
||||
click.echo(ctx.obj.group.commands["dump"].get_help(ctx), err=True)
|
||||
return
|
||||
|
||||
# set console for rich_echo to be same as for verbose_
|
||||
set_rich_console(get_verbose_console())
|
||||
set_rich_theme(get_default_theme())
|
||||
|
||||
photosdb = osxphotos.PhotosDB(dbfile=db)
|
||||
if deleted or deleted_only:
|
||||
photos = photosdb.photos(movies=True, intrash=True)
|
||||
@ -41,4 +71,22 @@ def dump(ctx, cli_obj, db, json_, deleted, deleted_only, photos_library):
|
||||
if not deleted_only:
|
||||
photos += photosdb.photos(movies=True)
|
||||
|
||||
print_photo_info(photos, json_ or cli_obj.json)
|
||||
if not print_template:
|
||||
# just dump and be done
|
||||
print_photo_info(photos, cli_json or json_)
|
||||
return
|
||||
|
||||
# have print template(s)
|
||||
options = RenderOptions()
|
||||
for p in photos:
|
||||
for template in print_template:
|
||||
rendered_templates, unmatched = p.render_template(
|
||||
template,
|
||||
options,
|
||||
)
|
||||
if unmatched:
|
||||
rich_click_echo(f"[warning]Unmatched template field: {unmatched}[/]")
|
||||
for rendered_template in rendered_templates:
|
||||
if not rendered_template:
|
||||
continue
|
||||
rich_click_echo(rendered_template)
|
||||
|
||||
@ -181,7 +181,8 @@ TEMPLATE_SUBSTITUTIONS = {
|
||||
"{newline}": r"A newline: '\n'",
|
||||
"{lf}": r"A line feed: '\n', alias for {newline}",
|
||||
"{cr}": r"A carriage return: '\r'",
|
||||
"{crlf}": r"a carriage return + line feed: '\r\n'",
|
||||
"{crlf}": r"A carriage return + line feed: '\r\n'",
|
||||
"{tab}": r":A tab: '\t'",
|
||||
"{osxphotos_version}": f"The osxphotos version, e.g. '{__version__}'",
|
||||
"{osxphotos_cmd_line}": "The full command line used to run osxphotos",
|
||||
}
|
||||
@ -312,6 +313,7 @@ PUNCTUATION = {
|
||||
"lf": "\n",
|
||||
"cr": "\r",
|
||||
"crlf": "\r\n",
|
||||
"tab": "\t",
|
||||
}
|
||||
|
||||
|
||||
|
||||
71
tests/test_cli_dump.py
Normal file
71
tests/test_cli_dump.py
Normal file
@ -0,0 +1,71 @@
|
||||
"""Test osxphotos dump command."""
|
||||
|
||||
import json
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
|
||||
from osxphotos.cli import dump
|
||||
from osxphotos.photosdb import PhotosDB
|
||||
|
||||
from .test_cli import CLI_PHOTOS_DB
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def photos():
|
||||
"""Return photos from CLI_PHOTOS_DB"""
|
||||
cwd = os.getcwd()
|
||||
db_path = os.path.join(cwd, CLI_PHOTOS_DB)
|
||||
return PhotosDB(db_path).photos(intrash=True)
|
||||
|
||||
|
||||
def test_dump_basic(photos):
|
||||
"""Test osxphotos dump"""
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
db_path = os.path.join(cwd, CLI_PHOTOS_DB)
|
||||
# pylint: disable=not-context-manager
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(dump, ["--db", db_path, "--deleted"])
|
||||
assert result.exit_code == 0
|
||||
assert result.output.startswith("uuid,filename")
|
||||
for photo in photos:
|
||||
assert photo.uuid in result.output
|
||||
|
||||
|
||||
def test_dump_json(photos):
|
||||
"""Test osxphotos dump --json"""
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
db_path = os.path.join(cwd, CLI_PHOTOS_DB)
|
||||
# pylint: disable=not-context-manager
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(dump, ["--db", db_path, "--deleted", "--json"])
|
||||
assert result.exit_code == 0
|
||||
json_data = {record["uuid"]: record for record in json.loads(result.output)}
|
||||
for photo in photos:
|
||||
assert photo.uuid in json_data
|
||||
|
||||
|
||||
def test_dump_print(photos):
|
||||
"""Test osxphotos dump --print"""
|
||||
runner = CliRunner()
|
||||
cwd = os.getcwd()
|
||||
db_path = os.path.join(cwd, CLI_PHOTOS_DB)
|
||||
# pylint: disable=not-context-manager
|
||||
with runner.isolated_filesystem():
|
||||
result = runner.invoke(
|
||||
dump,
|
||||
[
|
||||
"--db",
|
||||
db_path,
|
||||
"--deleted",
|
||||
"--print",
|
||||
"{uuid}_{photo.original_filename}",
|
||||
],
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
for photo in photos:
|
||||
assert f"{photo.uuid}_{photo.original_filename}" in result.output
|
||||
@ -8,12 +8,13 @@ import osxphotos
|
||||
from osxphotos.exiftool import get_exiftool_path
|
||||
from osxphotos.export_db import ExportDBInMemory
|
||||
from osxphotos.phototemplate import (
|
||||
PUNCTUATION,
|
||||
TEMPLATE_SUBSTITUTIONS,
|
||||
TEMPLATE_SUBSTITUTIONS_MULTI_VALUED,
|
||||
PhotoTemplate,
|
||||
RenderOptions,
|
||||
)
|
||||
|
||||
from osxphotos.photoinfo import PhotoInfoNone
|
||||
from .photoinfo_mock import PhotoInfoMock
|
||||
|
||||
try:
|
||||
@ -1345,3 +1346,16 @@ def test_bad_sslice(photosdb):
|
||||
# bad function raises ValueError
|
||||
with pytest.raises((SyntaxError, ValueError)):
|
||||
rendered, _ = photo.render_template("{photo.original_filename|sslice(1:2:3:4)}")
|
||||
|
||||
|
||||
def test_punctuation():
|
||||
"""Test punctuation template fields"""
|
||||
template_string = ""
|
||||
expected_string = ""
|
||||
for field, value in PUNCTUATION.items():
|
||||
template_string += "{" + field + "}"
|
||||
expected_string += f"{value}"
|
||||
template = PhotoTemplate(PhotoInfoNone())
|
||||
options = RenderOptions()
|
||||
rendered, _ = template.render(template_string, options)
|
||||
assert rendered == [expected_string]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user