Added --profile, --watch, --breakpoint, --debug as global options (#917)
This commit is contained in:
parent
106b258c6d
commit
4b3433fc20
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
),
|
||||
]
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user