diff --git a/README.md b/README.md index 5c30e70..100b7c9 100644 --- a/README.md +++ b/README.md @@ -348,6 +348,7 @@ See also git tags: https://github.com/jedie/manageprojects/tags [comment]: <> (✂✂✂ auto generated history start ✂✂✂) * [**dev**](https://github.com/jedie/manageprojects/compare/v0.19.2...main) + * 2024-09-27 - Replace click with tyro * 2024-09-25 - Add: test_pre_commit_hooks() * 2024-09-25 - Move git pre-commit hook from dev-cli.py to update command * [v0.19.2](https://github.com/jedie/manageprojects/compare/v0.19.1...v0.19.2) diff --git a/manageprojects/cli_app/__init__.py b/manageprojects/cli_app/__init__.py index 36393ef..75695ce 100644 --- a/manageprojects/cli_app/__init__.py +++ b/manageprojects/cli_app/__init__.py @@ -1,16 +1,18 @@ """ CLI for usage """ - +import dataclasses import logging import sys import rich_click as click from cli_base.autodiscover import import_all_files +from cli_base.cli_tools.rich_utils import rich_traceback_install from cli_base.cli_tools.version_info import print_version +from cli_base.tyro_commands import TyroCommandCli from rich import print # noqa from rich.console import Console -from rich.traceback import install as rich_traceback_install + from rich_click import RichGroup import manageprojects @@ -20,25 +22,14 @@ logger = logging.getLogger(__name__) -class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier? - def make_context(self, info_name, *args, **kwargs): - info_name = './cli.py' - return super().make_context(info_name, *args, **kwargs) - - -@click.group( - cls=ClickGroup, - epilog=constants.CLI_EPILOG, -) -def cli(): - pass +cli = TyroCommandCli() # Register all click commands, just by import all files in this package: import_all_files(package=__package__, init_file=__file__) -@cli.command() +@cli.register def version(): """Print version and exit""" # Pseudo command, because the version always printed on every CLI call ;) @@ -48,14 +39,10 @@ def version(): def main(): print_version(manageprojects) - console = Console() - rich_traceback_install( - width=console.size.width, # full terminal width - show_locals=True, - suppress=[click], - max_frames=2, - ) + rich_traceback_install() # Execute Click CLI: - cli.name = './cli.py' - cli() + cli.run( + prog='./cli.py', + description=constants.CLI_EPILOG, + ) diff --git a/manageprojects/cli_app/manage.py b/manageprojects/cli_app/manage.py index d708cee..5baa2ee 100644 --- a/manageprojects/cli_app/manage.py +++ b/manageprojects/cli_app/manage.py @@ -9,24 +9,14 @@ import subprocess import sys from pathlib import Path +from typing import Annotated -import rich_click as click from bx_py_utils.path import assert_is_dir from cli_base.cli_tools.subprocess_utils import verbose_check_call -from cli_base.cli_tools.verbosity import OPTION_KWARGS_VERBOSE -from cli_base.cli_tools.version_info import print_version -from cli_base.click_defaults import ( - ARGUMENT_EXISTING_DIR, - ARGUMENT_EXISTING_FILE, - ARGUMENT_NOT_EXISTING_DIR, - OPTION_ARGS_DEFAULT_FALSE, - OPTION_ARGS_DEFAULT_TRUE, -) +from cli_base.tyro_commands import TyroVerbosityArgType from rich import print # noqa -from rich.console import Console -from rich.traceback import install as rich_traceback_install +from tyro.conf import arg -import manageprojects from manageprojects.cli_app import cli from manageprojects.constants import ( FORMAT_PY_FILE_DARKER_PRE_FIXES, @@ -47,52 +37,55 @@ logger = logging.getLogger(__name__) -@cli.command() -@click.argument('template') -@click.argument('output_dir', **ARGUMENT_NOT_EXISTING_DIR) -@click.option( - '--directory', - default=None, - help=( - 'Cookiecutter Option: Directory within repo that holds cookiecutter.json file' - ' for advanced repositories with multi templates in it' +InputType = Annotated[ + bool, + arg( + help=( + 'Cookiecutter Option: Do not prompt for user input.' + ' Use default values for template parameters taken from `cookiecutter.json`.' + ) ), -) -@click.option( - '--checkout', - default=None, - help='Cookiecutter Option: branch, tag or commit to checkout after git clone', -) -@click.option( - '--input/--no-input', - **OPTION_ARGS_DEFAULT_TRUE, - help=('Cookiecutter Option: Do not prompt for parameters' ' and only use cookiecutter.json file content'), -) -@click.option( - '--replay/--no-replay', - **OPTION_ARGS_DEFAULT_FALSE, - help=('Cookiecutter Option: Do not prompt for parameters' ' and only use information entered previously'), -) -@click.option( - '--password', - default=None, - help='Cookiecutter Option: Password to use when extracting the repository', -) -@click.option( - '--config-file', - default=None, - type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), - help='Cookiecutter Option: Optional path to "cookiecutter_config.yaml"', -) +] +ConfigFileType = Annotated[ + Path, + arg(help='Cookiecutter Option: Optional path to "cookiecutter_config.yaml"'), +] +PasswordType = Annotated[ + str, + arg(help='Cookiecutter Option: Password to use when extracting the repository'), +] +CheckoutType = Annotated[ + str, + arg(help='Cookiecutter Option: Optional branch, tag or commit ID to checkout after clone'), +] + + +DirectoryType = Annotated[ + str, + arg( + help=( + 'Cookiecutter Option: Directory within repo that holds cookiecutter.json file' + ' for advanced repositories with multi templates in it' + ) + ), +] +ReplayType = Annotated[ + bool, + arg(help='Cookiecutter Option: Do not prompt for parameters and only use cookiecutter.json file content'), +] + + +@cli.register def start_project( template: str, + /, output_dir: Path, - directory: str | None, - checkout: str | None, - input: bool, - replay: bool, - password: str | None, - config_file: Path | None, + directory: str | None = None, + replay: ReplayType = False, + config_file: ConfigFileType | None = None, + password: PasswordType | None = None, + checkout: CheckoutType | None = None, + input: InputType = True, ): """ Start a new "managed" project via a CookieCutter Template. @@ -127,49 +120,32 @@ def start_project( return result -cli.add_command(start_project) +OverwriteType = Annotated[ + bool, + arg( + help=( + 'Overwrite all Cookiecutter template files to the last template state and' + ' do not apply the changes via git patches.' + ' The developer is supposed to apply the differences manually via git.' + ' Will be aborted if the project git repro is not in a clean state.' + ) + ), +] +CleanupType = Annotated[ + bool, + arg(help='Cleanup created temporary files'), +] -@cli.command() -@click.argument('project_path', **ARGUMENT_EXISTING_DIR) -@click.option( - '--overwrite/--no-overwrite', - **OPTION_ARGS_DEFAULT_TRUE, - help=( - 'Overwrite all Cookiecutter template files to the last template state and' - ' do not apply the changes via git patches.' - ' The developer is supposed to apply the differences manually via git.' - ' Will be aborted if the project git repro is not in a clean state.' - ), -) -@click.option( - '--password', - default=None, - help='Cookiecutter Option: Password to use when extracting the repository', -) -@click.option( - '--config-file', - default=None, - type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), - help='Cookiecutter Option: Optional path to "cookiecutter_config.yaml"', -) -@click.option( - '--input/--no-input', - **OPTION_ARGS_DEFAULT_FALSE, - help='Cookiecutter Option: Do not prompt for parameters and only use cookiecutter.json file content', -) -@click.option( - '--cleanup/--no-cleanup', - **OPTION_ARGS_DEFAULT_TRUE, - help='Cleanup created temporary files', -) +@cli.register def update_project( project_path: Path, - overwrite: bool, - password: str | None, - config_file: Path | None, - input: bool, - cleanup: bool, + /, + password: PasswordType | None, + config_file: ConfigFileType | None, + input: InputType, + overwrite: OverwriteType = True, + cleanup: CleanupType = True, ): """ Update a existing project. @@ -191,35 +167,15 @@ def update_project( print(f'Managed project "{project_path}" updated, ok.') -cli.add_command(update_project) - - -@cli.command() -@click.argument('project_path', **ARGUMENT_EXISTING_DIR) -@click.argument('output_dir', **ARGUMENT_NOT_EXISTING_DIR) -@click.option( - '--password', - default=None, - help='Cookiecutter Option: Password to use when extracting the repository', -) -@click.option( - '--config-file', - default=None, - type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), - help='Cookiecutter Option: Optional path to "cookiecutter_config.yaml"', -) -@click.option( - '--input/--no-input', - **OPTION_ARGS_DEFAULT_FALSE, - help=('Cookiecutter Option: Do not prompt for parameters' ' and only use cookiecutter.json file content'), -) +@cli.register def clone_project( project_path: Path, output_dir: Path, - input: bool, - checkout: str | None = None, - password: str | None = None, - config_file: Path | None = None, + /, + input: InputType = False, + checkout: CheckoutType | None = None, + password: PasswordType | None = None, + config_file: ConfigFileType | None = None, ): """ Clone existing project by replay the cookiecutter template in a new directory. @@ -240,23 +196,19 @@ def clone_project( ) -cli.add_command(clone_project) +OverwriteType = Annotated[ + bool, + arg(help='Overwrite existing files.'), +] -@cli.command() -@click.argument('project_path', **ARGUMENT_EXISTING_DIR) -@click.argument('destination', **ARGUMENT_NOT_EXISTING_DIR) -@click.option( - '--overwrite/--no-overwrite', - **OPTION_ARGS_DEFAULT_FALSE, - help='Overwrite existing files.', -) -@click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) +@cli.register def reverse( project_path: Path, destination: Path, - overwrite: bool, - verbosity: int, + /, + verbosity: TyroVerbosityArgType, + overwrite: OverwriteType = False, ): """ Create a cookiecutter template from a managed project. @@ -274,17 +226,14 @@ def reverse( ) -cli.add_command(reverse) +WordsType = Annotated[ + bool, + arg(help='wiggle Option: word-wise diff and merge.'), +] -@cli.command() -@click.argument('project_path', **ARGUMENT_EXISTING_DIR) -@click.option( - '--words/--no-words', - **OPTION_ARGS_DEFAULT_FALSE, - help='wiggle Option: word-wise diff and merge.', -) -def wiggle(project_path: Path, words: bool): +@cli.register +def wiggle(project_path: Path, /, words: WordsType = False): """ Run wiggle to merge *.rej in given directory. https://github.com/neilbrown/wiggle @@ -323,43 +272,32 @@ def wiggle(project_path: Path, words: bool): continue -cli.add_command(wiggle) - - -@cli.command() -@click.option( - '--py-version', - default=FORMAT_PY_FILE_DEFAULT_MIN_PYTHON_VERSION, - show_default=True, - help='Fallback Python version for darker/pyupgrade, if version is not defined in pyproject.toml', -) -@click.option( - '-l', - '--max-line-length', - default=FORMAT_PY_FILE_DEFAULT_MAX_LINE_LENGTH, - type=int, - show_default=True, - help='Fallback max. line length for darker/isort etc., if not defined in .editorconfig', -) -@click.option( - '--darker-prefixes', - default=FORMAT_PY_FILE_DARKER_PRE_FIXES, - show_default=True, - help='Apply prefixes via autopep8 before calling darker.', -) -@click.option( - '--remove-all-unused-imports', - help='Remove all unused imports (not just those from the standard library) via autoflake', - **OPTION_ARGS_DEFAULT_TRUE, -) -@click.argument('file_path', **ARGUMENT_EXISTING_FILE) +PyVersionType = Annotated[ + str, + arg(help='Fallback Python version for darker/pyupgrade, if version is not defined in pyproject.toml'), +] +MaxLineLengthType = Annotated[ + int, + arg(help='Fallback max. line length for darker/isort etc., if not defined in .editorconfig'), +] +DarkerPrefixesType = Annotated[ + str, + arg(help='Apply prefixes via autopep8 before calling darker.'), +] +RemoveAllUnusedImportsType = Annotated[ + bool, + arg(help='Remove all unused imports (not just those from the standard library) via autoflake'), +] + + +@cli.register def format_file( - *, - py_version: str, - max_line_length: int, - darker_prefixes: str, - remove_all_unused_imports: bool, - file_path: Path, + file_path: Annotated[Path, arg(help='The python source code file to format.')], + /, + py_version: PyVersionType = FORMAT_PY_FILE_DEFAULT_MIN_PYTHON_VERSION, + max_line_length: MaxLineLengthType = FORMAT_PY_FILE_DEFAULT_MAX_LINE_LENGTH, + darker_prefixes: DarkerPrefixesType = FORMAT_PY_FILE_DARKER_PRE_FIXES, + remove_all_unused_imports: RemoveAllUnusedImportsType = True, ): """ Format and check the given python source code file with darker/autoflake/isort/pyupgrade/autopep8/mypy etc. @@ -376,29 +314,8 @@ def format_file( ) -cli.add_command(format_file) - - -@cli.command() +@cli.register def version(): """Print version and exit""" # Pseudo command, because the version always printed on every CLI call ;) sys.exit(0) - - -cli.add_command(version) - - -def main(): - print_version(manageprojects) - console = Console() - rich_traceback_install( - width=console.size.width, # full terminal width - show_locals=True, - suppress=[click], - max_frames=2, - ) - - # Execute Click CLI: - cli.name = './cli.py' - cli() diff --git a/manageprojects/cli_app/update_readme_history.py b/manageprojects/cli_app/update_readme_history.py index 922f9b0..64421f8 100644 --- a/manageprojects/cli_app/update_readme_history.py +++ b/manageprojects/cli_app/update_readme_history.py @@ -8,7 +8,7 @@ from manageprojects.cli_app import cli -@cli.command() +@cli.register @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def update_readme_history(verbosity: int): """ diff --git a/manageprojects/cli_dev/__init__.py b/manageprojects/cli_dev/__init__.py index 531afc7..6687fd2 100644 --- a/manageprojects/cli_dev/__init__.py +++ b/manageprojects/cli_dev/__init__.py @@ -9,9 +9,11 @@ from bx_py_utils.path import assert_is_file from cli_base.autodiscover import import_all_files from cli_base.cli_tools.dev_tools import run_coverage, run_tox, run_unittest_cli +from cli_base.cli_tools.rich_utils import rich_traceback_install from cli_base.cli_tools.version_info import print_version +from cli_base.tyro_commands import TyroCommandCli from rich.console import Console -from rich.traceback import install as rich_traceback_install + from rich_click import RichGroup from typeguard import install_import_hook @@ -31,25 +33,14 @@ assert_is_file(PACKAGE_ROOT / 'pyproject.toml') # Exists only in cloned git repo -class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier? - def make_context(self, info_name, *args, **kwargs): - info_name = './dev-cli.py' - return super().make_context(info_name, *args, **kwargs) - - -@click.group( - cls=ClickGroup, - epilog=constants.CLI_EPILOG, -) -def cli(): - pass +cli = TyroCommandCli() # Register all click commands, just by import all files in this package: import_all_files(package=__package__, init_file=__file__) -@cli.command() +@cli.register def version(): """Print version and exit""" # Pseudo command, because the version always printed on every CLI call ;) @@ -59,13 +50,7 @@ def version(): def main(): print_version(manageprojects) - console = Console() - rich_traceback_install( - width=console.size.width, # full terminal width - show_locals=True, - suppress=[click], - max_frames=2, - ) + rich_traceback_install() if len(sys.argv) >= 2: # Check if we can just pass a command call to origin CLI: @@ -78,5 +63,7 @@ def main(): if real_func := command_map.get(command): real_func(argv=sys.argv, exit_after_run=True) - # Execute Click CLI: - cli() + cli.run( + prog='./dev-cli.py', + description=constants.CLI_EPILOG, + ) diff --git a/manageprojects/cli_dev/code_style.py b/manageprojects/cli_dev/code_style.py index 01bf7a0..b3f9381 100644 --- a/manageprojects/cli_dev/code_style.py +++ b/manageprojects/cli_dev/code_style.py @@ -6,7 +6,7 @@ from manageprojects.cli_dev import PACKAGE_ROOT, cli -@cli.command() +@cli.register @click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE) @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def fix_code_style(color: bool, verbosity: int): @@ -16,7 +16,7 @@ def fix_code_style(color: bool, verbosity: int): code_style.fix(package_root=PACKAGE_ROOT, darker_color=color, darker_verbose=verbosity > 0) -@cli.command() +@cli.register @click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE) @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def check_code_style(color: bool, verbosity: int): diff --git a/manageprojects/cli_dev/git_hooks.py b/manageprojects/cli_dev/git_hooks.py index 01be66a..b0bfe01 100644 --- a/manageprojects/cli_dev/git_hooks.py +++ b/manageprojects/cli_dev/git_hooks.py @@ -2,7 +2,7 @@ from manageprojects.format_file import ToolsExecutor -@cli.command() +@cli.register def git_hooks(): """ Setup our "pre-commit" git hooks @@ -11,7 +11,7 @@ def git_hooks(): executor.verbose_check_call('pre-commit', 'install') -@cli.command() +@cli.register def run_git_hooks(): """ Run the installed "pre-commit" git hooks diff --git a/manageprojects/cli_dev/packaging.py b/manageprojects/cli_dev/packaging.py index 884444b..5b595f7 100644 --- a/manageprojects/cli_dev/packaging.py +++ b/manageprojects/cli_dev/packaging.py @@ -12,7 +12,7 @@ from manageprojects.utilities.publish import publish_package -@cli.command() +@cli.register def install(): """ Run pip-sync and install 'manageprojects' via pip as editable. @@ -21,7 +21,7 @@ def install(): verbose_check_call('pip', 'install', '--no-deps', '-e', '.') -@cli.command() +@cli.register @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def pip_audit(verbosity: int): """ @@ -30,7 +30,7 @@ def pip_audit(verbosity: int): run_pip_audit(base_path=PACKAGE_ROOT, verbosity=verbosity) -@cli.command() +@cli.register def update(): """ Update "requirements*.txt" dependencies files @@ -71,10 +71,10 @@ def update(): verbose_check_call(bin_path / 'pip-sync', 'requirements.dev.txt') # Update git pre-commit hooks: - verbose_check_call(bin_path / 'pre_commit', 'autoupdate') + verbose_check_call(bin_path / 'pre-commit', 'autoupdate') -@cli.command() +@cli.register def publish(): """ Build and upload this project to PyPi diff --git a/manageprojects/cli_dev/testing.py b/manageprojects/cli_dev/testing.py index 62437eb..02b3efb 100644 --- a/manageprojects/cli_dev/testing.py +++ b/manageprojects/cli_dev/testing.py @@ -7,14 +7,14 @@ from manageprojects.cli_dev import PACKAGE_ROOT, cli -@cli.command() +@cli.register @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def mypy(verbosity: int): """Run Mypy (configured in pyproject.toml)""" verbose_check_call('mypy', '.', cwd=PACKAGE_ROOT, verbose=verbosity > 0, exit_on_error=True) -@cli.command() +@cli.register @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def update_test_snapshot_files(verbosity: int): """ @@ -32,7 +32,7 @@ def update_test_snapshot_files(verbosity: int): ) -@cli.command() # Dummy command +@cli.register # Dummy command def test(): """ Run unittests @@ -40,7 +40,7 @@ def test(): run_unittest_cli() -@cli.command() # Dummy command +@cli.register # Dummy command def coverage(): """ Run tests and show coverage report. @@ -48,7 +48,7 @@ def coverage(): run_coverage() -@cli.command() # Dummy "tox" command +@cli.register # Dummy "tox" command def tox(): """ Run tox diff --git a/manageprojects/cli_dev/update_readme_history.py b/manageprojects/cli_dev/update_readme_history.py index b49765c..7b2196d 100644 --- a/manageprojects/cli_dev/update_readme_history.py +++ b/manageprojects/cli_dev/update_readme_history.py @@ -8,7 +8,7 @@ from manageprojects.cli_dev import cli -@cli.command() +@cli.register @click.option('-v', '--verbosity', **OPTION_KWARGS_VERBOSE) def update_readme_history(verbosity: int): """ diff --git a/manageprojects/utilities/log_utils.py b/manageprojects/utilities/log_utils.py index fa1efe8..db2b2f4 100644 --- a/manageprojects/utilities/log_utils.py +++ b/manageprojects/utilities/log_utils.py @@ -27,7 +27,7 @@ def print_log_info(filename): print(f'\nLog file created here: {filename}\n') -def log_config( +def log_config( # TODO: Merge with cli_base.cli_tools.verbosity.setup_logging level=logging.DEBUG, format='%(asctime)s %(levelname)s %(name)s.%(funcName)s %(lineno)d | %(message)s', log_in_file=True, diff --git a/pyproject.toml b/pyproject.toml index 26a367c..9e4d496 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "codespell", # https://github.com/codespell-project/codespell "mypy", # https://github.com/python/mypy - "cli-base-utilities", # https://github.com/jedie/cli-base-utilities + "cli-base-utilities>=0.13.1", # https://github.com/jedie/cli-base-utilities "click", # https://github.com/pallets/click/ "rich-click", # https://github.com/ewels/rich-click "rich", # https://github.com/Textualize/rich diff --git a/requirements.dev.txt b/requirements.dev.txt index d22f2be..2e18741 100644 --- a/requirements.dev.txt +++ b/requirements.dev.txt @@ -14,11 +14,6 @@ astor==0.8.1 \ --hash=sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5 \ --hash=sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e # via flynt -async-timeout==4.0.3 \ - --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ - --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 \ - --hash=sha256:fd893e4cb1d9dff66d0e0576cc6376a23eacbbcd43b6607e4d3ecfae1ab15367 - # via cli-base-utilities attrs==24.2.0 \ --hash=sha256:09df292052496e45c3edea6e1046968c7e5231b5fee8106a49f950b42dd5eeef \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ @@ -151,6 +146,7 @@ cffi==1.17.1 \ --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \ --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \ --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \ + --hash=sha256:da2e6428aa89f81b9a97c5818e7e5875f2c40bef6abbbe17e0d768199aa943f1 \ --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \ --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \ --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \ @@ -274,10 +270,10 @@ charset-normalizer==3.3.2 \ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests -cli-base-utilities==0.11.0 \ - --hash=sha256:22c01bffece11781db0cba2110e9bf721361d50fb8a877bd251422ebaf3daee9 \ - --hash=sha256:2c674f3af4898f97d101f6687fb45e85a4b996b93fb9a155a29b4daaf302dc43 \ - --hash=sha256:fc503f8df7e19653167ebd12551718aa0c114114b959f177be2092eab1ce1b11 +cli-base-utilities==0.13.1 \ + --hash=sha256:1b5774764e6fea194b5fd36fee1325dba22abf37e8634cdba548d7ebc8a28627 \ + --hash=sha256:a0142b46ced685fda8e7393c90d2cb1a709ea7ae37469249e3f519bd8c7844e2 \ + --hash=sha256:abb265fee788af0e347395bd9c863370df04ddc6b8aff97e77841c994f5daee6 # via manageprojects (pyproject.toml) click==8.1.7 \ --hash=sha256:8e38806544348fdafedd47e92e90aca882377a0680918dec4c80c225a0e5ed13 \ @@ -435,6 +431,10 @@ distlib==0.3.8 \ --hash=sha256:0444bad8dcf71ec6c3281939ed79fe8a3a278dd0745b8e6d1374d038dd5d64c7 \ --hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64 # via virtualenv +docstring-parser==0.16 \ + --hash=sha256:538beabd0af1e2db0146b6bd3caa526c35a34d61af9fd2887f3a8a27a739aa6e \ + --hash=sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637 + # via tyro docutils==0.21.2 \ --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 \ @@ -980,18 +980,22 @@ rich==13.8.1 \ # pip-audit # rich-click # twine + # tyro rich-click==1.8.3 \ --hash=sha256:636d9c040d31c5eee242201b5bf4f2d358bfae4db14bb22ec1cafa717cfd02cd \ --hash=sha256:6d75bdfa7aa9ed2c467789a0688bc6da23fbe3a143e19aa6ad3f8bac113d2ab3 \ --hash=sha256:ef50d4087a5a4f1e7fcee7972f78775e9b33c0709a86dc10f9f5b929ba4d51b8 - # via - # cli-base-utilities - # manageprojects (pyproject.toml) + # via manageprojects (pyproject.toml) secretstorage==3.3.3 \ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \ --hash=sha256:cd7ed5cdeb3e5d7f18a7651500e0fec895205ae9c0abf7e5e63f6768d69418a2 \ --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99 # via keyring +shtab==1.7.1 \ + --hash=sha256:32d3d2ff9022d4c77a62492b6ec875527883891e33c6b479ba4d41a51e259983 \ + --hash=sha256:4e4bcb02eeb82ec45920a5d0add92eac9c9b63b2804c9196c1f1fdc2d039243c \ + --hash=sha256:60d06a16bf25f675d374b87fb0c020aaa13bc01f0e2f279541feeb7155db5141 + # via tyro six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -1018,10 +1022,6 @@ toml==0.10.2 \ # darker # darkgraylib # pip-audit -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via cli-base-utilities tomlkit==0.13.2 \ --hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde \ --hash=sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79 @@ -1054,6 +1054,12 @@ typing-extensions==4.12.2 \ # mypy # rich-click # typeguard + # tyro +tyro==0.8.11 \ + --hash=sha256:0a8dd180e6afcd5df9d9f940b7e6225f67ceb348678d49df9df00a59576174fb \ + --hash=sha256:241d95789733107829e7ea7c24727863db2e61aa74cf9b2251c85f4e7abccd4c \ + --hash=sha256:486e6ed6672df2222303877a39a498e8f0fc762cdb9deacac67320c44a8eba45 + # via cli-base-utilities urllib3==2.2.3 \ --hash=sha256:53042b594bc77c4b5d43f598b9eca1333bf4f884c300473192f4d4f47bab1d2d \ --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \ diff --git a/requirements.txt b/requirements.txt index 5acabfa..de31515 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,11 +14,6 @@ astor==0.8.1 \ --hash=sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5 \ --hash=sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e # via flynt -async-timeout==4.0.3 \ - --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ - --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 \ - --hash=sha256:fd893e4cb1d9dff66d0e0576cc6376a23eacbbcd43b6607e4d3ecfae1ab15367 - # via cli-base-utilities attrs==24.2.0 \ --hash=sha256:09df292052496e45c3edea6e1046968c7e5231b5fee8106a49f950b42dd5eeef \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ @@ -169,10 +164,10 @@ charset-normalizer==3.3.2 \ --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \ --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561 # via requests -cli-base-utilities==0.11.0 \ - --hash=sha256:22c01bffece11781db0cba2110e9bf721361d50fb8a877bd251422ebaf3daee9 \ - --hash=sha256:2c674f3af4898f97d101f6687fb45e85a4b996b93fb9a155a29b4daaf302dc43 \ - --hash=sha256:fc503f8df7e19653167ebd12551718aa0c114114b959f177be2092eab1ce1b11 +cli-base-utilities==0.13.1 \ + --hash=sha256:1b5774764e6fea194b5fd36fee1325dba22abf37e8634cdba548d7ebc8a28627 \ + --hash=sha256:a0142b46ced685fda8e7393c90d2cb1a709ea7ae37469249e3f519bd8c7844e2 \ + --hash=sha256:abb265fee788af0e347395bd9c863370df04ddc6b8aff97e77841c994f5daee6 # via manageprojects (pyproject.toml) click==8.1.7 \ --hash=sha256:8e38806544348fdafedd47e92e90aca882377a0680918dec4c80c225a0e5ed13 \ @@ -206,6 +201,10 @@ darkgraylib==1.2.1 \ # via # darker # graylint +docstring-parser==0.16 \ + --hash=sha256:538beabd0af1e2db0146b6bd3caa526c35a34d61af9fd2887f3a8a27a739aa6e \ + --hash=sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637 + # via tyro editorconfig==0.12.4 \ --hash=sha256:24857fa1793917dd9ccf0c7810a07e05404ce9b823521c7dce22a4fb5d125f80 \ --hash=sha256:bc3762aae43e78db19a28f21438d90d176e8a7a78b62c4b9b01b36c796863e9f @@ -492,13 +491,17 @@ rich==13.8.1 \ # cookiecutter # manageprojects (pyproject.toml) # rich-click + # tyro rich-click==1.8.3 \ --hash=sha256:636d9c040d31c5eee242201b5bf4f2d358bfae4db14bb22ec1cafa717cfd02cd \ --hash=sha256:6d75bdfa7aa9ed2c467789a0688bc6da23fbe3a143e19aa6ad3f8bac113d2ab3 \ --hash=sha256:ef50d4087a5a4f1e7fcee7972f78775e9b33c0709a86dc10f9f5b929ba4d51b8 - # via - # cli-base-utilities - # manageprojects (pyproject.toml) + # via manageprojects (pyproject.toml) +shtab==1.7.1 \ + --hash=sha256:32d3d2ff9022d4c77a62492b6ec875527883891e33c6b479ba4d41a51e259983 \ + --hash=sha256:4e4bcb02eeb82ec45920a5d0add92eac9c9b63b2804c9196c1f1fdc2d039243c \ + --hash=sha256:60d06a16bf25f675d374b87fb0c020aaa13bc01f0e2f279541feeb7155db5141 + # via tyro six==1.16.0 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 @@ -518,10 +521,6 @@ toml==0.10.2 \ # via # darker # darkgraylib -tomli==2.0.1 \ - --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ - --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f - # via cli-base-utilities tomlkit==0.13.2 \ --hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde \ --hash=sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79 @@ -539,6 +538,12 @@ typing-extensions==4.12.2 \ # via # mypy # rich-click + # tyro +tyro==0.8.11 \ + --hash=sha256:0a8dd180e6afcd5df9d9f940b7e6225f67ceb348678d49df9df00a59576174fb \ + --hash=sha256:241d95789733107829e7ea7c24727863db2e61aa74cf9b2251c85f4e7abccd4c \ + --hash=sha256:486e6ed6672df2222303877a39a498e8f0fc762cdb9deacac67320c44a8eba45 + # via cli-base-utilities urllib3==2.2.3 \ --hash=sha256:53042b594bc77c4b5d43f598b9eca1333bf4f884c300473192f4d4f47bab1d2d \ --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \