Added --profile, --watch, --breakpoint, --debug as global options (#917)

This commit is contained in:
Rhet Turnbull 2023-01-13 17:49:30 -08:00 committed by GitHub
parent 106b258c6d
commit 4b3433fc20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 71 deletions

View File

@ -1,4 +1,5 @@
"""cli package for osxphotos"""
import sys
from rich import print
@ -26,13 +27,13 @@ for func_name in args.get("--watch", []):
wrap_function(func_name, debug_watch)
print(f"Watching {func_name}")
except AttributeError:
print(f"{func_name} does not exist")
print(f"{func_name} does not exist", file=sys.stderr)
sys.exit(1)
for func_name in args.get("--breakpoint", []):
try:
wrap_function(func_name, debug_breakpoint)
print(f"Breakpoint added for {func_name}")
print(f"Breakpoint added for {func_name}", file=sys.stderr)
except AttributeError:
print(f"{func_name} does not exist")
sys.exit(1)
@ -40,7 +41,7 @@ for func_name in args.get("--breakpoint", []):
args = get_debug_flags(["--debug"], sys.argv)
if args.get("--debug", False):
set_debug(True)
print("Debugging enabled")
print("Debugging enabled", file=sys.stderr)
from .about import about
from .albums import albums

View File

@ -1,7 +1,13 @@
"""Command line interface for osxphotos """
import atexit
import cProfile
import io
import pstats
import click
from osxphotos._constants import PROFILE_SORT_KEYS
from osxphotos._version import __version__
from .about import about
@ -33,6 +39,7 @@ from .timewarp import timewarp
from .tutorial import tutorial
from .uuid import uuid
from .version import version
from .common import DEBUG_OPTIONS
# Click CLI object & context settings
@ -47,20 +54,51 @@ CTX_SETTINGS = dict(help_option_names=["-h", "--help"])
@click.group(context_settings=CTX_SETTINGS)
@click.version_option(__version__, "--version", "-v")
@DB_OPTION
@JSON_OPTION
@DEBUG_OPTIONS
@click.option(
"--debug",
required=False,
is_flag=True,
help="Enable debug output",
hidden=OSXPHOTOS_HIDDEN,
"--profile", is_flag=True, hidden=OSXPHOTOS_HIDDEN, help="Enable profiling"
)
@click.option(
"--profile-sort",
default=None,
hidden=OSXPHOTOS_HIDDEN,
multiple=True,
metavar="SORT_KEY",
type=click.Choice(
PROFILE_SORT_KEYS,
case_sensitive=True,
),
help="Sort profiler output by SORT_KEY as specified at https://docs.python.org/3/library/profile.html#pstats.Stats.sort_stats. "
f"Can be specified multiple times. Valid options are: {PROFILE_SORT_KEYS}. "
"Default = 'cumulative'.",
)
@click.version_option(__version__, "--version", "-v")
@click.pass_context
def cli_main(ctx, db, json_, debug):
"""osxphotos: query and export your Photos library"""
def cli_main(ctx, db, json_, profile, profile_sort, **kwargs):
"""osxphotos: the multi-tool for your Photos library"""
# Note: kwargs is used to catch any debug options passed in
# the debug options are handled in cli/__init__.py
# before this function is called
ctx.obj = CLI_Obj(db=db, json=json_, group=cli_main)
if profile:
click.echo("Profiling...")
profile_sort = profile_sort or ["cumulative"]
click.echo(f"Profile sort_stats order: {profile_sort}")
pr = cProfile.Profile()
pr.enable()
def at_exit():
pr.disable()
click.echo("Profiling completed")
s = io.StringIO()
pstats.Stats(pr, stream=s).strip_dirs().sort_stats(
*profile_sort
).print_stats()
click.echo(s.getvalue())
atexit.register(at_exit)
# install CLI commands

View File

@ -570,18 +570,24 @@ def DEBUG_OPTIONS(f):
),
o(
"--watch",
metavar="FUNCTION_PATH",
metavar="MODULE::NAME",
multiple=True,
help="Watch function calls. For example, to watch all calls to FileUtil.copy: "
"'--watch osxphotos.fileutil.FileUtil.copy'. More than one --watch option can be specified.",
help="Watch function or method calls. The function to watch must be in the form "
"MODULE::NAME where MODULE is the module path and NAME is the function or method name "
"contained in the module. For example, to watch all calls to FileUtil.copy() which is in "
"osxphotos.fileutil, use: "
"'--watch osxphotos.fileutil::FileUtil.copy'. More than one --watch option can be specified.",
hidden=OSXPHOTOS_HIDDEN,
),
o(
"--breakpoint",
metavar="FUNCTION_PATH",
metavar="MODULE::NAME",
multiple=True,
help="Add breakpoint to function calls. For example, to add breakpoint to FileUtil.copy: "
"'--breakpoint osxphotos.fileutil.FileUtil.copy'. More than one --breakpoint option can be specified.",
help="Add breakpoint to function calls. The function to watch must be in the form "
"MODULE::NAME where MODULE is the module path and NAME is the function or method name "
"contained in the module. For example, to set a breakpoint for calls to "
"FileUtil.copy() which is in osxphotos.fileutil, use: "
"'--breakpoint osxphotos.fileutil::FileUtil.copy'. More than one --breakpoint option can be specified.",
hidden=OSXPHOTOS_HIDDEN,
),
]

View File

@ -1,12 +1,7 @@
"""export command for osxphotos CLI"""
import atexit
import cProfile
import csv
import io
import os
import pathlib
import pstats
import shlex
import subprocess
import sys
@ -47,7 +42,7 @@ from osxphotos.configoptions import (
)
from osxphotos.crash_reporter import crash_reporter, set_crash_data
from osxphotos.datetime_formatter import DateTimeFormatter
from osxphotos.debug import is_debug, set_debug
from osxphotos.debug import is_debug
from osxphotos.exiftool import get_exiftool_path
from osxphotos.export_db import ExportDB, ExportDBInMemory
from osxphotos.fileutil import FileUtil, FileUtilNoOp, FileUtilShUtil
@ -78,7 +73,6 @@ from .common import (
CLI_COLOR_WARNING,
DB_ARGUMENT,
DB_OPTION,
DEBUG_OPTIONS,
DELETED_OPTIONS,
JSON_OPTION,
OSXPHOTOS_CRASH_LOG,
@ -713,29 +707,7 @@ from .verbose import get_verbose_console, time_stamp, verbose_print
hidden=OSXPHOTOS_HIDDEN,
help="Enable beta options.",
)
@click.option(
"--profile",
is_flag=True,
default=False,
hidden=OSXPHOTOS_HIDDEN,
help="Run export with code profiler.",
)
@click.option(
"--profile-sort",
default=None,
hidden=OSXPHOTOS_HIDDEN,
multiple=True,
metavar="SORT_KEY",
type=click.Choice(
PROFILE_SORT_KEYS,
case_sensitive=True,
),
help="Sort profiler output by SORT_KEY as specified at https://docs.python.org/3/library/profile.html#pstats.Stats.sort_stats. "
f"Can be specified multiple times. Valid options are: {PROFILE_SORT_KEYS}. "
"Default = 'cumulative'.",
)
@THEME_OPTION
@DEBUG_OPTIONS
@DB_ARGUMENT
@click.argument("dest", nargs=1, type=click.Path(exists=True))
@click.pass_obj
@ -865,8 +837,6 @@ def export(
preview_if_missing,
preview_suffix,
print_template,
profile,
profile_sort,
query_eval,
query_function,
ramdb,
@ -908,9 +878,9 @@ def export(
verbose,
xattr_template,
year,
debug, # debug, watch, breakpoint handled in cli/__init__.py
watch,
breakpoint,
# debug, # debug, watch, breakpoint handled in cli/__init__.py
# watch,
# breakpoint,
):
"""Export photos from the Photos database.
Export path DEST is required.
@ -936,27 +906,8 @@ def export(
# capture locals for use with ConfigOptions before changing any of them
locals_ = locals()
set_crash_data("locals", locals_)
if profile:
click.echo("Profiling...")
profile_sort = profile_sort or ["cumulative"]
click.echo(f"Profile sort_stats order: {profile_sort}")
pr = cProfile.Profile()
pr.enable()
def at_exit():
pr.disable()
click.echo("Profiling completed")
s = io.StringIO()
pstats.Stats(pr, stream=s).strip_dirs().sort_stats(
*profile_sort
).print_stats()
click.echo(s.getvalue())
atexit.register(at_exit)
# NOTE: because of the way ConfigOptions works, Click options must not
# set defaults which are not None or False. If defaults need to be set
# do so below after load_config and save_config are handled.

View File

@ -49,7 +49,7 @@ def debug_breakpoint(wrapped, instance, args, kwargs):
def wrap_function(function_path, wrapper):
"""Wrap a function with wrapper function"""
module, name = function_path.split(".", 1)
module, name = function_path.split("::", 1)
try:
return wrapt.wrap_function_wrapper(module, name, wrapper)
except AttributeError as e: